Skip to content

Fix Next.js build failure with runtime dynamic imports in WidgetRegistry#429

Merged
hotlong merged 3 commits intomainfrom
copilot/update-action-run-link-format
Feb 10, 2026
Merged

Fix Next.js build failure with runtime dynamic imports in WidgetRegistry#429
hotlong merged 3 commits intomainfrom
copilot/update-action-run-link-format

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 10, 2026

Turbopack fails on await import(source.url) when bundling WidgetRegistry because it attempts static analysis on runtime-determined URLs.

Changes

Core fix - Replace static import with Function constructor pattern:

// Before: Turbopack tries to statically analyze this
const mod = await import(source.url);

// After: Bypasses static analysis
const dynamicImport = new Function('url', 'return import(url)');
const mod = await dynamicImport(source.url);

Security documentation - Added warnings to WidgetSourceModule type that URLs must be from trusted sources, never user input.

Next.js configuration - Added transpilePackages array for workspace dependencies to ensure proper TypeScript transpilation.

Notes

  • Widget manifests are developer-controlled; URLs are not user-supplied
  • CSP-restricted environments can use inline or registry source types instead
  • Function constructor is intentional for runtime module loading
Original prompt

引用: https://github.com/objectstack-ai/objectui/actions/runs/21859730225/job/63085386579#step:7:1


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectui Ready Ready Preview, Comment Feb 10, 2026 10:53am
objectui-console Canceled Canceled Feb 10, 2026 10:53am
objectui-storybook Ready Ready Preview, Comment Feb 10, 2026 10:53am

Request Review

Copilot AI and others added 2 commits February 10, 2026 10:27
…idgetRegistry

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Update action run link format in documentation Fix Next.js build failure with runtime dynamic imports in WidgetRegistry Feb 10, 2026
Copilot AI requested a review from hotlong February 10, 2026 10:36
@hotlong hotlong marked this pull request as ready for review February 10, 2026 10:39
Copilot AI review requested due to automatic review settings February 10, 2026 10:39
@hotlong hotlong merged commit 328c99b into main Feb 10, 2026
3 of 6 checks passed
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes a Next.js (Turbopack) build failure caused by bundlers attempting static analysis on runtime-determined widget module URLs, by switching WidgetRegistry’s module loader to a runtime-only dynamic import pattern. Also strengthens guidance around the security implications of loading widgets from URLs and updates the site build config to transpile workspace packages.

Changes:

  • Replace import(source.url) with a Function-constructed dynamic import to bypass bundler static analysis for runtime URLs.
  • Add security warnings to WidgetSourceModule docs about trusted URL requirements and CSP constraints.
  • Add transpilePackages to apps/site Next.js config for monorepo/workspace package transpilation.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
packages/types/src/widget.ts Expands documentation for module-based widget sources with security/CSP warnings.
packages/core/src/registry/WidgetRegistry.ts Implements runtime-only dynamic import for source.type: 'module' widget loading.
apps/site/next.config.mjs Adds transpilePackages to ensure workspace dependencies are transpiled by Next.js.

Comment on lines +288 to +289
// CSP Consideration: If your application uses strict Content Security Policy,
// ensure dynamic imports are allowed or use 'inline' or 'registry' source types.
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

This CSP guidance is incomplete: the Function constructor itself requires allowing unsafe-eval in CSP (in addition to any dynamic import allowances). Please adjust the comment so users don’t interpret this as only a dynamic-import restriction.

Suggested change
// CSP Consideration: If your application uses strict Content Security Policy,
// ensure dynamic imports are allowed or use 'inline' or 'registry' source types.
// CSP Consideration: This pattern relies on the Function constructor plus
// dynamic import(). In a strict Content Security Policy, this typically
// requires allowing 'unsafe-eval' in script-src (for Function) and ensuring
// that dynamic module imports from the widget origins are permitted. If you
// cannot relax CSP to allow this, use 'inline' or 'registry' source types
// instead of 'module'.

Copilot uses AI. Check for mistakes.
Comment on lines +290 to +291
const dynamicImport = new Function('url', 'return import(url)');
const mod = await dynamicImport(source.url);
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

new Function('url', 'return import(url)') is being constructed each time a module widget is resolved. Consider hoisting this to a module-level constant (and giving it an explicit (url: string) => Promise<unknown> type) to avoid repeated Function compilation and to centralize/audit the unsafe-eval usage.

Copilot uses AI. Check for mistakes.
Comment on lines +290 to 293
const dynamicImport = new Function('url', 'return import(url)');
const mod = await dynamicImport(source.url);
const exportName = source.exportName ?? 'default';
const component = mod[exportName];
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

There are unit tests for WidgetRegistry, but none exercise the source.type === 'module' branch. Since this PR changes how module widgets are imported, please add a test that loads a small fixture module URL and verifies export resolution (including exportName handling) to prevent regressions.

Copilot uses AI. Check for mistakes.
Comment on lines +103 to +104
* and controlled by your application. This feature uses dynamic imports
* which bypass static analysis and may be restricted by Content Security Policy.
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

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

The CSP note here only mentions dynamic imports, but this code path also uses new Function(...), which is blocked unless script-src allows unsafe-eval. Please update the documentation to explicitly call out the unsafe-eval requirement (or clarify the alternative source types for environments where unsafe-eval is disallowed).

Suggested change
* and controlled by your application. This feature uses dynamic imports
* which bypass static analysis and may be restricted by Content Security Policy.
* and controlled by your application.
*
* This feature typically uses dynamic `import()` to load widget code and,
* depending on your runtime loader, may also rely on runtime evaluation
* (for example, via `new Function(...)`) to wire up the widget.
*
* Both mechanisms can be restricted by Content Security Policy (CSP):
* - Dynamic `import()` requires the module URL to be allowed by `script-src`.
* - `new Function(...)` is blocked unless `script-src` explicitly allows
* `'unsafe-eval'`.
*
* In environments where `'unsafe-eval'` is disallowed, prefer `inline` or
* `registry` widget sources, or provide a custom loader implementation that
* does not rely on `new Function(...)`.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants