Skip to content

fix(admin-ui): fix admin-ui build error#2417

Closed
duttarnab wants to merge 6 commits intomainfrom
admin-ui-2413
Closed

fix(admin-ui): fix admin-ui build error#2417
duttarnab wants to merge 6 commits intomainfrom
admin-ui-2413

Conversation

@duttarnab
Copy link
Contributor

@duttarnab duttarnab commented Nov 5, 2025

error log https://jenkins.gluu.org/jenkins/job/gluu-admin-ui/2664/console

ERROR in ./plugins/auth-server/components/Scopes/ScopeAddPage.test.tsx 51:29
Module parse failed: Unexpected token (51:29)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| })
| 
> const Wrapper = ({ children }: { children: React.ReactNode }) => (
|   <AppTestWrapper>
|     <Provider store={store}>{children}</Provider>
 @ ./plugins/ sync ^.*$ ./auth-server/components/Scopes/ScopeAddPage.test.tsx ./auth-server/components/Scopes/ScopeAddPage.test
 @ ./plugins/PluginReducersResolver.js 17:84-108
 @ ./app/redux/store/index.ts 10:0-53 33:0-7
 @ ./app/components/App/AppMain.tsx
 @ ./app/components/App/index.ts 2:0-32 3:15-22
 @ ./app/index.tsx 2:0-35 33:34-37

ERROR in ./plugins/auth-server/components/Scopes/ScopeDetailPage.test.tsx 6:12
Module parse failed: Unexpected token (6:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import scopes from './scopes.test'
| import AppTestWrapper from 'Routes/Apps/Gluu/Tests/Components/AppTestWrapper.test'
> import type { Scope } from './types'
| 
| const Wrapper = ({ children }: { children: React.ReactNode }) => (
 @ ./plugins/ sync ^.*$ ./auth-server/components/Scopes/ScopeDetailPage.test.tsx ./auth-server/components/Scopes/ScopeDetailPage.test
 @ ./plugins/PluginReducersResolver.js 17:84-108
 @ ./app/redux/store/index.ts 10:0-53 33:0-7
 @ ./app/components/App/AppMain.tsx
 @ ./app/components/App/index.ts 2:0-32 3:15-22
 @ ./app/index.tsx 2:0-35 33:34-37

ERROR in ./plugins/auth-server/components/Scopes/ScopeEditPage.test.tsx 8:12
Module parse failed: Unexpected token (8:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import AppTestWrapper from 'Routes/Apps/Gluu/Tests/Components/AppTestWrapper.test'
| import { combineReducers, configureStore } from '@reduxjs/toolkit'
> import type { Scope } from './types'
| import { BrowserRouter } from 'react-router-dom'
| 
 @ ./plugins/ sync ^.*$ ./auth-server/components/Scopes/ScopeEditPage.test.tsx ./auth-server/components/Scopes/ScopeEditPage.test
 @ ./plugins/PluginReducersResolver.js 17:84-108
 @ ./app/redux/store/index.ts 10:0-53 33:0-7
 @ ./app/components/App/AppMain.tsx
 @ ./app/components/App/index.ts 2:0-32 3:15-22
 @ ./app/index.tsx 2:0-35 33:34-37

ERROR in ./plugins/auth-server/components/Scopes/ScopeListPage.test.tsx 8:12
Module parse failed: Unexpected token (8:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import AppTestWrapper from 'Routes/Apps/Gluu/Tests/Components/AppTestWrapper.test'
| import { combineReducers, configureStore } from '@reduxjs/toolkit'
> import type { Scope } from './types'
| 
| // Mock orval hooks
 @ ./plugins/ sync ^.*$ ./auth-server/components/Scopes/ScopeListPage.test.tsx ./auth-server/components/Scopes/ScopeListPage.test
 @ ./plugins/PluginReducersResolver.js 17:84-108
 @ ./app/redux/store/index.ts 10:0-53 33:0-7
 @ ./app/components/App/AppMain.tsx
 @ ./app/components/App/index.ts 2:0-32 3:15-22
 @ ./app/index.tsx 2:0-35 33:34-37

ERROR in ./plugins/auth-server/components/Scopes/scopes.test.ts 1:12
Module parse failed: Unexpected token (1:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> import type { Scope } from './types'
| 
| export const scopes: Partial<Scope>[] = [
 @ ./plugins/ sync ^.*$ ./auth-server/components/Scopes/scopes.test.ts ./auth-server/components/Scopes/scopes.test
 @ ./plugins/PluginReducersResolver.js 17:84-108
 @ ./app/redux/store/index.ts 10:0-53 33:0-7
 @ ./app/components/App/AppMain.tsx
 @ ./app/components/App/index.ts 2:0-32 3:15-22
 @ ./app/index.tsx 2:0-35 33:34-37

webpack 5.102.1 compiled with 5 errors in 149571 ms
Build step 'Execute shell' marked build as failure
Finished: FAILURE

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced error handling during plugin loading with improved logging for failed loads
  • Chores

    • Transitioned plugin system from synchronous to fully asynchronous loading for improved reliability
    • Removed test files from production bundles to optimize build size
    • Eliminated legacy synchronous plugin loading fallback mechanisms

@duttarnab duttarnab requested a review from syntrydy as a code owner November 5, 2025 13:23
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

📝 Walkthrough

Walkthrough

Plugin loading infrastructure transitions from synchronous to asynchronous approaches. Synchronous fallback methods are removed, and webpack configuration adds test file exclusion rules to prevent test files from being bundled. Dynamic imports replace require calls with Promise-based loading patterns.

Changes

Cohort / File(s) Summary
Route Configuration
admin-ui/app/routes/index.tsx
Removes processRoutesSync from imports, replaces synchronous error fallback with empty array default and descriptive error logging.
Webpack Build Configuration
admin-ui/config/webpack.config.client.dev.ts
Expands Babel/loader exclusion rules to skip test files (.test.ts, .test.tsx, .test.js); adds dedicated ignore-loader rule for test files.
Plugin Menu Resolution
admin-ui/plugins/PluginMenuResolver.js
Removes processMenusSync() and processRoutesSync() synchronous methods; adds webpackExclude pattern to dynamic imports to skip test files.
Plugin Reducers Resolution
admin-ui/plugins/PluginReducersResolver.js
Converts process() from synchronous to async function; replaces synchronous require-based registration with sequential dynamic imports per plugin and awaited reducer registration.
Plugin Sagas Resolution
admin-ui/plugins/PluginSagasResolver.js
Converts process() from synchronous to async function; replaces synchronous file loading with concurrent dynamic imports per plugin using Promise.allSettled for aggregated result collection.

Sequence Diagram

sequenceDiagram
    participant App as App Route
    participant OldFlow as Old (Sync)
    participant NewFlow as New (Async)
    
    rect rgb(240, 248, 255)
    Note over OldFlow: Synchronous Flow
    App->>OldFlow: Load plugin routes
    OldFlow->>OldFlow: processRoutes() (sync require)
    alt Success
        OldFlow-->>App: Return routes
    else Error
        OldFlow->>OldFlow: Fallback to processRoutesSync()
        OldFlow-->>App: Return routes
    end
    end
    
    rect rgb(240, 255, 240)
    Note over NewFlow: Asynchronous Flow
    App->>NewFlow: Load plugin routes
    NewFlow->>NewFlow: processRoutes() (async)
    NewFlow->>NewFlow: for each plugin: dynamic import
    activate NewFlow
    NewFlow-->>NewFlow: Promise.allSettled()
    deactivate NewFlow
    alt Success
        NewFlow-->>App: Return routes
    else Error
        NewFlow->>NewFlow: Log error
        NewFlow-->>App: Return empty array
    end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • PluginReducersResolver.js: Sequential async conversion with per-plugin dynamic imports and individual reducer registration requires careful verification of execution order and error isolation.
  • PluginSagasResolver.js: Promise.allSettled pattern and concurrent import collection need review for proper error handling and result aggregation.
  • PluginMenuResolver.js: Removal of synchronous fallback methods eliminates safety net; verify all callers handle async-only API.
  • Webpack configuration: Regex pattern changes and loader ordering should be validated to ensure test files are properly excluded from all build paths.

Poem

🐰 From sync to async, the plugins now hop,
Promises settle as bundle tests stop,
No more fallbacks in the synchronous way,
Dynamic imports make loading delays okay! 🚀

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(admin-ui): fix admin-ui build error' accurately reflects the main objective of the PR—fixing a build failure in the admin-ui caused by Webpack parsing errors in test files.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch admin-ui-2413

Comment @coderabbitai help to get the list of available commands and usage tips.

@mo-auto mo-auto added comp-admin-ui Component affected by issue or PR kind-bug Issue or PR is a bug in existing functionality labels Nov 5, 2025
@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 5, 2025

@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 5, 2025

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f760fe5 and 066841c.

📒 Files selected for processing (5)
  • admin-ui/app/routes/index.tsx (2 hunks)
  • admin-ui/config/webpack.config.client.dev.ts (2 hunks)
  • admin-ui/plugins/PluginMenuResolver.js (2 hunks)
  • admin-ui/plugins/PluginReducersResolver.js (1 hunks)
  • admin-ui/plugins/PluginSagasResolver.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
admin-ui/plugins/PluginSagasResolver.js (2)
admin-ui/plugins/PluginMenuResolver.js (4)
  • pluginPromises (7-26)
  • pluginPromises (42-60)
  • results (28-28)
  • results (62-62)
admin-ui/plugins/PluginReducersResolver.js (2)
  • pluginName (9-9)
  • metadata (11-16)
🔇 Additional comments (1)
admin-ui/config/webpack.config.client.dev.ts (1)

193-196: Ensure the new loader is available.

Please double‑check that ignore-loader is listed in devDependencies; otherwise the build will fail with “Cannot resolve module 'ignore-loader'” when this rule runs.

Comment on lines +4 to +24
async function process() {
const metadataFilePath = plugins.map((item) => item.metadataFile)
let pluginReducers = []
metadataFilePath.forEach(async (path) => {
pluginReducers = await [...pluginReducers, ...require(`${path}`).default.reducers]

pluginReducers.forEach((element) => {
reducerRegistry.register(element.name, element.reducer)
})
})
for (const path of metadataFilePath) {
const pluginName = path?.match(/\.\/([^/]+)\/plugin-metadata/)?.[1]
if (pluginName) {
const metadata = await import(
/* webpackChunkName: "plugin-[request]" */
/* webpackMode: "lazy" */
/* webpackExclude: /\.test\.(js|jsx|ts|tsx)$/ */
`./${pluginName}/plugin-metadata`
)
const reducers = metadata.default.reducers || []
pluginReducers = [...pluginReducers, ...reducers]

reducers.forEach((element) => {
reducerRegistry.register(element.name, element.reducer)
})
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Return the reducer list.

process() now resolves to undefined, but the rest of the codebase still expects an array of plugin reducers. Even in this file we keep building pluginReducers, so this looks accidental. Add return pluginReducers at the end (after the loop) so callers aren’t broken.

 async function process() {
   const metadataFilePath = plugins.map((item) => item.metadataFile)
   let pluginReducers = []
 
   for (const path of metadataFilePath) {
     const pluginName = path?.match(/\.\/([^/]+)\/plugin-metadata/)?.[1]
     if (pluginName) {
       const metadata = await import(
         /* webpackChunkName: "plugin-[request]" */
         /* webpackMode: "lazy" */
         /* webpackExclude: /\.test\.(js|jsx|ts|tsx)$/ */
         `./${pluginName}/plugin-metadata`
       )
       const reducers = metadata.default.reducers || []
       pluginReducers = [...pluginReducers, ...reducers]
 
       reducers.forEach((element) => {
         reducerRegistry.register(element.name, element.reducer)
       })
     }
   }
+  return pluginReducers
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function process() {
const metadataFilePath = plugins.map((item) => item.metadataFile)
let pluginReducers = []
metadataFilePath.forEach(async (path) => {
pluginReducers = await [...pluginReducers, ...require(`${path}`).default.reducers]
pluginReducers.forEach((element) => {
reducerRegistry.register(element.name, element.reducer)
})
})
for (const path of metadataFilePath) {
const pluginName = path?.match(/\.\/([^/]+)\/plugin-metadata/)?.[1]
if (pluginName) {
const metadata = await import(
/* webpackChunkName: "plugin-[request]" */
/* webpackMode: "lazy" */
/* webpackExclude: /\.test\.(js|jsx|ts|tsx)$/ */
`./${pluginName}/plugin-metadata`
)
const reducers = metadata.default.reducers || []
pluginReducers = [...pluginReducers, ...reducers]
reducers.forEach((element) => {
reducerRegistry.register(element.name, element.reducer)
})
}
}
async function process() {
const metadataFilePath = plugins.map((item) => item.metadataFile)
let pluginReducers = []
for (const path of metadataFilePath) {
const pluginName = path?.match(/\.\/([^/]+)\/plugin-metadata/)?.[1]
if (pluginName) {
const metadata = await import(
/* webpackChunkName: "plugin-[request]" */
/* webpackMode: "lazy" */
/* webpackExclude: /\.test\.(js|jsx|ts|tsx)$/ */
`./${pluginName}/plugin-metadata`
)
const reducers = metadata.default.reducers || []
pluginReducers = [...pluginReducers, ...reducers]
reducers.forEach((element) => {
reducerRegistry.register(element.name, element.reducer)
})
}
}
return pluginReducers
}
🤖 Prompt for AI Agents
In admin-ui/plugins/PluginReducersResolver.js around lines 4 to 24, the async
function process builds pluginReducers but never returns it, causing callers to
receive undefined; add a final statement returning pluginReducers after the
for-loop so the function resolves to the array of reducers that the rest of the
code expects.

Comment on lines +8 to +24
for (const path of metadataFilePath) {
const pluginName = path?.match(/\.\/([^/]+)\/plugin-metadata/)?.[1]
if (pluginName) {
const metadata = await import(
/* webpackChunkName: "plugin-[request]" */
/* webpackMode: "lazy" */
/* webpackExclude: /\.test\.(js|jsx|ts|tsx)$/ */
`./${pluginName}/plugin-metadata`
)
const reducers = metadata.default.reducers || []
pluginReducers = [...pluginReducers, ...reducers]

reducers.forEach((element) => {
reducerRegistry.register(element.name, element.reducer)
})
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Bring back the fallback import.

Same concern as in the sagas resolver: without importing item.metadataFile when the regex misses, reducers shipped in plugins with non-standard metadata paths stop registering. Please add the fallback import branch so behaviour stays consistent with the menu resolver.

🤖 Prompt for AI Agents
In admin-ui/plugins/PluginReducersResolver.js around lines 8 to 24, the code
only imports plugin metadata when the path matches the regex and skips importing
item.metadataFile for non-standard paths, causing reducers from plugins with
custom metadata locations to not register; add a fallback branch that imports
the original path (e.g., await import(item.metadataFile)) when pluginName is not
found by the regex, then extract metadata.default.reducers from that fallback
import, append them to pluginReducers and register each reducer with
reducerRegistry.register exactly as done for the regex-success path so behavior
matches the menu resolver.

Comment on lines +8 to +21
const pluginPromises = plugins.map(async (item) => {
const path = item.metadataFile
const pluginName = path?.match(/\.\/([^/]+)\/plugin-metadata/)?.[1]
if (pluginName) {
const metadata = await import(
/* webpackChunkName: "plugin-[request]" */
/* webpackMode: "lazy" */
/* webpackExclude: /\.test\.(js|jsx|ts|tsx)$/ */
`./${pluginName}/plugin-metadata`
)
return metadata.default.sagas || []
}
return []
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Restore the metadata fallback.

Previously we supported plugin entries whose metadataFile didn’t follow ./<plugin>/plugin-metadata by importing item.metadataFile directly (see the menu resolver’s fallback). Dropping that path here means those plugins now return [] and their sagas never load. Please reintroduce the fallback import (ideally inside a try/catch) so non-standard metadataFile paths keep working.

🤖 Prompt for AI Agents
In admin-ui/plugins/PluginSagasResolver.js around lines 8 to 21, the code only
imports metadata when metadataFile matches "./<plugin>/plugin-metadata" and
returns [] for all other paths; reintroduce the previous fallback by wrapping
the import in a try/catch: first attempt the existing dynamic import using the
extracted pluginName, and if that path isn't present or pluginName is falsy, try
await import(item.metadataFile) (or if the first import throws, fall back to
importing item.metadataFile inside the catch), then return
metadata.default.sagas || []; on any import error return [] (and optionally log
or ignore the error) so non-standard metadataFile paths still load their sagas.

@syntrydy syntrydy closed this Nov 5, 2025
@duttarnab duttarnab deleted the admin-ui-2413 branch November 27, 2025 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp-admin-ui Component affected by issue or PR kind-bug Issue or PR is a bug in existing functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants