bundle-assets.py (2250B)
1 #!/usr/bin/env python3 2 """Bundle production entrypoints while preserving their import.meta.url bases.""" 3 import argparse 4 import json 5 from pathlib import Path 6 import shutil 7 import subprocess 8 9 ENTRIES = ['dist/app.js', 'dist/wasm-worker.js', 'dist/local-module-worker.js', 10 'runtime/haskell/client.mjs', 'runtime/haskell/worker.mjs'] 11 12 13 def bundle(root, probe): 14 root = root.resolve() 15 support = root / 'nix-support' 16 support.mkdir(exist_ok=True) 17 shutil.copyfile(root / 'runtime/haskell/pins.mjs', support / 'haskell-pins.mjs') 18 shutil.copyfile(probe, root / 'dist/probe-api.js') 19 graphs = {} 20 for entry in [*ENTRIES, 'dist/probe-api.js']: 21 output = 'bundled/' + entry 22 subprocess.run(['esbuild', entry, '--bundle', '--format=esm', 23 '--platform=browser', '--target=es2020', 24 '--legal-comments=inline', '--outfile=' + output, 25 '--metafile=graph.json'], cwd=root, check=True) 26 graph = json.loads((root / 'graph.json').read_text()) 27 # Computed URL imports retain explicit lazy runtime boundaries. All 28 # statically resolved imports must be contained in their entrypoint. 29 assert all(not row['imports'] for row in graph['outputs'].values()) 30 graphs[entry] = graph 31 (support / 'bundle-graphs.json').write_text(json.dumps(graphs, indent=2) + '\n') 32 (root / 'graph.json').unlink() 33 for name in ['dist', 'runtime']: 34 for path in (root / name).rglob('*'): 35 if path.suffix in ['.js', '.mjs']: 36 path.unlink() 37 for entry in ENTRIES: 38 shutil.move(root / 'bundled' / entry, root / entry) 39 shutil.move(root / 'bundled/dist/probe-api.js', support / 'probe-api.js') 40 shutil.rmtree(root / 'bundled') 41 # Empty module directories would otherwise imply unshipped entrypoints. 42 for path in sorted((root / 'runtime').rglob('*'), reverse=True): 43 if path.is_dir() and not any(path.iterdir()): 44 path.rmdir() 45 46 47 if __name__ == '__main__': 48 parser = argparse.ArgumentParser(description=__doc__) 49 parser.add_argument('root', type=Path) 50 parser.add_argument('probe', type=Path) 51 args = parser.parse_args() 52 bundle(args.root, args.probe)