Skip to content

Conversation

@mirko314
Copy link
Contributor

Summary

Fixes Webpack 5 / Angular compatibility issue where the plugin failed to build due to Node.js core module imports being statically analyzed.

  • Add environment-aware dynamic imports to prevent Webpack 5 static analysis
  • Post-process gs.js during build to add webpackIgnore magic comments
  • Add Webpack 5 compatibility test

Problem

Webpack 5 removed automatic Node.js core module polyfills. The plugin had imports of module, path, fs, and url that were only used in Node.js runtime code paths, but Webpack 5 statically analyzed them and failed with:

Module not found: Error: Can't resolve 'module'
Module not found: Error: Can't resolve 'path'

Solution

For gs.js (Emscripten-generated): Post-process during build to add /* webpackIgnore: true */ comments.

For TypeScript code: Use indirect dynamic import via new Function() that Webpack can't statically analyze, with fallback to direct imports in test environments (vitest):

const isTestEnv = process.env.VITEST === 'true' || process.env.NODE_ENV === 'test';

const dynamicImport = isTestEnv
  ? (specifier: string) => import(specifier)
  : new Function('specifier', 'return import(specifier)');

Test plan

  • pnpm run test:webpack5 - Webpack 5 bundling test passes
  • pnpm run test:silent - Vitest integration tests pass (5/5)
  • pnpm run test:node - Node.js runtime test passes

Fixes: https://github.com/imgly/ubq/issues/11471

Add test script to verify plugin works with Webpack 5 bundler (Angular).
Currently fails due to Node.js core module imports (module, path).

Relates to: imgly/ubq#11471
@vercel
Copy link

vercel bot commented Dec 17, 2025

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

Project Deployment Review Updated (UTC)
plugins-bytedance Ready Ready Preview, Comment Dec 18, 2025 1:59pm
plugins-web Ready Ready Preview, Comment Dec 18, 2025 1:59pm

Webpack 5 removed automatic Node.js core module polyfills. This caused
build failures when bundling the plugin because it statically analyzed
imports of 'module', 'path', 'fs', and 'url' even though they were only
used in Node.js runtime code paths.

Changes:
- Use indirect dynamic import via `new Function()` to prevent Webpack
  from statically analyzing Node.js module imports in production builds
- Use direct imports in test environments (vitest) where new Function
  doesn't have access to the module system's dynamic import callback
- Post-process gs.js during build to add `webpackIgnore` magic comments
  to Emscripten-generated Node.js imports

Fixes: imgly/ubq#11471
Copy link
Contributor

@Elia-Darwish Elia-Darwish left a comment

Choose a reason for hiding this comment

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

PR Review Summary

Critical Issues (2 found)

1. Silent failure in CSP-restricted environments

Files: pdfx.ts:154-161, ghostscript-module.ts:38-42

The indirect import pattern using new Function will throw an EvalError in environments with strict Content Security Policy (CSP) that disallows unsafe-eval. This affects Electron apps, sandboxed Node.js, and corporate environments.

Recommendation: Wrap the function creation in try-catch with meaningful error message and fallback to direct import.

2. Redundant regex pattern in addWebpackIgnoreComments

File: esbuild/config.mjs:24-30

The second regex pattern is a subset of the first and is redundant. The first pattern already matches both single and double quotes.

Fix: Remove the redundant second pattern from the array.


Important Issues (4 found)

3. Missing error context on dynamic import failures

Files: pdfx.ts:162-164, ghostscript-module.ts:44-48

If dynamic imports fail, users get cryptic errors like Cannot read properties of undefined instead of actionable messages about ICC profile loading or Ghostscript module initialization.

4. Inconsistent isTestEnv check pattern

Files: pdfx.ts:151-152 vs ghostscript-module.ts:33-35

pdfx.ts lacks the typeof process !== "undefined" guard that ghostscript-module.ts has, which could cause ReferenceError in some browser environments.

5. Comment inaccuracy about vitest

Files: pdfx.ts:149, ghostscript-module.ts:31

The comment "where new Function does not work" is technically inaccurate. The function constructor works in vitest Node.js environment. The real reason is likely test tooling compatibility (mocking, coverage, debugging).

6. No unit test for addWebpackIgnoreComments function

File: esbuild/config.mjs:15-35

The core transform function has no unit tests. If the regex breaks or gs.js format changes, there is no safety net.


Suggestions (4 found)

  • Test name misleading: webpack5-angular-test.sh does not use Angular - consider renaming to webpack5-compatibility-test.sh
  • Test uses cached project directory: Only creates project if it does not exist, which can lead to stale configurations
  • No verification that dist/gs.js is transformed: Test does not verify webpackIgnore comments were added
  • Quote style not preserved: Single-quote imports are converted to double-quotes

Strengths

  • Good documentation with links to GitHub issue #11471
  • Defense in depth approach (gs.js transformation + indirect imports)
  • Appropriate integration test that actually runs Webpack 5
  • Clean .gitignore for test artifacts

Recommended Action

  1. Must fix before merge: Critical issues #1 and #2
  2. Should fix: Important issues #3-5
  3. Consider for follow-up: Suggestions and unit tests

- Remove redundant regex pattern in addWebpackIgnoreComments (the first
  pattern already matches both single and double quotes)
- Rename webpack5-angular-test.sh to webpack5-compatibility-test.sh
  (the test doesn't use Angular)
- Fix misleading comment about vitest - the issue is that indirect
  imports bypass vitest's mocking system, not that new Function
  doesn't work
@mirko314
Copy link
Contributor Author

Review Response

Thank you for the detailed review! I've analyzed each issue and addressed the ones with merit.

Changes Made (d0ff834)

✅ Critical Issue #2: Redundant regex pattern
Fixed. The second regex pattern was indeed a subset of the first. Simplified to a single pattern that handles both single and double quotes.

✅ Suggestion: Test name misleading
Renamed webpack5-angular-test.shwebpack5-compatibility-test.sh since the test doesn't use Angular.

✅ Important Issue #5: Comment inaccuracy about vitest
Updated comment from "where new Function doesn't work" to "where indirect imports bypass mocking" - the actual reason is that vitest's module mocking system cannot intercept imports created via new Function.


Issues That Don't Require Changes

❌ Critical Issue #1: CSP-restricted environments
The new Function code only executes in Node.js (verified by the isNode check). CSP is a browser security mechanism that doesn't apply to server-side Node.js. Electron apps apply CSP only to renderer processes, not Node.js main process.

❌ Important Issue #3: Missing error context
Tested actual error behavior - Node.js provides informative error messages like "Cannot find package 'X'" for failed imports. These are built-in modules (fs, path, url, module) that will always be available in Node.js.

❌ Important Issue #4: Inconsistent isTestEnv check
Analysis was backwards - both checks are inside if (isNode) blocks which already verify process exists. The guard in ghostscript-module.ts is actually redundant (but harmless), not missing from pdfx.ts.

⚠️ Important Issue #6: No unit test
The integration test validates end-to-end Webpack 5 compatibility. Unit tests would provide faster feedback but the transformation is implicitly validated when the build succeeds.

…to Node.js

Address PR review feedback about potential CSP failures with new Function().
CSP is a browser security mechanism and doesn't apply to Node.js environments
where this code path executes.
- Add changelog entry for Webpack 5 compatibility fix
- Fix test:webpack5 script to reference renamed test file
@mirko314 mirko314 merged commit c79a0e4 into main Dec 18, 2025
10 checks passed
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.

2 participants