Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
ea0ed86
Cherry-pick 234940f032e4353a4390af02bbc59a6a9f87afcf
kleisauke Nov 10, 2022
decb8f8
Fix test failure in `core2.test_modularize_closure_pre`
kleisauke Feb 22, 2025
908c47c
Fix test failure in `core2.test_pthread_proxying_modularize`
kleisauke Feb 23, 2025
985f4dc
Remove redundant code
kleisauke Jan 10, 2026
254ed04
Automatic rebaseline of codesize expectations. NFC
kleisauke Jan 10, 2026
e194143
Fix test failure in `browser.test_cross_origin_es6`
kleisauke Jan 11, 2026
047b852
Ensure 2-space indent
kleisauke Jan 11, 2026
b077e9c
Fix test failure in `browser_2gb.test_source_phase_imports`
kleisauke Jan 11, 2026
b7c92f5
Avoid dependence on PR #23261
kleisauke Jan 16, 2026
1fbc5ca
Closure doesn't support top-level await
kleisauke Jan 16, 2026
dbf6e5e
Allow Babel to parse top-level await
kleisauke Jan 17, 2026
e9f3e23
Merge branch 'main' into es6-acorn-closure
kleisauke Jan 17, 2026
d745291
Automatic rebaseline of codesize expectations. NFC
kleisauke Jan 17, 2026
31cf27b
Merge branch 'main' into es6-acorn-closure
kleisauke Jan 17, 2026
f2fbf66
Revise comments
kleisauke Jan 17, 2026
6ac9b01
Allow Babel to parse `import.meta`
kleisauke Jan 17, 2026
083405a
Ensure `import()` expressions are not Babeled
kleisauke Jan 17, 2026
ef36474
Ensure Closure doesn't minify `require()`
kleisauke Jan 17, 2026
df79ebe
Automatic rebaseline of codesize expectations. NFC
kleisauke Jan 17, 2026
711efc1
`globalThis` -> `global`
kleisauke Jan 19, 2026
0972e63
Automatic rebaseline of codesize expectations. NFC
kleisauke Jan 19, 2026
5fd7830
Add comment regarding `export{};`
kleisauke Apr 4, 2026
06d1884
Merge branch 'main' into es6-acorn-closure
kleisauke Apr 4, 2026
0ea5e1c
Automatic rebaseline of codesize expectations. NFC
kleisauke Apr 4, 2026
bd18866
`modules.js` was renamed to `modules.mjs`
kleisauke Apr 5, 2026
2d6ba19
Merge branch 'main' into es6-acorn-closure
kleisauke Apr 7, 2026
af43dd1
Revert "Ensure Closure doesn't minify `require()`"
kleisauke Apr 7, 2026
5c2f12b
Restore the mangling logic to its original location
kleisauke Apr 7, 2026
0b218f2
Prefer use of `replaceAll`
kleisauke Apr 7, 2026
cf6417c
Add comment
kleisauke Apr 7, 2026
8283862
Automatic rebaseline of codesize expectations. NFC
kleisauke Apr 7, 2026
f74a9b7
`parseTools.js` was renamed to `parseTools.mjs`
kleisauke Apr 7, 2026
11a3324
Move unmangling to JS compiler
kleisauke Apr 8, 2026
decf760
Update comment
kleisauke Apr 8, 2026
f8be17f
Update comment (2)
kleisauke Apr 8, 2026
dd9e7bc
Merge branch 'main' into es6-acorn-closure
kleisauke May 4, 2026
39c3bae
Merge branch 'main' into es6-acorn-closure
kleisauke May 22, 2026
82db117
Automatic rebaseline of codesize expectations. NFC
kleisauke May 22, 2026
c5114bd
Merge branch 'main' into es6-acorn-closure
kleisauke Jun 9, 2026
75f626a
Automatic rebaseline of codesize expectations. NFC
kleisauke Jun 9, 2026
fc46e0a
Ensure Closure doesn't minify `Module` in `--chunk_output_type=ES_MOD…
kleisauke Jun 9, 2026
10e6383
Update comment references
kleisauke Jun 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions src/closure-externs/closure-externs.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
* The closure_compiler() method in tools/shared.py refers to this file when calling closure.
*/

// Special placeholder for `import.meta` and `await import`.
var EMSCRIPTEN$IMPORT$META;
// Special placeholder for `await import` and `await`.
var EMSCRIPTEN$AWAIT$IMPORT;
var EMSCRIPTEN$AWAIT;

Expand Down Expand Up @@ -188,13 +187,6 @@ var devicePixelRatio;
*/
var id;

/**
* Used in MODULARIZE mode as the name of the incoming module argument.
* This is generated outside of the code we pass to closure so from closure's
* POV this is "extern".
*/
var moduleArg;

/**
* This was removed from upstream closure compiler in
* https://github.com/google/closure-compiler/commit/f83322c1b.
Expand Down
14 changes: 10 additions & 4 deletions src/closure-externs/modularize-externs.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
// In MODULARIZE mode the JS code may be executed later, after `document.currentScript` is gone, so we store
// it to `_scriptName` outside the wrapper function. Therefore, it cannot be minified.
// In EXPORT_ES6 mode we use `import.meta.url` and for Node.js CommonJS builds we use `__filename`.

/**
* In MODULARIZE mode the JS code may be executed later, after `document.currentScript` is gone, so
* we store it to `_scriptName` outside the wrapper function. Therefore, it cannot be minified.
* In EXPORT_ES6 mode we use `import.meta.url` and for Node.js CommonJS builds we use `__filename`.
* @suppress {duplicate, undefinedVars}
*/
var _scriptName;

/**
* Used in MODULARIZE mode as the name of the incoming module argument.
* This is generated outside of the code we pass to closure so from closure's
* POV this is "extern".
*/
var moduleArg;

/**
* @suppress {duplicate, undefinedVars}
*/
Expand Down
6 changes: 6 additions & 0 deletions src/jsifier.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,12 @@ export async function runJSify(outputFile, symbolsOnly) {
}

async function writeOutput(str) {
// Unmangle previously mangled `import.meta` references.
// See also: `mangleUnsupportedSyntax` in parseTools.mjs.
if (EXPORT_ES6) {
str = str.replaceAll('EMSCRIPTEN$IMPORT$META', 'import.meta');
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Perhaps mention why we are doing this?

Something like "Unmangle import.meta which was only mangled to allow the code to flow through vm.runInContext".

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This is already mentioned in the comment that is referenced.

if (EXPORT_ES6) {
// `vm.runInContext` doesn't support module syntax; to allow it, we need to
// temporarily replace `import.meta` usages with placeholders.
// See also: `writeOutput` in jsifier.mjs.
text = text.replaceAll('import.meta', 'EMSCRIPTEN$IMPORT$META');
}


await outputHandle.write(str + '\n');
}

Expand Down
2 changes: 2 additions & 0 deletions src/modularize.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var {{{ EXPORT_NAME }}} = (() => {
var _scriptName = globalThis.document?.currentScript?.src;
#endif
return async function(moduleArg = {}) {
var Module = moduleArg;
"<<< INNER_JS_CODE >>>"

return Module;
Expand All @@ -38,6 +39,7 @@ var {{{ EXPORT_NAME }}} = (() => {
// When targeting node and ES6 we use `await import ..` in the generated code
// so the outer function needs to be marked as async.
async function {{{ EXPORT_NAME }}}(moduleArg = {}) {
var Module = moduleArg;
"<<< INNER_JS_CODE >>>"

return Module;
Expand Down
33 changes: 18 additions & 15 deletions src/parseTools.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,24 @@ function mangleUnsupportedSyntax(text) {
// Do special keyword replacement after macro processing, so that
// macros can generate keywords (easier to read preprocessed code).
if (EXPORT_ES6) {
// `eval`, Terser and Closure don't support module syntax; to allow it,
// we need to temporarily replace `import.meta` and `await import` usages
// with placeholders during preprocess phase, and back after all the other ops.
// See also: `phase_final_emitting` in emcc.py.
text = text
.replace(/\bimport\.meta\b/g, 'EMSCRIPTEN$IMPORT$META')
.replace(/\bawait import\b/g, 'EMSCRIPTEN$AWAIT$IMPORT');
}
if (MODULARIZE) {
// Same for our use of "top-level-await" which is not actually top level
// in the case of MODULARIZE.
text = text.replace(/\bawait createWasm\(\)/g, 'EMSCRIPTEN$AWAIT(createWasm())');
text = text.replace(/\bawait run\(\)/g, 'EMSCRIPTEN$AWAIT(run())');
text = text.replace(/\bawait instantiatePromise\b/g, 'EMSCRIPTEN$AWAIT(instantiatePromise)');
text = text.replace(/\bawait init\(\)/g, 'EMSCRIPTEN$AWAIT(init())');
// `vm.runInContext` doesn't support module syntax; to allow it, we need to
// temporarily replace `import.meta` usages with placeholders.
// See also: `writeOutput` in jsifier.mjs.
text = text.replaceAll('import.meta', 'EMSCRIPTEN$IMPORT$META');
}
if (MODULARIZE && USE_CLOSURE_COMPILER) {
// Closure doesn't support "top-level await" which is not actually the top
// level in case of MODULARIZE. Temporarily replace `await` usages with
// placeholders during preprocess phase, and back after all the other ops.
// See also: `fix_js_mangling` in link.py.
// FIXME: Remove after https://github.com/google/closure-compiler/issues/3835 is fixed.
if (EXPORT_ES6) {
text = text.replaceAll('await import', 'EMSCRIPTEN$AWAIT$IMPORT');
}
text = text.replaceAll('await createWasm()', 'EMSCRIPTEN$AWAIT(createWasm())');
text = text.replaceAll('await run()', 'EMSCRIPTEN$AWAIT(run())');
text = text.replaceAll('await instantiatePromise', 'EMSCRIPTEN$AWAIT(instantiatePromise)');
text = text.replaceAll('await init()', 'EMSCRIPTEN$AWAIT(init())');
}
return text;
}
Expand Down
4 changes: 1 addition & 3 deletions src/shell.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
#if MODULARIZE
#if MODULARIZE == 'instance'
var Module = {};
#else
var Module = moduleArg;
#endif
#elif USE_CLOSURE_COMPILER
/** @type{Object} */
Expand Down Expand Up @@ -130,7 +128,7 @@ if (ENVIRONMENT_IS_NODE) {
#endif
#endif // PTHREADS || WASM_WORKERS
}
#endif // ENVIRONMENT_MAY_BE_NODE
#endif // ENVIRONMENT_MAY_BE_NODE && (EXPORT_ES6 || PTHREADS || WASM_WORKERS)

// --pre-jses are emitted after the Module integration code, so that they can
// refer to Module (if they choose; they can also define Module)
Expand Down
6 changes: 3 additions & 3 deletions src/shell_minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@

#include "minimum_runtime_check.js"

#if MODULARIZE
var Module = moduleArg;
#elif USE_CLOSURE_COMPILER
#if !MODULARIZE
#if USE_CLOSURE_COMPILER
/** @type{Object} */
var Module;
// if (!Module) is crucial for Closure Compiler here as it will
Expand All @@ -30,6 +29,7 @@ var Module = globalThis.{{{ EXPORT_NAME }}} || {};
#else
var Module = {{{ EXPORT_NAME }}};
#endif
#endif // !MODULARIZE

#if ENVIRONMENT_MAY_BE_NODE
var ENVIRONMENT_IS_NODE = {{{ nodeDetectionCode() }}};
Expand Down
8 changes: 4 additions & 4 deletions test/codesize/test_codesize_minimal_esm.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"a.out.js": 2433,
"a.out.js.gz": 1138,
"a.out.js": 2368,
"a.out.js.gz": 1122,
"a.out.nodebug.wasm": 75,
"a.out.nodebug.wasm.gz": 87,
"total": 2508,
"total_gz": 1225,
"total": 2443,
"total_gz": 1209,
"sent": [],
"imports": [],
"exports": [
Expand Down
1 change: 1 addition & 0 deletions tools/acorn-optimizer.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,7 @@ const params = {
ecmaVersion: 'latest',
sourceType: exportES6 ? 'module' : 'script',
allowAwaitOutsideFunction: true,
allowImportExportEverywhere: exportES6,
};
if (closureFriendly) {
const currentComments = [];
Expand Down
8 changes: 8 additions & 0 deletions tools/building.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,14 @@ def closure_compiler(filename, advanced=True, extra_closure_args=None):

args = ['--compilation_level', 'ADVANCED_OPTIMIZATIONS' if advanced else 'SIMPLE_OPTIMIZATIONS']
args += ['--language_in', 'UNSTABLE']
# Make Closure aware of the ES6 module syntax;
# i.e. the `import.meta` and `await import` usages
if settings.EXPORT_ES6:
args += ['--chunk_output_type', 'ES_MODULES']
if settings.ENVIRONMENT_MAY_BE_NODE:
args += ['--module_resolution', 'NODE']
# https://github.com/google/closure-compiler/issues/3740
args += ['--jscomp_off=moduleLoad']
# We currently only use closure compiler for minification, not transpilation.
args += ['--language_out', 'NO_TRANSPILE']
# Tell closure never to inject the 'use strict' directive.
Expand Down
25 changes: 17 additions & 8 deletions tools/link.py
Original file line number Diff line number Diff line change
Expand Up @@ -2073,19 +2073,28 @@ def phase_source_transforms(options):
save_intermediate('transformed')


# Unmangle previously mangled `import.meta` and `await import` references in
# Unmangle previously mangled `await import` and `await` references in
# both main code and libraries.
# See also: `preprocess` in parseTools.js.
# See also: `mangleUnsupportedSyntax` in parseTools.mjs.
def fix_js_mangling(js_file):
# We don't apply these mangliings except in MODULARIZE/EXPORT_ES6 modes.
if not settings.MODULARIZE:
# Mangling only takes place under closure in MODULARIZE mode.
if not settings.MODULARIZE or not settings.USE_CLOSURE_COMPILER:
return

src = read_file(js_file)
write_file(js_file, src
.replace('EMSCRIPTEN$IMPORT$META', 'import.meta')
.replace('EMSCRIPTEN$AWAIT$IMPORT', 'await import')
.replace('EMSCRIPTEN$AWAIT(', 'await ('))

if settings.EXPORT_ES6:
# Also remove the line containing `export{};`, which is inserted by
# Closure to mark the file as an ES6 module.
# https://github.com/google/closure-compiler/issues/4084#issuecomment-1505056519
# https://github.com/google/closure-compiler/blob/v20260401/src/com/google/javascript/jscomp/ConvertChunksToESModules.java#L111-L113
src = src \
.replace('EMSCRIPTEN$AWAIT$IMPORT', 'await import') \
.replace('export{};\n', '')
Comment thread
sbc100 marked this conversation as resolved.

src = src.replace('EMSCRIPTEN$AWAIT(', 'await (')

write_file(js_file, src)
save_intermediate('js-mangling')


Expand Down
Loading