Skip to content

Commit d0d1498

Browse files
committed
Use babel for transpiling rather than closure compiler
We recently switch from using closure-compiler with `WHITESPACE_ONLY` to closure-compiler with `SIMPLE_OPTIMIZATIONS`. However this had the negative side effect that all input need to be free of closure compiler warnings, and this turned out not to be practical for all users. See #20810 for more on this When selecting a transpilation tool use I also evaluated `swx` (written in rust) and `esbuild` (written in go). `esbuild` was rejected because the simply don't support ES5 (evanw/esbuild#297). `swx` was rejected because it almost doubled the side of our `node_modules` directory by adding two 50mb binary files.
1 parent dabbde6 commit d0d1498

File tree

8 files changed

+6264
-2533
lines changed

8 files changed

+6264
-2533
lines changed

.flake8

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[flake8]
22
ignore = E111,E114,E501,E261,E266,E121,E402,E241,W504,E741,B011,B023,U101
33
exclude =
4+
./node_modules/, # third-party code
45
./third_party/, # third-party code
56
./tools/filelock.py, # third-party code
67
./tools/scons/, # third-party code

package-lock.json

Lines changed: 6213 additions & 2498 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
"ws": "^8.14.2"
1212
},
1313
"dependencies": {
14+
"@babel/cli": "^7.23.4",
15+
"@babel/core": "^7.23.5",
16+
"@babel/preset-env": "^7.23.5",
1417
"acorn": "^8.11.2",
1518
"google-closure-compiler": "20230802.0.0",
1619
"html-minifier-terser": "7.2.0"

src/settings_internal.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,9 @@ var LINK_AS_CXX = false;
243243
// emitted in that case for closure compiler.
244244
var MAYBE_CLOSURE_COMPILER = false;
245245

246-
// Set when some minimum browser version triggers doesn't support the
247-
// minimum set of ES6 features. This triggers transpilation to ES5
248-
// using closure compiler.
249-
var TRANSPILE_TO_ES5 = false;
246+
// Set when some minimum browser version triggers doesn't support the minimum
247+
// set of JavaScript features. This triggers transpilation using babel.
248+
var TRANSPILE = false;
250249

251250
// A copy of the default the default INCOMING_MODULE_JS_API. (Soon to
252251
// include additional items).

test/test_other.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13130,7 +13130,6 @@ def check_for_es6(filename, expect):
1313013130
self.assertContained('foo(arg="hello")', js)
1313113131
self.assertContained(['() => 2', '()=>2'], js)
1313213132
self.assertContained('const ', js)
13133-
self.assertContained('let ', js)
1313413133
self.assertContained('?.[', js)
1313513134
self.assertContained('?.(', js)
1313613135
self.assertContained('??=', js)
@@ -13142,7 +13141,6 @@ def check_for_es6(filename, expect):
1314213141
self.assertNotContained('() => 2', js)
1314313142
self.assertNotContained('()=>2', js)
1314413143
self.assertNotContained('const ', js)
13145-
self.assertNotContained('let ', js)
1314613144
self.assertNotContained('??', js)
1314713145
self.assertNotContained('?.', js)
1314813146
self.assertNotContained('||=', js)

tools/building.py

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
from .shared import get_emscripten_temp_dir, exe_suffix, is_c_symbol
3434
from .utils import WINDOWS
3535
from .settings import settings, default_setting
36+
from .feature_matrix import UNSUPPORTED
3637

3738
logger = logging.getLogger('building')
3839

@@ -509,14 +510,33 @@ def add_to_path(dirname):
509510
return closure_cmd, env
510511

511512

513+
def version_split(v):
514+
v = str(v)
515+
assert len(v) == 6
516+
rev = int(v[4:6])
517+
minor = int(v[2:4])
518+
major = int(v[0:2])
519+
return f'{major}.{minor}.{rev}'
520+
521+
512522
@ToolchainProfiler.profile()
513-
def closure_transpile(filename):
514-
user_args = []
515-
closure_cmd, env = get_closure_compiler_and_env(user_args)
516-
closure_cmd += ['--language_out', 'ES5']
517-
closure_cmd += ['--compilation_level', 'SIMPLE_OPTIMIZATIONS']
518-
closure_cmd += ['--formatting', 'PRETTY_PRINT']
519-
return run_closure_cmd(closure_cmd, filename, env)
523+
def transpile(filename):
524+
config = {'targets': {}}
525+
if settings.MIN_CHROME_VERSION != UNSUPPORTED:
526+
config['targets']['chrome'] = str(settings.MIN_CHROME_VERSION)
527+
if settings.MIN_FIREFOX_VERSION != UNSUPPORTED:
528+
config['targets']['firefox'] = str(settings.MIN_FIREFOX_VERSION)
529+
if settings.MIN_SAFARI_VERSION != UNSUPPORTED:
530+
config['targets']['safari'] = version_split(settings.MIN_SAFARI_VERSION)
531+
if settings.MIN_NODE_VERSION != UNSUPPORTED:
532+
config['targets']['node'] = version_split(settings.MIN_NODE_VERSION)
533+
config_json = json.dumps(config, indent=2)
534+
outfile = shared.get_temp_files().get('babel.js').name
535+
config_file = shared.get_temp_files().get('babel_config.json').name
536+
utils.write_file(config_file, config_json)
537+
cmd = shared.get_npm_cmd('babel') + [filename, '-o', outfile, '--presets', '@babel/preset-env', '--config-file', config_file]
538+
check_call(cmd, cwd=path_from_root())
539+
return outfile
520540

521541

522542
@ToolchainProfiler.profile()
@@ -581,13 +601,8 @@ def closure_compiler(filename, advanced=True, extra_closure_args=None):
581601
args = ['--compilation_level', 'ADVANCED_OPTIMIZATIONS' if advanced else 'SIMPLE_OPTIMIZATIONS']
582602
# Keep in sync with ecmaVersion in tools/acorn-optimizer.mjs
583603
args += ['--language_in', 'ECMASCRIPT_2021']
584-
# Tell closure not to do any transpiling or inject any polyfills.
585-
# At some point we may want to look into using this as way to convert to ES5 but
586-
# babel is perhaps a better tool for that.
587-
if settings.TRANSPILE_TO_ES5:
588-
args += ['--language_out', 'ES5']
589-
else:
590-
args += ['--language_out', 'NO_TRANSPILE']
604+
# We do transpilation using babel
605+
args += ['--language_out', 'NO_TRANSPILE']
591606
# Tell closure never to inject the 'use strict' directive.
592607
args += ['--emit_use_strict=false']
593608

tools/feature_matrix.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
logger = logging.getLogger('feature_matrix')
1515

16+
UNSUPPORTED = 0x7FFFFFFF
17+
1618

1719
class Feature(IntEnum):
1820
NON_TRAPPING_FPTOINT = auto()
@@ -96,7 +98,7 @@ def report_missing(setting_name):
9698
report_missing('MIN_SAFARI_VERSION')
9799
return False
98100
# IE don't support any non-MVP features
99-
if settings.MIN_IE_VERSION != 0x7FFFFFFF:
101+
if settings.MIN_IE_VERSION != UNSUPPORTED:
100102
report_missing('MIN_IE_VERSION')
101103
return False
102104
if 'node' in min_versions and settings.MIN_NODE_VERSION < min_versions['node']:

tools/link.py

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,15 +1138,12 @@ def phase_linker_setup(options, state, newargs):
11381138
# Taking the highest requirements gives is our minimum:
11391139
# Max Version: EDGE:85 FF:79 CHROME:85 SAFARI:14 NODE:16
11401140
# TODO: replace this with feature matrix in the future.
1141-
settings.TRANSPILE_TO_ES5 = (settings.MIN_EDGE_VERSION < 85 or
1142-
settings.MIN_FIREFOX_VERSION < 79 or
1143-
settings.MIN_CHROME_VERSION < 85 or
1144-
settings.MIN_SAFARI_VERSION < 140000 or
1145-
settings.MIN_NODE_VERSION < 160000 or
1146-
settings.MIN_IE_VERSION != 0x7FFFFFFF)
1147-
1148-
if options.use_closure_compiler is None and settings.TRANSPILE_TO_ES5:
1149-
diagnostics.warning('transpile', 'enabling transpilation via closure due to browser version settings. This warning can be suppressed by passing `--closure=1` or `--closure=0` to opt into this explicitly.')
1141+
settings.TRANSPILE = (settings.MIN_EDGE_VERSION < 85 or
1142+
settings.MIN_FIREFOX_VERSION < 79 or
1143+
settings.MIN_CHROME_VERSION < 85 or
1144+
settings.MIN_SAFARI_VERSION < 140000 or
1145+
settings.MIN_NODE_VERSION < 160000 or
1146+
settings.MIN_IE_VERSION != 0x7FFFFFFF)
11501147

11511148
# https://caniuse.com/class: EDGE:13 FF:45 CHROME:49 SAFARI:9
11521149
supports_es6_classes = (settings.MIN_EDGE_VERSION >= 13 and
@@ -2203,14 +2200,15 @@ def phase_binaryen(target, options, wasm_target, memfile):
22032200
with ToolchainProfiler.profile_block('asyncify_lazy_load_code'):
22042201
building.asyncify_lazy_load_code(wasm_target, debug=intermediate_debug_info)
22052202

2206-
if final_js and (options.use_closure_compiler or settings.TRANSPILE_TO_ES5):
2203+
if final_js:
22072204
if options.use_closure_compiler:
22082205
with ToolchainProfiler.profile_block('closure_compile'):
22092206
final_js = building.closure_compiler(final_js, extra_closure_args=options.closure_args)
2210-
else:
2211-
with ToolchainProfiler.profile_block('closure_transpile'):
2212-
final_js = building.closure_transpile(final_js)
2213-
save_intermediate_with_wasm('closure', wasm_target)
2207+
save_intermediate_with_wasm('closure', wasm_target)
2208+
if settings.TRANSPILE:
2209+
with ToolchainProfiler.profile_block('transpile'):
2210+
final_js = building.transpile(final_js)
2211+
save_intermediate_with_wasm('traspile', wasm_target)
22142212

22152213
symbols_file = None
22162214
if options.emit_symbol_map:

0 commit comments

Comments
 (0)