Skip to content

Commit 7b9f1c3

Browse files
authored
Add new internal setting: MINIFY_WHITESPACE (#19961)
This centralizes the control of JS whitespace minification behind a single setting. We have had a feature request to be able to disable this minification so the output can be passed to closure compiler after link time. This change doesn't yet allow the user to directly control this setting. We can consider that part as a followup. The `test_emcc_output_worker_mjs` test expectation changed because we now minify the worker.js file based on the same set of criteria as the main js file. Previously these were independent and had slightly different criteria.
1 parent 519986b commit 7b9f1c3

File tree

4 files changed

+31
-33
lines changed

4 files changed

+31
-33
lines changed

emcc.py

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,6 @@ def setup_environment_settings():
384384
exit_with_error('When building with multithreading enabled and a "-sENVIRONMENT=" directive is specified, it must include "worker" as a target! (Try e.g. -sENVIRONMENT=web,worker)')
385385

386386

387-
def minify_whitespace():
388-
return settings.OPT_LEVEL >= 2 and settings.DEBUG_LEVEL == 0
389-
390-
391387
def embed_memfile(options):
392388
return (settings.SINGLE_FILE or
393389
(settings.WASM2JS and not options.memory_init_file and
@@ -2951,6 +2947,8 @@ def get_full_import_name(name):
29512947
settings.PRE_JS_FILES = [os.path.abspath(f) for f in options.pre_js]
29522948
settings.POST_JS_FILES = [os.path.abspath(f) for f in options.post_js]
29532949

2950+
settings.MINIFY_WHITESPACE = settings.OPT_LEVEL >= 2 and settings.DEBUG_LEVEL == 0
2951+
29542952
return target, wasm_target
29552953

29562954

@@ -3223,8 +3221,8 @@ def create_worker_file(input_file, target_dir, output_file):
32233221
contents = shared.read_and_preprocess(input_file, expand_macros=True)
32243222
write_file(output_file, contents)
32253223

3226-
# Minify the worker JS files file in optimized builds
3227-
if (settings.OPT_LEVEL >= 1 or settings.SHRINK_LEVEL >= 1) and not settings.DEBUG_LEVEL:
3224+
# Minify the worker JS file, if JS minification is enabled.
3225+
if settings.MINIFY_WHITESPACE:
32283226
contents = building.acorn_optimizer(output_file, ['minifyWhitespace'], return_output=True)
32293227
write_file(output_file, contents)
32303228

@@ -3258,7 +3256,7 @@ def phase_final_emitting(options, state, target, wasm_target, memfile):
32583256
# Finally, rerun Closure compile with simple optimizations. It will be able
32593257
# to further minify the code. (n.b. it would not be safe to run in advanced
32603258
# mode)
3261-
final_js = building.closure_compiler(final_js, pretty=False, advanced=False, extra_closure_args=options.closure_args)
3259+
final_js = building.closure_compiler(final_js, advanced=False, extra_closure_args=options.closure_args)
32623260

32633261
# Unmangle previously mangled `import.meta` and `await import` references in
32643262
# both main code and libraries.
@@ -3769,7 +3767,6 @@ def phase_binaryen(target, options, wasm_target):
37693767
final_js = building.minify_wasm_js(js_file=final_js,
37703768
wasm_file=wasm_target,
37713769
expensive_optimizations=will_metadce(),
3772-
minify_whitespace=minify_whitespace() and not options.use_closure_compiler,
37733770
debug_info=intermediate_debug_info)
37743771
save_intermediate_with_wasm('postclean', wasm_target)
37753772

@@ -3780,11 +3777,10 @@ def phase_binaryen(target, options, wasm_target):
37803777
if final_js and (options.use_closure_compiler or settings.TRANSPILE_TO_ES5):
37813778
if options.use_closure_compiler:
37823779
with ToolchainProfiler.profile_block('closure_compile'):
3783-
final_js = building.closure_compiler(final_js, pretty=not minify_whitespace(),
3784-
extra_closure_args=options.closure_args)
3780+
final_js = building.closure_compiler(final_js, extra_closure_args=options.closure_args)
37853781
else:
37863782
with ToolchainProfiler.profile_block('closure_transpile'):
3787-
final_js = building.closure_transpile(final_js, pretty=not minify_whitespace())
3783+
final_js = building.closure_transpile(final_js)
37883784
save_intermediate_with_wasm('closure', wasm_target)
37893785

37903786
symbols_file = None
@@ -3810,7 +3806,6 @@ def phase_binaryen(target, options, wasm_target):
38103806
wasm2js = building.wasm2js(wasm2js_template,
38113807
wasm_target,
38123808
opt_level=settings.OPT_LEVEL,
3813-
minify_whitespace=minify_whitespace(),
38143809
use_closure_compiler=options.use_closure_compiler,
38153810
debug_info=debug_info,
38163811
symbols_file=symbols_file,

src/settings_internal.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,5 @@ var POST_JS_FILES = [];
265265
var PTHREADS = false;
266266

267267
var BULK_MEMORY = false;
268+
269+
var MINIFY_WHITESPACE = true;

test/test_other.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ def test_emcc_output_worker_mjs(self, args):
306306
self.assertContained("new Worker(new URL('hello_world.worker.js', import.meta.url))", src)
307307
self.assertContained('export default Module;', src)
308308
src = read_file('subdir/hello_world.worker.js')
309-
self.assertContained('import("./hello_world.mjs")', src)
309+
self.assertContained("import('./hello_world.mjs')", src)
310310
self.assertContained('hello, world!', self.run_js('subdir/hello_world.mjs'))
311311

312312
@node_pthreads

tools/building.py

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -485,16 +485,16 @@ def add_to_path(dirname):
485485

486486

487487
@ToolchainProfiler.profile()
488-
def closure_transpile(filename, pretty):
488+
def closure_transpile(filename):
489489
user_args = []
490490
closure_cmd, env = get_closure_compiler_and_env(user_args)
491491
closure_cmd += ['--language_out', 'ES5']
492492
closure_cmd += ['--compilation_level', 'WHITESPACE_ONLY']
493-
return run_closure_cmd(closure_cmd, filename, env, pretty)
493+
return run_closure_cmd(closure_cmd, filename, env)
494494

495495

496496
@ToolchainProfiler.profile()
497-
def closure_compiler(filename, pretty, advanced=True, extra_closure_args=None):
497+
def closure_compiler(filename, advanced=True, extra_closure_args=None):
498498
user_args = []
499499
env_args = os.environ.get('EMCC_CLOSURE_ARGS')
500500
if env_args:
@@ -573,10 +573,10 @@ def closure_compiler(filename, pretty, advanced=True, extra_closure_args=None):
573573
args += user_args
574574

575575
cmd = closure_cmd + args
576-
return run_closure_cmd(cmd, filename, env, pretty=pretty)
576+
return run_closure_cmd(cmd, filename, env)
577577

578578

579-
def run_closure_cmd(cmd, filename, env, pretty):
579+
def run_closure_cmd(cmd, filename, env):
580580
cmd += ['--js', filename]
581581

582582
# Closure compiler is unable to deal with path names that are not 7-bit ASCII:
@@ -605,7 +605,7 @@ def move_to_safe_7bit_ascii_filename(filename):
605605

606606
# Specify output file relative to the temp directory to avoid specifying non-7-bit-ASCII path names.
607607
cmd += ['--js_output_file', os.path.relpath(outfile, tempfiles.tmpdir)]
608-
if pretty:
608+
if not settings.MINIFY_WHITESPACE:
609609
cmd += ['--formatting', 'PRETTY_PRINT']
610610

611611
shared.print_compiler_stage(cmd)
@@ -645,7 +645,7 @@ def move_to_safe_7bit_ascii_filename(filename):
645645

646646
# Exit and print final hint to get clearer output
647647
msg = f'closure compiler failed (rc: {proc.returncode}): {shared.shlex_join(cmd)}'
648-
if not pretty:
648+
if settings.MINIFY_WHITESPACE:
649649
msg += ' the error message may be clearer with -g1 and EMCC_DEBUG=2 set'
650650
exit_with_error(msg)
651651

@@ -657,7 +657,7 @@ def move_to_safe_7bit_ascii_filename(filename):
657657
logger.warn(proc.stderr)
658658

659659
# Exit and/or print final hint to get clearer output
660-
if not pretty:
660+
if settings.MINIFY_WHITESPACE:
661661
logger.warn('(rerun with -g1 linker flag for an unminified output)')
662662
elif DEBUG != 2:
663663
logger.warn('(rerun with EMCC_DEBUG=2 enabled to dump Closure input file)')
@@ -670,14 +670,16 @@ def move_to_safe_7bit_ascii_filename(filename):
670670

671671
# minify the final wasm+JS combination. this is done after all the JS
672672
# and wasm optimizations; here we do the very final optimizations on them
673-
def minify_wasm_js(js_file, wasm_file, expensive_optimizations, minify_whitespace, debug_info):
673+
def minify_wasm_js(js_file, wasm_file, expensive_optimizations, debug_info):
674674
# start with JSDCE, to clean up obvious JS garbage. When optimizing for size,
675675
# use AJSDCE (aggressive JS DCE, performs multiple iterations). Clean up
676676
# whitespace if necessary too.
677677
passes = []
678678
if not settings.LINKABLE:
679679
passes.append('JSDCE' if not expensive_optimizations else 'AJSDCE')
680-
if minify_whitespace:
680+
# Don't minify if we are going to run closure compiler afterwards
681+
minify = settings.MINIFY_WHITESPACE and not settings.USE_CLOSURE_COMPILER
682+
if minify:
681683
passes.append('minifyWhitespace')
682684
if passes:
683685
logger.debug('running cleanup on shell code: ' + ' '.join(passes))
@@ -688,24 +690,23 @@ def minify_wasm_js(js_file, wasm_file, expensive_optimizations, minify_whitespac
688690
# if we are optimizing for size, shrink the combined wasm+JS
689691
# TODO: support this when a symbol map is used
690692
if expensive_optimizations:
691-
js_file = metadce(js_file, wasm_file, minify_whitespace=minify_whitespace, debug_info=debug_info)
693+
js_file = metadce(js_file, wasm_file, debug_info=debug_info)
692694
# now that we removed unneeded communication between js and wasm, we can clean up
693695
# the js some more.
694696
passes = ['AJSDCE']
695-
if minify_whitespace:
697+
if minify:
696698
passes.append('minifyWhitespace')
697699
logger.debug('running post-meta-DCE cleanup on shell code: ' + ' '.join(passes))
698700
js_file = acorn_optimizer(js_file, passes)
699701
if settings.MINIFY_WASM_IMPORTS_AND_EXPORTS:
700702
js_file = minify_wasm_imports_and_exports(js_file, wasm_file,
701-
minify_whitespace=minify_whitespace,
702703
minify_exports=settings.MINIFY_WASM_EXPORT_NAMES,
703704
debug_info=debug_info)
704705
return js_file
705706

706707

707708
# run binaryen's wasm-metadce to dce both js and wasm
708-
def metadce(js_file, wasm_file, minify_whitespace, debug_info):
709+
def metadce(js_file, wasm_file, debug_info):
709710
logger.debug('running meta-DCE')
710711
temp_files = shared.get_temp_files()
711712
# first, get the JS part of the graph
@@ -788,7 +789,7 @@ def metadce(js_file, wasm_file, minify_whitespace, debug_info):
788789
unused.append(name)
789790
# remove them
790791
passes = ['applyDCEGraphRemovals']
791-
if minify_whitespace:
792+
if settings.MINIFY_WHITESPACE:
792793
passes.append('minifyWhitespace')
793794
extra_info = {'unused': unused}
794795
return acorn_optimizer(js_file, passes, extra_info=json.dumps(extra_info))
@@ -819,7 +820,7 @@ def asyncify_lazy_load_code(wasm_target, debug):
819820
debug=debug)
820821

821822

822-
def minify_wasm_imports_and_exports(js_file, wasm_file, minify_whitespace, minify_exports, debug_info):
823+
def minify_wasm_imports_and_exports(js_file, wasm_file, minify_exports, debug_info):
823824
logger.debug('minifying wasm imports and exports')
824825
# run the pass
825826
if minify_exports:
@@ -850,13 +851,13 @@ def minify_wasm_imports_and_exports(js_file, wasm_file, minify_whitespace, minif
850851
mapping[old] = new
851852
# apply them
852853
passes = ['applyImportAndExportNameChanges']
853-
if minify_whitespace:
854+
if settings.MINIFY_WHITESPACE:
854855
passes.append('minifyWhitespace')
855856
extra_info = {'mapping': mapping}
856857
return acorn_optimizer(js_file, passes, extra_info=json.dumps(extra_info))
857858

858859

859-
def wasm2js(js_file, wasm_file, opt_level, minify_whitespace, use_closure_compiler, debug_info, symbols_file=None, symbols_file_js=None):
860+
def wasm2js(js_file, wasm_file, opt_level, use_closure_compiler, debug_info, symbols_file=None, symbols_file_js=None):
860861
logger.debug('wasm2js')
861862
args = ['--emscripten']
862863
if opt_level > 0:
@@ -876,7 +877,7 @@ def wasm2js(js_file, wasm_file, opt_level, minify_whitespace, use_closure_compil
876877
passes += ['minifyNames']
877878
if symbols_file_js:
878879
passes += ['symbolMap=%s' % symbols_file_js]
879-
if minify_whitespace:
880+
if settings.MINIFY_WHITESPACE:
880881
passes += ['minifyWhitespace']
881882
passes += ['last']
882883
if passes:
@@ -897,7 +898,7 @@ def wasm2js(js_file, wasm_file, opt_level, minify_whitespace, use_closure_compil
897898
temp = shared.get_temp_files().get('.js').name
898899
with open(temp, 'a') as f:
899900
f.write(wasm2js_js)
900-
temp = closure_compiler(temp, pretty=not minify_whitespace, advanced=False)
901+
temp = closure_compiler(temp, advanced=False)
901902
wasm2js_js = utils.read_file(temp)
902903
# closure may leave a trailing `;`, which would be invalid given where we place
903904
# this code (inside parens)

0 commit comments

Comments
 (0)