mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-05-17 21:10:43 +00:00
### Description
See
454996d496
for manual changes (excluded auto-generated formatting changes)
### Why
Because the toolsets for old clang-format is out-of-date. This reduces
the development efficiency.
- The NPM package `clang-format` is already in maintenance mode. not
updated since 2 years ago.
- The VSCode extension for clang-format is not maintained for a while,
and a recent Node.js security update made it not working at all in
Windows.
No one in community seems interested in fixing those.
Choose Prettier as it is the most popular TS/JS formatter.
### How to merge
It's easy to break the build:
- Be careful of any new commits on main not included in this PR.
- Be careful that after this PR is merged, other PRs that already passed
CI can merge.
So, make sure there is no new commits before merging this one, and
invalidate js PRs that already passed CI, force them to merge to latest.
660 lines
22 KiB
TypeScript
660 lines
22 KiB
TypeScript
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT License.
|
|
|
|
import * as esbuild from 'esbuild';
|
|
import minimist from 'minimist';
|
|
import * as fs from 'node:fs/promises';
|
|
import * as path from 'node:path';
|
|
import { SourceMapConsumer, SourceMapGenerator } from 'source-map';
|
|
|
|
console.time('BUILD');
|
|
|
|
/**
|
|
* @summary Build script for ort-web using esbuild.
|
|
*/
|
|
|
|
const args = minimist(process.argv.slice(2));
|
|
/**
|
|
* --bundle-mode=prod (default)
|
|
* Build multiple ort-web bundles for production.
|
|
*
|
|
* --bundle-mode=dev
|
|
* Build a single ort-web bundle for development, and a test bundle.
|
|
*
|
|
* --bundle-mode=perf
|
|
* Build a single ort-web bundle for performance test, and a test bundle.
|
|
*
|
|
* --bundle-mode=node
|
|
* Build a single ort-web bundle for nodejs.
|
|
*/
|
|
const BUNDLE_MODE: 'prod' | 'dev' | 'perf' | 'node' = args['bundle-mode'] || 'prod';
|
|
|
|
/**
|
|
* --debug
|
|
* Enable debug mode. In this mode, esbuild metafile feature will be enabled. Simple bundle analysis will be printed.
|
|
*
|
|
* --debug=verbose
|
|
* Enable debug mode. In this mode, esbuild metafile feature will be enabled. Detailed bundle analysis will be
|
|
* printed.
|
|
*
|
|
* --debug=save
|
|
* Enable debug mode. In this mode, esbuild metafile feature will be enabled. Full bundle analysis will be saved to a
|
|
* file as JSON.
|
|
*/
|
|
const DEBUG = args.debug; // boolean|'verbose'|'save'
|
|
|
|
/**
|
|
* Root folder of the source code: `<ORT_ROOT>/js/`
|
|
*/
|
|
const SOURCE_ROOT_FOLDER = path.join(__dirname, '../..');
|
|
|
|
/**
|
|
* Default define values for the build.
|
|
*/
|
|
const DEFAULT_DEFINE = {
|
|
'BUILD_DEFS.DISABLE_WEBGL': 'false',
|
|
'BUILD_DEFS.DISABLE_JSEP': 'false',
|
|
'BUILD_DEFS.DISABLE_WASM': 'false',
|
|
'BUILD_DEFS.DISABLE_WASM_PROXY': 'false',
|
|
'BUILD_DEFS.DISABLE_TRAINING': 'true',
|
|
'BUILD_DEFS.DISABLE_DYNAMIC_IMPORT': 'false',
|
|
|
|
'BUILD_DEFS.IS_ESM': 'false',
|
|
'BUILD_DEFS.ESM_IMPORT_META_URL': 'undefined',
|
|
} as const;
|
|
|
|
const COPYRIGHT_HEADER = `/*!
|
|
* ONNX Runtime Web v${require('../package.json').version}
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the MIT License.
|
|
*/`;
|
|
|
|
interface OrtBuildOptions {
|
|
readonly isProduction?: boolean;
|
|
readonly isNode?: boolean;
|
|
readonly format: 'iife' | 'cjs' | 'esm';
|
|
readonly outputName: string;
|
|
readonly define?: Record<string, string>;
|
|
}
|
|
|
|
const terserAlreadyBuilt = new Map();
|
|
|
|
/**
|
|
* This function is only used to minify the Emscripten generated JS code. The ESBuild minify option is not able to
|
|
* tree-shake some unused code as expected. Specifically, there are 2 issues:
|
|
* 1. the use of `await import("module")`
|
|
* 2. the use of `await import("worker_threads")`, with top-level "await".
|
|
*
|
|
* The 2 code snippets mentioned above are guarded by feature checks to make sure they are only run in Node.js. However,
|
|
* ESBuild fails to tree-shake them and will include them in the final bundle. It will generate code like this:
|
|
*
|
|
* ```js
|
|
* // original code (example, not exact generated code)
|
|
* var isNode = typeof process !== 'undefined' && process.versions?.node;
|
|
* if (isNode) {
|
|
* const {createRequire} = await import('module');
|
|
* ...
|
|
* }
|
|
*
|
|
* // minimized code (with setting "define: {'process': 'undefined'}")
|
|
* var x=!0;if(x){const{createRequire:rt}=await import("module");...}
|
|
* ```
|
|
*
|
|
* The remaining dynamic import call makes trouble for further building steps. To solve this issue, we use Terser to
|
|
* minify the Emscripten generated JS code. Terser does more aggressive optimizations and is able to tree-shake the
|
|
* unused code with special configurations.
|
|
*
|
|
* We assume the minimized code does not contain any dynamic import calls.
|
|
*/
|
|
async function minifyWasmModuleJsForBrowser(filepath: string): Promise<string> {
|
|
const code = terserAlreadyBuilt.get(filepath);
|
|
if (code) {
|
|
return code;
|
|
}
|
|
|
|
const doMinify = (async () => {
|
|
const TIME_TAG = `BUILD:terserMinify:${filepath}`;
|
|
console.time(TIME_TAG);
|
|
|
|
const contents = await fs.readFile(filepath, { encoding: 'utf-8' });
|
|
|
|
// Find the first and the only occurrence of minified function implementation of "_emscripten_thread_set_strongref":
|
|
// ```js
|
|
// _emscripten_thread_set_strongref: (thread) => {
|
|
// if (ENVIRONMENT_IS_NODE) {
|
|
// PThread.pthreads[thread].ref();
|
|
// }
|
|
// }
|
|
// ```
|
|
//
|
|
// It is minified to: (example)
|
|
// ```js
|
|
// function Pb(a){D&&N[a>>>0].ref()}
|
|
// ```
|
|
|
|
// The following code will look for the function name and mark the function call as pure, so that Terser will
|
|
// minify the code correctly.
|
|
|
|
const markedAsPure = [];
|
|
// First, try if we are working on the original (not minified) source file. This is when we are working with the
|
|
// debug build.
|
|
const isOriginal = contents.includes('PThread.pthreads[thread].ref()');
|
|
if (isOriginal) {
|
|
markedAsPure.push('PThread.pthreads[thread].ref');
|
|
} else {
|
|
// If it is not the original source file, we need to find the minified function call.
|
|
const matches = [...contents.matchAll(/\{[_a-zA-Z][_a-zA-Z0-9]*&&([_a-zA-Z][_a-zA-Z0-9]*\[.+?]\.ref)\(\)}/g)];
|
|
if (matches.length !== 1) {
|
|
throw new Error(
|
|
`Unexpected number of matches for minified "PThread.pthreads[thread].ref()" in "${filepath}": ${
|
|
matches.length
|
|
}.`,
|
|
);
|
|
}
|
|
// matches[0] is the first and the only match.
|
|
// matches[0][0] is the full matched string and matches[0][1] is the first capturing group.
|
|
markedAsPure.push(matches[0][1]);
|
|
}
|
|
|
|
const terser = await import('terser');
|
|
const result = await terser.minify(contents, {
|
|
module: true,
|
|
compress: {
|
|
passes: 2,
|
|
global_defs: { process: undefined, 'globalThis.process': undefined },
|
|
pure_funcs: markedAsPure,
|
|
},
|
|
});
|
|
|
|
console.timeEnd(TIME_TAG);
|
|
|
|
return result.code!;
|
|
})();
|
|
|
|
terserAlreadyBuilt.set(filepath, doMinify);
|
|
return doMinify;
|
|
}
|
|
|
|
const esbuildAlreadyBuilt = new Map<string, string>();
|
|
async function buildBundle(options: esbuild.BuildOptions) {
|
|
// Skip if the same build options have been built before.
|
|
const serializedOptions = JSON.stringify(options);
|
|
const storedBuildOptions = esbuildAlreadyBuilt.get(options.outfile!);
|
|
if (storedBuildOptions) {
|
|
if (serializedOptions !== storedBuildOptions) {
|
|
throw new Error(`Inconsistent build options for "${options.outfile!}".`);
|
|
}
|
|
console.log(`Already built "${options.outfile!}", skipping...`);
|
|
return;
|
|
} else {
|
|
esbuildAlreadyBuilt.set(options.outfile!, serializedOptions);
|
|
console.log(`Building "${options.outfile!}"...`);
|
|
}
|
|
|
|
// Patch banner:
|
|
//
|
|
// - Add copy right header.
|
|
// - For Node + ESM, add a single line fix to make it work.
|
|
// (see: https://github.com/evanw/esbuild/pull/2067#issuecomment-1981642558)
|
|
const NODE_ESM_FIX_MIN = 'import{createRequire}from"module";const require=createRequire(import.meta.url);';
|
|
const banner = {
|
|
js:
|
|
options.platform === 'node' && options.format === 'esm'
|
|
? COPYRIGHT_HEADER + '\n' + NODE_ESM_FIX_MIN
|
|
: COPYRIGHT_HEADER,
|
|
};
|
|
|
|
// Patch footer:
|
|
//
|
|
// For IIFE format, add a custom footer to make it compatible with CommonJS module system.
|
|
// For other formats, no footer is needed.
|
|
//
|
|
// ESBuild does not support UMD format (which is a combination of IIFE and CommonJS). We don't want to generate 2
|
|
// build targets (IIFE and CommonJS) because it will increase the package size. Instead, we generate IIFE and append
|
|
// this footer to make it compatible with CommonJS module system.
|
|
//
|
|
// see also: https://github.com/evanw/esbuild/issues/507
|
|
//
|
|
const COMMONJS_FOOTER_MIN = 'typeof exports=="object"&&typeof module=="object"&&(module.exports=ort);';
|
|
const footer = options.format === 'iife' ? { js: COMMONJS_FOOTER_MIN } : undefined;
|
|
|
|
// set BUILD_DEFS for ESM.
|
|
if (options.format === 'esm') {
|
|
options.define = {
|
|
...options.define,
|
|
'BUILD_DEFS.ESM_IMPORT_META_URL': 'import.meta.url',
|
|
'BUILD_DEFS.IS_ESM': 'true',
|
|
};
|
|
}
|
|
|
|
const result = await esbuild.build({
|
|
logLevel: DEBUG ? (DEBUG === 'verbose' || DEBUG === 'save' ? 'verbose' : 'debug') : 'info',
|
|
metafile: !!DEBUG,
|
|
absWorkingDir: SOURCE_ROOT_FOLDER,
|
|
bundle: true,
|
|
banner,
|
|
footer,
|
|
...options,
|
|
});
|
|
if (DEBUG) {
|
|
if (DEBUG === 'save') {
|
|
await fs.writeFile(
|
|
`${path.basename(options.outfile!)}.esbuild.metafile.json`,
|
|
JSON.stringify(result.metafile!, null, 2),
|
|
);
|
|
} else {
|
|
console.log(await esbuild.analyzeMetafile(result.metafile!, { verbose: DEBUG === 'verbose' }));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Build one ort-web target.
|
|
*
|
|
* The distribution code is split into multiple files:
|
|
* - [output-name][.min].[m]js
|
|
* - ort[-training]-wasm-simd-threaded[.jsep].mjs
|
|
*/
|
|
async function buildOrt({
|
|
isProduction = false,
|
|
isNode = false,
|
|
format,
|
|
outputName,
|
|
define = DEFAULT_DEFINE,
|
|
}: OrtBuildOptions) {
|
|
const platform = isNode ? 'node' : 'browser';
|
|
const external = isNode
|
|
? ['onnxruntime-common']
|
|
: ['node:fs/promises', 'node:fs', 'node:os', 'module', 'worker_threads'];
|
|
const plugins: esbuild.Plugin[] = [];
|
|
const defineOverride: Record<string, string> = {};
|
|
if (!isNode) {
|
|
defineOverride.process = 'undefined';
|
|
defineOverride['globalThis.process'] = 'undefined';
|
|
}
|
|
|
|
if (define['BUILD_DEFS.DISABLE_DYNAMIC_IMPORT'] === 'true') {
|
|
plugins.push({
|
|
name: 'emscripten-mjs-handler',
|
|
setup(build: esbuild.PluginBuild) {
|
|
build.onLoad({ filter: /dist[\\/]ort-.*wasm.*\.mjs$/ }, async (args) => ({
|
|
contents: await minifyWasmModuleJsForBrowser(args.path),
|
|
}));
|
|
},
|
|
});
|
|
}
|
|
|
|
await buildBundle({
|
|
entryPoints: ['web/lib/index.ts'],
|
|
outfile: `web/dist/${outputName}${isProduction ? '.min' : ''}.${format === 'esm' ? 'mjs' : 'js'}`,
|
|
platform,
|
|
format,
|
|
globalName: 'ort',
|
|
plugins,
|
|
external,
|
|
define: { ...define, ...defineOverride },
|
|
sourcemap: isProduction ? 'linked' : 'inline',
|
|
minify: isProduction,
|
|
});
|
|
}
|
|
|
|
async function buildTest() {
|
|
const isProduction = BUNDLE_MODE === 'perf';
|
|
|
|
await buildBundle({
|
|
absWorkingDir: path.join(SOURCE_ROOT_FOLDER, 'web/test'),
|
|
|
|
entryPoints: ['test-main.ts'],
|
|
outfile: isProduction ? 'ort.test.min.js' : 'ort.test.js',
|
|
platform: 'browser',
|
|
format: 'iife',
|
|
define: DEFAULT_DEFINE,
|
|
sourcemap: isProduction ? false : 'inline',
|
|
sourceRoot: path.join(SOURCE_ROOT_FOLDER, 'web/test'),
|
|
external: ['../../node'],
|
|
plugins: [
|
|
// polyfill nodejs modules
|
|
require('esbuild-plugin-polyfill-node').polyfillNode({ globals: false }),
|
|
// make "ort" external
|
|
{
|
|
name: 'make-ort-external',
|
|
setup(build: esbuild.PluginBuild) {
|
|
build.onResolve({ filter: /^onnxruntime-common$/ }, (_args) => ({
|
|
path: 'onnxruntime-common',
|
|
namespace: 'make-ort-external',
|
|
}));
|
|
build.onLoad({ filter: /.*/, namespace: 'make-ort-external' }, (_args) => ({
|
|
contents: 'module.exports = globalThis.ort;',
|
|
}));
|
|
},
|
|
},
|
|
],
|
|
minify: isProduction,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Perform the post-process step after ESBuild finishes the build.
|
|
*
|
|
* This is a custom post process step to insert magic comments to a specific import call:
|
|
* ```
|
|
* ... await import(...
|
|
* ```
|
|
* to:
|
|
* ```
|
|
* ... await import(/* webpackIgnore: true *\/...
|
|
* ```
|
|
*
|
|
* Why we need this?
|
|
*
|
|
* If a project uses Webpack to bundle the code, Webpack will try to resolve the dynamic import calls. However, we don't
|
|
* want Webpack to resolve the dynamic import calls inside the ort-web bundle because:
|
|
*
|
|
* - We want to keep the ort-*.mjs and ort-*.wasm as-is. This makes it able to replace the ort-*.mjs and ort-*.wasm with
|
|
* a custom build if needed.
|
|
* - The Emscripten generated code uses `require()` to load Node.js modules. Those code is guarded by a feature check to
|
|
* make sure only run in Node.js. Webpack does not recognize the feature check and will try to resolve the `require()`
|
|
* in browser environment. This will cause the Webpack build to fail.
|
|
* - There are multiple entry points that use dynamic import to load the ort-*.mjs and ort-*.wasm. If the content of the
|
|
* dynamic import is resolved by Webpack, it will be duplicated in the final bundle. This will increase the bundle size.
|
|
*
|
|
* What about other bundlers?
|
|
*
|
|
* TBD
|
|
*
|
|
*/
|
|
async function postProcess() {
|
|
const IMPORT_MAGIC_COMMENT = '/*webpackIgnore:true*/';
|
|
const IMPORT_ORIGINAL = 'await import(';
|
|
const IMPORT_NEW = `await import(${IMPORT_MAGIC_COMMENT}`;
|
|
|
|
const files = await fs.readdir(path.join(SOURCE_ROOT_FOLDER, 'web/dist'));
|
|
for (const file of files) {
|
|
// only process on "ort.*.min.js" and "ort.*.min.mjs" files.
|
|
if ((file.endsWith('.min.js') || file.endsWith('.min.mjs')) && file.startsWith('ort.')) {
|
|
const jsFilePath = path.join(SOURCE_ROOT_FOLDER, 'web/dist', file);
|
|
const sourcemapFilePath = jsFilePath + '.map';
|
|
|
|
const originalJsFileSize = (await fs.stat(jsFilePath)).size;
|
|
|
|
if (!files.includes(file + '.map')) {
|
|
continue;
|
|
}
|
|
|
|
const jsFileLines = (await fs.readFile(jsFilePath, 'utf-8')).split('\n');
|
|
|
|
let line = -1,
|
|
column = -1,
|
|
found = false;
|
|
for (let i = 0; i < jsFileLines.length; i++) {
|
|
const importColumnIndex = jsFileLines[i].indexOf(IMPORT_ORIGINAL);
|
|
if (importColumnIndex !== -1) {
|
|
if (found || importColumnIndex !== jsFileLines[i].lastIndexOf(IMPORT_ORIGINAL)) {
|
|
throw new Error(`Multiple dynamic import calls found in "${jsFilePath}". Should not happen.`);
|
|
}
|
|
line = i + 1;
|
|
column = importColumnIndex + IMPORT_ORIGINAL.length;
|
|
jsFileLines[i] = jsFileLines[i].replace(IMPORT_ORIGINAL, IMPORT_NEW);
|
|
found = true;
|
|
}
|
|
}
|
|
if (!found) {
|
|
if (file.includes('.webgl.') || file.includes('.bundle.')) {
|
|
// skip webgl and bundle, they don't have dynamic import calls.
|
|
continue;
|
|
}
|
|
throw new Error(`Dynamic import call not found in "${jsFilePath}". Should not happen.`);
|
|
}
|
|
|
|
const originalSourcemapString = await fs.readFile(sourcemapFilePath, 'utf-8');
|
|
await SourceMapConsumer.with(originalSourcemapString, null, async (consumer) => {
|
|
// create new source map and set source content
|
|
const updatedSourceMap = new SourceMapGenerator();
|
|
for (const source of consumer.sources) {
|
|
const content = consumer.sourceContentFor(source);
|
|
if (!content) {
|
|
throw new Error(`Source content not found for source "${source}".`);
|
|
}
|
|
updatedSourceMap.setSourceContent(source, content);
|
|
}
|
|
|
|
consumer.eachMapping((mapping) => {
|
|
if (mapping.generatedLine === line && mapping.generatedColumn >= column) {
|
|
mapping.generatedColumn += IMPORT_MAGIC_COMMENT.length;
|
|
}
|
|
|
|
updatedSourceMap.addMapping({
|
|
generated: { line: mapping.generatedLine, column: mapping.generatedColumn },
|
|
source: mapping.source,
|
|
original: { line: mapping.originalLine, column: mapping.originalColumn },
|
|
name: mapping.name,
|
|
});
|
|
});
|
|
|
|
const updatedSourcemapString = updatedSourceMap.toString();
|
|
|
|
// perform simple validation
|
|
const originalSourcemap = JSON.parse(originalSourcemapString);
|
|
const updatedSourcemap = JSON.parse(updatedSourcemapString);
|
|
|
|
if (
|
|
originalSourcemap.sources.length !== updatedSourcemap.sources.length ||
|
|
originalSourcemap.sourcesContent.length !== updatedSourcemap.sourcesContent.length ||
|
|
new Set(originalSourcemap.names).size !== new Set(updatedSourcemap.names).size
|
|
) {
|
|
throw new Error('Failed to update source map: source map length mismatch.');
|
|
}
|
|
const originalMappingsCount = originalSourcemap.mappings.split(/[;,]/);
|
|
const updatedMappingsCount = updatedSourcemap.mappings.split(/[;,]/);
|
|
if (originalMappingsCount.length !== updatedMappingsCount.length) {
|
|
throw new Error('Failed to update source map: mappings count mismatch.');
|
|
}
|
|
|
|
await fs.writeFile(sourcemapFilePath, updatedSourcemapString);
|
|
});
|
|
|
|
await fs.writeFile(jsFilePath, jsFileLines.join('\n'));
|
|
const newJsFileSize = (await fs.stat(jsFilePath)).size;
|
|
if (newJsFileSize - originalJsFileSize !== IMPORT_MAGIC_COMMENT.length) {
|
|
throw new Error(
|
|
`Failed to insert magic comment to file "${file}". Original size: ${
|
|
originalJsFileSize
|
|
}, New size: ${newJsFileSize}`,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async function validate() {
|
|
const files = await fs.readdir(path.join(SOURCE_ROOT_FOLDER, 'web/dist'));
|
|
for (const file of files) {
|
|
// validate on all "ort.*.min.js" and "ort.*.min.mjs" files.
|
|
if ((file.endsWith('.js') || file.endsWith('.mjs')) && file.startsWith('ort.')) {
|
|
const isMinified = file.endsWith('.min.js') || file.endsWith('.min.mjs');
|
|
const content = await fs.readFile(path.join(SOURCE_ROOT_FOLDER, 'web/dist', file), 'utf-8');
|
|
|
|
if (isMinified) {
|
|
// all files should not contain BUILD_DEFS definition. BUILD_DEFS should be defined in the build script only.
|
|
//
|
|
// If the final bundle contains BUILD_DEFS definition, it means the build script is not working correctly. In
|
|
// this case, we should fix the build script (this file).
|
|
//
|
|
if (content.includes('BUILD_DEFS')) {
|
|
throw new Error(`Validation failed: "${file}" contains BUILD_DEFS definition.`);
|
|
}
|
|
}
|
|
|
|
// all files should contain the magic comment to ignore dynamic import calls.
|
|
//
|
|
if (!file.includes('.webgl.') && !file.includes('.bundle.')) {
|
|
const contentToSearch = isMinified ? '/*webpackIgnore:true*/' : '/* webpackIgnore: true */';
|
|
if (!content.includes(contentToSearch)) {
|
|
throw new Error(`Validation failed: "${file}" does not contain magic comment.`);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
async function main() {
|
|
console.timeLog('BUILD', 'Start building ort-web bundles...');
|
|
|
|
/**
|
|
* add all 6 build tasks for web bundles. Includes:
|
|
* - IIFE/CJS, debug: [name].js
|
|
* - IIFE/CJS, production: [name].min.js
|
|
* - ESM, debug: [name].mjs
|
|
* - ESM, production: [name].min.mjs
|
|
*/
|
|
const addAllWebBuildTasks = async (options: Omit<OrtBuildOptions, 'format'>) => {
|
|
// [name].js
|
|
await buildOrt({
|
|
...options,
|
|
format: 'iife',
|
|
});
|
|
// [name].min.js
|
|
await buildOrt({
|
|
...options,
|
|
outputName: options.outputName,
|
|
format: 'iife',
|
|
isProduction: true,
|
|
});
|
|
// [name].mjs
|
|
await buildOrt({
|
|
...options,
|
|
outputName: options.outputName,
|
|
format: 'esm',
|
|
});
|
|
// [name].min.mjs
|
|
await buildOrt({
|
|
...options,
|
|
outputName: options.outputName,
|
|
format: 'esm',
|
|
isProduction: true,
|
|
});
|
|
};
|
|
|
|
if (BUNDLE_MODE === 'node' || BUNDLE_MODE === 'prod') {
|
|
// ort.node.min.js
|
|
await buildOrt({
|
|
isProduction: true,
|
|
isNode: true,
|
|
format: 'cjs',
|
|
outputName: 'ort.node',
|
|
define: {
|
|
...DEFAULT_DEFINE,
|
|
'BUILD_DEFS.DISABLE_JSEP': 'true',
|
|
'BUILD_DEFS.DISABLE_WEBGL': 'true',
|
|
'BUILD_DEFS.DISABLE_WASM_PROXY': 'true',
|
|
},
|
|
});
|
|
// ort.node.min.mjs
|
|
await buildOrt({
|
|
isProduction: true,
|
|
isNode: true,
|
|
format: 'esm',
|
|
outputName: 'ort.node',
|
|
define: {
|
|
...DEFAULT_DEFINE,
|
|
'BUILD_DEFS.DISABLE_JSEP': 'true',
|
|
'BUILD_DEFS.DISABLE_WEBGL': 'true',
|
|
'BUILD_DEFS.DISABLE_WASM_PROXY': 'true',
|
|
},
|
|
});
|
|
}
|
|
|
|
if (BUNDLE_MODE === 'dev') {
|
|
// ort.all.js
|
|
await buildOrt({ outputName: 'ort.all', format: 'iife', define: { ...DEFAULT_DEFINE } });
|
|
}
|
|
|
|
if (BUNDLE_MODE === 'perf') {
|
|
// ort.all.min.js
|
|
await buildOrt({
|
|
isProduction: true,
|
|
outputName: 'ort.all',
|
|
format: 'iife',
|
|
});
|
|
}
|
|
|
|
if (BUNDLE_MODE === 'prod') {
|
|
// ort.all[.min].[m]js
|
|
await addAllWebBuildTasks({ outputName: 'ort.all' });
|
|
// ort.all.bundle.min.mjs
|
|
await buildOrt({
|
|
isProduction: true,
|
|
outputName: 'ort.all.bundle',
|
|
format: 'esm',
|
|
define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_DYNAMIC_IMPORT': 'true' },
|
|
});
|
|
|
|
// ort[.min].[m]js
|
|
await addAllWebBuildTasks({
|
|
outputName: 'ort',
|
|
define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_JSEP': 'true' },
|
|
});
|
|
// ort.bundle.min.mjs
|
|
await buildOrt({
|
|
isProduction: true,
|
|
outputName: 'ort.bundle',
|
|
format: 'esm',
|
|
define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_JSEP': 'true', 'BUILD_DEFS.DISABLE_DYNAMIC_IMPORT': 'true' },
|
|
});
|
|
|
|
// ort.webgpu[.min].[m]js
|
|
await addAllWebBuildTasks({
|
|
outputName: 'ort.webgpu',
|
|
define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGL': 'true' },
|
|
});
|
|
// ort.webgpu.bundle.min.mjs
|
|
await buildOrt({
|
|
isProduction: true,
|
|
outputName: 'ort.webgpu.bundle',
|
|
format: 'esm',
|
|
define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGL': 'true', 'BUILD_DEFS.DISABLE_DYNAMIC_IMPORT': 'true' },
|
|
});
|
|
|
|
// ort.wasm[.min].[m]js
|
|
await addAllWebBuildTasks({
|
|
outputName: 'ort.wasm',
|
|
define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_JSEP': 'true', 'BUILD_DEFS.DISABLE_WEBGL': 'true' },
|
|
});
|
|
// ort.webgl[.min].[m]js
|
|
await addAllWebBuildTasks({
|
|
outputName: 'ort.webgl',
|
|
define: {
|
|
...DEFAULT_DEFINE,
|
|
'BUILD_DEFS.DISABLE_JSEP': 'true',
|
|
'BUILD_DEFS.DISABLE_WASM': 'true',
|
|
'BUILD_DEFS.DISABLE_WASM_PROXY': 'true',
|
|
},
|
|
});
|
|
// ort.training.wasm[.min].[m]js
|
|
await addAllWebBuildTasks({
|
|
outputName: 'ort.training.wasm',
|
|
define: {
|
|
...DEFAULT_DEFINE,
|
|
'BUILD_DEFS.DISABLE_TRAINING': 'false',
|
|
'BUILD_DEFS.DISABLE_JSEP': 'true',
|
|
'BUILD_DEFS.DISABLE_WEBGL': 'true',
|
|
},
|
|
});
|
|
}
|
|
|
|
if (BUNDLE_MODE === 'dev' || BUNDLE_MODE === 'perf') {
|
|
await buildTest();
|
|
}
|
|
|
|
if (BUNDLE_MODE === 'prod') {
|
|
console.timeLog('BUILD', 'Start post-processing...');
|
|
await postProcess();
|
|
|
|
console.timeLog('BUILD', 'Start validating...');
|
|
await validate();
|
|
}
|
|
|
|
console.timeEnd('BUILD');
|
|
}
|
|
|
|
void main();
|