From dccdb6d87ac69b1073bc5339d782ccb90a85c44f Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Fri, 15 Dec 2023 10:50:58 +0700 Subject: [PATCH 1/4] feat(web): creates a Web-bundling cmd script --- common/web/es-bundling/src/common-bundle.mts | 123 +++++++++++++++++++ common/web/es-bundling/tsconfig.json | 3 + 2 files changed, 126 insertions(+) create mode 100644 common/web/es-bundling/src/common-bundle.mts diff --git a/common/web/es-bundling/src/common-bundle.mts b/common/web/es-bundling/src/common-bundle.mts new file mode 100644 index 00000000000..9ce8227d7db --- /dev/null +++ b/common/web/es-bundling/src/common-bundle.mts @@ -0,0 +1,123 @@ +import fs from 'fs'; +import esbuild from 'esbuild'; +import { esmConfiguration, iifeConfiguration } from './configuration.mjs'; +import { prepareTslibTreeshaking } from './tslibTreeshaking.mjs'; + +let FORMAT = 'iife'; +let MINIFY = false; + +let sourceFromArgs; +let destFromArgs; +let profilePath; + +function doHelp(errCode?: number) { + console.log(` +Summary: + Uses esbuild to generate bundled-JS according to common, repo-wide KeymanWeb-oriented settings. + +Usage: + common-bundle.mjs --outDir [options...] + +Parameters: + : Fully-bundled and compiled JS file to be wrapped. + : Specifies the destination path for the wrapped output. + +Options: + --help Shows this script's documentation + --format= Sets the format type to use for the generated bundle. Should be + 'iife' or 'esm'. + + If not specified, 'iife' will be used. + --minify Enables minification. + --profile= Generates an associated filesize profile at the specified path. +` ); + process.exit(errCode || 0); +} + +if(process.argv.length > 2) { + for(let i = 2; i < process.argv.length; i++) { + const arg = process.argv[i]; + + switch(arg) { + case '--help': + doHelp(); + break; + case '--format': // bc TS uses this exact flag. esbuild... uses sourcemap (in the JS config) + let input = process.argv[++i]; + switch(input) { + case 'iife': + case 'esm': + FORMAT = input; + break; + default: + console.error(`Invalid bundling format specified: ${input}. Must be 'iife' or 'esm'.`); + doHelp(1); + break; + } + break; + case '--minify': + MINIFY = true; + break; + case '--out': + destFromArgs = process.argv[++i]; + break; + case '--profile': + profilePath = process.argv[++i]; + break; + default: + if(!sourceFromArgs) { + sourceFromArgs = arg; + } else { + doHelp(1); + } + } + } +} + +function fileSpecError(type: 'input' | 'output', file?: string) { + console.error(`${file ? 'Invalid' : 'No'} ${type} file ${file ? `(${file})`: ''} has been specified; aborting.`); + console.log(); + doHelp(1); +} + +function checkFileSpec(file: string, type: 'input' | 'output') { + if(!file) { + fileSpecError(type); + } else { + const ext = file.substring(file.lastIndexOf('.')); + switch(ext) { + case '.js': + case '.mjs': + case '.ts': + case '.mts': + break; + default: + fileSpecError(type, file); + } + } +} + +checkFileSpec(sourceFromArgs, 'input'); +checkFileSpec(destFromArgs, 'output'); + +const sourceFile = sourceFromArgs; +const destFile = destFromArgs; + +// And now to start the actual bundling config + operation. +const baseConfig = FORMAT == 'iife' ? iifeConfiguration : esmConfiguration; + +const config: esbuild.BuildOptions = { + ...baseConfig, + entryPoints: [sourceFile], + outfile: destFile, + minify: MINIFY, + metafile: !!profilePath +}; + +await prepareTslibTreeshaking(config); +const results = await esbuild.build(config); + +if(results.metafile) { + let filesizeProfile = await esbuild.analyzeMetafile(results.metafile, { verbose: true }); + fs.writeFileSync(profilePath, filesizeProfile); +} \ No newline at end of file diff --git a/common/web/es-bundling/tsconfig.json b/common/web/es-bundling/tsconfig.json index a5149b51c6f..e3076e3e12c 100644 --- a/common/web/es-bundling/tsconfig.json +++ b/common/web/es-bundling/tsconfig.json @@ -1,6 +1,9 @@ { "extends": "../../../tsconfig.base.json", "compilerOptions": { + // Primary settings - the version of ES6 we can target in TS, our downcompile target, + // and our module-related settings. + "allowSyntheticDefaultImports": true, "baseUrl": "./", "outDir": "build/", "tsBuildInfoFile": "build/tsconfig.tsbuildinfo", From 0b8ee4e6dbec2a6503f07d8a61f9a3135a4d8e16 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Fri, 15 Dec 2023 10:51:34 +0700 Subject: [PATCH 2/4] refactor(web): drops lm-worker primary bundle script --- common/web/lm-worker/build-bundler.js | 72 --------------------------- common/web/lm-worker/build.sh | 8 ++- 2 files changed, 6 insertions(+), 74 deletions(-) delete mode 100644 common/web/lm-worker/build-bundler.js diff --git a/common/web/lm-worker/build-bundler.js b/common/web/lm-worker/build-bundler.js deleted file mode 100644 index 3319aaa2d06..00000000000 --- a/common/web/lm-worker/build-bundler.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Note: while this file is not meant to exist long-term, it provides a nice - * low-level proof-of-concept for esbuild bundling of the various Web submodules. - * - * Add some extra code at the end of src/index.ts and run it to verify successful bundling! - */ - -import esbuild from 'esbuild'; -import { bundleObjEntryPoints, iifeConfiguration, prepareTslibTreeshaking } from '../es-bundling/build/index.mjs'; - -import fs from 'fs'; - -let EMIT_FILESIZE_PROFILE = false; - -if(process.argv.length > 2) { - for(let i = 2; i < process.argv.length; i++) { - const arg = process.argv[i]; - - switch(arg) { - case '': - break; - case '--ci': - EMIT_FILESIZE_PROFILE=true - break; - // May add other options if desired in the future. - default: - console.error("Invalid command-line option set for script; only --ci is permitted."); - process.exit(1); - } - } -} - -const embeddedWorkerBuildOptions = await prepareTslibTreeshaking({ - ...iifeConfiguration, - ...bundleObjEntryPoints('intermediate', 'build/obj/worker-main.js'), - // To be explicit, in comparison to the other build below. Even if our other - // configs change their default, we should not minify for THIS build; we'll - // have a separate minify pass later, after concatenating our polyfills. - minify: false - // No treeshaking at the moment (in case it treeshakes out certain model templates!) -}); - -// Direct-use version -await esbuild.build(embeddedWorkerBuildOptions); - -// ------------------------ - -// Now to generate a filesize profile for the minified version of the worker. -// We want a specialized bundle build here instead; no output, but minified like -// the actual release worker. -const minifiedProfilingOptions = { - ...embeddedWorkerBuildOptions, - minify: true, - // Do NOT enable - will break under Android 5.0 / Chrome 35 environments, likely through Chrome 42. - // https://caniuse.com/mdn-javascript_builtins_function_name_configurable_true - keepNames: false, - metafile: true, - write: false // don't actually write the file. -} - -let result = await esbuild.build(minifiedProfilingOptions); -let filesizeProfile = await esbuild.analyzeMetafile(result.metafile, { verbose: true }); -fs.writeFileSync('build/filesize-profile.log', ` -// Minified Worker filesize profile, before polyfilling -${filesizeProfile} -`); - -if(EMIT_FILESIZE_PROFILE) { - console.log("Minified, pre-polyfill worker filesize profile:"); - // Profiles the sourcecode! - console.log(filesizeProfile); -} diff --git a/common/web/lm-worker/build.sh b/common/web/lm-worker/build.sh index 48ba1f908d0..0c07c100c37 100755 --- a/common/web/lm-worker/build.sh +++ b/common/web/lm-worker/build.sh @@ -26,6 +26,8 @@ WORKER_OUTPUT_FILENAME=build/lib/worker-main.js INTERMEDIATE=./build/intermediate LIB=./build/lib +bundle_cmd="node ../es-bundling/build/common-bundle.mjs" + ################################ Main script ################################ builder_describe \ @@ -38,14 +40,16 @@ builder_describe \ builder_describe_outputs \ configure /node_modules \ - build /common/web/lm-worker/build/lib/worker-main.wrapped.min.js + build /common/web/lm-worker/$LIB/worker-main.wrapped.min.js builder_parse "$@" function do_build() { # Build worker with tsc first tsc -b $builder_verbose || builder_die "Could not build worker." - node build-bundler.js + + $bundle_cmd build/obj/worker-main.js --out $INTERMEDIATE/worker-main.js + $bundle_cmd build/obj/worker-main.js --out $INTERMEDIATE/worker-main.min.js --minify --profile build/filesize-profile.log EXT_FLAGS= if builder_has_option --ci; then From 85996ca05722fc6b75316316a851ed960bd448a2 Mon Sep 17 00:00:00 2001 From: "Joshua A. Horton" Date: Wed, 20 Dec 2023 09:24:19 +0700 Subject: [PATCH 3/4] fix(web): low-arg count handling --- common/web/es-bundling/src/common-bundle.mts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/common/web/es-bundling/src/common-bundle.mts b/common/web/es-bundling/src/common-bundle.mts index 9ce8227d7db..12d2cb8d07c 100644 --- a/common/web/es-bundling/src/common-bundle.mts +++ b/common/web/es-bundling/src/common-bundle.mts @@ -72,6 +72,9 @@ if(process.argv.length > 2) { } } } +} else { + // Not enough args; display help + abort. + doHelp(1); } function fileSpecError(type: 'input' | 'output', file?: string) { From 0eb146d60ceaed41fbc6fea6f09dc845bf03d170 Mon Sep 17 00:00:00 2001 From: Joshua Horton Date: Wed, 20 Dec 2023 09:56:31 +0700 Subject: [PATCH 4/4] chore(web): removes new, improperly-placed comment --- common/web/es-bundling/tsconfig.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/common/web/es-bundling/tsconfig.json b/common/web/es-bundling/tsconfig.json index e3076e3e12c..54c922e1bd8 100644 --- a/common/web/es-bundling/tsconfig.json +++ b/common/web/es-bundling/tsconfig.json @@ -1,8 +1,6 @@ { "extends": "../../../tsconfig.base.json", "compilerOptions": { - // Primary settings - the version of ES6 we can target in TS, our downcompile target, - // and our module-related settings. "allowSyntheticDefaultImports": true, "baseUrl": "./", "outDir": "build/",