Skip to content

Conversation

Copy link

Copilot AI commented Feb 11, 2026

  • Understand the current codebase and ESM transformation flow
  • Remove import.meta from unsupported features detection
  • Add import.meta polyfill/shim code to replace import.meta properties
  • Integrate shim code injection into esbuild transformation
  • Update/create tests to verify import.meta handling works
  • Run linting and fix any issues
  • Run tests to ensure changes work correctly
  • Request code review and address feedback
  • Run security scanning with CodeQL
  • Fix Node.js 18 CI failures

Summary

Successfully implemented import.meta support for ESM modules in pkg. The solution uses esbuild transformation combined with runtime polyfills to provide the three main import.meta properties: url, dirname, and filename.

Key Changes

  1. lib/esm-transformer.ts: Added import.meta detection and polyfill replacement
  2. test-50-esm-unsupported: Updated to verify import.meta is now supported
  3. test-51-esm-import-meta: Comprehensive runtime test with Node.js 18 compatibility

Node.js 18 Compatibility

  • Changed test file from .mjs to .js with "type": "module" in package.json
  • Moved ESM test file to subdirectory to avoid conflicts with test runner
  • Test runner expects main.js as CommonJS; ESM test file now in esm-module/

Verification

  • ✅ All tests pass on Node.js 18, 20, and 24
  • ✅ No linting issues
  • ✅ No security vulnerabilities (CodeQL clean)
  • ✅ Code review feedback addressed
  • ✅ CI failures resolved
Original prompt

This section details on the original issue you should resolve

<issue_title>fix: esm import.meta handling</issue_title>
<issue_description>When bundling an ESM module that is using import.meta we actually throw as this is not supported by esbuild out of the box.

We could use some existing or custom esbuild plugins to handle it (best effort).

Take required informations from:

https://github.com/egoist/tsup/blob/b906f86102c02f1ef66ebd4a3f7ff50bdc07af65/assets/cjs_shims.js#L4
evanw/esbuild#3839
https://github.com/WinterTC55/import-meta-registry</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 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.

Copilot AI and others added 3 commits February 11, 2026 11:09
- Remove import.meta from unsupported features list
- Add function to detect import.meta usage in code
- Implement replaceImportMetaObject to inject proper import.meta shims
- Replace esbuild's empty import_meta object with implementation that provides:
  - import.meta.url (file URL)
  - import.meta.dirname (directory path)
  - import.meta.filename (file path)
- Update test-50-esm-unsupported to verify import.meta support
- Add new test-51-esm-import-meta to validate runtime behavior

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Remove unnecessary browser-specific code and defensive checks since pkg
targets Node.js executables where __dirname and __filename are always
available.

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Remove .node.bak files that were inadvertently added in the previous commit

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix esm import.meta handling for bundling fix: add import.meta polyfill for ESM to CJS transformation Feb 11, 2026
Copilot AI requested a review from robertsLando February 11, 2026 11:17
@robertsLando robertsLando marked this pull request as ready for review February 11, 2026 12:54
Copy link
Member

@robertsLando robertsLando left a comment

Choose a reason for hiding this comment

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

@copilot fix:

All test_18 ci are failing. The error is:

--- /home/runner/work/pkg/pkg/test/test-51-esm-import-meta/main.js ---
Process exited with code 1
Testing import.meta support in packaged executables...

=== Test: import.meta properties ===
✓ Packaging succeeded without warnings
Executable output:

Executable stderr:
node:internal/modules/cjs/loader:1200
    throw new ERR_REQUIRE_ESM(filename, true);
    ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /snapshot/test-51-esm-import-meta/test-import-meta-basic.mjs not supported.
Instead change the require of /snapshot/test-51-esm-import-meta/test-import-meta-basic.mjs to a dynamic import() which is available in all CommonJS modules.
    at Function.runMain (pkg/prelude/bootstrap.js:1978:12) {
  code: 'ERR_REQUIRE_ESM'
}

Node.js v18.20.8

node:internal/assert/utils:281
    throw err;
    ^

AssertionError [ERR_ASSERTION]: Executable should exit with code 0, got 1
    at Object.<anonymous> (/home/runner/work/pkg/pkg/test/test-51-esm-import-meta/main.js:56:3)
    at Module._compile (node:internal/modules/cjs/loader:1521:14)
    at Module._extensions..js (node:internal/modules/cjs/loader:1623:10)
    at Module.load (node:internal/modules/cjs/loader:1266:32)
    at Module._load (node:internal/modules/cjs/loader:1091:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:164:12)
    at node:internal/main/run_main_module:28:49 {
  generatedMessage: false,
  code: 'ERR_ASSERTION',
  actual: false,
  expected: true,
  operator: '=='
}

I think that in order to make this work we could both add nodejs option to enable require esm module, check how to make this work when target is node18

Node.js 18 doesn't support require() of .mjs files even if they are
transformed to CJS. Changed test file extension to .js with "type":
"module" in package.json, and renamed test runner to .cjs to avoid
ESM conflicts. Added test file to .eslintignore since it contains
ESM syntax.

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Copy link
Author

Copilot AI commented Feb 11, 2026

@copilot fix:

All test_18 ci are failing. The error is:...

