[js/common] allow import onnxruntime-common as ESM and CJS (#15772)

### Description
allow import onnxruntime-common as ESM and CJS.
This commit is contained in:
Yulong Wang 2023-06-12 12:05:11 -07:00 committed by GitHub
parent 0df9e42960
commit e3e4926d00
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 222 additions and 127 deletions

View file

@ -1,5 +1,6 @@
/.vscode/
build.js
webpack.config.js
typedoc.json
tsconfig.json

26
js/common/build.js Normal file
View file

@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import {execSync} from 'node:child_process';
import {writeFileSync} from 'node:fs';
import {resolve, dirname} from 'node:path';
import {fileURLToPath} from 'node:url';
const __dirname = dirname(fileURLToPath(import.meta.url));
// build the following folders:
// - dist/cjs
// - dist/esm
execSync('npm run build:cjs', {shell: true, stdio: 'inherit', cwd: __dirname});
execSync('npm run build:esm', {shell: true, stdio: 'inherit', cwd: __dirname});
// 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/
writeFileSync(resolve(__dirname, './dist/cjs', 'package.json'), '{"type": "commonjs"}');
writeFileSync(resolve(__dirname, './dist/esm', 'package.json'), '{"type": "module"}');
// launch webpack to generate bundles
execSync('npm run build:bundles', {shell: true, stdio: 'inherit', cwd: __dirname});

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Backend} from './backend';
import {Backend} from './backend.js';
interface BackendInfo {
backend: Backend;

View file

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {InferenceSession} from './inference-session';
import {OnnxValue} from './onnx-value';
import {InferenceSession} from './inference-session.js';
import {OnnxValue} from './onnx-value.js';
/**
* @internal
@ -46,4 +46,4 @@ export interface Backend {
Promise<SessionHandler>;
}
export {registerBackend} from './backend-impl';
export {registerBackend} from './backend-impl.js';

View file

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Env} from './env';
import {version} from './version';
import {Env} from './env.js';
import {version} from './version.js';
type LogLevelType = Env['logLevel'];

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {env as envImpl} from './env-impl';
import {env as envImpl} from './env-impl.js';
export declare namespace Env {
export type WasmPrefixOrFilePaths = string|{

View file

@ -17,8 +17,8 @@
* @packageDocumentation
*/
export * from './backend';
export * from './env';
export * from './inference-session';
export * from './tensor';
export * from './onnx-value';
export * from './backend.js';
export * from './env.js';
export * from './inference-session.js';
export * from './tensor.js';
export * from './onnx-value.js';

View file

@ -1,11 +1,11 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {SessionHandler} from './backend';
import {resolveBackend} from './backend-impl';
import {InferenceSession as InferenceSessionInterface} from './inference-session';
import {OnnxValue} from './onnx-value';
import {Tensor} from './tensor';
import {resolveBackend} from './backend-impl.js';
import {SessionHandler} from './backend.js';
import {InferenceSession as InferenceSessionInterface} from './inference-session.js';
import {OnnxValue} from './onnx-value.js';
import {Tensor} from './tensor.js';
type SessionOptions = InferenceSessionInterface.SessionOptions;
type RunOptions = InferenceSessionInterface.RunOptions;

View file

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {InferenceSession as InferenceSessionImpl} from './inference-session-impl';
import {OnnxValue} from './onnx-value';
import {InferenceSession as InferenceSessionImpl} from './inference-session-impl.js';
import {OnnxValue} from './onnx-value.js';
/* eslint-disable @typescript-eslint/no-redeclare */

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor} from './tensor';
import {Tensor} from './tensor.js';
type NonTensorType = never;

