@yao-pkg/pkg 6.13.0 → 6.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -26
- package/lib-es5/esm-transformer.js +191 -27
- package/lib-es5/packer.js +10 -1
- package/lib-es5/walker.js +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -422,6 +422,37 @@ await exec(['app.js', '--target', 'host', '--output', 'app.exe']);
|
|
|
422
422
|
// do something with app.exe, run, test, upload, deploy, etc
|
|
423
423
|
```
|
|
424
424
|
|
|
425
|
+
## ECMAScript Modules (ESM) Support
|
|
426
|
+
|
|
427
|
+
Starting from version **6.13.0**, pkg has improved support for ECMAScript Modules (ESM). Most ESM features are now automatically transformed to CommonJS during the packaging process.
|
|
428
|
+
|
|
429
|
+
### Supported ESM Features
|
|
430
|
+
|
|
431
|
+
The following ESM features are now supported and will work in your packaged executables:
|
|
432
|
+
|
|
433
|
+
- **`import` and `export` statements** - Automatically transformed to `require()` and `module.exports`
|
|
434
|
+
- **Top-level `await`** - Wrapped in an async IIFE to work in CommonJS context
|
|
435
|
+
- **Top-level `for await...of`** - Wrapped in an async IIFE to work in CommonJS context
|
|
436
|
+
- **`import.meta.url`** - Polyfilled to provide the file URL of the current module
|
|
437
|
+
- **`import.meta.dirname`** - Polyfilled to provide the directory path (Node.js 20.11+ property)
|
|
438
|
+
- **`import.meta.filename`** - Polyfilled to provide the file path (Node.js 20.11+ property)
|
|
439
|
+
|
|
440
|
+
### Known Limitations
|
|
441
|
+
|
|
442
|
+
While most ESM features work, there are some limitations to be aware of:
|
|
443
|
+
|
|
444
|
+
1. **Modules with both top-level await and exports**: Modules that use `export` statements alongside top-level `await` cannot be wrapped in an async IIFE and will not be transformed to bytecode. These modules will be included as source code instead.
|
|
445
|
+
|
|
446
|
+
2. **`import.meta.main`** and other custom properties: Only the standard `import.meta` properties listed above are polyfilled. Custom properties added by your code or other tools may not work as expected.
|
|
447
|
+
|
|
448
|
+
3. **Dynamic imports**: `import()` expressions work but may have limitations depending on the module being imported.
|
|
449
|
+
|
|
450
|
+
### Best Practices
|
|
451
|
+
|
|
452
|
+
- For entry point scripts (the main file you're packaging), feel free to use top-level await
|
|
453
|
+
- For library modules that will be imported by other code, avoid using both exports and top-level await together
|
|
454
|
+
- Test your packaged executable to ensure all ESM features work as expected in your specific use case
|
|
455
|
+
|
|
425
456
|
## Use custom Node.js binary
|
|
426
457
|
|
|
427
458
|
In case you want to use custom node binary, you can set `PKG_NODE_PATH` environment variable to the path of the node binary you want to use and `pkg` will use it instead of the default one.
|
|
@@ -535,43 +566,45 @@ or
|
|
|
535
566
|
Note: make sure not to use --debug flag in production.
|
|
536
567
|
|
|
537
568
|
### Injecting Windows Executable Metadata After Packaging
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
569
|
+
|
|
570
|
+
Executables created with `pkg` are based on a Node.js binary and, by default,
|
|
571
|
+
inherit its embedded metadata – such as version number, product name, company
|
|
572
|
+
name, icon, and description. This can be misleading or unpolished in
|
|
541
573
|
distributed applications.
|
|
542
574
|
|
|
543
575
|
There are two ways to customize the metadata of the resulting `.exe`:
|
|
576
|
+
|
|
544
577
|
1. **Use a custom Node.js binary** with your own metadata already embedded.
|
|
545
578
|
See: [Use Custom Node.js Binary](#use-custom-nodejs-binary)
|
|
546
579
|
|
|
547
|
-
2. **Post-process the generated executable** using
|
|
548
|
-
[`resedit`](https://www.npmjs.com/package/resedit), a Node.js-compatible
|
|
549
|
-
tool for modifying Windows executable resources. This allows injecting
|
|
580
|
+
2. **Post-process the generated executable** using
|
|
581
|
+
[`resedit`](https://www.npmjs.com/package/resedit), a Node.js-compatible
|
|
582
|
+
tool for modifying Windows executable resources. This allows injecting
|
|
550
583
|
correct version info, icons, copyright,
|
|
551
584
|
and more.
|
|
552
585
|
|
|
553
586
|
This section focuses on the second approach: post-processing the packaged
|
|
554
|
-
binary using
|
|
587
|
+
binary using [`resedit`](https://www.npmjs.com/package/resedit).
|
|
555
588
|
|
|
556
589
|
> ⚠️ Other tools may corrupt the executable, resulting in runtime errors such as
|
|
557
|
-
> `Pkg: Error reading from file.` –
|
|
590
|
+
> `Pkg: Error reading from file.` –
|
|
558
591
|
> [`resedit`](https://www.npmjs.com/package/resedit) has proven to work reliably
|
|
559
592
|
> with `pkg`-generated binaries.
|
|
560
593
|
|
|
561
594
|
Below is a working example for post-processing an `.exe` file using the Node.js API of [`resedit`](https://www.npmjs.com/package/resedit):
|
|
562
595
|
|
|
563
596
|
```ts
|
|
564
|
-
import * as ResEdit from
|
|
565
|
-
import * as fs from
|
|
566
|
-
import * as path from
|
|
597
|
+
import * as ResEdit from 'resedit';
|
|
598
|
+
import * as fs from 'fs';
|
|
599
|
+
import * as path from 'path';
|
|
567
600
|
|
|
568
601
|
// Set your inputs:
|
|
569
|
-
const exePath =
|
|
570
|
-
const outputPath = exePath;
|
|
571
|
-
const version =
|
|
602
|
+
const exePath = 'dist/my-tool.exe'; // Path to the generated executable
|
|
603
|
+
const outputPath = exePath; // Overwrite or use a different path
|
|
604
|
+
const version = '1.2.3'; // Your application version
|
|
572
605
|
|
|
573
|
-
const lang = 1033;
|
|
574
|
-
const codepage = 1200;
|
|
606
|
+
const lang = 1033; // en-US
|
|
607
|
+
const codepage = 1200; // Unicode
|
|
575
608
|
|
|
576
609
|
const exeData = fs.readFileSync(exePath);
|
|
577
610
|
const exe = ResEdit.NtExecutable.from(exeData);
|
|
@@ -580,19 +613,22 @@ const res = ResEdit.NtExecutableResource.from(exe);
|
|
|
580
613
|
const viList = ResEdit.Resource.VersionInfo.fromEntries(res.entries);
|
|
581
614
|
const vi = viList[0];
|
|
582
615
|
|
|
583
|
-
const [major, minor, patch] = version.split(
|
|
616
|
+
const [major, minor, patch] = version.split('.');
|
|
584
617
|
vi.setFileVersion(Number(major), Number(minor), Number(patch), 0, lang);
|
|
585
618
|
vi.setProductVersion(Number(major), Number(minor), Number(patch), 0, lang);
|
|
586
619
|
|
|
587
|
-
vi.setStringValues(
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
620
|
+
vi.setStringValues(
|
|
621
|
+
{ lang, codepage },
|
|
622
|
+
{
|
|
623
|
+
FileDescription: 'ACME CLI Tool',
|
|
624
|
+
ProductName: 'ACME Application',
|
|
625
|
+
CompanyName: 'ACME Corporation',
|
|
626
|
+
ProductVersion: version,
|
|
627
|
+
FileVersion: version,
|
|
628
|
+
OriginalFilename: path.basename(exePath),
|
|
629
|
+
LegalCopyright: `© ${new Date().getFullYear()} ACME Corporation`,
|
|
630
|
+
},
|
|
631
|
+
);
|
|
596
632
|
|
|
597
633
|
vi.outputToResourceEntries(res.entries);
|
|
598
634
|
res.outputResource(exe);
|
|
@@ -610,6 +646,7 @@ The following command examples inject an icon and metadata into the executable
|
|
|
610
646
|
`dist/bin/app.exe`.
|
|
611
647
|
|
|
612
648
|
- **Example (PowerShell on Windows)**
|
|
649
|
+
|
|
613
650
|
```powershell
|
|
614
651
|
npx resedit dist/bin/app.exe dist/bin/app_with_metadata.exe `
|
|
615
652
|
--icon 1,dist/favicon.ico `
|
|
@@ -33,39 +33,72 @@ const esbuild = __importStar(require("esbuild"));
|
|
|
33
33
|
const log_1 = require("./log");
|
|
34
34
|
const common_1 = require("./common");
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
* Wrapper for top-level await support
|
|
37
|
+
* Wraps code in an async IIFE to allow top-level await in CommonJS
|
|
38
|
+
*/
|
|
39
|
+
const ASYNC_IIFE_WRAPPER = {
|
|
40
|
+
prefix: '(async () => {\n',
|
|
41
|
+
suffix: '\n})()',
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Check if code contains import.meta usage
|
|
40
45
|
*
|
|
41
46
|
* @param code - The ESM source code to check
|
|
42
|
-
* @
|
|
43
|
-
* @returns Array of unsupported features found, or null if parse fails
|
|
47
|
+
* @returns true if import.meta is used, false otherwise
|
|
44
48
|
*/
|
|
45
|
-
function
|
|
49
|
+
function hasImportMeta(code) {
|
|
46
50
|
try {
|
|
47
51
|
const ast = babel.parse(code, {
|
|
48
52
|
sourceType: 'module',
|
|
49
53
|
plugins: [],
|
|
50
54
|
});
|
|
51
55
|
if (!ast) {
|
|
52
|
-
return
|
|
56
|
+
return false;
|
|
53
57
|
}
|
|
54
|
-
|
|
58
|
+
let found = false;
|
|
55
59
|
// @ts-expect-error Type mismatch due to @babel/types version in @types/babel__traverse
|
|
56
60
|
(0, traverse_1.default)(ast, {
|
|
57
61
|
// Detect import.meta usage
|
|
58
62
|
MetaProperty(path) {
|
|
59
63
|
if (path.node.meta.name === 'import' &&
|
|
60
64
|
path.node.property.name === 'meta') {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
line: path.node.loc?.start.line ?? null,
|
|
64
|
-
column: path.node.loc?.start.column ?? null,
|
|
65
|
-
});
|
|
65
|
+
found = true;
|
|
66
|
+
path.stop(); // Stop traversal once found
|
|
66
67
|
}
|
|
67
68
|
},
|
|
68
|
-
|
|
69
|
+
});
|
|
70
|
+
return found;
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
// If we can't parse, assume no import.meta
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Detect ESM features that require special handling or cannot be transformed
|
|
79
|
+
* These include:
|
|
80
|
+
* - Top-level await (can be handled with async IIFE wrapper)
|
|
81
|
+
*
|
|
82
|
+
* Note: import.meta is now supported via polyfills and is no longer in the unsupported list
|
|
83
|
+
*
|
|
84
|
+
* @param code - The ESM source code to check
|
|
85
|
+
* @param filename - The filename for error reporting
|
|
86
|
+
* @returns Object with arrays of features requiring special handling
|
|
87
|
+
*/
|
|
88
|
+
function detectESMFeatures(code, filename) {
|
|
89
|
+
try {
|
|
90
|
+
const ast = babel.parse(code, {
|
|
91
|
+
sourceType: 'module',
|
|
92
|
+
plugins: [],
|
|
93
|
+
});
|
|
94
|
+
if (!ast) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const topLevelAwait = [];
|
|
98
|
+
const unsupportedFeatures = [];
|
|
99
|
+
// @ts-expect-error Type mismatch due to @babel/types version in @types/babel__traverse
|
|
100
|
+
(0, traverse_1.default)(ast, {
|
|
101
|
+
// Detect top-level await - can be handled with async IIFE wrapper
|
|
69
102
|
AwaitExpression(path) {
|
|
70
103
|
// Check if await is at top level (not inside a function)
|
|
71
104
|
let parent = path.parentPath;
|
|
@@ -82,14 +115,14 @@ function detectUnsupportedESMFeatures(code, filename) {
|
|
|
82
115
|
parent = parent.parentPath;
|
|
83
116
|
}
|
|
84
117
|
if (isTopLevel) {
|
|
85
|
-
|
|
118
|
+
topLevelAwait.push({
|
|
86
119
|
feature: 'top-level await',
|
|
87
120
|
line: path.node.loc?.start.line ?? null,
|
|
88
121
|
column: path.node.loc?.start.column ?? null,
|
|
89
122
|
});
|
|
90
123
|
}
|
|
91
124
|
},
|
|
92
|
-
// Detect for-await-of at top level
|
|
125
|
+
// Detect for-await-of at top level - can be handled with async IIFE wrapper
|
|
93
126
|
ForOfStatement(path) {
|
|
94
127
|
if (path.node.await) {
|
|
95
128
|
let parent = path.parentPath;
|
|
@@ -106,7 +139,7 @@ function detectUnsupportedESMFeatures(code, filename) {
|
|
|
106
139
|
parent = parent.parentPath;
|
|
107
140
|
}
|
|
108
141
|
if (isTopLevel) {
|
|
109
|
-
|
|
142
|
+
topLevelAwait.push({
|
|
110
143
|
feature: 'top-level for-await-of',
|
|
111
144
|
line: path.node.loc?.start.line ?? null,
|
|
112
145
|
column: path.node.loc?.start.column ?? null,
|
|
@@ -115,14 +148,51 @@ function detectUnsupportedESMFeatures(code, filename) {
|
|
|
115
148
|
}
|
|
116
149
|
},
|
|
117
150
|
});
|
|
118
|
-
return unsupportedFeatures;
|
|
151
|
+
return { topLevelAwait, unsupportedFeatures };
|
|
119
152
|
}
|
|
120
153
|
catch (error) {
|
|
121
154
|
// If we can't parse, return null to let the transform attempt proceed
|
|
122
|
-
log_1.log.debug(`Could not parse ${filename} to detect
|
|
155
|
+
log_1.log.debug(`Could not parse ${filename} to detect ESM features: ${error instanceof Error ? error.message : String(error)}`);
|
|
123
156
|
return null;
|
|
124
157
|
}
|
|
125
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Replace esbuild's empty import_meta object with a proper implementation
|
|
161
|
+
*
|
|
162
|
+
* When esbuild transforms ESM to CJS, it converts `import.meta` to a `const import_meta = {}`.
|
|
163
|
+
* This function replaces that empty object with a proper implementation of import.meta properties.
|
|
164
|
+
*
|
|
165
|
+
* Shims provided:
|
|
166
|
+
* - import.meta.url: File URL of the current module
|
|
167
|
+
* - import.meta.dirname: Directory path of the current module (Node.js 20.11+)
|
|
168
|
+
* - import.meta.filename: File path of the current module (Node.js 20.11+)
|
|
169
|
+
*
|
|
170
|
+
* Based on approach from tsup and esbuild discussions
|
|
171
|
+
* @see https://github.com/egoist/tsup/blob/main/assets/cjs_shims.js
|
|
172
|
+
* @see https://github.com/evanw/esbuild/issues/3839
|
|
173
|
+
*
|
|
174
|
+
* @param code - The transformed CJS code from esbuild
|
|
175
|
+
* @returns Code with import_meta properly implemented
|
|
176
|
+
*/
|
|
177
|
+
function replaceImportMetaObject(code) {
|
|
178
|
+
// esbuild generates: const import_meta = {};
|
|
179
|
+
// We need to replace this with a proper implementation
|
|
180
|
+
// Note: We use getters to ensure values are computed at runtime in the correct context
|
|
181
|
+
const shimImplementation = `const import_meta = {
|
|
182
|
+
get url() {
|
|
183
|
+
return require('url').pathToFileURL(__filename).href;
|
|
184
|
+
},
|
|
185
|
+
get dirname() {
|
|
186
|
+
return __dirname;
|
|
187
|
+
},
|
|
188
|
+
get filename() {
|
|
189
|
+
return __filename;
|
|
190
|
+
}
|
|
191
|
+
};`;
|
|
192
|
+
// Replace esbuild's empty import_meta object with our implementation
|
|
193
|
+
// Match: const import_meta = {};
|
|
194
|
+
return code.replace(/const import_meta\s*=\s*\{\s*\};/, shimImplementation);
|
|
195
|
+
}
|
|
126
196
|
/**
|
|
127
197
|
* Transform ESM code to CommonJS using esbuild
|
|
128
198
|
* This allows ESM modules to be compiled to bytecode via vm.Script
|
|
@@ -141,10 +211,13 @@ function transformESMtoCJS(code, filename) {
|
|
|
141
211
|
isTransformed: false,
|
|
142
212
|
};
|
|
143
213
|
}
|
|
144
|
-
// First, check for
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
214
|
+
// First, check for ESM features that need special handling
|
|
215
|
+
const esmFeatures = detectESMFeatures(code, filename);
|
|
216
|
+
// Handle truly unsupported features (import.meta)
|
|
217
|
+
if (esmFeatures &&
|
|
218
|
+
esmFeatures.unsupportedFeatures &&
|
|
219
|
+
esmFeatures.unsupportedFeatures.length > 0) {
|
|
220
|
+
const featureList = esmFeatures.unsupportedFeatures
|
|
148
221
|
.map((f) => {
|
|
149
222
|
const location = f.line !== null ? ` at line ${f.line}` : '';
|
|
150
223
|
return ` - ${f.feature}${location}`;
|
|
@@ -169,15 +242,101 @@ function transformESMtoCJS(code, filename) {
|
|
|
169
242
|
isTransformed: false,
|
|
170
243
|
};
|
|
171
244
|
}
|
|
245
|
+
// Check if we need to wrap in async IIFE for top-level await
|
|
246
|
+
const hasTopLevelAwait = esmFeatures &&
|
|
247
|
+
esmFeatures.topLevelAwait &&
|
|
248
|
+
esmFeatures.topLevelAwait.length > 0;
|
|
249
|
+
let codeToTransform = code;
|
|
250
|
+
// If top-level await is detected, we need to wrap in async IIFE
|
|
251
|
+
// But we must handle imports and exports specially
|
|
252
|
+
if (hasTopLevelAwait) {
|
|
253
|
+
try {
|
|
254
|
+
// Parse the code to check for exports and collect imports
|
|
255
|
+
const ast = babel.parse(code, {
|
|
256
|
+
sourceType: 'module',
|
|
257
|
+
plugins: [],
|
|
258
|
+
});
|
|
259
|
+
let hasExports = false;
|
|
260
|
+
const codeLines = code.split('\n');
|
|
261
|
+
const importLineIndices = new Set();
|
|
262
|
+
// @ts-expect-error Type mismatch due to @babel/types version
|
|
263
|
+
(0, traverse_1.default)(ast, {
|
|
264
|
+
ExportNamedDeclaration() {
|
|
265
|
+
hasExports = true;
|
|
266
|
+
},
|
|
267
|
+
ExportDefaultDeclaration() {
|
|
268
|
+
hasExports = true;
|
|
269
|
+
},
|
|
270
|
+
ExportAllDeclaration() {
|
|
271
|
+
hasExports = true;
|
|
272
|
+
},
|
|
273
|
+
ImportDeclaration(path) {
|
|
274
|
+
// Track import statements by line number
|
|
275
|
+
const { loc } = path.node;
|
|
276
|
+
if (loc) {
|
|
277
|
+
const { start, end } = loc;
|
|
278
|
+
for (let i = start.line; i <= end.line; i += 1) {
|
|
279
|
+
importLineIndices.add(i - 1); // Convert to 0-based index
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
});
|
|
284
|
+
if (hasExports) {
|
|
285
|
+
// If the file has exports, we can't wrap it in an IIFE
|
|
286
|
+
// because exports need to be synchronous and at the top level.
|
|
287
|
+
log_1.log.warn(`Module ${filename} has both top-level await and export statements. ` +
|
|
288
|
+
`This combination cannot be safely transformed to CommonJS in pkg's ESM transformer. ` +
|
|
289
|
+
`The original source code will be used as-is; depending on the package visibility and build configuration, ` +
|
|
290
|
+
`bytecode compilation may fail and the module may need to be loaded from source or be skipped.`);
|
|
291
|
+
return {
|
|
292
|
+
code,
|
|
293
|
+
isTransformed: false,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
// If there are imports, extract them to keep outside the async IIFE
|
|
297
|
+
if (importLineIndices.size > 0) {
|
|
298
|
+
const imports = [];
|
|
299
|
+
const rest = [];
|
|
300
|
+
codeLines.forEach((line, index) => {
|
|
301
|
+
if (importLineIndices.has(index)) {
|
|
302
|
+
imports.push(line);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
rest.push(line);
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
// Reconstruct: imports at top, then async IIFE wrapping the rest
|
|
309
|
+
codeToTransform = `${imports.join('\n')}\n${ASYNC_IIFE_WRAPPER.prefix}${rest.join('\n')}${ASYNC_IIFE_WRAPPER.suffix}`;
|
|
310
|
+
log_1.log.debug(`Wrapping ${filename} in async IIFE with imports extracted to top level`);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
// No imports, wrap everything
|
|
314
|
+
codeToTransform =
|
|
315
|
+
ASYNC_IIFE_WRAPPER.prefix + code + ASYNC_IIFE_WRAPPER.suffix;
|
|
316
|
+
log_1.log.debug(`Wrapping ${filename} in async IIFE to support top-level await`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
catch (parseError) {
|
|
320
|
+
// If we can't parse, wrap everything and hope for the best
|
|
321
|
+
codeToTransform =
|
|
322
|
+
ASYNC_IIFE_WRAPPER.prefix + code + ASYNC_IIFE_WRAPPER.suffix;
|
|
323
|
+
log_1.log.warn(`Could not parse ${filename} to detect exports/imports (${parseError instanceof Error ? parseError.message : String(parseError)}). ` +
|
|
324
|
+
`Wrapping entire code in async IIFE - this may fail if the module has export or import statements.`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
// Check if code uses import.meta before transformation
|
|
328
|
+
const usesImportMeta = hasImportMeta(code);
|
|
172
329
|
try {
|
|
173
|
-
|
|
330
|
+
// Build esbuild options
|
|
331
|
+
const esbuildOptions = {
|
|
174
332
|
loader: 'js',
|
|
175
333
|
format: 'cjs',
|
|
176
334
|
target: 'node18',
|
|
177
335
|
sourcemap: false,
|
|
178
336
|
minify: false,
|
|
179
337
|
keepNames: true,
|
|
180
|
-
}
|
|
338
|
+
};
|
|
339
|
+
const result = esbuild.transformSync(codeToTransform, esbuildOptions);
|
|
181
340
|
if (!result || !result.code) {
|
|
182
341
|
log_1.log.warn(`esbuild transform returned no code for ${filename}`);
|
|
183
342
|
return {
|
|
@@ -185,8 +344,13 @@ function transformESMtoCJS(code, filename) {
|
|
|
185
344
|
isTransformed: false,
|
|
186
345
|
};
|
|
187
346
|
}
|
|
347
|
+
// Inject import.meta shims after esbuild transformation if needed
|
|
348
|
+
let finalCode = result.code;
|
|
349
|
+
if (usesImportMeta) {
|
|
350
|
+
finalCode = replaceImportMetaObject(result.code);
|
|
351
|
+
}
|
|
188
352
|
return {
|
|
189
|
-
code:
|
|
353
|
+
code: finalCode,
|
|
190
354
|
isTransformed: true,
|
|
191
355
|
};
|
|
192
356
|
}
|
package/lib-es5/packer.js
CHANGED
|
@@ -27,13 +27,22 @@ function hasAnyStore(record) {
|
|
|
27
27
|
}
|
|
28
28
|
function packer({ records, entrypoint, bytecode, }) {
|
|
29
29
|
const stripes = [];
|
|
30
|
-
|
|
30
|
+
// If the entrypoint was a .mjs file that got transformed, update its extension
|
|
31
|
+
if (records[entrypoint]?.wasTransformed && entrypoint.endsWith('.mjs')) {
|
|
32
|
+
entrypoint = `${entrypoint.slice(0, -4)}.js`;
|
|
33
|
+
}
|
|
34
|
+
for (let snap in records) {
|
|
31
35
|
if (records[snap]) {
|
|
32
36
|
const record = records[snap];
|
|
33
37
|
const { file } = record;
|
|
34
38
|
if (!hasAnyStore(record)) {
|
|
35
39
|
continue;
|
|
36
40
|
}
|
|
41
|
+
// If .mjs file was transformed to CJS, rename it to .js in the snapshot
|
|
42
|
+
// This prevents Node.js from treating it as an ES module
|
|
43
|
+
if (record.wasTransformed && snap.endsWith('.mjs')) {
|
|
44
|
+
snap = `${snap.slice(0, -4)}.js`;
|
|
45
|
+
}
|
|
37
46
|
(0, assert_1.default)(record[common_1.STORE_STAT], 'packer: no STORE_STAT');
|
|
38
47
|
(0, assert_1.default)(record[common_1.STORE_BLOB] ||
|
|
39
48
|
record[common_1.STORE_CONTENT] ||
|
package/lib-es5/walker.js
CHANGED
|
@@ -852,6 +852,10 @@ class Walker {
|
|
|
852
852
|
const result = (0, esm_transformer_1.transformESMtoCJS)(record.body.toString('utf8'), record.file);
|
|
853
853
|
if (result.isTransformed) {
|
|
854
854
|
record.body = Buffer.from(result.code, 'utf8');
|
|
855
|
+
// Mark .mjs files as transformed so packer can rename them to .js
|
|
856
|
+
if (record.file.endsWith('.mjs')) {
|
|
857
|
+
record.wasTransformed = true;
|
|
858
|
+
}
|
|
855
859
|
}
|
|
856
860
|
}
|
|
857
861
|
catch (error) {
|