From a441a71e8e1b9f8cd1fa83cbc4d6aa5f4bec8e2f Mon Sep 17 00:00:00 2001 From: Yulong Wang <7679871+fs-eire@users.noreply.github.com> Date: Wed, 11 Oct 2023 09:38:51 -0700 Subject: [PATCH] [js/web] support different export format for ort-web (#17878) ### Description support different export format for ort-web. --- js/web/package.json | 87 +++++++++++++++++++++++++--- js/web/script/build.ts | 125 +++++++++++++++++++++++++++++------------ js/web/types.d.ts | 16 ++++++ 3 files changed, 184 insertions(+), 44 deletions(-) diff --git a/js/web/package.json b/js/web/package.json index d0bad8ffba128..997860055ff50 100644 --- a/js/web/package.json +++ b/js/web/package.json @@ -66,18 +66,91 @@ "main": "dist/ort-web.node.js", "exports": { ".": { - "node": { - "types": "./types.d.ts", - "default": "./dist/ort.node.min.js" + "node": "./dist/ort.node.min.js", + "default": { + "import": { + "development": "./dist/esm/ort.js", + "default": "./dist/esm/ort.min.js" + }, + "require": { + "development": "./dist/cjs/ort.js", + "default": "./dist/cjs/ort.min.js" + }, + "default": { + "development": "./dist/ort.js", + "default": "./dist/ort.min.js" + } + } + }, + "./experimental": { + "import": { + "development": "./dist/esm/ort.all.js", + "default": "./dist/esm/ort.all.min.js" + }, + "require": { + "development": "./dist/cjs/ort.all.js", + "default": "./dist/cjs/ort.all.min.js" + }, + "default": { + "development": "./dist/ort.all.js", + "default": "./dist/ort.all.min.js" + } + }, + "./wasm": { + "import": { + "development": "./dist/esm/ort.wasm.js", + "default": "./dist/esm/ort.wasm.min.js" + }, + "require": { + "development": "./dist/cjs/ort.wasm.js", + "default": "./dist/cjs/ort.wasm.min.js" }, "default": { - "types": "./types.d.ts", - "default": "./dist/ort.min.js" + "development": "./dist/ort.wasm.js", + "default": "./dist/ort.wasm.min.js" + } + }, + "./wasm-core": { + "import": { + "development": "./dist/esm/ort.wasm-core.js", + "default": "./dist/esm/ort.wasm-core.min.js" + }, + "require": { + "development": "./dist/cjs/ort.wasm-core.js", + "default": "./dist/cjs/ort.wasm-core.min.js" + }, + "default": { + "development": "./dist/ort.wasm-core.js", + "default": "./dist/ort.wasm-core.min.js" + } + }, + "./webgl": { + "import": { + "development": "./dist/esm/ort.webgl.js", + "default": "./dist/esm/ort.webgl.min.js" + }, + "require": { + "development": "./dist/cjs/ort.webgl.js", + "default": "./dist/cjs/ort.webgl.min.js" + }, + "default": { + "development": "./dist/ort.webgl.js", + "default": "./dist/ort.webgl.min.js" } }, "./webgpu": { - "types": "./types.d.ts", - "default": "./dist/ort.webgpu.min.js" + "import": { + "development": "./dist/esm/ort.webgpu.js", + "default": "./dist/esm/ort.webgpu.min.js" + }, + "require": { + "development": "./dist/cjs/ort.webgpu.js", + "default": "./dist/cjs/ort.webgpu.min.js" + }, + "default": { + "development": "./dist/ort.webgpu.js", + "default": "./dist/ort.webgpu.min.js" + } } }, "types": "./types.d.ts", diff --git a/js/web/script/build.ts b/js/web/script/build.ts index 3a54aa158823c..9743cbe8ec326 100644 --- a/js/web/script/build.ts +++ b/js/web/script/build.ts @@ -58,7 +58,7 @@ const COPYRIGHT_HEADER = `/*! interface OrtBuildOptions { isProduction?: boolean; isNode?: boolean; - isEsm?: boolean; + format: 'iife'|'cjs'|'esm'; outputBundleName: string; define?: Record; } @@ -94,7 +94,7 @@ async function minifyCode(sourceCode: string): Promise { async function buildOrt({ isProduction = false, isNode = false, - isEsm = false, + format, outputBundleName, define = DEFAULT_DEFINE, }: OrtBuildOptions) { @@ -238,7 +238,7 @@ async function buildOrt({ entryPoints: ['web/lib/index.ts'], outfile: `web/dist/${outputBundleName}.js`, platform: isNode ? 'node' : 'browser', - format: isEsm ? 'esm' : (isNode ? 'cjs' : 'iife'), + format, globalName: 'ort', plugins: isNode ? undefined : [excludeNodejsImports, proxyWorkerHandler, wasmThreadedHandler, emscriptenThreadedJsHandler], @@ -286,6 +286,9 @@ async function buildTest() { async function main() { // tasks for each esbuild bundle const buildTasks: Array> = []; + /** + * add one build task + */ const addBuildTask = async (task: Promise) => { if (DEBUG) { // in DEBUG mode, build sequentially @@ -294,12 +297,62 @@ async function main() { buildTasks.push(task); } }; + /** + * add all 6 build tasks for web bundles. Includes: + * - IIFE, debug: [name].js + * - IIFE, production: [name].min.js + * - CJS, debug: cjs/[name].js + * - CJS, production: cjs/[name].min.js + * - ESM, debug: esm/[name].js + * - ESM, production: esm/[name].min.js + */ + const addAllWebBuildTasks = async (options: Omit) => { + // [name].js + await addBuildTask(buildOrt({ + ...options, + format: 'iife', + })); + // [name].min.js + await addBuildTask(buildOrt({ + ...options, + outputBundleName: options.outputBundleName + '.min', + format: 'iife', + isProduction: true, + })); + // cjs/[name].js + await addBuildTask(buildOrt({ + ...options, + outputBundleName: 'cjs/' + options.outputBundleName, + format: 'cjs', + })); + // cjs/[name].min.js + await addBuildTask(buildOrt({ + ...options, + outputBundleName: 'cjs/' + options.outputBundleName + '.min', + format: 'cjs', + isProduction: true, + })); + // esm/[name].js + await addBuildTask(buildOrt({ + ...options, + outputBundleName: 'esm/' + options.outputBundleName, + format: 'esm', + })); + // esm/[name].min.js + await addBuildTask(buildOrt({ + ...options, + outputBundleName: 'esm/' + options.outputBundleName + '.min', + format: 'esm', + isProduction: true, + })); + }; if (BUNDLE_MODE === 'node' || BUNDLE_MODE === 'prod') { // ort.node.min.js await addBuildTask(buildOrt({ isProduction: true, isNode: true, + format: 'cjs', outputBundleName: 'ort.node.min', define: { ...DEFAULT_DEFINE, @@ -311,59 +364,49 @@ async function main() { })); } - if (BUNDLE_MODE === 'dev' || BUNDLE_MODE === 'prod') { + if (BUNDLE_MODE === 'dev') { // ort.all.js await addBuildTask(buildOrt({ outputBundleName: 'ort.all', + format: 'iife', })); } - if (BUNDLE_MODE === 'perf' || BUNDLE_MODE === 'prod') { + if (BUNDLE_MODE === 'perf') { // ort.all.min.js await addBuildTask(buildOrt({ isProduction: true, outputBundleName: 'ort.all.min', + format: 'iife', })); } if (BUNDLE_MODE === 'prod') { - // ort.js - await addBuildTask(buildOrt({ + // ort.all[.min].js + await addAllWebBuildTasks({outputBundleName: 'ort.all'}); + + // ort[.min].js + await addAllWebBuildTasks({ outputBundleName: 'ort', define: {...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGPU': 'true'}, - })); - // ort.webgpu.js - await addBuildTask(buildOrt({ + }); + // ort.webgpu[.min].js + await addAllWebBuildTasks({ outputBundleName: 'ort.webgpu', define: {...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGL': 'true'}, - })); - // ort.min.js - await addBuildTask(buildOrt({ - isProduction: true, - outputBundleName: 'ort.min', - define: {...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGPU': 'true'}, - })); - // ort.webgpu.min.js - await addBuildTask(buildOrt({ - isProduction: true, - outputBundleName: 'ort.webgpu.min', - define: {...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGL': 'true'}, - })); - // ort.wasm.min.js - await addBuildTask(buildOrt({ - isProduction: true, - outputBundleName: 'ort.wasm.min', + }); + // ort.wasm[.min].js + await addAllWebBuildTasks({ + outputBundleName: 'ort.wasm', define: {...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGPU': 'true', 'BUILD_DEFS.DISABLE_WEBGL': 'true'}, - })); - // ort.webgl.min.js - await addBuildTask(buildOrt({ - isProduction: true, - outputBundleName: 'ort.webgl.min', + }); + // ort.webgl[.min].js + await addAllWebBuildTasks({ + outputBundleName: 'ort.webgl', define: {...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGPU': 'true', 'BUILD_DEFS.DISABLE_WASM': 'true'}, - })); - // ort.wasm-core.min.js - await addBuildTask(buildOrt({ - isProduction: true, + }); + // ort.wasm-core[.min].js + await addAllWebBuildTasks({ outputBundleName: 'ort.wasm-core.min', define: { ...DEFAULT_DEFINE, @@ -372,7 +415,7 @@ async function main() { 'BUILD_DEFS.DISABLE_WASM_PROXY': 'true', 'BUILD_DEFS.DISABLE_WASM_THREAD': 'true', }, - })); + }); } if (BUNDLE_MODE === 'dev' || BUNDLE_MODE === 'perf') { @@ -380,6 +423,14 @@ async function main() { } await Promise.all(buildTasks); + + if (BUNDLE_MODE === 'prod') { + // generate package.json files under each of the dist folders for commonJS and ESModule + // this trick allows typescript to import this package as different module type + // see also: https://evertpot.com/universal-commonjs-esm-typescript-packages/ + await fs.writeFile(path.resolve(__dirname, '../dist/cjs', 'package.json'), '{"type": "commonjs"}'); + await fs.writeFile(path.resolve(__dirname, '../dist/esm', 'package.json'), '{"type": "module"}'); + } } void main(); diff --git a/js/web/types.d.ts b/js/web/types.d.ts index c6cff64c8a732..2cb4578d99687 100644 --- a/js/web/types.d.ts +++ b/js/web/types.d.ts @@ -5,6 +5,22 @@ declare module 'onnxruntime-web' { export * from 'onnxruntime-common'; } +declare module 'onnxruntime-web/experimental' { + export * from 'onnxruntime-web'; +} + +declare module 'onnxruntime-web/wasm' { + export * from 'onnxruntime-web'; +} + +declare module 'onnxruntime-web/wasm-core' { + export * from 'onnxruntime-web'; +} + +declare module 'onnxruntime-web/webgl' { + export * from 'onnxruntime-web'; +} + declare module 'onnxruntime-web/webgpu' { export * from 'onnxruntime-web'; }