View file

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor} from './tensor';
import {TensorToDataUrlOptions, TensorToImageDataOptions} from './tensor-conversion';
import {TensorToDataUrlOptions, TensorToImageDataOptions} from './tensor-conversion.js';
import {Tensor} from './tensor.js';
/**
* implementation of Tensor.toDataURL()

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {OptionsFormat, OptionsNormalizationParameters, OptionsTensorLayout} from './tensor-factory';
import {OptionsFormat, OptionsNormalizationParameters, OptionsTensorLayout} from './tensor-factory.js';
export interface TensorToDataUrlOptions extends OptionsTensorLayout, OptionsFormat, OptionsNormalizationParameters {}

View file

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor, TypedTensor} from './tensor';
import {OptionsDimensions, OptionsFormat, OptionsNormalizationParameters, OptionsTensorFormat, OptionsTensorLayout, TensorFromImageBitmapOptions, TensorFromImageDataOptions, TensorFromImageElementOptions, TensorFromUrlOptions} from './tensor-factory';
import {OptionsDimensions, OptionsFormat, OptionsNormalizationParameters, OptionsTensorFormat, OptionsTensorLayout, TensorFromImageBitmapOptions, TensorFromImageDataOptions, TensorFromImageElementOptions, TensorFromUrlOptions} from './tensor-factory.js';
import {Tensor, TypedTensor} from './tensor.js';
interface BufferToTensorOptions extends OptionsDimensions, OptionsTensorLayout, OptionsNormalizationParameters,
OptionsFormat, OptionsTensorFormat {}

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {TypedTensor} from './tensor';
import {TypedTensor} from './tensor.js';
export type ImageFormat = 'RGB'|'RGBA'|'BGR'|'RBG';
export type ImageTensorLayout = 'NHWC'|'NCHW';

View file

@ -1,12 +1,12 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor as TensorInterface} from './tensor';
import {TensorToDataUrlOptions, TensorToImageDataOptions} from './tensor-conversion';
import {tensorToDataURL, tensorToImageData} from './tensor-conversion-impl';
import {TensorFromImageBitmapOptions, TensorFromImageDataOptions, TensorFromImageElementOptions, TensorFromUrlOptions} from './tensor-factory';
import {tensorFromImage} from './tensor-factory-impl';
import {calculateSize, tensorReshape} from './tensor-utils-impl';
import {tensorToDataURL, tensorToImageData} from './tensor-conversion-impl.js';
import {TensorToDataUrlOptions, TensorToImageDataOptions} from './tensor-conversion.js';
import {tensorFromImage} from './tensor-factory-impl.js';
import {TensorFromImageBitmapOptions, TensorFromImageDataOptions, TensorFromImageElementOptions, TensorFromUrlOptions} from './tensor-factory.js';
import {calculateSize, tensorReshape} from './tensor-utils-impl.js';
import {Tensor as TensorInterface} from './tensor.js';
type TensorType = TensorInterface.Type;
type TensorDataType = TensorInterface.DataType;

View file

@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor} from './tensor';
import {Tensor} from './tensor.js';
/**
* calculate size from dims.

View file

@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {Tensor, TypedTensor} from './tensor';
import {ConversionUtils} from './tensor-conversion';
import {ConversionUtils} from './tensor-conversion.js';
import {Tensor, TypedTensor} from './tensor.js';
interface Properties {
/**

View file

@ -1,9 +1,9 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import {TensorFactory} from './tensor-factory';
import {Tensor as TensorImpl} from './tensor-impl';
import {TypedTensorUtils} from './tensor-utils';
import {TensorFactory} from './tensor-factory.js';
import {Tensor as TensorImpl} from './tensor-impl.js';
import {TypedTensorUtils} from './tensor-utils.js';
/* eslint-disable @typescript-eslint/no-redeclare */

View file

@ -1,27 +1,32 @@
{
"license": "MIT",
"unpkg": "dist/ort-common.min.js",
"type": "module",
"name": "onnxruntime-common",
"version": "1.16.0",
"repository": {
"url": "https://github.com/Microsoft/onnxruntime.git",
"type": "git"
},
"author": "fs-eire",
"module": "dist/lib/index.js",
"version": "1.16.0",
"jsdelivr": "dist/ort-common.min.js",
"scripts": {
"prepare": "tsc && webpack"
"build:cjs": "npx tsc --module commonjs --outDir ./dist/cjs",
"build:esm": "npx tsc",
"build:bundles": "webpack",
"build": "node ./build.js",
"prepare": "npm run build"
},
"devDependencies": {
"typedoc": "^0.23.22"
},
"main": "dist/cjs/index.js",
"exports": {
"require": "./dist/cjs/index.js",
"import": "./dist/esm/index.js"
},
"keywords": [
"ONNX",
"ONNXRuntime",
"ONNX Runtime"
],
"devDependencies": {
"typedoc": "^0.23.22"
},
"main": "dist/ort-common.node.js",
"types": "dist/lib/index.d.ts",
"description": "ONNXRuntime JavaScript API library"
}

