diff --git a/js/web/lib/backend-wasm.ts b/js/web/lib/backend-wasm.ts index 766937dc4c4cf..72b51d565896a 100644 --- a/js/web/lib/backend-wasm.ts +++ b/js/web/lib/backend-wasm.ts @@ -5,7 +5,6 @@ import { Backend, env, InferenceSession, InferenceSessionHandler } from 'onnxrun import { initializeOrtEp, initializeWebAssemblyAndOrtRuntime } from './wasm/proxy-wrapper'; import { OnnxruntimeWebAssemblySessionHandler } from './wasm/session-handler-inference'; -import { scriptSrc } from './wasm/wasm-utils-import'; /** * This function initializes all flags for WebAssembly. @@ -54,13 +53,6 @@ export const initializeFlags = (): void => { env.wasm.numThreads = Math.min(4, Math.ceil((numCpuLogicalCores || 1) / 2)); } } - - if (!BUILD_DEFS.DISABLE_DYNAMIC_IMPORT) { - // overwrite wasm paths override if not set - if (env.wasm.wasmPaths === undefined && scriptSrc && scriptSrc.indexOf('blob:') !== 0) { - env.wasm.wasmPaths = scriptSrc.substring(0, scriptSrc.lastIndexOf('/') + 1); - } - } }; export class OnnxruntimeWebAssemblyBackend implements Backend { diff --git a/js/web/lib/build-def.d.ts b/js/web/lib/build-def.d.ts index 188aaebc7d187..59f64a3179605 100644 --- a/js/web/lib/build-def.d.ts +++ b/js/web/lib/build-def.d.ts @@ -21,7 +21,7 @@ interface BuildDefinitions { */ readonly DISABLE_JSEP: boolean; /** - * defines whether to disable the whole WebNN backend in the build. + * defines whether to disable the whole WebAssembly backend in the build. */ readonly DISABLE_WASM: boolean; /** @@ -29,13 +29,16 @@ interface BuildDefinitions { */ readonly DISABLE_WASM_PROXY: boolean; /** - * defines whether to disable training APIs in WebAssembly backend. + * defines whether to enable bundling the wasm JS in the build. + * + * The "wasm JS" is the JavaScript file generated by Emscripten when compiling the WebAssembly code. + * It is usually one of the following files: + * - `ort-wasm-simd-threaded.mjs` + * - `ort-wasm-simd-threaded.jsep.mjs` + * + * The value is valid only when it's an ESM build. */ - readonly DISABLE_TRAINING: boolean; - /** - * defines whether to disable dynamic importing WASM module in the build. - */ - readonly DISABLE_DYNAMIC_IMPORT: boolean; + readonly ENABLE_BUNDLE_WASM_JS: boolean; // #endregion @@ -48,9 +51,38 @@ interface BuildDefinitions { /** * placeholder for the import.meta.url in ESM. in CJS, this is undefined. */ - readonly ESM_IMPORT_META_URL: string|undefined; + readonly ESM_IMPORT_META_URL: string | undefined; // #endregion + + /** + * placeholder for the bundle filename. + * + * This is used for bundler compatibility fix when using Webpack with `import.meta.url` inside ESM module. + * + * The default behavior of some bundlers (eg. Webpack) is to rewrite `import.meta.url` to the file local path at + * compile time. This behavior will break the following code: + * ```js + * new Worker(new URL(import.meta.url), { type: 'module' }); + * ``` + * + * This is because the `import.meta.url` will be rewritten to a local path, so the line above will be equivalent to: + * ```js + * new Worker(new URL('file:///path/to/your/file.js'), { type: 'module' }); + * ``` + * + * This will cause the browser fails to load the worker script. + * + * To fix this, we need to align with how the bundlers deal with `import.meta.url`: + * ```js + * new Worker(new URL('path-to-bundle.mjs', import.meta.url), { type: 'module' }); + * ``` + * + * This will make the browser load the worker script correctly. + * + * Since we have multiple bundle outputs, we need to define this placeholder in the build definitions. + */ + readonly BUNDLE_FILENAME: string; } declare const BUILD_DEFS: BuildDefinitions; diff --git a/js/web/lib/wasm/proxy-wrapper.ts b/js/web/lib/wasm/proxy-wrapper.ts index ada06cada8584..5d97bb83e3475 100644 --- a/js/web/lib/wasm/proxy-wrapper.ts +++ b/js/web/lib/wasm/proxy-wrapper.ts @@ -12,7 +12,7 @@ import { } from './proxy-messages'; import * as core from './wasm-core-impl'; import { initializeWebAssembly } from './wasm-factory'; -import { importProxyWorker } from './wasm-utils-import'; +import { importProxyWorker, inferWasmPathPrefixFromScriptSrc } from './wasm-utils-import'; const isProxy = (): boolean => !!env.wasm.proxy && typeof document !== 'undefined'; let proxyWorker: Worker | undefined; @@ -98,6 +98,40 @@ export const initializeWebAssemblyAndOrtRuntime = async (): Promise => { proxyWorker.onmessage = onProxyWorkerMessage; initWasmCallbacks = [resolve, reject]; const message: OrtWasmMessage = { type: 'init-wasm', in: env }; + + // if the proxy worker is loaded from a blob URL, we need to make sure the path information is not lost. + // + // when `env.wasm.wasmPaths` is not set, we need to pass the path information to the worker. + // + if (!BUILD_DEFS.ENABLE_BUNDLE_WASM_JS && !message.in!.wasm.wasmPaths && objectUrl) { + // for a build not bundled the wasm JS, we need to pass the path prefix to the worker. + // the path prefix will be used to resolve the path to both the wasm JS and the wasm file. + const inferredWasmPathPrefix = inferWasmPathPrefixFromScriptSrc(); + if (inferredWasmPathPrefix) { + message.in!.wasm.wasmPaths = inferredWasmPathPrefix; + } + } + + if ( + BUILD_DEFS.IS_ESM && + BUILD_DEFS.ENABLE_BUNDLE_WASM_JS && + !message.in!.wasm.wasmPaths && + (objectUrl || BUILD_DEFS.ESM_IMPORT_META_URL?.startsWith('file:')) + ) { + // for a build bundled the wasm JS, if either of the following conditions is met: + // - the proxy worker is loaded from a blob URL + // - `import.meta.url` is a file URL, it means it is overwriten by the bundler. + // + // in either case, the path information is lost, we need to pass the path of the .wasm file to the worker. + // we need to use the bundler preferred URL format: + // new URL('filename', import.meta.url) + // so that the bundler can handle the file using corresponding loaders. + message.in!.wasm.wasmPaths = { + wasm: !BUILD_DEFS.DISABLE_JSEP + ? new URL('ort-wasm-simd-threaded.jsep.wasm', BUILD_DEFS.ESM_IMPORT_META_URL).href + : new URL('ort-wasm-simd-threaded.wasm', BUILD_DEFS.ESM_IMPORT_META_URL).href, + }; + } proxyWorker.postMessage(message); temporaryObjectUrl = objectUrl; } catch (e) { diff --git a/js/web/lib/wasm/wasm-factory.ts b/js/web/lib/wasm/wasm-factory.ts index 316adf6706074..0f49d25040409 100644 --- a/js/web/lib/wasm/wasm-factory.ts +++ b/js/web/lib/wasm/wasm-factory.ts @@ -4,7 +4,7 @@ import { Env } from 'onnxruntime-common'; import type { OrtWasmModule } from './wasm-types'; -import { importWasmModule } from './wasm-utils-import'; +import { importWasmModule, inferWasmPathPrefixFromScriptSrc } from './wasm-utils-import'; let wasm: OrtWasmModule | undefined; let initialized = false; @@ -146,18 +146,22 @@ export const initializeWebAssembly = async (flags: Env.WebAssemblyFlags): Promis }; if (wasmBinaryOverride) { - /** - * Set a custom buffer which contains the WebAssembly binary. This will skip the wasm file fetching. - */ + // Set a custom buffer which contains the WebAssembly binary. This will skip the wasm file fetching. config.wasmBinary = wasmBinaryOverride; } else if (wasmPathOverride || wasmPrefixOverride) { - /** - * A callback function to locate the WebAssembly file. The function should return the full path of the file. - * - * Since Emscripten 3.1.58, this function is only called for the .wasm file. - */ - config.locateFile = (fileName, scriptDirectory) => - wasmPathOverride ?? (wasmPrefixOverride ?? scriptDirectory) + fileName; + // A callback function to locate the WebAssembly file. The function should return the full path of the file. + // + // Since Emscripten 3.1.58, this function is only called for the .wasm file. + config.locateFile = (fileName) => wasmPathOverride ?? wasmPrefixOverride + fileName; + } else if (mjsPathOverride && mjsPathOverride.indexOf('blob:') !== 0) { + // if mjs path is specified, use it as the base path for the .wasm file. + config.locateFile = (fileName) => new URL(fileName, mjsPathOverride).href; + } else if (objectUrl) { + const inferredWasmPathPrefix = inferWasmPathPrefixFromScriptSrc(); + if (inferredWasmPathPrefix) { + // if the wasm module is preloaded, use the inferred wasm path as the base path for the .wasm file. + config.locateFile = (fileName) => inferredWasmPathPrefix + fileName; + } } ortWasmFactory(config).then( diff --git a/js/web/lib/wasm/wasm-utils-import.ts b/js/web/lib/wasm/wasm-utils-import.ts index bd9e0ce083ef0..871b575d71edc 100644 --- a/js/web/lib/wasm/wasm-utils-import.ts +++ b/js/web/lib/wasm/wasm-utils-import.ts @@ -5,30 +5,61 @@ import type { OrtWasmModule } from './wasm-types'; import { isNode } from './wasm-utils-env'; /** - * The classic script source URL. This is not always available in non ESModule environments. + * The origin of the current location. * * In Node.js, this is undefined. */ -export const scriptSrc = +const origin = isNode || typeof location === 'undefined' ? undefined : location.origin; + +const getScriptSrc = (): string | undefined => { // if Nodejs, return undefined - isNode - ? undefined - : // if It's ESM, use import.meta.url - (BUILD_DEFS.ESM_IMPORT_META_URL ?? - // use `document.currentScript.src` if available - (typeof document !== 'undefined' - ? (document.currentScript as HTMLScriptElement)?.src - : // use `self.location.href` if available - typeof self !== 'undefined' - ? self.location?.href - : undefined)); + if (isNode) { + return undefined; + } + // if It's ESM, use import.meta.url + if (BUILD_DEFS.IS_ESM) { + // For ESM, if the import.meta.url is a file URL, this usually means the bundler rewrites `import.meta.url` to + // the file path at compile time. In this case, this file path cannot be used to determine the runtime URL. + // + // We need to use the URL constructor like this: + // ```js + // new URL('actual-bundle-name.js', import.meta.url).href + // ``` + // So that bundler can preprocess the URL correctly. + if (BUILD_DEFS.ESM_IMPORT_META_URL?.startsWith('file:')) { + // if the rewritten URL is a relative path, we need to use the origin to resolve the URL. + return new URL(new URL(BUILD_DEFS.BUNDLE_FILENAME, BUILD_DEFS.ESM_IMPORT_META_URL).href, origin).href; + } + + return BUILD_DEFS.ESM_IMPORT_META_URL; + } + + return typeof document !== 'undefined' + ? (document.currentScript as HTMLScriptElement)?.src + : // use `self.location.href` if available + typeof self !== 'undefined' + ? self.location?.href + : undefined; +}; /** - * The origin of the current location. + * The classic script source URL. This is not always available in non ESModule environments. * * In Node.js, this is undefined. */ -const origin = isNode || typeof location === 'undefined' ? undefined : location.origin; +export const scriptSrc = getScriptSrc(); + +/** + * Infer the wasm path prefix from the script source URL. + * + * @returns The inferred wasm path prefix, or undefined if the script source URL is not available or is a blob URL. + */ +export const inferWasmPathPrefixFromScriptSrc = (): string | undefined => { + if (scriptSrc && !scriptSrc.startsWith('blob:')) { + return scriptSrc.substring(0, scriptSrc.lastIndexOf('/') + 1); + } + return undefined; +}; /** * Check if the given filename with prefix is from the same origin. @@ -132,7 +163,7 @@ export const importProxyWorker = async (): Promise<[undefined | string, Worker]> * This is only available in ESM and when embedding is not disabled. */ const embeddedWasmModule: EmscriptenModuleFactory | undefined = - BUILD_DEFS.IS_ESM && BUILD_DEFS.DISABLE_DYNAMIC_IMPORT + BUILD_DEFS.IS_ESM && BUILD_DEFS.ENABLE_BUNDLE_WASM_JS ? // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires require( !BUILD_DEFS.DISABLE_JSEP @@ -145,7 +176,7 @@ const embeddedWasmModule: EmscriptenModuleFactory | undefined = * Import the WebAssembly module. * * This function will perform the following steps: - * 1. If BUILD_DEFS.DISABLE_DYNAMIC_IMPORT is true, use the embedded module. + * 1. If the embedded module exists and no custom URL is specified, use the embedded module. * 2. If a preload is needed, it will preload the module and return the object URL. * 3. Otherwise, it will perform a dynamic import of the module. * @@ -158,8 +189,8 @@ export const importWasmModule = async ( prefixOverride: string | undefined, isMultiThreaded: boolean, ): Promise<[undefined | string, EmscriptenModuleFactory]> => { - if (BUILD_DEFS.DISABLE_DYNAMIC_IMPORT) { - return [undefined, embeddedWasmModule!]; + if (!urlOverride && !prefixOverride && embeddedWasmModule && scriptSrc && isSameOrigin(scriptSrc)) { + return [undefined, embeddedWasmModule]; } else { const wasmModuleFilename = !BUILD_DEFS.DISABLE_JSEP ? 'ort-wasm-simd-threaded.jsep.mjs' diff --git a/js/web/script/build.ts b/js/web/script/build.ts index 529e9d1065e69..6e8c3f0df8192 100644 --- a/js/web/script/build.ts +++ b/js/web/script/build.ts @@ -56,7 +56,7 @@ const DEFAULT_DEFINE = { 'BUILD_DEFS.DISABLE_JSEP': 'false', 'BUILD_DEFS.DISABLE_WASM': 'false', 'BUILD_DEFS.DISABLE_WASM_PROXY': 'false', - 'BUILD_DEFS.DISABLE_DYNAMIC_IMPORT': 'false', + 'BUILD_DEFS.ENABLE_BUNDLE_WASM_JS': 'false', 'BUILD_DEFS.IS_ESM': 'false', 'BUILD_DEFS.ESM_IMPORT_META_URL': 'undefined', @@ -115,7 +115,35 @@ async function minifyWasmModuleJsForBrowser(filepath: string): Promise { const TIME_TAG = `BUILD:terserMinify:${filepath}`; console.time(TIME_TAG); - const contents = await fs.readFile(filepath, { encoding: 'utf-8' }); + let contents = await fs.readFile(filepath, { encoding: 'utf-8' }); + + // Replace the following line to create worker: + // ``` + // new Worker(new URL(import.meta.url), ... + // ``` + // with: + // ``` + // new Worker(import.meta.url.startsWith('file:') + // ? new URL(BUILD_DEFS.BUNDLE_FILENAME, import.meta.url) + // : new URL(import.meta.url), ... + // ``` + // + // NOTE: this is a workaround for some bundlers that does not support runtime import.meta.url. + // TODO: in emscripten 3.1.61+, need to update this code. + + // First, check if there is exactly one occurrence of "new Worker(new URL(import.meta.url)". + const matches = [...contents.matchAll(/new Worker\(new URL\(import\.meta\.url\),/g)]; + if (matches.length !== 1) { + throw new Error( + `Unexpected number of matches for "new Worker(new URL(import.meta.url)" in "${filepath}": ${matches.length}.`, + ); + } + + // Replace the only occurrence. + contents = contents.replace( + /new Worker\(new URL\(import\.meta\.url\),/, + `new Worker(import.meta.url.startsWith('file:')?new URL(BUILD_DEFS.BUNDLE_FILENAME, import.meta.url):new URL(import.meta.url),`, + ); // Find the first and the only occurrence of minified function implementation of "_emscripten_thread_set_strongref": // ```js @@ -265,14 +293,17 @@ async function buildOrt({ const external = isNode ? ['onnxruntime-common'] : ['node:fs/promises', 'node:fs', 'node:os', 'module', 'worker_threads']; + const bundleFilename = `${outputName}${isProduction ? '.min' : ''}.${format === 'esm' ? 'mjs' : 'js'}`; const plugins: esbuild.Plugin[] = []; - const defineOverride: Record = {}; + const defineOverride: Record = { + 'BUILD_DEFS.BUNDLE_FILENAME': JSON.stringify(bundleFilename), + }; if (!isNode) { defineOverride.process = 'undefined'; defineOverride['globalThis.process'] = 'undefined'; } - if (define['BUILD_DEFS.DISABLE_DYNAMIC_IMPORT'] === 'true') { + if (define['BUILD_DEFS.ENABLE_BUNDLE_WASM_JS'] === 'true') { plugins.push({ name: 'emscripten-mjs-handler', setup(build: esbuild.PluginBuild) { @@ -285,7 +316,7 @@ async function buildOrt({ await buildBundle({ entryPoints: ['web/lib/index.ts'], - outfile: `web/dist/${outputName}${isProduction ? '.min' : ''}.${format === 'esm' ? 'mjs' : 'js'}`, + outfile: `web/dist/${bundleFilename}`, platform, format, globalName: 'ort', @@ -585,7 +616,7 @@ async function main() { isProduction: true, outputName: 'ort.all.bundle', format: 'esm', - define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_DYNAMIC_IMPORT': 'true' }, + define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.ENABLE_BUNDLE_WASM_JS': 'true' }, }); // ort[.min].[m]js @@ -598,7 +629,7 @@ async function main() { isProduction: true, outputName: 'ort.bundle', format: 'esm', - define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGL': 'true', 'BUILD_DEFS.DISABLE_DYNAMIC_IMPORT': 'true' }, + define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGL': 'true', 'BUILD_DEFS.ENABLE_BUNDLE_WASM_JS': 'true' }, }); // ort.webgpu[.min].[m]js @@ -611,7 +642,7 @@ async function main() { isProduction: true, outputName: 'ort.webgpu.bundle', format: 'esm', - define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGL': 'true', 'BUILD_DEFS.DISABLE_DYNAMIC_IMPORT': 'true' }, + define: { ...DEFAULT_DEFINE, 'BUILD_DEFS.DISABLE_WEBGL': 'true', 'BUILD_DEFS.ENABLE_BUNDLE_WASM_JS': 'true' }, }); // ort.wasm[.min].[m]js diff --git a/js/web/test/e2e/exports/README.md b/js/web/test/e2e/exports/README.md new file mode 100644 index 0000000000000..7f2fd23335b79 --- /dev/null +++ b/js/web/test/e2e/exports/README.md @@ -0,0 +1,4 @@ +This folder includes test data, scripts and source code that used to test the export functionality of onnxruntime-web package. + +- [nextjs-default](./testcases/nextjs-default.md) +- [vite-default](./testcases/vite-default.md) diff --git a/js/web/test/e2e/exports/main.js b/js/web/test/e2e/exports/main.js new file mode 100644 index 0000000000000..8ed22a6784e7c --- /dev/null +++ b/js/web/test/e2e/exports/main.js @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +const { runDevTest, runProdTest } = require('./test'); +const { installOrtPackages } = require('./utils'); + +/** + * Entry point for package exports tests. + * + * @param {string[]} packagesToInstall + */ +module.exports = async function main(PRESERVE, PACKAGES_TO_INSTALL) { + console.log('Running exports tests...'); + + // testcases/nextjs-default + { + await installOrtPackages('nextjs-default', PRESERVE, PACKAGES_TO_INSTALL); + + await runDevTest('nextjs-default', '✓ Ready in', 3000); + await runDevTest('nextjs-default', '✓ Ready in', 3000, 'turbopack', 'npm run dev -- --turbopack'); + await runProdTest('nextjs-default', '✓ Ready in', 3000); + } + + // testcases/vite-default + { + await installOrtPackages('vite-default', PRESERVE, PACKAGES_TO_INSTALL); + + await runDevTest('vite-default', '\x1b[32m➜\x1b[39m \x1b[1mLocal\x1b[22m:', 5173); + await runProdTest('vite-default', '\x1b[32m➜\x1b[39m \x1b[1mLocal\x1b[22m:', 4173); + } +}; diff --git a/js/web/test/e2e/exports/test.js b/js/web/test/e2e/exports/test.js new file mode 100644 index 0000000000000..9c5ed745ab0b5 --- /dev/null +++ b/js/web/test/e2e/exports/test.js @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +const EventEmitter = require('node:events'); +const path = require('path'); +const { runShellCmd } = require('./utils'); + +const launchBrowserAndRunTests = async (logPrefix, port) => { + const testResults = []; + const puppeteer = require('puppeteer-core'); + let browser; + try { + browser = await puppeteer.launch({ + executablePath: 'C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe', + browser: 'chrome', + headless: true, + args: ['--enable-features=SharedArrayBuffer', '--no-sandbox', '--disable-setuid-sandbox'], + }); + + for await (const flags of [ + [false, false], + [false, true], + [true, false], + [true, true], + ]) { + const [multiThread, proxy] = flags; + console.log(`[${logPrefix}] Running test with multi-thread: ${multiThread}, proxy: ${proxy}...`); + + const page = await browser.newPage(); + await page.goto(`http://localhost:${port}`); + // wait for the page to load + await page.waitForSelector('#ortstate', { visible: true }); + // if multi-thread is enabled, check the checkbox + if (multiThread) { + await page.locator('#cb-mt').click(); + } + // if proxy is enabled, check the checkbox + if (proxy) { + await page.locator('#cb-px').click(); + } + // click the load model button + await page.locator('#btn-load').click(); + // wait for the model to load or fail + await page.waitForFunction("['2','3'].includes(document.getElementById('ortstate').innerText)"); + // verify the model is loaded + const modelLoadState = await page.$eval('#ortstate', (el) => el.innerText); + if (modelLoadState !== '2') { + const ortLog = await page.$eval('#ortlog', (el) => el.innerText); + testResults.push({ multiThread, proxy, success: false, message: `Failed to load model: ${ortLog}` }); + continue; + } + + // click the run test button + await page.locator('#btn-run').click(); + // wait for the inference run to complete or fail + await page.waitForFunction("['5','6'].includes(document.getElementById('ortstate').innerText)"); + // verify the inference run result + const runState = await page.$eval('#ortstate', (el) => el.innerText); + if (runState !== '5') { + const ortLog = await page.$eval('#ortlog', (el) => el.innerText); + testResults.push({ multiThread, proxy, success: false, message: `Failed to run model: ${ortLog}` }); + continue; + } + + testResults.push({ multiThread, proxy, success: true }); + } + + return testResults; + } finally { + console.log(`[${logPrefix}] Closing the browser...`); + // close the browser + if (browser) { + await browser.close(); + } + } +}; + +async function runTest(testCaseName, logPrefix, ready, cmd, port) { + const wd = path.join(__dirname, 'testcases', testCaseName); + logPrefix = [testCaseName, ...logPrefix].join(':'); + + console.log(`[${logPrefix}] Testing...`); + const npmRunDevEvent = new EventEmitter(); + const npmRunDev = runShellCmd(cmd, { + wd, + event: npmRunDevEvent, + ready, + ignoreExitCode: true, + }); + + let testResults; + npmRunDevEvent.on('serverReady', async () => { + try { + testResults = await launchBrowserAndRunTests(logPrefix, port); + } finally { + console.log(`[${logPrefix}] Killing the server...`); + // kill the server as the last step + npmRunDevEvent.emit('kill'); + } + }); + + await npmRunDev; + + console.log(`[${logPrefix}] test result:`, testResults); + if (testResults.some((r) => !r.success)) { + throw new Error(`[${logPrefix}] test failed.`); + } +} + +async function runDevTest(testCaseName, ready, port, logPrefix = '', cmd = 'npm run dev') { + return runTest(testCaseName, logPrefix ? ['dev', logPrefix] : ['dev'], ready, cmd, port); +} + +async function runProdTest(testCaseName, ready, port) { + const wd = path.join(__dirname, 'testcases', testCaseName); + + console.log(`[${testCaseName}:prod] Building...`); + await runShellCmd('npm run build', { wd }); + await runTest(testCaseName, ['prod'], ready, 'npm run start', port); +} + +module.exports = { + runDevTest, + runProdTest, +}; diff --git a/js/web/test/e2e/exports/testcases/nextjs-default.md b/js/web/test/e2e/exports/testcases/nextjs-default.md new file mode 100644 index 0000000000000..2990d9463d44e --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default.md @@ -0,0 +1,61 @@ +## nextjs-default + +### Summary + +This is a Next.js application created by `npx create-next-app@latest` using the following config: + +``` +\js\web\test\e2e\exports\testcases>npx create-next-app@latest + +√ What is your project named? ... nextjs-default +√ Would you like to use TypeScript? ... No +√ Would you like to use ESLint? ... No +√ Would you like to use Tailwind CSS? ... No +√ Would you like your code inside a `src/` directory? ... No +√ Would you like to use App Router? (recommended) ... No +√ Would you like to use Turbopack for `next dev`? ... No +√ Would you like to customize the import alias (`@/*` by default)? ... No +Creating a new Next.js app in \js\web\test\e2e\exports\testcases\nextjs-default. + +Using npm. + +Initializing project with template: app + + +Installing dependencies: +- react +- react-dom +- next +``` + +Small changes were made based on the application template, including: + +- Remove default Logos, images, CSS and SVG +- Add a client side rendering (CSR) component which contains: + - a checkbox for multi-thread + - a checkbox for proxy + - a "Load Model" button + - a "Run Model" button + - a state DIV + - a log DIV +- Add a helper module for creating ORT session and run + +### Tests + +Uses puppeteer to simulate the following tests: + +- Tests on `npm run dev` (dev server) + - multi-thread OFF, proxy OFF + - multi-thread OFF, proxy ON + - multi-thread ON, proxy OFF + - multi-thread ON, proxy ON +- Tests on `npm run dev -- --turbopack` (dev server using TurboPack) + - multi-thread OFF, proxy OFF + - multi-thread OFF, proxy ON + - multi-thread ON, proxy OFF + - multi-thread ON, proxy ON +- Tests on `npm run build` + `npm run start` (prod) + - multi-thread OFF, proxy OFF + - multi-thread OFF, proxy ON + - multi-thread ON, proxy OFF + - multi-thread ON, proxy ON diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/.gitignore b/js/web/test/e2e/exports/testcases/nextjs-default/.gitignore new file mode 100644 index 0000000000000..5ef6a52078020 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/app/favicon.ico b/js/web/test/e2e/exports/testcases/nextjs-default/app/favicon.ico new file mode 100644 index 0000000000000..718d6fea4835e Binary files /dev/null and b/js/web/test/e2e/exports/testcases/nextjs-default/app/favicon.ico differ diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/app/layout.js b/js/web/test/e2e/exports/testcases/nextjs-default/app/layout.js new file mode 100644 index 0000000000000..ac2b8dff7e005 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default/app/layout.js @@ -0,0 +1,12 @@ +export const metadata = { + title: 'Next.js app', + description: 'Generated by Next.js', +}; + +export default function RootLayout({ children }) { + return ( + + {children} + + ); +} diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/app/page.js b/js/web/test/e2e/exports/testcases/nextjs-default/app/page.js new file mode 100644 index 0000000000000..7892bd814c8a6 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default/app/page.js @@ -0,0 +1,15 @@ +'use client'; + +import dynamic from 'next/dynamic'; + +const OnnxTestBarComponent = dynamic(() => import('../components/onnx-test-bar'), { ssr: false }); + +export default function Home() { + return ( +
+
+ +
+
+ ); +} diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/components/onnx-helper.js b/js/web/test/e2e/exports/testcases/nextjs-default/components/onnx-helper.js new file mode 100644 index 0000000000000..332745f8e5a80 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default/components/onnx-helper.js @@ -0,0 +1,58 @@ +import * as ort from 'onnxruntime-web'; + +// Model data for "test_abs/model.onnx" +const testModelData = + 'CAcSDGJhY2tlbmQtdGVzdDpJCgsKAXgSAXkiA0FicxIIdGVzdF9hYnNaFwoBeBISChAIARIMCgIIAwoCCAQKAggFYhcKAXkSEgoQCAESDAoCCAMKAggECgIIBUIECgAQDQ=='; + +const base64StringToUint8Array = (base64String) => { + const charArray = atob(base64String); + const length = charArray.length; + const buffer = new Uint8Array(new ArrayBuffer(length)); + for (let i = 0; i < length; i++) { + buffer[i] = charArray.charCodeAt(i); + } + return buffer; +}; + +let mySession; + +const assert = (cond, msg) => { + if (!cond) throw new Error(msg); +}; + +export const createTestSession = async (multiThreaded, proxy) => { + const model = base64StringToUint8Array(testModelData); + const options = {}; + + if (multiThreaded) { + ort.env.wasm.numThreads = 2; + assert(typeof SharedArrayBuffer !== 'undefined', 'SharedArrayBuffer is not supported'); + } + if (proxy) { + ort.env.wasm.proxy = true; + } + mySession = await ort.InferenceSession.create(model, options); +}; + +export const runTestSessionAndValidate = async () => { + try { + // test data: [0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, ... 58, -59] + const inputData = [...Array(60).keys()].map((i) => (i % 2 === 0 ? i : -i)); + const expectedOutputData = inputData.map((i) => Math.abs(i)); + + const fetches = await mySession.run({ x: new ort.Tensor('float32', inputData, [3, 4, 5]) }); + + const y = fetches.y; + + assert(y instanceof ort.Tensor, 'unexpected result'); + assert(y.dims.length === 3 && y.dims[0] === 3 && y.dims[1] === 4 && y.dims[2] === 5, 'incorrect shape'); + + for (let i = 0; i < expectedOutputData.length; i++) { + assert(y.data[i] === expectedOutputData[i], `output data mismatch at index ${i}`); + } + + return 'PASS'; + } catch (e) { + return `FAIL: ${e}`; + } +}; diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/components/onnx-test-bar.js b/js/web/test/e2e/exports/testcases/nextjs-default/components/onnx-test-bar.js new file mode 100644 index 0000000000000..1afcf5d6a3384 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default/components/onnx-test-bar.js @@ -0,0 +1,59 @@ +'use client'; + +import { useState } from 'react'; + +export default function OnnxTestBar() { + const [ortState, setOrtState] = useState(0); + const [ortLog, setOrtLog] = useState('Ready.'); + + const loadModel = async () => { + setOrtState(1); + setOrtLog('Loading model...'); + try { + const { createTestSession } = await import('./onnx-helper'); + await createTestSession(document.getElementById('cb-mt').checked, document.getElementById('cb-px').checked); + setOrtState(2); + setOrtLog('Model loaded.'); + } catch (e) { + setOrtState(3); + setOrtLog(`Failed to load model: ${e}`); + return; + } + }; + + const runTest = async () => { + setOrtState(4); + setOrtLog('Running model test...'); + try { + const { runTestSessionAndValidate } = await import('./onnx-helper'); + const testResult = await runTestSessionAndValidate(); + setOrtState(5); + setOrtLog(`Test result: ${testResult}`); + } catch (e) { + setOrtState(6); + setOrtLog(`Failed to load model: ${e}`); + return; + } + }; + + return ( +
+ + + + +
{ortState}
+
{ortLog}
+
+ ); +} diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/jsconfig.json b/js/web/test/e2e/exports/testcases/nextjs-default/jsconfig.json new file mode 100644 index 0000000000000..2a2e4b3bf8ba1 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default/jsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./*"] + } + } +} diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/next.config.mjs b/js/web/test/e2e/exports/testcases/nextjs-default/next.config.mjs new file mode 100644 index 0000000000000..4678774e6d606 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default/next.config.mjs @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {}; + +export default nextConfig; diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/package-lock.json b/js/web/test/e2e/exports/testcases/nextjs-default/package-lock.json new file mode 100644 index 0000000000000..174812402f578 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default/package-lock.json @@ -0,0 +1,878 @@ +{ + "name": "nextjs-default", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "nextjs-default", + "version": "0.1.0", + "dependencies": { + "next": "15.1.2", + "react": "^19.0.0", + "react-dom": "^19.0.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", + "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", + "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", + "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", + "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", + "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", + "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", + "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", + "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", + "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", + "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", + "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", + "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.5" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", + "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", + "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", + "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", + "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", + "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", + "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.2.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", + "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", + "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@next/env": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.2.tgz", + "integrity": "sha512-Hm3jIGsoUl6RLB1vzY+dZeqb+/kWPZ+h34yiWxW0dV87l8Im/eMOwpOA+a0L78U0HM04syEjXuRlCozqpwuojQ==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.2.tgz", + "integrity": "sha512-b9TN7q+j5/7+rGLhFAVZiKJGIASuo8tWvInGfAd8wsULjB1uNGRCj1z1WZwwPWzVQbIKWFYqc+9L7W09qwt52w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.2.tgz", + "integrity": "sha512-caR62jNDUCU+qobStO6YJ05p9E+LR0EoXh1EEmyU69cYydsAy7drMcOlUlRtQihM6K6QfvNwJuLhsHcCzNpqtA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.2.tgz", + "integrity": "sha512-fHHXBusURjBmN6VBUtu6/5s7cCeEkuGAb/ZZiGHBLVBXMBy4D5QpM8P33Or8JD1nlOjm/ZT9sEE5HouQ0F+hUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.2.tgz", + "integrity": "sha512-9CF1Pnivij7+M3G74lxr+e9h6o2YNIe7QtExWq1KUK4hsOLTBv6FJikEwCaC3NeYTflzrm69E5UfwEAbV2U9/g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.2.tgz", + "integrity": "sha512-tINV7WmcTUf4oM/eN3Yuu/f8jQ5C6AkueZPKeALs/qfdfX57eNv4Ij7rt0SA6iZ8+fMobVfcFVv664Op0caCCg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.2.tgz", + "integrity": "sha512-jf2IseC4WRsGkzeUw/cK3wci9pxR53GlLAt30+y+B+2qAQxMw6WAC3QrANIKxkcoPU3JFh/10uFfmoMDF9JXKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.2.tgz", + "integrity": "sha512-wvg7MlfnaociP7k8lxLX4s2iBJm4BrNiNFhVUY+Yur5yhAJHfkS8qPPeDEUH8rQiY0PX3u/P7Q/wcg6Mv6GSAA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.2.tgz", + "integrity": "sha512-D3cNA8NoT3aWISWmo7HF5Eyko/0OdOO+VagkoJuiTk7pyX3P/b+n8XA/MYvyR+xSVcbKn68B1rY9fgqjNISqzQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001690", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz", + "integrity": "sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT", + "optional": true + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "optional": true, + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "15.1.2", + "resolved": "https://registry.npmjs.org/next/-/next-15.1.2.tgz", + "integrity": "sha512-nLJDV7peNy+0oHlmY2JZjzMfJ8Aj0/dd3jCwSZS8ZiO5nkQfcZRqDrRN3U5rJtqVTQneIOGZzb6LCNrk7trMCQ==", + "license": "MIT", + "dependencies": { + "@next/env": "15.1.2", + "@swc/counter": "0.1.3", + "@swc/helpers": "0.5.15", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.1.2", + "@next/swc-darwin-x64": "15.1.2", + "@next/swc-linux-arm64-gnu": "15.1.2", + "@next/swc-linux-arm64-musl": "15.1.2", + "@next/swc-linux-x64-gnu": "15.1.2", + "@next/swc-linux-x64-musl": "15.1.2", + "@next/swc-win32-arm64-msvc": "15.1.2", + "@next/swc-win32-x64-msvc": "15.1.2", + "sharp": "^0.33.5" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", + "integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz", + "integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.25.0" + }, + "peerDependencies": { + "react": "^19.0.0" + } + }, + "node_modules/scheduler": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.33.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", + "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.6.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.5", + "@img/sharp-darwin-x64": "0.33.5", + "@img/sharp-libvips-darwin-arm64": "1.0.4", + "@img/sharp-libvips-darwin-x64": "1.0.4", + "@img/sharp-libvips-linux-arm": "1.0.5", + "@img/sharp-libvips-linux-arm64": "1.0.4", + "@img/sharp-libvips-linux-s390x": "1.0.4", + "@img/sharp-libvips-linux-x64": "1.0.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", + "@img/sharp-libvips-linuxmusl-x64": "1.0.4", + "@img/sharp-linux-arm": "0.33.5", + "@img/sharp-linux-arm64": "0.33.5", + "@img/sharp-linux-s390x": "0.33.5", + "@img/sharp-linux-x64": "0.33.5", + "@img/sharp-linuxmusl-arm64": "0.33.5", + "@img/sharp-linuxmusl-x64": "0.33.5", + "@img/sharp-wasm32": "0.33.5", + "@img/sharp-win32-ia32": "0.33.5", + "@img/sharp-win32-x64": "0.33.5" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + } + } +} diff --git a/js/web/test/e2e/exports/testcases/nextjs-default/package.json b/js/web/test/e2e/exports/testcases/nextjs-default/package.json new file mode 100644 index 0000000000000..6688445cded26 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/nextjs-default/package.json @@ -0,0 +1,16 @@ +{ + "name": "nextjs-default", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "react": "^19.0.0", + "react-dom": "^19.0.0", + "next": "15.1.2" + } +} diff --git a/js/web/test/e2e/exports/testcases/vite-default.md b/js/web/test/e2e/exports/testcases/vite-default.md new file mode 100644 index 0000000000000..71327933e6d68 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default.md @@ -0,0 +1,51 @@ +## vite-default + +### Summary + +This is a web application created by `npm create vite@latest` using the following config: + +``` +\js\web\test\e2e\exports\testcases>npm create vite@latest + +> npx +> create-vite + +√ Project name: ... vite-default +√ Select a framework: » Vue +√ Select a variant: » JavaScript + +Scaffolding project in \js\web\test\e2e\exports\testcases\vite-default... + +Done. Now run: + + cd vite-default + npm install + npm run dev +``` + +Small changes were made based on the application template, including: + +- Remove default Logos, images, CSS and SVG +- Add a client side rendering (CSR) component which contains: + - a checkbox for multi-thread + - a checkbox for proxy + - a "Load Model" button + - a "Run Model" button + - a state DIV + - a log DIV +- Add a helper module for creating ORT session and run + +### Tests + +Uses puppeteer to simulate the following tests: + +- Tests on `npm run dev` (dev server) + - multi-thread OFF, proxy OFF + - multi-thread OFF, proxy ON + - multi-thread ON, proxy OFF + - multi-thread ON, proxy ON +- Tests on `npm run build` + `npm run start` (prod) + - multi-thread OFF, proxy OFF + - multi-thread OFF, proxy ON + - multi-thread ON, proxy OFF + - multi-thread ON, proxy ON diff --git a/js/web/test/e2e/exports/testcases/vite-default/.gitignore b/js/web/test/e2e/exports/testcases/vite-default/.gitignore new file mode 100644 index 0000000000000..a547bf36d8d11 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/js/web/test/e2e/exports/testcases/vite-default/index.html b/js/web/test/e2e/exports/testcases/vite-default/index.html new file mode 100644 index 0000000000000..db9cf0a4aadab --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/index.html @@ -0,0 +1,12 @@ + + + + + + Vite + Vue + + +
+ + + diff --git a/js/web/test/e2e/exports/testcases/vite-default/package-lock.json b/js/web/test/e2e/exports/testcases/vite-default/package-lock.json new file mode 100644 index 0000000000000..96c19af9479e4 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/package-lock.json @@ -0,0 +1,1165 @@ +{ + "name": "vite-default", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vite-default", + "version": "0.0.0", + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.2.1", + "vite": "^6.0.5" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.26.3" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", + "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz", + "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", + "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz", + "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", + "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", + "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", + "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", + "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", + "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", + "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", + "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", + "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", + "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", + "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", + "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", + "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", + "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", + "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", + "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", + "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", + "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", + "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", + "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", + "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", + "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.2.tgz", + "integrity": "sha512-s/8RiF4bdmGnc/J0N7lHAr5ZFJj+NdJqJ/Hj29K+c4lEdoVlukzvWXB9XpWZCdakVT0YAw8iyIqUP2iFRz5/jA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.2.tgz", + "integrity": "sha512-mKRlVj1KsKWyEOwR6nwpmzakq6SgZXW4NUHNWlYSiyncJpuXk7wdLzuKdWsRoR1WLbWsZBKvsUCdCTIAqRn9cA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.2.tgz", + "integrity": "sha512-vJX+vennGwygmutk7N333lvQ/yKVAHnGoBS2xMRQgXWW8tvn46YWuTDOpKroSPR9BEW0Gqdga2DHqz8Pwk6X5w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.2.tgz", + "integrity": "sha512-e2rW9ng5O6+Mt3ht8fH0ljfjgSCC6ffmOipiLUgAnlK86CHIaiCdHCzHzmTkMj6vEkqAiRJ7ss6Ibn56B+RE5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.2.tgz", + "integrity": "sha512-/xdNwZe+KesG6XJCK043EjEDZTacCtL4yurMZRLESIgHQdvtNyul3iz2Ab03ZJG0pQKbFTu681i+4ETMF9uE/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.2.tgz", + "integrity": "sha512-eXKvpThGzREuAbc6qxnArHh8l8W4AyTcL8IfEnmx+bcnmaSGgjyAHbzZvHZI2csJ+e0MYddl7DX0X7g3sAuXDQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.2.tgz", + "integrity": "sha512-h4VgxxmzmtXLLYNDaUcQevCmPYX6zSj4SwKuzY7SR5YlnCBYsmvfYORXgiU8axhkFCDtQF3RW5LIXT8B14Qykg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.2.tgz", + "integrity": "sha512-EObwZ45eMmWZQ1w4N7qy4+G1lKHm6mcOwDa+P2+61qxWu1PtQJ/lz2CNJ7W3CkfgN0FQ7cBUy2tk6D5yR4KeXw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.2.tgz", + "integrity": "sha512-Z7zXVHEXg1elbbYiP/29pPwlJtLeXzjrj4241/kCcECds8Zg9fDfURWbZHRIKrEriAPS8wnVtdl4ZJBvZr325w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.2.tgz", + "integrity": "sha512-TF4kxkPq+SudS/r4zGPf0G08Bl7+NZcFrUSR3484WwsHgGgJyPQRLCNrQ/R5J6VzxfEeQR9XRpc8m2t7lD6SEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.2.tgz", + "integrity": "sha512-kO9Fv5zZuyj2zB2af4KA29QF6t7YSxKrY7sxZXfw8koDQj9bx5Tk5RjH+kWKFKok0wLGTi4bG117h31N+TIBEg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.2.tgz", + "integrity": "sha512-gIh776X7UCBaetVJGdjXPFurGsdWwHHinwRnC5JlLADU8Yk0EdS/Y+dMO264OjJFo7MXQ5PX4xVFbxrwK8zLqA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.2.tgz", + "integrity": "sha512-YgikssQ5UNq1GoFKZydMEkhKbjlUq7G3h8j6yWXLBF24KyoA5BcMtaOUAXq5sydPmOPEqB6kCyJpyifSpCfQ0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.2.tgz", + "integrity": "sha512-9ouIR2vFWCyL0Z50dfnon5nOrpDdkTG9lNDs7MRaienQKlTyHcDxplmk3IbhFlutpifBSBr2H4rVILwmMLcaMA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.2.tgz", + "integrity": "sha512-ckBBNRN/F+NoSUDENDIJ2U9UWmIODgwDB/vEXCPOMcsco1niTkxTXa6D2Y/pvCnpzaidvY2qVxGzLilNs9BSzw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.2.tgz", + "integrity": "sha512-jycl1wL4AgM2aBFJFlpll/kGvAjhK8GSbEmFT5v3KC3rP/b5xZ1KQmv0vQQ8Bzb2ieFQ0kZFPRMbre/l3Bu9JA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.2.tgz", + "integrity": "sha512-S2V0LlcOiYkNGlRAWZwwUdNgdZBfvsDHW0wYosYFV3c7aKgEVcbonetZXsHv7jRTTX+oY5nDYT4W6B1oUpMNOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.2.tgz", + "integrity": "sha512-pW8kioj9H5f/UujdoX2atFlXNQ9aCfAxFRaa+mhczwcsusm6gGrSo4z0SLvqLF5LwFqFTjiLCCzGkNK/LE0utQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.2.tgz", + "integrity": "sha512-p6fTArexECPf6KnOHvJXRpAEq0ON1CBtzG/EY4zw08kCHk/kivBc5vUEtnCFNCHOpJZ2ne77fxwRLIKD4wuW2Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.1.tgz", + "integrity": "sha512-cxh314tzaWwOLqVes2gnnCtvBDcM1UMdn+iFR+UjAn411dPT3tOmqrJjbMd7koZpMAmBM/GqeV4n9ge7JSiJJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", + "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.13", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", + "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", + "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.13", + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.11", + "postcss": "^8.4.48", + "source-map-js": "^1.2.0" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", + "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.13.tgz", + "integrity": "sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.13.tgz", + "integrity": "sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/shared": "3.5.13" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.13.tgz", + "integrity": "sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.13", + "@vue/runtime-core": "3.5.13", + "@vue/shared": "3.5.13", + "csstype": "^3.1.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.13.tgz", + "integrity": "sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "vue": "3.5.13" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", + "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz", + "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.24.2", + "@esbuild/android-arm": "0.24.2", + "@esbuild/android-arm64": "0.24.2", + "@esbuild/android-x64": "0.24.2", + "@esbuild/darwin-arm64": "0.24.2", + "@esbuild/darwin-x64": "0.24.2", + "@esbuild/freebsd-arm64": "0.24.2", + "@esbuild/freebsd-x64": "0.24.2", + "@esbuild/linux-arm": "0.24.2", + "@esbuild/linux-arm64": "0.24.2", + "@esbuild/linux-ia32": "0.24.2", + "@esbuild/linux-loong64": "0.24.2", + "@esbuild/linux-mips64el": "0.24.2", + "@esbuild/linux-ppc64": "0.24.2", + "@esbuild/linux-riscv64": "0.24.2", + "@esbuild/linux-s390x": "0.24.2", + "@esbuild/linux-x64": "0.24.2", + "@esbuild/netbsd-arm64": "0.24.2", + "@esbuild/netbsd-x64": "0.24.2", + "@esbuild/openbsd-arm64": "0.24.2", + "@esbuild/openbsd-x64": "0.24.2", + "@esbuild/sunos-x64": "0.24.2", + "@esbuild/win32-arm64": "0.24.2", + "@esbuild/win32-ia32": "0.24.2", + "@esbuild/win32-x64": "0.24.2" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.29.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.2.tgz", + "integrity": "sha512-tJXpsEkzsEzyAKIaB3qv3IuvTVcTN7qBw1jL4SPPXM3vzDrJgiLGFY6+HodgFaUHAJ2RYJ94zV5MKRJCoQzQeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.6" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.29.2", + "@rollup/rollup-android-arm64": "4.29.2", + "@rollup/rollup-darwin-arm64": "4.29.2", + "@rollup/rollup-darwin-x64": "4.29.2", + "@rollup/rollup-freebsd-arm64": "4.29.2", + "@rollup/rollup-freebsd-x64": "4.29.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.29.2", + "@rollup/rollup-linux-arm-musleabihf": "4.29.2", + "@rollup/rollup-linux-arm64-gnu": "4.29.2", + "@rollup/rollup-linux-arm64-musl": "4.29.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.29.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.29.2", + "@rollup/rollup-linux-riscv64-gnu": "4.29.2", + "@rollup/rollup-linux-s390x-gnu": "4.29.2", + "@rollup/rollup-linux-x64-gnu": "4.29.2", + "@rollup/rollup-linux-x64-musl": "4.29.2", + "@rollup/rollup-win32-arm64-msvc": "4.29.2", + "@rollup/rollup-win32-ia32-msvc": "4.29.2", + "@rollup/rollup-win32-x64-msvc": "4.29.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vite": { + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.0.7.tgz", + "integrity": "sha512-RDt8r/7qx9940f8FcOIAH9PTViRrghKaK2K1jY3RaAURrEUbm9Du1mJ72G+jlhtG3WwodnfzY8ORQZbBavZEAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.24.2", + "postcss": "^8.4.49", + "rollup": "^4.23.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.13.tgz", + "integrity": "sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.13", + "@vue/compiler-sfc": "3.5.13", + "@vue/runtime-dom": "3.5.13", + "@vue/server-renderer": "3.5.13", + "@vue/shared": "3.5.13" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + } + } +} diff --git a/js/web/test/e2e/exports/testcases/vite-default/package.json b/js/web/test/e2e/exports/testcases/vite-default/package.json new file mode 100644 index 0000000000000..7a1f370885bf4 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/package.json @@ -0,0 +1,18 @@ +{ + "name": "vite-default", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "start": "vite preview" + }, + "dependencies": { + "vue": "^3.5.13" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^5.2.1", + "vite": "^6.0.5" + } +} diff --git a/js/web/test/e2e/exports/testcases/vite-default/src/App.vue b/js/web/test/e2e/exports/testcases/vite-default/src/App.vue new file mode 100644 index 0000000000000..98503cac1e4cd --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/src/App.vue @@ -0,0 +1,22 @@ + + + + + diff --git a/js/web/test/e2e/exports/testcases/vite-default/src/components/HelloWorld.vue b/js/web/test/e2e/exports/testcases/vite-default/src/components/HelloWorld.vue new file mode 100644 index 0000000000000..51ad2e6a642e4 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/src/components/HelloWorld.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/js/web/test/e2e/exports/testcases/vite-default/src/components/onnx-helper.js b/js/web/test/e2e/exports/testcases/vite-default/src/components/onnx-helper.js new file mode 100644 index 0000000000000..f6b458ce55683 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/src/components/onnx-helper.js @@ -0,0 +1,68 @@ +import * as ort from 'onnxruntime-web'; + +// The following line uses Vite's "Explicit URL Imports" feature to load the wasm files as asset. +// +// see https://vite.dev/guide/assets.html#explicit-url-imports +// +import wasmFileUrl from '/node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.wasm?url'; +import mjsFileUrl from '/node_modules/onnxruntime-web/dist/ort-wasm-simd-threaded.jsep.mjs?url'; + +// wasmFileUrl is a string that contains the URL of the wasm file. +ort.env.wasm.wasmPaths = { wasm: wasmFileUrl, mjs: mjsFileUrl }; + +// Model data for "test_abs/model.onnx" +const testModelData = + 'CAcSDGJhY2tlbmQtdGVzdDpJCgsKAXgSAXkiA0FicxIIdGVzdF9hYnNaFwoBeBISChAIARIMCgIIAwoCCAQKAggFYhcKAXkSEgoQCAESDAoCCAMKAggECgIIBUIECgAQDQ=='; + +const base64StringToUint8Array = (base64String) => { + const charArray = atob(base64String); + const length = charArray.length; + const buffer = new Uint8Array(new ArrayBuffer(length)); + for (let i = 0; i < length; i++) { + buffer[i] = charArray.charCodeAt(i); + } + return buffer; +}; + +let mySession; + +const assert = (cond, msg) => { + if (!cond) throw new Error(msg); +}; + +export const createTestSession = async (multiThreaded, proxy) => { + const model = base64StringToUint8Array(testModelData); + const options = {}; + + if (multiThreaded) { + ort.env.wasm.numThreads = 2; + assert(typeof SharedArrayBuffer !== 'undefined', 'SharedArrayBuffer is not supported'); + } + if (proxy) { + ort.env.wasm.proxy = true; + } + mySession = await ort.InferenceSession.create(model, options); +}; + +export const runTestSessionAndValidate = async () => { + try { + // test data: [0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, ... 58, -59] + const inputData = [...Array(60).keys()].map((i) => (i % 2 === 0 ? i : -i)); + const expectedOutputData = inputData.map((i) => Math.abs(i)); + + const fetches = await mySession.run({ x: new ort.Tensor('float32', inputData, [3, 4, 5]) }); + + const y = fetches.y; + + assert(y instanceof ort.Tensor, 'unexpected result'); + assert(y.dims.length === 3 && y.dims[0] === 3 && y.dims[1] === 4 && y.dims[2] === 5, 'incorrect shape'); + + for (let i = 0; i < expectedOutputData.length; i++) { + assert(y.data[i] === expectedOutputData[i], `output data mismatch at index ${i}`); + } + + return 'PASS'; + } catch (e) { + return `FAIL: ${e}`; + } +}; diff --git a/js/web/test/e2e/exports/testcases/vite-default/src/main.js b/js/web/test/e2e/exports/testcases/vite-default/src/main.js new file mode 100644 index 0000000000000..f8c23e476c2bc --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/src/main.js @@ -0,0 +1,5 @@ +import { createApp } from 'vue'; +import './style.css'; +import App from './App.vue'; + +createApp(App).mount('#app'); diff --git a/js/web/test/e2e/exports/testcases/vite-default/src/style.css b/js/web/test/e2e/exports/testcases/vite-default/src/style.css new file mode 100644 index 0000000000000..bb131d6b8fe5d --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/src/style.css @@ -0,0 +1,79 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + display: flex; + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +.card { + padding: 2em; +} + +#app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + text-align: center; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/js/web/test/e2e/exports/testcases/vite-default/vite.config.js b/js/web/test/e2e/exports/testcases/vite-default/vite.config.js new file mode 100644 index 0000000000000..37d3d6f22bd04 --- /dev/null +++ b/js/web/test/e2e/exports/testcases/vite-default/vite.config.js @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite'; +import vue from '@vitejs/plugin-vue'; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [vue()], +}); diff --git a/js/web/test/e2e/exports/utils.js b/js/web/test/e2e/exports/utils.js new file mode 100644 index 0000000000000..9ce2240f6a7e7 --- /dev/null +++ b/js/web/test/e2e/exports/utils.js @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +const path = require('path'); +const { spawn } = require('child_process'); +const treeKill = require('tree-kill'); + +async function installOrtPackages(testCaseName, PRESERVE, PACKAGES_TO_INSTALL) { + if (!PRESERVE) { + const wd = path.join(__dirname, 'testcases', testCaseName); + if (PACKAGES_TO_INSTALL.length === 0) { + await runShellCmd('npm ci', { wd }); + } else { + await runShellCmd(`npm install ${PACKAGES_TO_INSTALL.map((i) => `"${i}"`).join(' ')}`, { wd }); + } + } +} + +async function runShellCmd(cmd, { wd = __dirname, event = null, ready = null, ignoreExitCode = false }) { + console.log('==============================================================='); + console.log(' Running command in shell:'); + console.log(' > ' + cmd); + console.log('==============================================================='); + + return new Promise((resolve, reject) => { + const childProcess = spawn(cmd, { shell: true, stdio: ['ignore', 'pipe', 'inherit'], cwd: wd }); + childProcess.on('close', function (code, signal) { + if (code === 0 || ignoreExitCode) { + resolve(); + } else { + reject(`Process exits with code ${code}`); + } + }); + childProcess.stdout.on('data', (data) => { + process.stdout.write(data); + + if (ready && event && data.toString().includes(ready)) { + event.emit('serverReady'); + } + }); + if (event) { + event.on('kill', () => { + childProcess.stdout.destroy(); + treeKill(childProcess.pid); + console.log('killing process...'); + }); + } + }); +} + +module.exports = { + runShellCmd, + installOrtPackages, +}; diff --git a/js/web/test/e2e/karma.conf.js b/js/web/test/e2e/karma.conf.js index e6dadfaac248d..adb5bd85a12b7 100644 --- a/js/web/test/e2e/karma.conf.js +++ b/js/web/test/e2e/karma.conf.js @@ -58,6 +58,10 @@ if (ENABLE_SHARED_ARRAY_BUFFER) { flags.push('--enable-features=SharedArrayBuffer'); } +// In Node.js v16 and below, 'localhost' is using IPv4, so need to listen to '0.0.0.0' +// In Node.js v17+, 'localhost' is using IPv6, so need to listen to '::' +const listenAddress = Number.parseInt(process.versions.node.split('.')[0]) >= 17 ? '::' : '0.0.0.0'; + module.exports = function (config) { config.set({ frameworks: ['mocha'], @@ -78,9 +82,11 @@ module.exports = function (config) { browserDisconnectTolerance: 0, browserSocketTimeout: 60000, hostname: 'localhost', + listenAddress, browsers: [], customLaunchers: { Chrome_default: { base: 'Chrome', flags, chromeDataDir: USER_DATA }, + Chrome_headless: { base: 'Chrome', flags: ['--headless', ...flags], chromeDataDir: USER_DATA }, Chrome_no_threads: { base: 'Chrome', chromeDataDir: USER_DATA, diff --git a/js/web/test/e2e/package.json b/js/web/test/e2e/package.json index 36417742eec54..318fd5a6196d5 100644 --- a/js/web/test/e2e/package.json +++ b/js/web/test/e2e/package.json @@ -16,8 +16,10 @@ "mocha": "^10.4.0", "parcel": "^2.12.0", "parcel-reporter-static-files-copy": "^1.5.3", + "puppeteer-core": "23.11.0", "rollup": "^4.13.2", "rollup-plugin-copy": "^3.5.0", + "tree-kill": "^1.2.2", "webpack-cli": "^5.1.4" }, "scripts": { diff --git a/js/web/test/e2e/run-data.js b/js/web/test/e2e/run-data.js index dbc3ca0bd2460..1db04095497c6 100644 --- a/js/web/test/e2e/run-data.js +++ b/js/web/test/e2e/run-data.js @@ -31,10 +31,10 @@ const BROWSER_TEST_CASES = [ [true, true, './browser-test-wasm.js', 'ort.min.mjs', ['num_threads=1', 'proxy=1']], // wasm, 1 thread, proxy // ort.bundle.min.mjs - [true, false, './browser-test-wasm.js', 'ort.bundle.min.mjs', ['num_threads=1']], // 1 thread - [true, false, './browser-test-wasm.js', 'ort.bundle.min.mjs', ['num_threads=2']], // 2 threads - [true, false, './browser-test-wasm.js', 'ort.bundle.min.mjs', ['num_threads=2', 'proxy=1']], // 2 threads, proxy - [true, false, './browser-test-wasm.js', 'ort.bundle.min.mjs', ['num_threads=1', 'proxy=1']], // 1 thread, proxy + [true, true, './browser-test-wasm.js', 'ort.bundle.min.mjs', ['num_threads=1']], // 1 thread + [true, true, './browser-test-wasm.js', 'ort.bundle.min.mjs', ['num_threads=2']], // 2 threads + [true, true, './browser-test-wasm.js', 'ort.bundle.min.mjs', ['num_threads=2', 'proxy=1']], // 2 threads, proxy + [true, true, './browser-test-wasm.js', 'ort.bundle.min.mjs', ['num_threads=1', 'proxy=1']], // 1 thread, proxy // wasm binary override: [true, false, './browser-test-wasm-binary-override.js', 'ort.min.js'], diff --git a/js/web/test/e2e/run.js b/js/web/test/e2e/run.js index 3361bbece64ed..d508625a04a5c 100644 --- a/js/web/test/e2e/run.js +++ b/js/web/test/e2e/run.js @@ -11,6 +11,15 @@ const minimist = require('minimist'); const { NODEJS_TEST_CASES, BROWSER_TEST_CASES, BUNDLER_TEST_CASES } = require('./run-data'); +// commandline arguments +const parsedArgs = minimist(process.argv.slice(2)); +const BROWSER = parsedArgs.browser || 'Chrome_headless'; +// Preserve the existing test folder +// When this flag is set, the test folder will not be cleared before running the tests. +// NPM install will not be run again. +// This is useful for debugging test failures as it makes it much faster to re-run. +const PRESERVE = parsedArgs.preserve || parsedArgs.p; + // copy whole folder to out-side of /js/ because we need to test in a folder that no `package.json` file // exists in its parent folder. // here we use /build/js/e2e/ for the test @@ -20,9 +29,11 @@ const JS_ROOT_FOLDER = path.resolve(__dirname, '../../..'); const TEST_E2E_RUN_FOLDER = path.resolve(JS_ROOT_FOLDER, '../build/js/e2e'); const NPM_CACHE_FOLDER = path.resolve(TEST_E2E_RUN_FOLDER, '../npm_cache'); const CHROME_USER_DATA_FOLDER = path.resolve(TEST_E2E_RUN_FOLDER, '../user_data'); -fs.emptyDirSync(TEST_E2E_RUN_FOLDER); -fs.emptyDirSync(NPM_CACHE_FOLDER); -fs.emptyDirSync(CHROME_USER_DATA_FOLDER); +if (!PRESERVE) { + fs.emptyDirSync(TEST_E2E_RUN_FOLDER); + fs.emptyDirSync(NPM_CACHE_FOLDER); + fs.emptyDirSync(CHROME_USER_DATA_FOLDER); +} fs.copySync(TEST_E2E_SRC_FOLDER, TEST_E2E_RUN_FOLDER); // always use a new folder as user-data-dir @@ -34,9 +45,6 @@ function getNextUserDataDir() { return dir; } -// commandline arguments -const BROWSER = minimist(process.argv.slice(2)).browser || 'Chrome_default'; - async function main() { // find packed package const { globbySync } = await import('globby'); @@ -61,11 +69,19 @@ async function main() { // we start here: - // install dev dependencies - await runInShell(`npm install`); + if (!PRESERVE) { + // install dev dependencies + await runInShell(`npm install`); + + // npm install with "--cache" to install packed packages with an empty cache folder + await runInShell(`npm install --cache "${NPM_CACHE_FOLDER}" ${PACKAGES_TO_INSTALL.map((i) => `"${i}"`).join(' ')}`); + } - // npm install with "--cache" to install packed packages with an empty cache folder - await runInShell(`npm install --cache "${NPM_CACHE_FOLDER}" ${PACKAGES_TO_INSTALL.map((i) => `"${i}"`).join(' ')}`); + // perform exports testing + { + const testExportsMain = require(path.join(TEST_E2E_RUN_FOLDER, './exports/main')); + await testExportsMain(PRESERVE, PACKAGES_TO_INSTALL); + } // prepare .wasm files for path override testing prepareWasmPathOverrideFiles();