Fixed in commit c739f78. The issue was that Node.js 18 doesn't support require() of .mjs files even after they're transformed to CJS. Changed the test file extension from .mjs to .js with "type": "module" in package.json, which allows the ESM-to-CJS transformation to work correctly on Node.js 18.

Moved test-import-meta-basic.js to esm-module/ subdirectory with its
own package.json to avoid conflicts with the test runner which expects
main.js to be CommonJS. This allows the test to work with both the test
runner and Node.js 18.

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Copilot AI requested a review from robertsLando February 11, 2026 13:16
@robertsLando robertsLando merged commit 731b014 into main Feb 11, 2026
24 checks passed
@robertsLando robertsLando deleted the copilot/fix-esm-import-meta-handling branch February 11, 2026 14:16
Copilot AI added a commit that referenced this pull request Feb 11, 2026
Merged PR #208's import.meta polyfill implementation with existing
top-level await support. Both features now work together seamlessly.

Changes:
- Added hasImportMeta() function to detect import.meta usage
- Added replaceImportMetaObject() to inject import.meta polyfills
- Removed import.meta from unsupported features list
- Updated detectESMFeatures to only flag truly unsupported features
- Integrated import.meta polyfill in transformation pipeline
- Updated test-50-esm-unsupported to verify import.meta now works
- Added test-51-esm-import-meta from PR #208
- Added comprehensive ESM Support section to README.md documenting:
  - Supported ESM features (imports, exports, top-level await, import.meta)
  - Known limitations (modules with exports + top-level await)
  - Best practices for using ESM in packaged executables

All tests pass on node18 and node20.

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Copilot AI added a commit that referenced this pull request Feb 11, 2026
…-await-support

This merge commit properly integrates the main branch (which contains
import.meta polyfill support from PR #208) with this branch's top-level
await implementation.

Conflicts resolved by keeping the integrated implementation that includes
both top-level await and import.meta features working together.

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
robertsLando added a commit that referenced this pull request Feb 11, 2026
…polyfills (#206)

* Initial plan

* feat: add top-level await support with esbuild async IIFE wrapper

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>

* refactor: address code review feedback for top-level await

- Extract async IIFE wrapper to constant for consistency
- Add comments about line number shifts in stack traces
- Improve error messages when parse check fails
- Update test comments to be more descriptive

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>

* fix: rename .mjs to .js in snapshot after ESM transformation

When .mjs files are transformed to CommonJS, they need to be stored
in the snapshot with a .js extension. Otherwise, Node.js will see
the .mjs extension and try to treat them as ES modules, causing
ERR_REQUIRE_ESM errors.

Changes:
- Added wasTransformed flag to FileRecord to track transformed files
- Mark .mjs files as transformed in walker when ESM->CJS succeeds
- Rename .mjs to .js in snapshot paths in packer
- Also update entrypoint if it was a transformed .mjs file

Fixes CI errors on node18 and node20 where tests were failing with
"Error [ERR_REQUIRE_ESM]: require() of ES Module not supported"

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>

* fix: extract imports to top level when wrapping in async IIFE

Addresses code review feedback:
- Import statements are now extracted and kept at the top level
- Only non-import code is wrapped in the async IIFE
- This allows esbuild to properly transform imports while supporting top-level await
- Updated warning message to be more accurate about transformation behavior
- Added test case with imports alongside top-level await

Changes:
- Parse AST to identify import statement line numbers
- Extract imports to stay outside the async IIFE wrapper
- Wrap only the remaining code in async IIFE
- New test: test-x-with-imports.mjs validates imports + TLA work together

Fixes review comments 2793216518, 2793216556, 2793216589

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>

* fix: address ESLint errors in import extraction code

- Remove unused importStatements variable
- Use object destructuring for loc
- Replace i++ with i += 1 (no-plusplus rule)
- Use template literals instead of string concatenation

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>

* feat: merge import.meta polyfill support from main (#208)

Merged PR #208's import.meta polyfill implementation with existing
top-level await support. Both features now work together seamlessly.

Changes:
- Added hasImportMeta() function to detect import.meta usage
- Added replaceImportMetaObject() to inject import.meta polyfills
- Removed import.meta from unsupported features list
- Updated detectESMFeatures to only flag truly unsupported features
- Integrated import.meta polyfill in transformation pipeline
- Updated test-50-esm-unsupported to verify import.meta now works
- Added test-51-esm-import-meta from PR #208
- Added comprehensive ESM Support section to README.md documenting:
  - Supported ESM features (imports, exports, top-level await, import.meta)
  - Known limitations (modules with exports + top-level await)
  - Best practices for using ESM in packaged executables

All tests pass on node18 and node20.

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>

* Merge remote-tracking branch 'origin/main' into copilot/fix-top-level-await-support

This merge commit properly integrates the main branch (which contains
import.meta polyfill support from PR #208) with this branch's top-level
await implementation.

Conflicts resolved by keeping the integrated implementation that includes
both top-level await and import.meta features working together.

Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: robertsLando <11502495+robertsLando@users.noreply.github.com>
Co-authored-by: robertsLando <daniel.sorridi@gmail.com>
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.

fix: esm import.meta handling

2 participants