View file

@ -1,7 +1,9 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"outDir": "dist/lib",
"outDir": "./dist/esm",
"declaration": true,
"declarationMap": true,
"esModuleInterop": false,
"noUnusedParameters": true,
},

View file

@ -3,98 +3,65 @@
'use strict';
const path = require('path');
const webpack = require('webpack');
const TerserPlugin = require("terser-webpack-plugin");
function terserEcmaVersionFromWebpackTarget(target) {
switch (target) {
case 'es5':
return 5;
case 'es6':
case 'es2015':
return 2015;
case 'es2017':
return 2017;
default:
throw new RangeError(`not supported ECMA version: ${target}`);
}
}
function addCopyrightBannerPlugin(mode, target) {
const VERSION = require(path.join(__dirname, 'package.json')).version;
const COPYRIGHT_BANNER = `/*!
* ONNX Runtime Common v${VERSION}
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/`;
if (mode === 'production') {
return new TerserPlugin({
extractComments: false,
terserOptions: {
ecma: terserEcmaVersionFromWebpackTarget(target),
format: {
preamble: COPYRIGHT_BANNER,
comments: false,
},
compress: {
passes: 2
}
}
});
} else {
return new webpack.BannerPlugin({ banner: COPYRIGHT_BANNER, raw: true });
}
}
import webpack from 'webpack';
import {resolve} from 'node:path';
import {DEFAULT_ES_VERSION, addCopyrightBannerPlugin} from '../webpack.shared.mjs';
function buildConfig({
suffix = '',
format = 'umd',
target = 'es2017',
mode = 'production',
devtool = 'source-map'
suffix = '.js', // '.js', '.min.js', ...
format = 'umd', // 'umd', 'commonjs'
target = 'web', // 'web', 'node'
esVersion = DEFAULT_ES_VERSION, // 'es5', 'es6', ...
mode = 'production', // 'development', 'production'
devtool = 'source-map' // 'inline-source-map', 'source-map'
}) {
// output file name
const filename = `ort-common${suffix}`;
// variable name of the exported object.
// - set to 'ort' when building 'umd' format.
// - set to undefined when building other formats (commonjs/module)
const exportName = format === 'umd' ? 'ort' : undefined;
return {
target: [format === 'commonjs' ? 'node' : 'web', target],
entry: path.resolve(__dirname, 'lib/index.ts'),
target: [target, esVersion],
entry: resolve('./lib/index.ts'),
output: {
path: path.resolve(__dirname, 'dist'),
filename: `ort-common${suffix}.js`,
library: {
name: format === 'commonjs' ? undefined : 'ort',
type: format
}
path: resolve('./dist'),
filename,
library: {name: exportName, type: format},
},
resolve: {
extensions: ['.ts', '.js'],
extensionAlias: {'.js': ['.ts', '.js']},
},
resolve: { extensions: ['.ts', '.js'] },
plugins: [
new webpack.WatchIgnorePlugin({ paths: [/\.js$/, /\.d\.ts$/] }),
addCopyrightBannerPlugin(mode, target),
new webpack.WatchIgnorePlugin({paths: [/\.js$/, /\.d\.ts$/]}),
addCopyrightBannerPlugin(mode, 'common', esVersion),
],
module: {
rules: [{
test: /\.tsx?$/,
use: [
{
loader: 'ts-loader',
options: {
compilerOptions: { target }
}
}
]
test: /\.ts$/,
use: [{
loader: 'ts-loader',
options: {compilerOptions: {target: esVersion}},
}]
}]
},
mode: mode,
devtool: devtool,
mode,
devtool,
};
}
module.exports = (env, argv) => {
export default (env, argv) => {
return [
buildConfig({ suffix: '.es5.min', target: 'es5' }),
buildConfig({ suffix: '.es6.min', target: 'es6' }),
buildConfig({ suffix: '.min' }),
buildConfig({ mode: 'development', devtool: 'inline-source-map' }),
buildConfig({ format: 'commonjs', suffix: '.node' }),
buildConfig({suffix: '.es5.min.js', target: 'web', esVersion: 'es5'}),
buildConfig({suffix: '.min.js'}),
buildConfig({mode: 'development', devtool: 'inline-source-map'}),
buildConfig({
suffix: '.node.cjs',
target: 'node',
format: 'commonjs',
}),
];
};

View file

@ -2,7 +2,6 @@
"compilerOptions": {
"module": "ES2015",
"moduleResolution": "node16",
"declaration": true,
"esModuleInterop": true,
"target": "ES2020",
"lib": ["ES2020", "ESNext.BigInt", "dom"],

View file

@ -3,6 +3,7 @@
"compilerOptions": {
"module": "CommonJS",
"downlevelIteration": true,
"declaration": true,
"declarationDir": "./types",
"typeRoots": ["./node_modules/@webgpu/types", "./node_modules/@types"]
},

94
js/webpack.shared.mjs Normal file
View file

@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import webpack from 'webpack';
import TerserPlugin from 'terser-webpack-plugin';
import {resolve, dirname} from 'node:path';
import {readFileSync} from 'node:fs';
import {fileURLToPath} from 'node:url';
/**
* ECMAScript version for default onnxruntime JavaScript API builds
*/
export const DEFAULT_ES_VERSION = 'es2017';
// how to use "__dirname" in ESM: https://shramko.dev/blog/dirname-error
const __dirname = dirname(fileURLToPath(import.meta.url));
const terserEcmaVersionFromWebpackEsVersion = (target) => {
switch (target) {
case 'es5':
return 5;
case 'es6':
case 'es2015':
return 2015;
case 'es2017':
return 2017;
default:
throw new RangeError(`not supported ECMA version: ${target}`);
}
};
const getPackageFullName = (name) => {
switch (name) {
case 'common':
return `ONNX Runtime Common`;
case 'node':
return `ONNX Runtime Node.js Binding`;
case 'web':
return `ONNX Runtime Web`;
case 'react-native':
return `ONNX Runtime React-native`;
default:
throw new RangeError(`unknown package name: ${name}`);
}
};
/**
* Get package version by reading the file "package.json" under the package folder
* @param {'common'|'node'|'web'|'react-native'} name - the package name
* @returns a string representing the package version
*/
const getPackageVersion = (name) => {
const normalizedName = name.replace('-', '_');
const packageJsonFileContent = readFileSync(resolve(__dirname, normalizedName, 'package.json'));
const packageJson = JSON.parse(packageJsonFileContent);
return packageJson.version;
};
/**
*
* @param {'development'|'production'} mode - specify webpack build mode
* @param {'common'|'node'|'web'|'react-native'} packageName - specify the name of the package
* @param {'es5'|'es6'|'es2015'|'es2017'} esVersion - specify the ECMAScript version
* @returns
*/
export const addCopyrightBannerPlugin = (mode, packageName, esVersion) => {
const COPYRIGHT_BANNER = `/*!
* ${getPackageFullName(packageName)} v${getPackageVersion(packageName)}
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License.
*/`;
if (mode === 'production') {
// in 'production' mode, webpack uses terser to minimize the code.
// we set options.format.preamble to make sure terser generates correct copyright banner.
return new TerserPlugin({
extractComments: false,
terserOptions: {
ecma: terserEcmaVersionFromWebpackEsVersion(esVersion),
format: {
preamble: COPYRIGHT_BANNER,
comments: false,
},
compress: {passes: 2}
}
});
} else {
// in 'development' mode, webpack does not minimize the code.
// we use the webpack builtin plugin BannerPlugin to insert the banner.
return new webpack.BannerPlugin({banner: COPYRIGHT_BANNER, raw: true});
}
};