From d041c8f747466a9c8ef37826ac2ab439822b55c6 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Sun, 9 Mar 2025 23:00:49 +0800 Subject: [PATCH 01/14] migrate to type: "module" (wip) --- .eslintignore | 3 +- .eslintrc.js => .eslintrc.cjs | 4 +- .vscode/settings.json | 4 + package.json | 2 + packages/shared/package.json | 24 +++ packages/shared/src/build.ts | 91 +++++++++ packages/shared/src/index.ts | 2 + packages/shared/src/rollup.ts | 146 ++++++++++++++ packages/shared/tsconfig.json | 17 ++ packages/test/package.json | 1 + packages/wasi-threads/package.json | 30 ++- packages/wasi-threads/rollup.config.js | 6 + packages/wasi-threads/script/build.js | 195 ------------------- packages/wasi-threads/test/browser-worker.js | 6 + packages/wasi-threads/test/browser.js | 6 + packages/wasi-threads/test/build.js | 8 +- packages/wasi-threads/test/index.html | 11 +- packages/wasi-threads/test/index.js | 117 +---------- packages/wasi-threads/test/proxy.js | 159 ++++++++------- packages/wasi-threads/test/run.js | 105 ++++++++++ packages/wasi-threads/test/worker.js | 111 ++--------- script/release.js | 14 +- script/spawn.js | 16 +- script/which.js | 14 +- 24 files changed, 550 insertions(+), 542 deletions(-) rename .eslintrc.js => .eslintrc.cjs (98%) create mode 100644 packages/shared/package.json create mode 100644 packages/shared/src/build.ts create mode 100644 packages/shared/src/index.ts create mode 100644 packages/shared/src/rollup.ts create mode 100644 packages/shared/tsconfig.json create mode 100644 packages/wasi-threads/rollup.config.js delete mode 100644 packages/wasi-threads/script/build.js create mode 100644 packages/wasi-threads/test/browser-worker.js create mode 100644 packages/wasi-threads/test/browser.js create mode 100644 packages/wasi-threads/test/run.js diff --git a/.eslintignore b/.eslintignore index a639cfb4..509b1144 100644 --- a/.eslintignore +++ b/.eslintignore @@ -3,6 +3,7 @@ node_modules /lib/typings .eslintrc.js +.eslintrc.cjs /example /test/.build /test/CMakeFiles @@ -13,4 +14,4 @@ node_modules /packages/**/test/**/actual /packages/**/test/**/expected /packages/**/test/**/rollup/src -/out +out diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 98% rename from .eslintrc.js rename to .eslintrc.cjs index e79553e6..1513e601 100644 --- a/.eslintrc.js +++ b/.eslintrc.cjs @@ -4,7 +4,7 @@ const sharedRules = { 'no-new-func': 'off', 'no-implied-eval': 'off', 'no-var': 'off', - 'camelcase': 'off' + camelcase: 'off' } module.exports = { @@ -72,7 +72,7 @@ module.exports = { project: './tsconfig.json', tsconfigRootDir: __dirname, createDefaultProgram: true - }, + } } ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index d19295ae..354e88f0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,5 +17,9 @@ "launch": { "statusBarVisibility": "hidden" } + }, + "livePreview.httpHeaders": { + "Cross-Origin-Embedder-Policy": "require-corp", + "Cross-Origin-Opener-Policy": "same-origin" } } diff --git a/package.json b/package.json index 353d8fda..268e586e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "private": true, "version": "0.0.0", + "type": "module", "scripts": { "prepare": "npm run build", "build": "npm run build --workspaces --if-present", @@ -53,6 +54,7 @@ "typescript": "~5.7.2" }, "workspaces": [ + "packages/shared", "packages/ts-transform-macro", "packages/ts-transform-emscripten-esm-library", "packages/ts-transform-emscripten-parse-tools", diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 00000000..a668518a --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,24 @@ +{ + "name": "@emnapi/shared", + "version": "1.3.1", + "private": true, + "description": "", + "type": "module", + "scripts": { + "build": "tsc -p ./tsconfig.json" + }, + "main": "./out/index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/toyobayashi/emnapi.git" + }, + "author": "toyobayashi", + "license": "MIT", + "bugs": { + "url": "https://github.com/toyobayashi/emnapi/issues" + }, + "homepage": "https://github.com/toyobayashi/emnapi/tree/main/packages/shared", + "publishConfig": { + "access": "public" + } +} diff --git a/packages/shared/src/build.ts b/packages/shared/src/build.ts new file mode 100644 index 00000000..a2fbec52 --- /dev/null +++ b/packages/shared/src/build.ts @@ -0,0 +1,91 @@ +#!/usr/bin/env node + +import path from 'path' +import fs from 'fs' +import ts from 'typescript' +import type { RollupOptions, RollupBuild, OutputOptions } from 'rollup' +import { loadConfigFile } from 'rollup/loadConfigFile' +import { pathToFileURL } from 'url' + +export async function build (workspace: string): Promise { + const { compile } = await import('@tybys/tsapi') + const { rollup } = await import('rollup') + + compile(path.resolve(workspace, 'tsconfig.json'), { + optionsToExtend: { + target: ts.ScriptTarget.ES2021, + outDir: path.resolve(workspace, 'lib'), + emitDeclarationOnly: true, + declaration: true, + declarationMap: true, + declarationDir: path.resolve(workspace, 'lib/typings') + } + }) + + const { + Extractor, + ExtractorConfig + } = await import('@microsoft/api-extractor') + const apiExtractorJsonPath = path.resolve(workspace, 'api-extractor.json') + const extractorConfig = ExtractorConfig.loadFileAndPrepare(apiExtractorJsonPath) + const extractorResult = Extractor.invoke(extractorConfig, { + localBuild: true, + showVerboseMessages: true + }) + if (extractorResult.succeeded) { + console.log('API Extractor completed successfully') + } else { + const errmsg = `API Extractor completed with ${extractorResult.errorCount} errors and ${extractorResult.warningCount} warnings` + throw new Error(errmsg) + } + + const dts = extractorConfig.publicTrimmedFilePath + + const { options } = await loadConfigFile(path.resolve(workspace, 'rollup.config.js'), {}) + + const runRollup = async (conf: RollupOptions): Promise => { + const bundle = await rollup(conf) + + const writeBundle = async (bundle: RollupBuild, output: OutputOptions): Promise => { + const writeOutput = await bundle.write(output ?? {}) + + for (const file of writeOutput.output) { + if (file.type === 'asset') { + console.log(`[Asset] ${output.file ?? file.fileName}`) + } else if (file.type === 'chunk') { + console.log(`[Chunk] ${output.file ?? file.fileName}`) + } + } + + if (output?.file) { + if (output.file.endsWith('.umd.cjs')) { + const umdDts = output.file.replace(/\.cjs$/, '.d.cts') + fs.copyFileSync(dts, umdDts) + if (output.name) { + fs.appendFileSync(umdDts, `\nexport as namespace ${output.name};\n`, 'utf8') + } + } else if (output.file.endsWith('.umd.min.cjs')) { + // ignore + } else if (output.file.endsWith('.cjs')) { + const cjsDts = output.file.replace(/\.cjs$/, '.d.cts') + fs.copyFileSync(dts, cjsDts) + } + } + } + + if (Array.isArray(conf.output)) { + await Promise.all(conf.output.map(o => writeBundle(bundle, o ?? {}))) + } else { + await writeBundle(bundle, conf.output ?? {}) + } + } + + await Promise.all(options.map(runRollup)) +} + +if (import.meta.url === pathToFileURL(process.argv[1]).href) { + build(process.argv[2] ?? process.cwd()).catch(err => { + console.error(err) + process.exit(1) + }) +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts new file mode 100644 index 00000000..22d85a12 --- /dev/null +++ b/packages/shared/src/index.ts @@ -0,0 +1,2 @@ +export * from './rollup.ts' +export * from './build.ts' diff --git a/packages/shared/src/rollup.ts b/packages/shared/src/rollup.ts new file mode 100644 index 00000000..96d824ff --- /dev/null +++ b/packages/shared/src/rollup.ts @@ -0,0 +1,146 @@ +import type { InputPluginOption, InputOptions, RollupOptions, NullValue, ExternalOption } from 'rollup' +import ts from 'typescript' + +import { createRequire } from 'module' +const require = createRequire(import.meta.url) + +const rollupTypescript = require('@rollup/plugin-typescript').default as typeof import('@rollup/plugin-typescript').default +const rollupNodeResolve = require('@rollup/plugin-node-resolve').default as typeof import('@rollup/plugin-node-resolve').default +const rollupReplace = require('@rollup/plugin-replace').default as typeof import('@rollup/plugin-replace').default +const transformPureClass = require('@tybys/ts-transform-pure-class').default as typeof import('@tybys/ts-transform-pure-class').default +const rollupTerser = require('@rollup/plugin-terser').default + +export type Format = 'esm' | 'cjs' | 'umd' | 'esm-browser' + +export interface Options extends Omit { + outputName: string + outputFile: string + compilerOptions?: ts.CompilerOptions + defines?: Record + external?: ExternalOption | ((source: string, importer: string | undefined, isResolved: boolean, format: Format) => boolean | NullValue) +} + +interface CreateConfigOptions extends Options { + format: Format + minify?: boolean +} + +function createConfig (options: CreateConfigOptions): RollupOptions { + const { + input, + outputName, + outputFile, + compilerOptions, + plugins, + minify, + format, + defines, + external, + ...restInput + } = options ?? {} + const target = compilerOptions?.target ?? ts.ScriptTarget.ES2021 + + const defaultPlugins: InputPluginOption[] = [ + rollupTypescript({ + compilerOptions: { + ...(target !== ts.ScriptTarget.ES5 ? { removeComments: true, downlevelIteration: false } : {}), + ...options?.compilerOptions + }, + transformers: { + after: [ + transformPureClass + ] + } + }), + rollupNodeResolve({ + mainFields: ['module', 'module-sync', 'import', 'main'] + }), + rollupReplace({ + preventAssignment: true, + values: { + __FORMAT__: JSON.stringify(format), + __DEV__: format === 'umd' || format === 'esm-browser' ? (minify ? 'false' : 'true') : '(process.env.NODE_ENV !== "production")', + 'process.env.NODE_ENV': JSON.stringify(minify ? 'production' : 'development'), + ...defines + } + }), + ...(minify + ? [ + rollupTerser.default({ + compress: true, + mangle: true, + format: { + comments: false + } + }) + ] + : []) + ] + + const outputDir = 'dist' + const outputs = { + esm: { + file: `${outputDir}/${outputFile}${minify ? '.min' : ''}.js`, + format: 'esm', + exports: 'named' + } satisfies RollupOptions['output'], + 'esm-browser': { + file: `${outputDir}/${outputFile}.browser${minify ? '.min' : ''}.js`, + format: 'esm', + exports: 'named' + } satisfies RollupOptions['output'], + cjs: { + file: `${outputDir}/${outputFile}${minify ? '.min' : ''}.cjs`, + format: 'cjs', + exports: 'named' + } satisfies RollupOptions['output'], + umd: { + file: `${outputDir}/${outputFile}.umd${minify ? '.min' : ''}.cjs`, + format: 'umd', + name: outputName, + exports: 'named' + } satisfies RollupOptions['output'] + } + + const defaultExternals: Record = { + esm: ['tslib'], + 'esm-browser': [], + cjs: ['tslib'], + umd: [] + } + + return { + input: input ?? 'src/index.ts', + external: typeof external === 'function' + ? function (this: any, id: string, parent, isResolved) { + const result = external.call(this, id, parent, isResolved, format) + if (result) return result + return defaultExternals[format]?.includes(id) + } + : Array.isArray(external) + ? [...new Set([...(defaultExternals[format] ?? []), ...external])] + : defaultExternals[format], + plugins: plugins instanceof Promise + ? plugins.then(p => { + return [...defaultPlugins, ...(Array.isArray(p) ? p : [p])] + }) + : [...defaultPlugins, ...(Array.isArray(plugins) ? plugins : [plugins])], + ...restInput, + output: outputs[format] + } +} + +export function defineConfig (options: Options): RollupOptions[] { + return ([ + ['esm', false], + ['cjs', false], + ['umd', false], + ['umd', true], + ['esm-browser', false], + ['esm-browser', true] + ] as const).map(([format, minify]) => createConfig({ + ...options, + format, + minify + })) +} diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json new file mode 100644 index 00000000..5834c0cc --- /dev/null +++ b/packages/shared/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "target": "ES2021", + "module": "NodeNext", + "moduleResolution": "nodenext", + "strict": true, + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "outDir": "out", + "rewriteRelativeImportExtensions": true + }, + "include": [ + "src/**/*.ts" + ] +} diff --git a/packages/test/package.json b/packages/test/package.json index faab0b2c..638414ff 100644 --- a/packages/test/package.json +++ b/packages/test/package.json @@ -14,6 +14,7 @@ "node-addon-api": "8.1.0", "why-is-node-running": "^2.3.0" }, + "type": "commonjs", "scripts": { "rebuild": "cross-env UV_THREADPOOL_SIZE=2 node ./script/build-emscripten.js Debug", "rebuild:r": "cross-env UV_THREADPOOL_SIZE=2 node ./script/build-emscripten.js Release", diff --git a/packages/wasi-threads/package.json b/packages/wasi-threads/package.json index 0a11daa4..465411c7 100644 --- a/packages/wasi-threads/package.json +++ b/packages/wasi-threads/package.json @@ -2,35 +2,33 @@ "name": "@emnapi/wasi-threads", "version": "1.0.1", "description": "WASI threads proposal implementation in JavaScript", - "main": "index.js", - "module": "./dist/wasi-threads.esm-bundler.js", + "type": "module", + "main": "./dist/wasi-threads.cjs", + "module": "./dist/wasi-threads.js", "types": "./dist/wasi-threads.d.ts", "sideEffects": false, "exports": { ".": { "types": { "module": "./dist/wasi-threads.d.ts", - "import": "./dist/wasi-threads.d.mts", - "default": "./dist/wasi-threads.d.ts" + "module-sync": "./dist/wasi-threads.d.ts", + "import": "./dist/wasi-threads.d.ts", + "require": "./dist/wasi-threads.d.cts", + "default": "./dist/wasi-threads.d.cts" }, - "module": "./dist/wasi-threads.esm-bundler.js", - "import": "./dist/wasi-threads.mjs", - "default": "./index.js" + "module": "./dist/wasi-threads.js", + "module-sync": "./dist/wasi-threads.js", + "import": "./dist/wasi-threads.js", + "require": "./dist/wasi-threads.cjs", + "default": "./dist/wasi-threads.cjs" }, - "./dist/wasi-threads.cjs.min": { - "types": "./dist/wasi-threads.d.ts", - "default": "./dist/wasi-threads.cjs.min.js" - }, - "./dist/wasi-threads.min.mjs": { - "types": "./dist/wasi-threads.d.mts", - "default": "./dist/wasi-threads.min.mjs" - } + "./package.json": "./package.json" }, "dependencies": { "tslib": "^2.4.0" }, "scripts": { - "build": "node ./script/build.js", + "build": "node ../shared/out/build.js .", "build:test": "node ./test/build.js", "test": "node ./test/index.js" }, diff --git a/packages/wasi-threads/rollup.config.js b/packages/wasi-threads/rollup.config.js new file mode 100644 index 00000000..a9fed3ce --- /dev/null +++ b/packages/wasi-threads/rollup.config.js @@ -0,0 +1,6 @@ +import { defineConfig } from '@emnapi/shared' + +export default defineConfig({ + outputName: 'wasiThreads', + outputFile: 'wasi-threads' +}) diff --git a/packages/wasi-threads/script/build.js b/packages/wasi-threads/script/build.js deleted file mode 100644 index 5556f7d2..00000000 --- a/packages/wasi-threads/script/build.js +++ /dev/null @@ -1,195 +0,0 @@ -const path = require('path') -const fs = require('fs-extra') -const rollup = require('rollup') -const ts = require('typescript') -const rollupTypescript = require('@rollup/plugin-typescript').default -const rollupNodeResolve = require('@rollup/plugin-node-resolve').default -const rollupReplace = require('@rollup/plugin-replace').default -const rollupTerser = require('@rollup/plugin-terser').default -const rollupAlias = require('@rollup/plugin-alias').default -const { compile } = require('@tybys/tsapi') -const dist = path.join(__dirname, '../dist') - -function build () { - compile(path.join(__dirname, '../tsconfig.json'), { - optionsToExtend: { - target: require('typescript').ScriptTarget.ES2021, - outDir: path.join(__dirname, '../lib'), - emitDeclarationOnly: true, - declaration: true, - declarationMap: true, - declarationDir: path.join(__dirname, '../lib/typings') - } - }) - - /** - * @param {ts.ScriptTarget} esversion - * @param {boolean=} minify - * @returns {rollup.RollupOptions} - */ - function createInput (esversion, minify, external) { - return { - input: path.join(__dirname, '../src/index.ts'), - external, - plugins: [ - rollupTypescript({ - tsconfig: path.join(__dirname, '../tsconfig.json'), - tslib: path.join( - path.dirname(require.resolve('tslib')), - JSON.parse(fs.readFileSync(path.join(path.dirname(require.resolve('tslib')), 'package.json'))).module - ), - compilerOptions: { - target: esversion, - ...(esversion !== ts.ScriptTarget.ES5 ? { removeComments: true, downlevelIteration: false } : {}) - }, - include: [ - './src/**/*' - ], - transformers: { - after: [ - require('@tybys/ts-transform-pure-class').default - ] - } - }), - rollupAlias({ - entries: [ - { find: '@', replacement: path.join(__dirname, '../src') } - ] - }), - rollupNodeResolve({ - mainFields: ['module', 'main'] - }), - rollupReplace({ - preventAssignment: true, - values: { - __VERSION__: JSON.stringify(require('../package.json').version) - } - }), - ...(minify - ? [ - rollupTerser({ - compress: true, - mangle: true, - format: { - comments: false - } - }) - ] - : []) - ] - } - } - - const globalName = 'wasiThreads' - - return Promise.all(([ - { - input: createInput(ts.ScriptTarget.ES2021, false), - output: { - file: path.join(dist, 'wasi-threads.js'), - format: 'umd', - name: globalName, - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, true), - output: { - file: path.join(dist, 'wasi-threads.min.js'), - format: 'umd', - name: globalName, - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, false, ['tslib']), - output: { - file: path.join(dist, 'wasi-threads.cjs.js'), - format: 'cjs', - name: globalName, - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, true, ['tslib']), - output: { - file: path.join(dist, 'wasi-threads.cjs.min.js'), - format: 'cjs', - name: globalName, - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, false, ['tslib']), - output: { - file: path.join(dist, 'wasi-threads.mjs'), - format: 'esm', - name: globalName, - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, true, ['tslib']), - output: { - file: path.join(dist, 'wasi-threads.min.mjs'), - format: 'esm', - name: globalName, - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, false, ['tslib']), - output: { - file: path.join(dist, 'wasi-threads.esm-bundler.js'), - format: 'esm', - name: globalName, - exports: 'named', - strict: false - } - } - ]).map(conf => { - return rollup.rollup(conf.input).then(bundle => bundle.write(conf.output)) - })).then(() => { - const { - Extractor, - ExtractorConfig - } = require('@microsoft/api-extractor') - const apiExtractorJsonPath = path.join(__dirname, '../api-extractor.json') - const extractorConfig = ExtractorConfig.loadFileAndPrepare(apiExtractorJsonPath) - const extractorResult = Extractor.invoke(extractorConfig, { - localBuild: true, - showVerboseMessages: true - }) - if (extractorResult.succeeded) { - console.log('API Extractor completed successfully') - } else { - const errmsg = `API Extractor completed with ${extractorResult.errorCount} errors and ${extractorResult.warningCount} warnings` - return Promise.reject(new Error(errmsg)) - } - - const dts = extractorConfig.publicTrimmedFilePath - - const mDts = path.join(__dirname, '../dist/wasi-threads.d.mts') - const cjsMinDts = path.join(__dirname, '../dist/wasi-threads.cjs.min.d.ts') - const mjsMinDts = path.join(__dirname, '../dist/wasi-threads.min.d.mts') - fs.copyFileSync(dts, mDts) - fs.copyFileSync(dts, cjsMinDts) - fs.copyFileSync(dts, mjsMinDts) - fs.appendFileSync(dts, `\nexport as namespace ${globalName};\n`, 'utf8') - }) -} - -exports.build = build - -if (module === require.main) { - build().catch(err => { - console.error(err) - process.exit(1) - }) -} diff --git a/packages/wasi-threads/test/browser-worker.js b/packages/wasi-threads/test/browser-worker.js new file mode 100644 index 00000000..28eb354e --- /dev/null +++ b/packages/wasi-threads/test/browser-worker.js @@ -0,0 +1,6 @@ +import { WASI } from '../../../node_modules/@tybys/wasm-util/dist/wasm-util.esm.js' +import { ThreadMessageHandler, WASIThreads } from '../dist/wasi-threads.js' +import { child } from './run.js' + +console.log(`name: ${globalThis.name}`) +child(WASI, ThreadMessageHandler, WASIThreads) diff --git a/packages/wasi-threads/test/browser.js b/packages/wasi-threads/test/browser.js new file mode 100644 index 00000000..8306ce41 --- /dev/null +++ b/packages/wasi-threads/test/browser.js @@ -0,0 +1,6 @@ +import { WASI } from '../../../node_modules/@tybys/wasm-util/dist/wasm-util.esm.js' +import { Worker } from './proxy.js' +import { WASIThreads } from '../dist/wasi-threads.js' +import { main } from './run.js' + +main(WASI, WASIThreads, Worker, { env: {} }, './browser-worker.js') diff --git a/packages/wasi-threads/test/build.js b/packages/wasi-threads/test/build.js index 9623e2b1..b8131825 100644 --- a/packages/wasi-threads/test/build.js +++ b/packages/wasi-threads/test/build.js @@ -1,5 +1,5 @@ -const { join, resolve } = require('node:path') -const { spawnSync } = require('node:child_process') +import { join, resolve } from 'node:path' +import { spawnSync } from 'node:child_process' const ExecutionModel = { Command: 'command', @@ -9,7 +9,7 @@ const ExecutionModel = { function build (model) { const bin = resolve(process.env.WASI_SDK_PATH, 'bin', 'clang') + (process.platform === 'win32' ? '.exe' : '') const args = [ - '-o', join(__dirname, model === ExecutionModel.Command ? 'main.wasm' : 'lib.wasm'), + '-o', join(import.meta.dirname, model === ExecutionModel.Command ? 'main.wasm' : 'lib.wasm'), '-mbulk-memory', '-matomics', `-mexec-model=${model}`, @@ -31,7 +31,7 @@ function build (model) { '-Wl,--export-dynamic', '-Wl,--max-memory=2147483648', '-Wl,--export=malloc,--export=free', - join(__dirname, 'main.c') + join(import.meta.dirname, 'main.c') ] const quote = s => s.includes(' ') ? `"${s}"` : s console.log(`> ${quote(bin)} ${args.map(quote).join(' ')}`) diff --git a/packages/wasi-threads/test/index.html b/packages/wasi-threads/test/index.html index 0a0fda57..946ceacb 100644 --- a/packages/wasi-threads/test/index.html +++ b/packages/wasi-threads/test/index.html @@ -6,12 +6,11 @@ test - - - - diff --git a/packages/wasi-threads/test/index.js b/packages/wasi-threads/test/index.js index 511a04f4..f34b6469 100644 --- a/packages/wasi-threads/test/index.js +++ b/packages/wasi-threads/test/index.js @@ -1,113 +1,6 @@ -(function (main) { - const ENVIRONMENT_IS_NODE = - typeof process === 'object' && process !== null && - typeof process.versions === 'object' && process.versions !== null && - typeof process.versions.node === 'string' +import { WASI } from 'wasi' +import { Worker } from 'worker_threads' +import { WASIThreads } from '@emnapi/wasi-threads' +import { main } from './run.js' - if (ENVIRONMENT_IS_NODE) { - const _require = function (request) { - if (request === '@emnapi/wasi-threads') return require('..') - return require(request) - } - main(_require, process, __dirname) - } else { - if (typeof importScripts === 'function') { - // eslint-disable-next-line no-undef - importScripts('../../../node_modules/@tybys/wasm-util/dist/wasm-util.min.js') - // eslint-disable-next-line no-undef - importScripts('../dist/wasi-threads.js') - // eslint-disable-next-line no-undef - importScripts('./proxy.js') - } - - const nodeWasi = { WASI: globalThis.wasmUtil.WASI } - const nodePath = { - join: function () { - return Array.prototype.join.call(arguments, '/') - } - } - const nodeWorkerThreads = { - Worker: globalThis.proxyWorker.Worker - } - const _require = function (request) { - if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads - if (request === 'node:worker_threads' || request === 'worker_threads') return nodeWorkerThreads - if (request === 'node:wasi' || request === 'wasi') return nodeWasi - if (request === 'node:path' || request === 'path') return nodePath - throw new Error('Can not find module: ' + request) - } - const _process = { - env: {}, - exit: () => {} - } - main(_require, _process, '.') - } -})(async function (require, process, __dirname) { - const { WASI } = require('node:wasi') - const { WASIThreads } = require('@emnapi/wasi-threads') - const { Worker } = require('node:worker_threads') - const { join } = require('node:path') - - async function run (file) { - const wasi = new WASI({ - version: 'preview1', - args: [file, 'node'], - env: process.env - }) - const wasiThreads = new WASIThreads({ - wasi, - onCreateWorker: ({ name }) => { - return new Worker(join(__dirname, 'worker.js'), { - name, - workerData: { - name - }, - env: process.env, - execArgv: ['--experimental-wasi-unstable-preview1'] - }) - }, - // optional - waitThreadStart: 1000 - }) - const memory = new WebAssembly.Memory({ - initial: 16777216 / 65536, - maximum: 2147483648 / 65536, - shared: true - }) - let input - try { - input = require('node:fs').readFileSync(require('node:path').join(__dirname, file)) - } catch (err) { - console.warn(err) - const response = await fetch(file) - input = await response.arrayBuffer() - } - let { module, instance } = await WebAssembly.instantiate(input, { - env: { - memory, - print_string: function (ptr) { - const HEAPU8 = new Uint8Array(memory.buffer) - let len = 0 - while (HEAPU8[ptr + len] !== 0) len++ - const string = new TextDecoder().decode(HEAPU8.slice(ptr, ptr + len)) - console.log(string) - } - }, - ...wasi.getImportObject(), - ...wasiThreads.getImportObject() - }) - - if (typeof instance.exports._start === 'function') { - const { exitCode } = wasiThreads.start(instance, module, memory) - return exitCode - } else { - instance = wasiThreads.initialize(instance, module, memory) - return instance.exports.fn(1) - } - } - - console.log('-------- command --------') - await run('main.wasm') - console.log('-------- reactor --------') - await run('lib.wasm') -}) +main(WASI, WASIThreads, Worker, process, './worker.js') diff --git a/packages/wasi-threads/test/proxy.js b/packages/wasi-threads/test/proxy.js index e4377d03..8ea40025 100644 --- a/packages/wasi-threads/test/proxy.js +++ b/packages/wasi-threads/test/proxy.js @@ -1,93 +1,86 @@ -(function (exports) { - function addProxyListener (worker) { - const map = new Map() - worker.onmessage = (e) => { - const { type, payload } = e.data - if (type === 'new') { - const { id, url, options } = payload - const w = new globalThis.Worker(url, options) - map.set(id, w) - w.onmessage = (e) => { - worker.postMessage({ type: 'onmessage', payload: { id, data: e.data } }) - } - w.onmessageerror = (e) => { - worker.postMessage({ type: 'onmessageerror', payload: { id, data: e.data } }) +export class Worker { + constructor (url, options) { + if (typeof window !== 'undefined') { + return new window.Worker(url, options) + } + this.id = String(Math.random()) + globalThis.addEventListener('message', ({ data }) => { + if (data.payload.id === this.id) { + if (data.type === 'onmessage' || data.type === 'onmessageerror') { + this[data.type]?.({ data: data.payload.data }) } - w.onerror = (e) => { - worker.postMessage({ - type: 'onerror', - payload: { - id, - data: { - message: e.message, - filename: e.filename, - lineno: e.lineno, - colno: e.colno, - error: e.error - } - } - }) + if (data.type === 'error') { + this.onerror?.(data.payload.data) } - } else if (type === 'postMessage') { - const { id, args } = payload - const w = map.get(id) - w.postMessage.apply(w, args) - } else if (type === 'terminate') { - const { id } = payload - map.get(id).terminate() - map.delete(id) } - } + }) + postMessage({ + type: 'new', + payload: { + id: this.id, + url: typeof url === 'string' ? url : url.href, + options + } + }) } - class Worker { - constructor (url, options) { - if (typeof window !== 'undefined') { - throw new Error('Can not use ProxyWorker in browser main thread') + postMessage () { + postMessage({ + type: 'postMessage', + payload: { + id: this.id, + args: Array.prototype.slice.call(arguments) } - this.id = String(Math.random()) - globalThis.addEventListener('message', ({ data }) => { - if (data.payload.id === this.id) { - if (data.type === 'onmessage' || data.type === 'onmessageerror') { - this[data.type]?.({ data: data.payload.data }) - } - if (data.type === 'error') { - this.onerror?.(data.payload.data) - } - } - }) - postMessage({ - type: 'new', - payload: { - id: this.id, - url, - options - } - }) - } - - postMessage () { - postMessage({ - type: 'postMessage', - payload: { - id: this.id, - args: Array.prototype.slice.call(arguments) - } - }) - } + }) + } - terminate () { - postMessage({ - type: 'terminate', - payload: { - id: this.id - } - }) - } + terminate () { + postMessage({ + type: 'terminate', + payload: { + id: this.id + } + }) } +} - exports.proxyWorker = { - Worker, - addProxyListener +export function addProxyListener (worker) { + const map = new Map() + worker.onmessage = (e) => { + const { type, payload } = e.data + if (type === 'new') { + const { id, url, options } = payload + const w = new globalThis.Worker(url, options) + map.set(id, w) + w.onmessage = (e) => { + worker.postMessage({ type: 'onmessage', payload: { id, data: e.data } }) + } + w.onmessageerror = (e) => { + worker.postMessage({ type: 'onmessageerror', payload: { id, data: e.data } }) + } + w.onerror = (e) => { + worker.postMessage({ + type: 'onerror', + payload: { + id, + data: { + message: e.message, + filename: e.filename, + lineno: e.lineno, + colno: e.colno, + error: e.error + } + } + }) + } + } else if (type === 'postMessage') { + const { id, args } = payload + const w = map.get(id) + w.postMessage.apply(w, args) + } else if (type === 'terminate') { + const { id } = payload + map.get(id).terminate() + map.delete(id) + } } -})(globalThis) +} diff --git a/packages/wasi-threads/test/run.js b/packages/wasi-threads/test/run.js new file mode 100644 index 00000000..db5bf959 --- /dev/null +++ b/packages/wasi-threads/test/run.js @@ -0,0 +1,105 @@ +export async function main (WASI, WASIThreads, Worker, process, workerSource) { + async function run (file) { + const wasi = new WASI({ + version: 'preview1', + args: [file, 'node'], + env: process.env + }) + const wasiThreads = new WASIThreads({ + wasi, + onCreateWorker: ({ name }) => { + return new Worker(new URL(workerSource, import.meta.url), { + type: 'module', + name, + workerData: { + name + }, + env: process.env, + execArgv: ['--experimental-wasi-unstable-preview1'] + }) + }, + // optional + waitThreadStart: 1000 + }) + const memory = new WebAssembly.Memory({ + initial: 16777216 / 65536, + maximum: 2147483648 / 65536, + shared: true + }) + let input + try { + const { readFileSync } = await import('fs') + input = readFileSync(new URL(file, import.meta.url)) + } catch (err) { + console.warn(err) + const response = await fetch(file) + input = await response.arrayBuffer() + } + let { module, instance } = await WebAssembly.instantiate(input, { + env: { + memory, + print_string: function (ptr) { + const HEAPU8 = new Uint8Array(memory.buffer) + let len = 0 + while (HEAPU8[ptr + len] !== 0) len++ + const string = new TextDecoder().decode(HEAPU8.slice(ptr, ptr + len)) + console.log(string) + } + }, + ...wasi.getImportObject(), + ...wasiThreads.getImportObject() + }) + + if (typeof instance.exports._start === 'function') { + const { exitCode } = wasiThreads.start(instance, module, memory) + return exitCode + } else { + instance = wasiThreads.initialize(instance, module, memory) + return instance.exports.fn(1) + } + } + + console.log('-------- command --------') + await run('main.wasm') + console.log('-------- reactor --------') + await run('lib.wasm') +} + +export function child (WASI, ThreadMessageHandler, WASIThreads) { + const handler = new ThreadMessageHandler({ + async onLoad ({ wasmModule, wasmMemory }) { + const wasi = new WASI({ + version: 'preview1' + }) + + const wasiThreads = new WASIThreads({ + wasi, + childThread: true + }) + + const originalInstance = await WebAssembly.instantiate(wasmModule, { + env: { + memory: wasmMemory, + print_string: function (ptr) { + const HEAPU8 = new Uint8Array(wasmMemory.buffer) + let len = 0 + while (HEAPU8[ptr + len] !== 0) len++ + const string = new TextDecoder().decode(HEAPU8.slice(ptr, ptr + len)) + console.log(string) + } + }, + ...wasi.getImportObject(), + ...wasiThreads.getImportObject() + }) + + const instance = wasiThreads.initialize(originalInstance, wasmModule, wasmMemory) + + return { module: wasmModule, instance } + } + }) + + globalThis.onmessage = function (e) { + handler.handle(e) + // handle other messages + } +} diff --git a/packages/wasi-threads/test/worker.js b/packages/wasi-threads/test/worker.js index f69e7f42..f6d6c6b1 100644 --- a/packages/wasi-threads/test/worker.js +++ b/packages/wasi-threads/test/worker.js @@ -1,103 +1,16 @@ -/* eslint-disable no-eval */ +import { WASI } from 'wasi' +import { ThreadMessageHandler, WASIThreads } from '@emnapi/wasi-threads' +import { child } from './run.js' +import { workerData, parentPort } from 'worker_threads' -(function (main) { - const ENVIRONMENT_IS_NODE = - typeof process === 'object' && process !== null && - typeof process.versions === 'object' && process.versions !== null && - typeof process.versions.node === 'string' - - if (ENVIRONMENT_IS_NODE) { - const _require = function (request) { - if (request === '@emnapi/wasi-threads') return require('..') - return require(request) - } - - const _init = function () { - const nodeWorkerThreads = require('node:worker_threads') - const parentPort = nodeWorkerThreads.parentPort - - parentPort.on('message', (data) => { - globalThis.onmessage({ data }) - }) - - Object.assign(globalThis, { - self: globalThis, - require, - Worker: nodeWorkerThreads.Worker, - importScripts: function (f) { - (0, eval)(require('node:fs').readFileSync(f, 'utf8') + '//# sourceURL=' + f) - }, - postMessage: function (msg) { - parentPort.postMessage(msg) - } - }) - } - - main(_require, _init) - } else { - // eslint-disable-next-line no-undef - importScripts('../../../node_modules/@tybys/wasm-util/dist/wasm-util.min.js') - // eslint-disable-next-line no-undef - importScripts('../dist/wasi-threads.js') - - const nodeWasi = { WASI: globalThis.wasmUtil.WASI } - const nodeWorkerThreads = { - workerData: { - name: globalThis.name - } - } - const _require = function (request) { - if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads - if (request === 'node:worker_threads' || request === 'worker_threads') return nodeWorkerThreads - if (request === 'node:wasi' || request === 'wasi') return nodeWasi - throw new Error('Can not find module: ' + request) - } - const _init = function () {} - main(_require, _init) - } -})(function main (require, init) { - init() - - const { WASI } = require('node:wasi') - const { workerData } = require('node:worker_threads') - const { ThreadMessageHandler, WASIThreads } = require('@emnapi/wasi-threads') - - console.log(`name: ${workerData.name}`) - - const handler = new ThreadMessageHandler({ - async onLoad ({ wasmModule, wasmMemory }) { - const wasi = new WASI({ - version: 'preview1' - }) - - const wasiThreads = new WASIThreads({ - wasi, - childThread: true - }) - - const originalInstance = await WebAssembly.instantiate(wasmModule, { - env: { - memory: wasmMemory, - print_string: function (ptr) { - const HEAPU8 = new Uint8Array(wasmMemory.buffer) - let len = 0 - while (HEAPU8[ptr + len] !== 0) len++ - const string = new TextDecoder().decode(HEAPU8.slice(ptr, ptr + len)) - console.log(string) - } - }, - ...wasi.getImportObject(), - ...wasiThreads.getImportObject() - }) +parentPort.on('message', (data) => { + globalThis.onmessage({ data }) +}) - const instance = wasiThreads.initialize(originalInstance, wasmModule, wasmMemory) +globalThis.postMessage = function (...args) { + parentPort.postMessage(...args) +} - return { module: wasmModule, instance } - } - }) +console.log(`name: ${workerData.name}`) - globalThis.onmessage = function (e) { - handler.handle(e) - // handle other messages - } -}) +child(WASI, ThreadMessageHandler, WASIThreads) diff --git a/script/release.js b/script/release.js index 2622fa17..dc716c15 100644 --- a/script/release.js +++ b/script/release.js @@ -1,8 +1,10 @@ -const fs = require('fs-extra') -const path = require('path') -const crossZip = require('@tybys/cross-zip') -const { which } = require('./which.js') -const { spawn, spawnSync, ChildProcessError } = require('./spawn.js') +import fs from 'fs-extra' +import path from 'path' +import crossZip from '@tybys/cross-zip' +import { which } from './which.js' +import { spawn, spawnSync, ChildProcessError } from './spawn.js' + +const __dirname = import.meta.dirname async function main () { await Promise.resolve() @@ -41,7 +43,7 @@ async function main () { let runtimeNapiVersion try { - runtimeNapiVersion = require('@emnapi/runtime').NAPI_VERSION_EXPERIMENTAL + runtimeNapiVersion = (await import('@emnapi/runtime')).NAPI_VERSION_EXPERIMENTAL } catch (_) { runtimeNapiVersion = 0x7fffffff } diff --git a/script/spawn.js b/script/spawn.js index 6140f3a9..003e6309 100644 --- a/script/spawn.js +++ b/script/spawn.js @@ -1,4 +1,6 @@ -class ChildProcessError extends Error { +import childProcess from 'child_process' + +export class ChildProcessError extends Error { constructor (message, code) { super(message) this.code = code @@ -13,11 +15,11 @@ class ChildProcessError extends Error { * @param {'inherit' | 'pipe' | 'ignore'=} stdio * @returns {Promise & { cp: import('child_process').ChildProcess }} */ -function spawn (command, args, cwdPath, stdio, env) { +export function spawn (command, args, cwdPath, stdio, env) { const argsString = args.map(a => a.indexOf(' ') !== -1 ? ('"' + a + '"') : a).join(' ') const cwd = cwdPath || process.cwd() console.log(`[spawn] ${cwd}${process.platform === 'win32' ? '>' : '$'} ${command} ${argsString}`) - const cp = require('child_process').spawn(command, args, { + const cp = childProcess.spawn(command, args, { env: env || process.env, cwd, stdio: stdio || 'inherit', @@ -39,11 +41,11 @@ function spawn (command, args, cwdPath, stdio, env) { return p } -function spawnSync (command, args, cwdPath) { +export function spawnSync (command, args, cwdPath) { const argsString = args.map(a => a.indexOf(' ') !== -1 ? ('"' + a + '"') : a).join(' ') const cwd = cwdPath || process.cwd() console.log(`[spawn] ${cwd}${process.platform === 'win32' ? '>' : '$'} ${command} ${argsString}`) - const result = require('child_process').spawnSync(command, args, { + const result = childProcess.spawnSync(command, args, { env: process.env, cwd }) @@ -55,7 +57,3 @@ function spawnSync (command, args, cwdPath) { } return result } - -exports.spawn = spawn -exports.spawnSync = spawnSync -exports.ChildProcessError = ChildProcessError diff --git a/script/which.js b/script/which.js index 333fee91..ae6aeaca 100644 --- a/script/which.js +++ b/script/which.js @@ -1,20 +1,19 @@ #!/usr/bin/env node -'use strict' +import { pathToFileURL } from 'url' +import path from 'path' +import fs from 'fs' /** * @param {string} cmd * @param {NodeJS.ProcessEnv} env * @returns {string} */ -function which (cmd, env = process.env) { +export function which (cmd, env = process.env) { const PATH = process.platform === 'win32' ? env.Path : env.PATH const pathList = PATH ? (process.platform === 'win32' ? PATH.split(';') : PATH.split(':')) : undefined if (pathList === undefined || pathList.length === 0) return '' - const path = require('path') - const fs = require('fs') - const PATHEXT = process.platform === 'win32' ? (env.PATHEXT ? env.PATHEXT : '.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.RB;.RBW') : '' const extlist = process.platform === 'win32' ? PATHEXT.split(';').map(v => v.toLowerCase()) : ['', '.sh'] for (let i = 0; i < pathList.length; i++) { @@ -49,10 +48,7 @@ function which (cmd, env = process.env) { return '' } -exports.which = which -Object.defineProperty(exports, '__esModule', { value: true }) - -if (require.main === module) { +if (import.meta.url === pathToFileURL(process.argv[1]).href) { const p = which(process.argv[2]) if (p) { console.log(p) From 783c67869bc61ff929d7ff2efb741a8d21cce046 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Sun, 9 Mar 2025 23:32:01 +0800 Subject: [PATCH 02/14] replace `process.env.NODE_ENV` only in umd and esm-browser --- packages/shared/src/rollup.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/shared/src/rollup.ts b/packages/shared/src/rollup.ts index 96d824ff..b459fb9c 100644 --- a/packages/shared/src/rollup.ts +++ b/packages/shared/src/rollup.ts @@ -60,7 +60,7 @@ function createConfig (options: CreateConfigOptions): RollupOptions { values: { __FORMAT__: JSON.stringify(format), __DEV__: format === 'umd' || format === 'esm-browser' ? (minify ? 'false' : 'true') : '(process.env.NODE_ENV !== "production")', - 'process.env.NODE_ENV': JSON.stringify(minify ? 'production' : 'development'), + ...(format === 'umd' || format === 'esm-browser' ? { 'process.env.NODE_ENV': minify ? '"production"' : '"development"' } : {}), ...defines } }), From 3173941f868e98dc45c5eec93521febe092da7ef Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Sun, 9 Mar 2025 23:42:05 +0800 Subject: [PATCH 03/14] default to cjs --- packages/wasi-threads/package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/wasi-threads/package.json b/packages/wasi-threads/package.json index 465411c7..4cfd4196 100644 --- a/packages/wasi-threads/package.json +++ b/packages/wasi-threads/package.json @@ -12,14 +12,12 @@ "types": { "module": "./dist/wasi-threads.d.ts", "module-sync": "./dist/wasi-threads.d.ts", - "import": "./dist/wasi-threads.d.ts", + "import": "./dist/wasi-threads.d.cts", "require": "./dist/wasi-threads.d.cts", "default": "./dist/wasi-threads.d.cts" }, "module": "./dist/wasi-threads.js", "module-sync": "./dist/wasi-threads.js", - "import": "./dist/wasi-threads.js", - "require": "./dist/wasi-threads.cjs", "default": "./dist/wasi-threads.cjs" }, "./package.json": "./package.json" From beb21a0386da34a4eea93e13abbe64998ef12cf1 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Thu, 13 Mar 2025 17:26:04 +0800 Subject: [PATCH 04/14] change rollup options --- packages/shared/src/rollup.ts | 39 +++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/packages/shared/src/rollup.ts b/packages/shared/src/rollup.ts index b459fb9c..ae9de58b 100644 --- a/packages/shared/src/rollup.ts +++ b/packages/shared/src/rollup.ts @@ -10,22 +10,23 @@ const rollupReplace = require('@rollup/plugin-replace').default as typeof import const transformPureClass = require('@tybys/ts-transform-pure-class').default as typeof import('@tybys/ts-transform-pure-class').default const rollupTerser = require('@rollup/plugin-terser').default -export type Format = 'esm' | 'cjs' | 'umd' | 'esm-browser' +export type Format = 'esm' | 'cjs' | 'umd' | 'esm-browser' | 'iife' -export interface Options extends Omit { +export interface MakeConfigOptions extends Omit { outputName: string outputFile: string + format: Format + minify?: boolean compilerOptions?: ts.CompilerOptions defines?: Record external?: ExternalOption | ((source: string, importer: string | undefined, isResolved: boolean, format: Format) => boolean | NullValue) } -interface CreateConfigOptions extends Options { - format: Format - minify?: boolean +export interface Options extends Omit { + browser?: boolean } -function createConfig (options: CreateConfigOptions): RollupOptions { +export function makeConfig (options: MakeConfigOptions): RollupOptions { const { input, outputName, @@ -99,14 +100,21 @@ function createConfig (options: CreateConfigOptions): RollupOptions { format: 'umd', name: outputName, exports: 'named' + } satisfies RollupOptions['output'], + iife: { + file: `${outputDir}/${outputFile}.iife${minify ? '.min' : ''}.cjs`, + format: 'iife', + name: outputName, + exports: 'named' } satisfies RollupOptions['output'] } - const defaultExternals: Record = { + const defaultExternals: Record = { esm: ['tslib'], 'esm-browser': [], cjs: ['tslib'], - umd: [] + umd: [], + iife: [] } return { @@ -131,14 +139,19 @@ function createConfig (options: CreateConfigOptions): RollupOptions { } export function defineConfig (options: Options): RollupOptions[] { + const { browser = true } = options return ([ ['esm', false], ['cjs', false], - ['umd', false], - ['umd', true], - ['esm-browser', false], - ['esm-browser', true] - ] as const).map(([format, minify]) => createConfig({ + ...(browser + ? [ + ['umd', false], + ['umd', true], + ['esm-browser', false], + ['esm-browser', true] + ] as const + : []) + ] as const).map(([format, minify]) => makeConfig({ ...options, format, minify From 0d491b94f0d38faea982b3eb53699d11b9359bad Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Fri, 14 Mar 2025 18:44:56 +0800 Subject: [PATCH 05/14] wip --- packages/core/.npmignore | 1 + packages/core/api-extractor.json | 2 +- packages/core/index.js | 5 - packages/core/package.json | 30 ++-- packages/core/rollup.config.js | 6 + packages/core/script/build.js | 210 ++--------------------- packages/core/tsconfig.json | 2 +- packages/emnapi/src/core/scope.d.ts | 8 +- packages/emnapi/src/typings/emnapi.d.ts | 10 +- packages/runtime/.npmignore | 1 + packages/runtime/api-extractor.json | 2 +- packages/runtime/index.js | 5 - packages/runtime/package.json | 30 ++-- packages/runtime/rollup.config.js | 18 ++ packages/shared/src/rollup.ts | 94 +++++++++- packages/wasi-threads/.npmignore | 1 + packages/wasi-threads/api-extractor.json | 2 +- packages/wasi-threads/index.js | 5 - packages/wasi-threads/package.json | 4 +- packages/wasi-threads/tsconfig.json | 2 +- 20 files changed, 170 insertions(+), 268 deletions(-) delete mode 100644 packages/core/index.js create mode 100644 packages/core/rollup.config.js delete mode 100644 packages/runtime/index.js create mode 100644 packages/runtime/rollup.config.js delete mode 100644 packages/wasi-threads/index.js diff --git a/packages/core/.npmignore b/packages/core/.npmignore index f944142a..f6ce3c8f 100644 --- a/packages/core/.npmignore +++ b/packages/core/.npmignore @@ -7,3 +7,4 @@ node_modules .npmignore api-extractor.json tsconfig.json +/dist/types diff --git a/packages/core/api-extractor.json b/packages/core/api-extractor.json index 9f068bb7..0efd1ea4 100644 --- a/packages/core/api-extractor.json +++ b/packages/core/api-extractor.json @@ -6,7 +6,7 @@ "projectFolder": ".", - "mainEntryPointFilePath": "/lib/typings/index.d.ts", + "mainEntryPointFilePath": "/dist/types/index.d.ts", "bundledPackages": [], diff --git a/packages/core/index.js b/packages/core/index.js deleted file mode 100644 index 11764ede..00000000 --- a/packages/core/index.js +++ /dev/null @@ -1,5 +0,0 @@ -if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') { - module.exports = require('./dist/emnapi-core.cjs.min.js') -} else { - module.exports = require('./dist/emnapi-core.cjs.js') -} diff --git a/packages/core/package.json b/packages/core/package.json index 079640c0..24e6fab4 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -2,36 +2,32 @@ "name": "@emnapi/core", "version": "1.3.1", "description": "emnapi core", - "main": "index.js", - "module": "./dist/emnapi-core.esm-bundler.js", - "types": "./dist/emnapi-core.d.ts", + "type": "module", + "main": "./dist/emnapi-core.cjs", + "module": "./dist/emnapi-core.js", + "types": "./dist/emnapi-core.d.cts", "sideEffects": false, "exports": { ".": { "types": { "module": "./dist/emnapi-core.d.ts", - "import": "./dist/emnapi-core.d.mts", - "default": "./dist/emnapi-core.d.ts" + "module-sync": "./dist/emnapi-core.d.ts", + "import": "./dist/emnapi-core.d.cts", + "require": "./dist/emnapi-core.d.cts", + "default": "./dist/emnapi-core.d.cts" }, - "module": "./dist/emnapi-core.esm-bundler.js", - "import": "./dist/emnapi-core.mjs", - "default": "./index.js" + "module": "./dist/emnapi-core.js", + "module-sync": "./dist/emnapi-core.js", + "default": "./dist/emnapi-core.cjs" }, - "./dist/emnapi-core.cjs.min": { - "types": "./dist/emnapi-core.d.ts", - "default": "./dist/emnapi-core.cjs.min.js" - }, - "./dist/emnapi-core.min.mjs": { - "types": "./dist/emnapi-core.d.mts", - "default": "./dist/emnapi-core.min.mjs" - } + "./package.json": "./package.json" }, "dependencies": { "@emnapi/wasi-threads": "1.0.1", "tslib": "^2.4.0" }, "scripts": { - "build": "node ./script/build.js" + "build": "node ./script/build.js && rollup -c" }, "repository": { "type": "git", diff --git a/packages/core/rollup.config.js b/packages/core/rollup.config.js new file mode 100644 index 00000000..3c748442 --- /dev/null +++ b/packages/core/rollup.config.js @@ -0,0 +1,6 @@ +import { defineConfig } from '@emnapi/shared' + +export default defineConfig({ + outputName: 'emnapiCore', + outputFile: 'emnapi-core' +}) diff --git a/packages/core/script/build.js b/packages/core/script/build.js index 9d3a01b3..248e3468 100644 --- a/packages/core/script/build.js +++ b/packages/core/script/build.js @@ -1,200 +1,10 @@ -const path = require('path') -const fs = require('fs-extra') -const rollup = require('rollup') -const ts = require('typescript') -const rollupTypescript = require('@rollup/plugin-typescript').default -const rollupNodeResolve = require('@rollup/plugin-node-resolve').default -const rollupReplace = require('@rollup/plugin-replace').default -const rollupTerser = require('@rollup/plugin-terser').default -const rollupAlias = require('@rollup/plugin-alias').default -const { compile } = require('@tybys/tsapi') -const { globSync } = require('glob') -const dist = path.join(__dirname, '../dist') - -function build () { - compile(path.join(__dirname, '../tsconfig.json'), { - optionsToExtend: { - target: ts.ScriptTarget.ES2021, - outDir: path.join(__dirname, '../lib'), - emitDeclarationOnly: true, - declaration: true, - declarationDir: path.join(__dirname, '../lib/typings') - } - }) - - globSync('**/*.d.ts', { cwd: path.join(__dirname, '../src/emnapi') }).forEach(file => { - const from = path.join(path.join(__dirname, '../src/emnapi', file)) - const to = path.join(path.join(__dirname, '../lib/typings/emnapi', file)) - fs.mkdirSync(path.dirname(to), { recursive: true }) - fs.copyFileSync(from, to) - }) - - /** - * @param {ts.ScriptTarget} esversion - * @param {boolean=} minify - * @returns {rollup.RollupOptions} - */ - function createInput (esversion, minify, external) { - return { - input: path.join(__dirname, '../src/index.ts'), - external, - plugins: [ - rollupTypescript({ - tsconfig: path.join(__dirname, '../tsconfig.json'), - tslib: path.join( - path.dirname(require.resolve('tslib')), - JSON.parse(fs.readFileSync(path.join(path.dirname(require.resolve('tslib')), 'package.json'))).module - ), - compilerOptions: { - target: esversion, - ...(esversion !== ts.ScriptTarget.ES5 ? { removeComments: true, downlevelIteration: false } : {}) - }, - include: [ - './src/**/*' - ], - transformers: { - after: [ - require('@tybys/ts-transform-pure-class').default - ] - } - }), - rollupAlias({ - entries: [ - { find: '@', replacement: path.join(__dirname, '../src') } - ] - }), - rollupNodeResolve({ - mainFields: ['module', 'main'] - }), - rollupReplace({ - preventAssignment: true, - values: { - __VERSION__: JSON.stringify(require('../package.json').version) - } - }), - ...(minify - ? [ - rollupTerser({ - compress: true, - mangle: true, - format: { - comments: false - } - }) - ] - : []) - ] - } - } - - return Promise.all(([ - { - input: createInput(ts.ScriptTarget.ES2021, false), - output: { - file: path.join(dist, 'emnapi-core.js'), - format: 'umd', - name: 'emnapiCore', - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, true), - output: { - file: path.join(dist, 'emnapi-core.min.js'), - format: 'umd', - name: 'emnapiCore', - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, false, ['tslib', '@emnapi/wasi-threads']), - output: { - file: path.join(dist, 'emnapi-core.cjs.js'), - format: 'cjs', - name: 'emnapiCore', - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, true, ['tslib', '@emnapi/wasi-threads']), - output: { - file: path.join(dist, 'emnapi-core.cjs.min.js'), - format: 'cjs', - name: 'emnapiCore', - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, false, ['tslib', '@emnapi/wasi-threads']), - output: { - file: path.join(dist, 'emnapi-core.mjs'), - format: 'esm', - name: 'emnapiCore', - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, true, ['tslib', '@emnapi/wasi-threads']), - output: { - file: path.join(dist, 'emnapi-core.min.mjs'), - format: 'esm', - name: 'emnapiCore', - exports: 'named', - strict: false - } - }, - { - input: createInput(ts.ScriptTarget.ES2021, false, ['tslib', '@emnapi/wasi-threads']), - output: { - file: path.join(dist, 'emnapi-core.esm-bundler.js'), - format: 'esm', - name: 'emnapiCore', - exports: 'named', - strict: false - } - } - ]).map(conf => { - return rollup.rollup(conf.input).then(bundle => bundle.write(conf.output)) - })).then(() => { - const { - Extractor, - ExtractorConfig - } = require('@microsoft/api-extractor') - const apiExtractorJsonPath = path.join(__dirname, '../api-extractor.json') - const extractorConfig = ExtractorConfig.loadFileAndPrepare(apiExtractorJsonPath) - const extractorResult = Extractor.invoke(extractorConfig, { - localBuild: true, - showVerboseMessages: true - }) - if (extractorResult.succeeded) { - console.log('API Extractor completed successfully') - } else { - const errmsg = `API Extractor completed with ${extractorResult.errorCount} errors and ${extractorResult.warningCount} warnings` - return Promise.reject(new Error(errmsg)) - } - - const dts = extractorConfig.publicTrimmedFilePath - - const mDts = path.join(__dirname, '../dist/emnapi-core.d.mts') - const cjsMinDts = path.join(__dirname, '../dist/emnapi-core.cjs.min.d.ts') - const mjsMinDts = path.join(__dirname, '../dist/emnapi-core.min.d.mts') - fs.copyFileSync(dts, mDts) - fs.copyFileSync(dts, cjsMinDts) - fs.copyFileSync(dts, mjsMinDts) - fs.appendFileSync(dts, '\nexport as namespace emnapiCore;\n', 'utf8') - }) -} - -exports.build = build - -if (module === require.main) { - build().catch(err => { - console.error(err) - process.exit(1) - }) -} +import path from 'path' +import fs from 'fs' +import { globSync } from 'glob' + +globSync('**/*.d.ts', { cwd: path.join(import.meta.dirname, '../src/emnapi') }).forEach(file => { + const from = path.join(path.join(import.meta.dirname, '../src/emnapi', file)) + const to = path.join(path.join(import.meta.dirname, '../dist/types/emnapi', file)) + fs.mkdirSync(path.dirname(to), { recursive: true }) + fs.copyFileSync(from, to) +}) diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index a34a2a46..cf64b210 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -10,7 +10,7 @@ "outDir": "./dist", "paths": { "tslib" : ["../../node_modules/tslib/tslib.d.ts"], - "@emnapi/wasi-threads": ["../wasi-threads/lib/typings/index.d.ts"], + "@emnapi/wasi-threads": ["../wasi-threads/dist/types/index.d.ts"], "@/*": ["./src/*"], } }, diff --git a/packages/emnapi/src/core/scope.d.ts b/packages/emnapi/src/core/scope.d.ts index 5df9bcab..79becf68 100644 --- a/packages/emnapi/src/core/scope.d.ts +++ b/packages/emnapi/src/core/scope.d.ts @@ -15,8 +15,8 @@ declare interface CreateOptions { // factory parameter declare const options: CreateOptions -declare type MainThreadBaseOptions = import('../../../wasi-threads/lib/typings/index').MainThreadBaseOptions -declare type ThreadManagerOptionsMain = import('../../../wasi-threads/lib/typings/index').ThreadManagerOptionsMain -declare const ThreadManager: typeof import('../../../wasi-threads/lib/typings/index').ThreadManager +declare type MainThreadBaseOptions = import('../../../wasi-threads/dist/types/index').MainThreadBaseOptions +declare type ThreadManagerOptionsMain = import('../../../wasi-threads/dist/types/index').ThreadManagerOptionsMain +declare const ThreadManager: typeof import('../../../wasi-threads/dist/types/index').ThreadManager // eslint-disable-next-line @typescript-eslint/no-redeclare -declare type ThreadManager = import('../../../wasi-threads/lib/typings/index').ThreadManager +declare type ThreadManager = import('../../../wasi-threads/dist/types/index').ThreadManager diff --git a/packages/emnapi/src/typings/emnapi.d.ts b/packages/emnapi/src/typings/emnapi.d.ts index 3bbd3ef1..87e12f60 100644 --- a/packages/emnapi/src/typings/emnapi.d.ts +++ b/packages/emnapi/src/typings/emnapi.d.ts @@ -1,7 +1,7 @@ -declare type Env = import('../../../runtime/lib/typings/index').Env -declare type NodeEnv = import('../../../runtime/lib/typings/index').NodeEnv -declare type Handle = import('../../../runtime/lib/typings/index').Handle -declare type Context = import('../../../runtime/lib/typings/index').Context -declare type Reference = import('../../../runtime/lib/typings/index').Reference +declare type Env = import('../../../runtime/dist/types/index').Env +declare type NodeEnv = import('../../../runtime/dist/types/index').NodeEnv +declare type Handle = import('../../../runtime/dist/types/index').Handle +declare type Context = import('../../../runtime/dist/types/index').Context +declare type Reference = import('../../../runtime/dist/types/index').Reference declare type NodeBinding = typeof import('../../../node/index') diff --git a/packages/runtime/.npmignore b/packages/runtime/.npmignore index f944142a..f6ce3c8f 100644 --- a/packages/runtime/.npmignore +++ b/packages/runtime/.npmignore @@ -7,3 +7,4 @@ node_modules .npmignore api-extractor.json tsconfig.json +/dist/types diff --git a/packages/runtime/api-extractor.json b/packages/runtime/api-extractor.json index 66e3ba8b..306ccaca 100644 --- a/packages/runtime/api-extractor.json +++ b/packages/runtime/api-extractor.json @@ -6,7 +6,7 @@ "projectFolder": ".", - "mainEntryPointFilePath": "/lib/typings/index.d.ts", + "mainEntryPointFilePath": "/dist/types/index.d.ts", "bundledPackages": [], diff --git a/packages/runtime/index.js b/packages/runtime/index.js deleted file mode 100644 index efd0f2fe..00000000 --- a/packages/runtime/index.js +++ /dev/null @@ -1,5 +0,0 @@ -if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') { - module.exports = require('./dist/emnapi.cjs.min.js') -} else { - module.exports = require('./dist/emnapi.cjs.js') -} diff --git a/packages/runtime/package.json b/packages/runtime/package.json index a73bd056..5e36566d 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -2,35 +2,31 @@ "name": "@emnapi/runtime", "version": "1.3.1", "description": "emnapi runtime", - "main": "index.js", - "module": "./dist/emnapi.esm-bundler.js", - "types": "./dist/emnapi.d.ts", + "type": "module", + "main": "./dist/emnapi.cjs", + "module": "./dist/emnapi.js", + "types": "./dist/emnapi.d.cts", "sideEffects": false, "exports": { ".": { "types": { "module": "./dist/emnapi.d.ts", - "import": "./dist/emnapi.d.mts", - "default": "./dist/emnapi.d.ts" + "module-sync": "./dist/emnapi.d.ts", + "import": "./dist/emnapi.d.cts", + "require": "./dist/emnapi.d.cts", + "default": "./dist/emnapi.d.cts" }, - "module": "./dist/emnapi.esm-bundler.js", - "import": "./dist/emnapi.mjs", - "default": "./index.js" + "module": "./dist/emnapi.js", + "module-sync": "./dist/emnapi.js", + "default": "./dist/emnapi.cjs" }, - "./dist/emnapi.cjs.min": { - "types": "./dist/emnapi.d.ts", - "default": "./dist/emnapi.cjs.min.js" - }, - "./dist/emnapi.min.mjs": { - "types": "./dist/emnapi.d.mts", - "default": "./dist/emnapi.min.mjs" - } + "./package.json": "./package.json" }, "dependencies": { "tslib": "^2.4.0" }, "scripts": { - "build": "node ./script/build.js" + "build": "rollup -c" }, "repository": { "type": "git", diff --git a/packages/runtime/rollup.config.js b/packages/runtime/rollup.config.js new file mode 100644 index 00000000..a24eab4d --- /dev/null +++ b/packages/runtime/rollup.config.js @@ -0,0 +1,18 @@ +import { defineConfig } from '@emnapi/shared' +import fs from 'fs' +import path from 'path' + +export default defineConfig({ + outputName: 'emnapi', + outputFile: 'emnapi', + apiExtractorCallback: (result) => { + if (result.succeeded) { + let dts = '' + dts += fs.readFileSync(path.join(import.meta.dirname, 'src/typings/common.d.ts'), 'utf8').replace(/declare/g, 'export declare') + dts += fs.readFileSync(path.join(import.meta.dirname, 'src/typings/ctype.d.ts'), 'utf8').replace(/declare/g, 'export declare') + dts += fs.readFileSync(path.join(import.meta.dirname, 'src/typings/napi.d.ts'), 'utf8').replace(/declare/g, 'export declare') + dts += fs.readFileSync(result.extractorConfig.publicTrimmedFilePath, 'utf8') + fs.writeFileSync(result.extractorConfig.publicTrimmedFilePath, dts, 'utf8') + } + } +}) diff --git a/packages/shared/src/rollup.ts b/packages/shared/src/rollup.ts index ae9de58b..1aacbc11 100644 --- a/packages/shared/src/rollup.ts +++ b/packages/shared/src/rollup.ts @@ -1,5 +1,14 @@ -import type { InputPluginOption, InputOptions, RollupOptions, NullValue, ExternalOption } from 'rollup' +import type { InputPluginOption, InputOptions, RollupOptions, NullValue, ExternalOption, Plugin } from 'rollup' import ts from 'typescript' +import path from 'path' +import fs from 'fs' +import { + Extractor, + ExtractorConfig, + type IConfigFile, + type ExtractorResult +} from '@microsoft/api-extractor' +import { PackageJsonLookup } from '@rushstack/node-core-library' import { createRequire } from 'module' const require = createRequire(import.meta.url) @@ -10,6 +19,47 @@ const rollupReplace = require('@rollup/plugin-replace').default as typeof import const transformPureClass = require('@tybys/ts-transform-pure-class').default as typeof import('@tybys/ts-transform-pure-class').default const rollupTerser = require('@rollup/plugin-terser').default +interface RollupApiExtractorOptions { + configObject?: IConfigFile + callback?: (result: ExtractorResult) => any +} + +function rollupApiExtractor (options?: RollupApiExtractorOptions): Plugin { + const { callback, configObject } = options ?? {} + return { + name: 'rollup-plugin-api-extractor', + async writeBundle (outputOptions) { + const configObjectFullPath = path.resolve('api-extractor.json') + const configFromConfigFile = ExtractorConfig.loadFile(configObjectFullPath) + const config = { + ...configFromConfigFile, + ...configObject, + dtsRollup: { + ...configFromConfigFile.dtsRollup, + enabled: true, + untrimmedFilePath: '', + publicTrimmedFilePath: outputOptions.file?.replace(/\.cjs$/, '.d.cts').replace(/\.js$/, '.d.ts'), + ...configObject?.dtsRollup + } + } + const packageJsonLookup = new PackageJsonLookup() + const packageJsonFullPath = packageJsonLookup.tryGetPackageJsonFilePathFor(configObjectFullPath) + const extractorConfig = ExtractorConfig.prepare({ + configObject: config, + configObjectFullPath, + packageJsonFullPath + }) + const extractorResult = Extractor.invoke(extractorConfig, { + localBuild: true, + showVerboseMessages: true + }) + if (typeof callback === 'function') { + await Promise.resolve(callback(extractorResult)) + } + } + } +} + export type Format = 'esm' | 'cjs' | 'umd' | 'esm-browser' | 'iife' export interface MakeConfigOptions extends Omit { @@ -20,6 +70,7 @@ export interface MakeConfigOptions extends Omit { compilerOptions?: ts.CompilerOptions defines?: Record external?: ExternalOption | ((source: string, importer: string | undefined, isResolved: boolean, format: Format) => boolean | NullValue) + apiExtractorCallback?: (result: ExtractorResult, format: Format) => any } export interface Options extends Omit { @@ -33,10 +84,11 @@ export function makeConfig (options: MakeConfigOptions): RollupOptions { outputFile, compilerOptions, plugins, - minify, + minify = false, format, defines, external, + apiExtractorCallback, ...restInput } = options ?? {} const target = compilerOptions?.target ?? ts.ScriptTarget.ES2021 @@ -53,6 +105,31 @@ export function makeConfig (options: MakeConfigOptions): RollupOptions { ] } }), + ...(minify || format === 'esm-browser' || format === 'iife' + ? [] + : [ + rollupApiExtractor({ + configObject: { + mainEntryPointFilePath: 'dist/types/index.d.ts' + }, + callback (result) { + if (result.succeeded) { + if (format === 'umd') { + fs.appendFileSync(result.extractorConfig.publicTrimmedFilePath, '\nexport as namespace ' + outputName) + } + apiExtractorCallback?.(result, format) + } else { + if (typeof apiExtractorCallback === 'function') { + apiExtractorCallback(result, format) + return + } + const errmsg = `API Extractor completed with ${result.errorCount} errors and ${result.warningCount} warnings` + throw new Error(errmsg) + } + } + }) + ] + ), rollupNodeResolve({ mainFields: ['module', 'module-sync', 'import', 'main'] }), @@ -151,8 +228,19 @@ export function defineConfig (options: Options): RollupOptions[] { ['esm-browser', true] ] as const : []) - ] as const).map(([format, minify]) => makeConfig({ + ] as const).map(([format, minify], index) => makeConfig({ ...options, + ...(index === 0 + ? { + compilerOptions: { + declaration: true, + declarationMap: true, + declarationDir: 'dist/types', + emitDeclarationOnly: true, + ...options.compilerOptions + } + } + : {}), format, minify })) diff --git a/packages/wasi-threads/.npmignore b/packages/wasi-threads/.npmignore index d6275066..3e164cbc 100644 --- a/packages/wasi-threads/.npmignore +++ b/packages/wasi-threads/.npmignore @@ -8,3 +8,4 @@ node_modules api-extractor.json tsconfig.json /test +/dist/types diff --git a/packages/wasi-threads/api-extractor.json b/packages/wasi-threads/api-extractor.json index b4269167..3df7f0ab 100644 --- a/packages/wasi-threads/api-extractor.json +++ b/packages/wasi-threads/api-extractor.json @@ -6,7 +6,7 @@ "projectFolder": ".", - "mainEntryPointFilePath": "/lib/typings/index.d.ts", + "mainEntryPointFilePath": "/dist/types/index.d.ts", "bundledPackages": [], diff --git a/packages/wasi-threads/index.js b/packages/wasi-threads/index.js deleted file mode 100644 index 7e6eabd6..00000000 --- a/packages/wasi-threads/index.js +++ /dev/null @@ -1,5 +0,0 @@ -if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') { - module.exports = require('./dist/wasi-threads.cjs.min.js') -} else { - module.exports = require('./dist/wasi-threads.cjs.js') -} diff --git a/packages/wasi-threads/package.json b/packages/wasi-threads/package.json index 4cfd4196..7939d5be 100644 --- a/packages/wasi-threads/package.json +++ b/packages/wasi-threads/package.json @@ -5,7 +5,7 @@ "type": "module", "main": "./dist/wasi-threads.cjs", "module": "./dist/wasi-threads.js", - "types": "./dist/wasi-threads.d.ts", + "types": "./dist/wasi-threads.d.cts", "sideEffects": false, "exports": { ".": { @@ -26,7 +26,7 @@ "tslib": "^2.4.0" }, "scripts": { - "build": "node ../shared/out/build.js .", + "build": "rollup -c", "build:test": "node ./test/build.js", "test": "node ./test/index.js" }, diff --git a/packages/wasi-threads/tsconfig.json b/packages/wasi-threads/tsconfig.json index 5fbf9ca4..0fa6259a 100644 --- a/packages/wasi-threads/tsconfig.json +++ b/packages/wasi-threads/tsconfig.json @@ -9,7 +9,7 @@ "importHelpers": true, "paths": { "tslib" : ["../../node_modules/tslib/tslib.d.ts"], - "@/*": ["./src/*"], + "@/*": ["./src/*"] } }, "include": [ From cba0f2cbae0bb770f0aed4d20b88457f836efbfe Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Fri, 14 Mar 2025 20:56:12 +0800 Subject: [PATCH 06/14] define __VERSION__ --- packages/core/rollup.config.js | 6 +++++- packages/runtime/rollup.config.js | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/core/rollup.config.js b/packages/core/rollup.config.js index 3c748442..a13e06c4 100644 --- a/packages/core/rollup.config.js +++ b/packages/core/rollup.config.js @@ -1,6 +1,10 @@ import { defineConfig } from '@emnapi/shared' +import pkg from './package.json' export default defineConfig({ outputName: 'emnapiCore', - outputFile: 'emnapi-core' + outputFile: 'emnapi-core', + defines: { + __VERSION__: JSON.stringify(pkg.version) + } }) diff --git a/packages/runtime/rollup.config.js b/packages/runtime/rollup.config.js index a24eab4d..ebc9b319 100644 --- a/packages/runtime/rollup.config.js +++ b/packages/runtime/rollup.config.js @@ -1,10 +1,14 @@ import { defineConfig } from '@emnapi/shared' import fs from 'fs' import path from 'path' +import pkg from './package.json' export default defineConfig({ outputName: 'emnapi', outputFile: 'emnapi', + defines: { + __VERSION__: JSON.stringify(pkg.version) + }, apiExtractorCallback: (result) => { if (result.succeeded) { let dts = '' From ac588c3028d3ed0f3bd41a90e43a8c4cd2658598 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Fri, 14 Mar 2025 22:10:22 +0800 Subject: [PATCH 07/14] type json --- packages/core/rollup.config.js | 2 +- packages/runtime/rollup.config.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/rollup.config.js b/packages/core/rollup.config.js index a13e06c4..30306bc3 100644 --- a/packages/core/rollup.config.js +++ b/packages/core/rollup.config.js @@ -1,5 +1,5 @@ import { defineConfig } from '@emnapi/shared' -import pkg from './package.json' +import pkg from './package.json' with { type: "json" } export default defineConfig({ outputName: 'emnapiCore', diff --git a/packages/runtime/rollup.config.js b/packages/runtime/rollup.config.js index ebc9b319..d13232f7 100644 --- a/packages/runtime/rollup.config.js +++ b/packages/runtime/rollup.config.js @@ -1,7 +1,7 @@ import { defineConfig } from '@emnapi/shared' import fs from 'fs' import path from 'path' -import pkg from './package.json' +import pkg from './package.json' with { type: "json" } export default defineConfig({ outputName: 'emnapi', From 49672615844009eb208c62c68d3eccca9419d3e9 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Fri, 14 Mar 2025 23:22:43 +0800 Subject: [PATCH 08/14] share api extractor config --- .vscode/settings.json | 2 +- packages/core/api-extractor.json | 114 +----------------- .../.gitignore | 1 + .../.npmignore | 2 + .../api-extractor.json | 3 + .../package.json | 27 +++-- .../rollup.config.js | 8 ++ .../src/index.mts | 61 ---------- .../src/index.ts | 2 +- .../tsconfig.json | 10 +- packages/runtime/api-extractor.json | 114 +----------------- packages/runtime/rollup.config.js | 1 + packages/shared/api-extractor-base.json | 113 +++++++++++++++++ packages/shared/src/rollup.ts | 29 +++-- packages/wasi-threads/api-extractor.json | 114 +----------------- 15 files changed, 174 insertions(+), 427 deletions(-) create mode 100644 packages/rollup-plugin-emscripten-esm-library/api-extractor.json create mode 100644 packages/rollup-plugin-emscripten-esm-library/rollup.config.js delete mode 100644 packages/rollup-plugin-emscripten-esm-library/src/index.mts create mode 100644 packages/shared/api-extractor-base.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 354e88f0..c211ebf6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,6 @@ { "files.associations": { - "**/api-extractor.json": "jsonc" + "**/api-extractor*.json": "jsonc" }, "typescript.tsdk": "./node_modules/typescript/lib", "cmake.sourceDirectory": "${workspaceFolder}/packages/test", diff --git a/packages/core/api-extractor.json b/packages/core/api-extractor.json index 0efd1ea4..0769ff33 100644 --- a/packages/core/api-extractor.json +++ b/packages/core/api-extractor.json @@ -1,115 +1,3 @@ { - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - // "extends": "./shared/api-extractor-base.json" - // "extends": "my-package/include/api-extractor-base.json" - - "projectFolder": ".", - - "mainEntryPointFilePath": "/dist/types/index.d.ts", - - "bundledPackages": [], - - "compiler": { - "tsconfigFilePath": "/tsconfig.json" - - // "overrideTsconfig": { - // . . . - // } - - // "skipLibCheck": true, - }, - - "apiReport": { - "enabled": false - - // "reportFileName": ".api.md", - - // "reportFolder": "/etc/", - - // "reportTempFolder": "/api/temp/" - }, - - "docModel": { - "enabled": false - - // "apiJsonFilePath": "/temp/.api.json" - }, - - "dtsRollup": { - "enabled": true, - - "untrimmedFilePath": "", - - // "betaTrimmedFilePath": "/dist/-beta.d.ts", - - "publicTrimmedFilePath": "/dist/emnapi-core.d.ts" - - // "omitTrimmingComments": true - }, - - "tsdocMetadata": { - "enabled": false, - - "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" - }, - - // "newlineKind": "crlf", - - "messages": { - /** - * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing - * the input .d.ts files. - * - * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "compilerMessageReporting": { - "default": { - "logLevel": "warning" - - // "addToApiReportFile": false - } - - // "TS2551": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - "extractorMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - }, - "ae-missing-release-tag": { - "logLevel": "none", - "addToApiReportFile": false - } - - // "ae-extra-release-tag": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - "tsdocMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - } - - // "tsdoc-link-tag-unescaped-text": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - } - } + "extends": "../shared/api-extractor-base.json" } diff --git a/packages/rollup-plugin-emscripten-esm-library/.gitignore b/packages/rollup-plugin-emscripten-esm-library/.gitignore index 502167fa..13d357aa 100644 --- a/packages/rollup-plugin-emscripten-esm-library/.gitignore +++ b/packages/rollup-plugin-emscripten-esm-library/.gitignore @@ -1 +1,2 @@ /lib +/dist diff --git a/packages/rollup-plugin-emscripten-esm-library/.npmignore b/packages/rollup-plugin-emscripten-esm-library/.npmignore index a6f4a228..620b3f2e 100644 --- a/packages/rollup-plugin-emscripten-esm-library/.npmignore +++ b/packages/rollup-plugin-emscripten-esm-library/.npmignore @@ -5,3 +5,5 @@ node_modules .npmignore tsconfig.json *.map +/dist/types +api-extractor.json diff --git a/packages/rollup-plugin-emscripten-esm-library/api-extractor.json b/packages/rollup-plugin-emscripten-esm-library/api-extractor.json new file mode 100644 index 00000000..0769ff33 --- /dev/null +++ b/packages/rollup-plugin-emscripten-esm-library/api-extractor.json @@ -0,0 +1,3 @@ +{ + "extends": "../shared/api-extractor-base.json" +} diff --git a/packages/rollup-plugin-emscripten-esm-library/package.json b/packages/rollup-plugin-emscripten-esm-library/package.json index 38e04c09..c288becc 100644 --- a/packages/rollup-plugin-emscripten-esm-library/package.json +++ b/packages/rollup-plugin-emscripten-esm-library/package.json @@ -2,23 +2,26 @@ "name": "@emnapi/rollup-plugin-emscripten-esm-library", "version": "1.0.0", "description": "Using ESM to write Emscripten JavaScript library", - "type": "commonjs", - "main": "./lib/index.js", - "types": "./lib/index.d.ts", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.cts", + "sideEffects": false, "exports": { ".": { - "import": { - "types": "./lib/index.d.mts", - "default": "./lib/index.mjs" + "types": { + "module-sync": "./dist/index.d.ts", + "import": "./dist/index.d.cts", + "require": "./dist/index.d.cts", + "default": "./dist/index.d.cts" }, - "require": { - "types": "./lib/index.d.ts", - "default": "./lib/index.js" - } - } + "module-sync": "./dist/index.js", + "default": "./dist/index.cjs" + }, + "./package.json": "./package.json" }, "scripts": { - "build": "tsc" + "build": "rollup -c" }, "repository": { "type": "git", diff --git a/packages/rollup-plugin-emscripten-esm-library/rollup.config.js b/packages/rollup-plugin-emscripten-esm-library/rollup.config.js new file mode 100644 index 00000000..04cc1f81 --- /dev/null +++ b/packages/rollup-plugin-emscripten-esm-library/rollup.config.js @@ -0,0 +1,8 @@ +import { defineConfig } from '@emnapi/shared' + +export default defineConfig({ + outputFile: 'index', + browser: false, + sourcemap: true, + external: ['@emnapi/ts-transform-emscripten-esm-library'] +}) diff --git a/packages/rollup-plugin-emscripten-esm-library/src/index.mts b/packages/rollup-plugin-emscripten-esm-library/src/index.mts deleted file mode 100644 index d0f96ec1..00000000 --- a/packages/rollup-plugin-emscripten-esm-library/src/index.mts +++ /dev/null @@ -1,61 +0,0 @@ -import type { Plugin, ExternalOption } from 'rollup' -import { transformWithOptions, getDefaultOptions as getDefaultOptionsBase, type TransformOptions } from '@emnapi/ts-transform-emscripten-esm-library' - -export interface PluginOptions extends TransformOptions { - /** @default _ => _ */ - modifyOutput?: (output: string) => string -} - -export function getDefaultOptions (options?: PluginOptions): Required { - return { - ...getDefaultOptionsBase(options), - modifyOutput: options?.modifyOutput ?? ((_) => _) - } -} - -export default function (options?: PluginOptions): Plugin { - const { - modifyOutput, - runtimeModuleSpecifier, - parseToolsModuleSpecifier - } = getDefaultOptions(options) - - const addExternal = (originalExternal: ExternalOption | undefined, sp: string): ExternalOption => { - if (originalExternal == null) { - return [sp] - } else if (typeof originalExternal === 'string' || originalExternal instanceof RegExp) { - return [originalExternal, sp] - } else if (Array.isArray(originalExternal)) { - return [...originalExternal, sp] - } else if (typeof originalExternal === 'function') { - return ((id, ...args) => { - if (id === sp) { - return true - } - return originalExternal(id, ...args) - }) satisfies ExternalOption - } - throw new TypeError('Invalid external option') - } - - return { - name: '@emnapi/rollup-plugin-emscripten-esm-library', - options (options) { - let external = options.external - if (runtimeModuleSpecifier) { - external = addExternal(external, runtimeModuleSpecifier) - } - if (parseToolsModuleSpecifier) { - external = addExternal(external, parseToolsModuleSpecifier) - } - - return { - ...options, - external - } - }, - renderChunk: function (code, chunk) { - return modifyOutput(transformWithOptions(chunk.fileName, code, options)) - } - } -} diff --git a/packages/rollup-plugin-emscripten-esm-library/src/index.ts b/packages/rollup-plugin-emscripten-esm-library/src/index.ts index d0f96ec1..2e0036fc 100644 --- a/packages/rollup-plugin-emscripten-esm-library/src/index.ts +++ b/packages/rollup-plugin-emscripten-esm-library/src/index.ts @@ -13,7 +13,7 @@ export function getDefaultOptions (options?: PluginOptions): Required/dist/types/index.d.ts", - - "bundledPackages": [], - - "compiler": { - "tsconfigFilePath": "/tsconfig.json" - - // "overrideTsconfig": { - // . . . - // } - - // "skipLibCheck": true, - }, - - "apiReport": { - "enabled": false - - // "reportFileName": ".api.md", - - // "reportFolder": "/etc/", - - // "reportTempFolder": "/api/temp/" - }, - - "docModel": { - "enabled": false - - // "apiJsonFilePath": "/temp/.api.json" - }, - - "dtsRollup": { - "enabled": true, - - "untrimmedFilePath": "", - - // "betaTrimmedFilePath": "/dist/-beta.d.ts", - - "publicTrimmedFilePath": "/dist/emnapi.d.ts" - - // "omitTrimmingComments": true - }, - - "tsdocMetadata": { - "enabled": false, - - "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" - }, - - // "newlineKind": "crlf", - - "messages": { - /** - * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing - * the input .d.ts files. - * - * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "compilerMessageReporting": { - "default": { - "logLevel": "warning" - - // "addToApiReportFile": false - } - - // "TS2551": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - "extractorMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - }, - "ae-missing-release-tag": { - "logLevel": "none", - "addToApiReportFile": false - } - - // "ae-extra-release-tag": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - "tsdocMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - } - - // "tsdoc-link-tag-unescaped-text": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - } - } + "extends": "../shared/api-extractor-base.json" } diff --git a/packages/runtime/rollup.config.js b/packages/runtime/rollup.config.js index d13232f7..f8207369 100644 --- a/packages/runtime/rollup.config.js +++ b/packages/runtime/rollup.config.js @@ -6,6 +6,7 @@ import pkg from './package.json' with { type: "json" } export default defineConfig({ outputName: 'emnapi', outputFile: 'emnapi', + sourcemap: true, defines: { __VERSION__: JSON.stringify(pkg.version) }, diff --git a/packages/shared/api-extractor-base.json b/packages/shared/api-extractor-base.json new file mode 100644 index 00000000..f32f7b2f --- /dev/null +++ b/packages/shared/api-extractor-base.json @@ -0,0 +1,113 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + // "extends": "./shared/api-extractor-base.json" + // "extends": "my-package/include/api-extractor-base.json" + + "mainEntryPointFilePath": "/dist/types/index.d.ts", + + "bundledPackages": [], + + "compiler": { + "tsconfigFilePath": "/tsconfig.json" + + // "overrideTsconfig": { + // . . . + // } + + // "skipLibCheck": true, + }, + + "apiReport": { + "enabled": false + + // "reportFileName": ".api.md", + + // "reportFolder": "/etc/", + + // "reportTempFolder": "/api/temp/" + }, + + "docModel": { + "enabled": false + + // "apiJsonFilePath": "/temp/.api.json" + }, + + "dtsRollup": { + "enabled": true, + + "untrimmedFilePath": "" + + // "betaTrimmedFilePath": "/dist/-beta.d.ts", + + // "publicTrimmedFilePath": "" + + // "omitTrimmingComments": true + }, + + "tsdocMetadata": { + "enabled": false, + + "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" + }, + + // "newlineKind": "crlf", + + "messages": { + /** + * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing + * the input .d.ts files. + * + * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" + * + * DEFAULT VALUE: A single "default" entry with logLevel=warning. + */ + "compilerMessageReporting": { + "default": { + "logLevel": "warning" + + // "addToApiReportFile": false + } + + // "TS2551": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + "extractorMessageReporting": { + "default": { + "logLevel": "warning" + // "addToApiReportFile": false + }, + "ae-missing-release-tag": { + "logLevel": "none", + "addToApiReportFile": false + } + + // "ae-extra-release-tag": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + }, + + "tsdocMessageReporting": { + "default": { + "logLevel": "warning" + // "addToApiReportFile": false + } + + // "tsdoc-link-tag-unescaped-text": { + // "logLevel": "warning", + // "addToApiReportFile": true + // }, + // + // . . . + } + } +} diff --git a/packages/shared/src/rollup.ts b/packages/shared/src/rollup.ts index 1aacbc11..847779fe 100644 --- a/packages/shared/src/rollup.ts +++ b/packages/shared/src/rollup.ts @@ -30,6 +30,7 @@ function rollupApiExtractor (options?: RollupApiExtractorOptions): Plugin { name: 'rollup-plugin-api-extractor', async writeBundle (outputOptions) { const configObjectFullPath = path.resolve('api-extractor.json') + if (!fs.existsSync(configObjectFullPath)) return const configFromConfigFile = ExtractorConfig.loadFile(configObjectFullPath) const config = { ...configFromConfigFile, @@ -66,6 +67,7 @@ export interface MakeConfigOptions extends Omit { outputName: string outputFile: string format: Format + sourcemap?: boolean | 'inline' | 'hidden' minify?: boolean compilerOptions?: ts.CompilerOptions defines?: Record @@ -88,6 +90,7 @@ export function makeConfig (options: MakeConfigOptions): RollupOptions { format, defines, external, + sourcemap, apiExtractorCallback, ...restInput } = options ?? {} @@ -160,29 +163,34 @@ export function makeConfig (options: MakeConfigOptions): RollupOptions { esm: { file: `${outputDir}/${outputFile}${minify ? '.min' : ''}.js`, format: 'esm', - exports: 'named' + exports: 'named', + sourcemap } satisfies RollupOptions['output'], 'esm-browser': { file: `${outputDir}/${outputFile}.browser${minify ? '.min' : ''}.js`, format: 'esm', - exports: 'named' + exports: 'named', + sourcemap } satisfies RollupOptions['output'], cjs: { file: `${outputDir}/${outputFile}${minify ? '.min' : ''}.cjs`, format: 'cjs', - exports: 'named' + exports: 'named', + sourcemap } satisfies RollupOptions['output'], umd: { file: `${outputDir}/${outputFile}.umd${minify ? '.min' : ''}.cjs`, format: 'umd', name: outputName, - exports: 'named' + exports: 'named', + sourcemap } satisfies RollupOptions['output'], iife: { file: `${outputDir}/${outputFile}.iife${minify ? '.min' : ''}.cjs`, format: 'iife', name: outputName, - exports: 'named' + exports: 'named', + sourcemap } satisfies RollupOptions['output'] } @@ -194,8 +202,11 @@ export function makeConfig (options: MakeConfigOptions): RollupOptions { iife: [] } + const defaultCjsEntry = './src/index.cts' + const defaultEsmEntry = './src/index.ts' + return { - input: input ?? 'src/index.ts', + input: input ?? ((format === 'cjs' || format === 'umd') ? (fs.existsSync(path.resolve(defaultCjsEntry)) ? defaultCjsEntry : defaultEsmEntry) : defaultEsmEntry), external: typeof external === 'function' ? function (this: any, id: string, parent, isResolved) { const result = external.call(this, id, parent, isResolved, format) @@ -216,7 +227,7 @@ export function makeConfig (options: MakeConfigOptions): RollupOptions { } export function defineConfig (options: Options): RollupOptions[] { - const { browser = true } = options + const { browser = true, ...restOptions } = options return ([ ['esm', false], ['cjs', false], @@ -229,7 +240,7 @@ export function defineConfig (options: Options): RollupOptions[] { ] as const : []) ] as const).map(([format, minify], index) => makeConfig({ - ...options, + ...restOptions, ...(index === 0 ? { compilerOptions: { @@ -237,7 +248,7 @@ export function defineConfig (options: Options): RollupOptions[] { declarationMap: true, declarationDir: 'dist/types', emitDeclarationOnly: true, - ...options.compilerOptions + ...restOptions.compilerOptions } } : {}), diff --git a/packages/wasi-threads/api-extractor.json b/packages/wasi-threads/api-extractor.json index 3df7f0ab..0769ff33 100644 --- a/packages/wasi-threads/api-extractor.json +++ b/packages/wasi-threads/api-extractor.json @@ -1,115 +1,3 @@ { - "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - // "extends": "./shared/api-extractor-base.json" - // "extends": "my-package/include/api-extractor-base.json" - - "projectFolder": ".", - - "mainEntryPointFilePath": "/dist/types/index.d.ts", - - "bundledPackages": [], - - "compiler": { - "tsconfigFilePath": "/tsconfig.json" - - // "overrideTsconfig": { - // . . . - // } - - // "skipLibCheck": true, - }, - - "apiReport": { - "enabled": false - - // "reportFileName": ".api.md", - - // "reportFolder": "/etc/", - - // "reportTempFolder": "/api/temp/" - }, - - "docModel": { - "enabled": false - - // "apiJsonFilePath": "/temp/.api.json" - }, - - "dtsRollup": { - "enabled": true, - - "untrimmedFilePath": "", - - // "betaTrimmedFilePath": "/dist/-beta.d.ts", - - "publicTrimmedFilePath": "/dist/wasi-threads.d.ts" - - // "omitTrimmingComments": true - }, - - "tsdocMetadata": { - "enabled": false, - - "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" - }, - - // "newlineKind": "crlf", - - "messages": { - /** - * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing - * the input .d.ts files. - * - * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "compilerMessageReporting": { - "default": { - "logLevel": "warning" - - // "addToApiReportFile": false - } - - // "TS2551": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - "extractorMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - }, - "ae-missing-release-tag": { - "logLevel": "none", - "addToApiReportFile": false - } - - // "ae-extra-release-tag": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - "tsdocMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - } - - // "tsdoc-link-tag-unescaped-text": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - } - } + "extends": "../shared/api-extractor-base.json" } From a7622e9f3fc95f84013ef8cbbefbf5049878ba03 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Sat, 15 Mar 2025 00:22:15 +0800 Subject: [PATCH 09/14] wip --- packages/emnapi/script/build.js | 2 +- .../.gitignore | 1 + .../package.json | 17 ++++++++++++++--- .../src/index.ts | 2 +- .../tsconfig.json | 4 ++-- 5 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/emnapi/script/build.js b/packages/emnapi/script/build.js index ba24e49c..4ac08800 100644 --- a/packages/emnapi/script/build.js +++ b/packages/emnapi/script/build.js @@ -50,7 +50,7 @@ async function build () { { find: sharedModuleSpecifier, replacement: path.join(__dirname, '../src/emscripten/init.ts') } ] }), - require('@emnapi/rollup-plugin-emscripten-esm-library').default({ + require('@emnapi/rollup-plugin-emscripten-esm-library').plugin({ defaultLibraryFuncsToInclude: ['$emnapiInit'], exportedRuntimeMethods: ['emnapiInit'], runtimeModuleSpecifier, diff --git a/packages/ts-transform-emscripten-parse-tools/.gitignore b/packages/ts-transform-emscripten-parse-tools/.gitignore index 502167fa..13d357aa 100644 --- a/packages/ts-transform-emscripten-parse-tools/.gitignore +++ b/packages/ts-transform-emscripten-parse-tools/.gitignore @@ -1 +1,2 @@ /lib +/dist diff --git a/packages/ts-transform-emscripten-parse-tools/package.json b/packages/ts-transform-emscripten-parse-tools/package.json index 13338c0f..2be607ca 100644 --- a/packages/ts-transform-emscripten-parse-tools/package.json +++ b/packages/ts-transform-emscripten-parse-tools/package.json @@ -3,9 +3,20 @@ "version": "1.3.1", "private": true, "description": "", - "type": "commonjs", - "main": "./lib/index.js", - "types": "./lib/index.d.ts", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": { + "module-sync": "./dist/index.d.ts", + "default": "./dist/index.d.ts" + }, + "module-sync": "./dist/index.js", + "default": "./dist/index.js" + }, + "./package.json": "./package.json" + }, "scripts": { "build": "tsc" }, diff --git a/packages/ts-transform-emscripten-parse-tools/src/index.ts b/packages/ts-transform-emscripten-parse-tools/src/index.ts index e497b007..7703c8be 100644 --- a/packages/ts-transform-emscripten-parse-tools/src/index.ts +++ b/packages/ts-transform-emscripten-parse-tools/src/index.ts @@ -21,7 +21,7 @@ import type { } from 'typescript' import { cloneNode, type CloneNodeOptions } from 'ts-clone-node' -import ts = require('typescript') +import * as ts from 'typescript' import { join, resolve } from 'path' import { getDefaultBaseOptions, type BaseTransformOptions } from '@emnapi/ts-transform-emscripten-esm-library' diff --git a/packages/ts-transform-emscripten-parse-tools/tsconfig.json b/packages/ts-transform-emscripten-parse-tools/tsconfig.json index e9e556f3..fc0bb43a 100644 --- a/packages/ts-transform-emscripten-parse-tools/tsconfig.json +++ b/packages/ts-transform-emscripten-parse-tools/tsconfig.json @@ -1,14 +1,14 @@ { "extends": "../shared/tsconfig.base.json", "compilerOptions": { - "target": "ES2019", + "target": "ES2021", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "declaration": true, "sourceMap": true, "declarationMap": true, - "outDir": "lib" + "outDir": "dist" }, "include": [ "./src/**/*", From 792e8eaea3657bfb6507b437f2f2bf939c8721c3 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Sat, 15 Mar 2025 00:26:17 +0800 Subject: [PATCH 10/14] fix --- packages/ts-transform-emscripten-parse-tools/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ts-transform-emscripten-parse-tools/src/index.ts b/packages/ts-transform-emscripten-parse-tools/src/index.ts index 7703c8be..665bd7a2 100644 --- a/packages/ts-transform-emscripten-parse-tools/src/index.ts +++ b/packages/ts-transform-emscripten-parse-tools/src/index.ts @@ -820,7 +820,7 @@ function createTransformerFactory (program: Program, config: TransformOptions): injectedSrc = factory.updateSourceFile(injectedSrc, newStatements) - const doNotInsertImport = join(__dirname, '../../emnapi/src/core/init.ts') + const doNotInsertImport = join(import.meta.dirname, '../../emnapi/src/core/init.ts') if (process.platform === 'win32') { const resolvedFileName = resolve(src.fileName) From 5607bba4db634fc994030c57192febab4f11d2f9 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Sat, 15 Mar 2025 17:23:47 +0800 Subject: [PATCH 11/14] fix --- .../test/rollup/rollup.config.mjs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/ts-transform-emscripten-esm-library/test/rollup/rollup.config.mjs b/packages/ts-transform-emscripten-esm-library/test/rollup/rollup.config.mjs index ebc88c90..8bf83053 100644 --- a/packages/ts-transform-emscripten-esm-library/test/rollup/rollup.config.mjs +++ b/packages/ts-transform-emscripten-esm-library/test/rollup/rollup.config.mjs @@ -1,20 +1,16 @@ -import { join, dirname } from 'path' +import { join } from 'path' import { defineConfig } from 'rollup' import rollupTs from '@rollup/plugin-typescript' -import { fileURLToPath } from 'url' -import rollupEmscripten from '@emnapi/rollup-plugin-emscripten-esm-library' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = dirname(__filename) +import { plugin as rollupEmscripten } from '@emnapi/rollup-plugin-emscripten-esm-library' export default defineConfig({ - input: join(__dirname, './src/index.ts'), + input: join(import.meta.dirname, './src/index.ts'), output: { - file: join(__dirname, '../actual/bundle.js'), + file: join(import.meta.dirname, '../actual/bundle.js'), format: 'esm' }, plugins: [ - rollupTs({ tsconfig: join(__dirname, 'tsconfig.json') }), + rollupTs({ tsconfig: join(import.meta.dirname, 'tsconfig.json') }), rollupEmscripten() ] }) From fe9a349157994cde80b007ffc4b099083dd422f5 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Sat, 15 Mar 2025 19:03:57 +0800 Subject: [PATCH 12/14] wip --- .../.gitignore | 1 + .../package.json | 19 +++++++++++--- .../src/index.ts | 7 ++--- .../test/index.js | 26 +++++++++++-------- .../tsconfig.json | 4 +-- 5 files changed, 38 insertions(+), 19 deletions(-) diff --git a/packages/ts-transform-emscripten-esm-library/.gitignore b/packages/ts-transform-emscripten-esm-library/.gitignore index dc56df33..10eab12f 100644 --- a/packages/ts-transform-emscripten-esm-library/.gitignore +++ b/packages/ts-transform-emscripten-esm-library/.gitignore @@ -1,2 +1,3 @@ /lib /test/actual +/dist diff --git a/packages/ts-transform-emscripten-esm-library/package.json b/packages/ts-transform-emscripten-esm-library/package.json index ea0646a0..237537b1 100644 --- a/packages/ts-transform-emscripten-esm-library/package.json +++ b/packages/ts-transform-emscripten-esm-library/package.json @@ -2,9 +2,22 @@ "name": "@emnapi/ts-transform-emscripten-esm-library", "version": "1.0.0", "description": "Using ESM to write Emscripten JavaScript library", - "type": "commonjs", - "main": "./lib/index.js", - "types": "./lib/index.d.ts", + "type": "module", + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": { + "module-sync": "./dist/index.d.ts", + "import": "./dist/index.d.ts", + "require": "./dist/index.d.ts", + "default": "./dist/index.d.ts" + }, + "module-sync": "./dist/index.js", + "default": "./dist/index.js" + }, + "./package.json": "./package.json" + }, "scripts": { "build": "tsc", "test": "node --test ./test/index.js" diff --git a/packages/ts-transform-emscripten-esm-library/src/index.ts b/packages/ts-transform-emscripten-esm-library/src/index.ts index dc411eb6..157e0b5c 100644 --- a/packages/ts-transform-emscripten-esm-library/src/index.ts +++ b/packages/ts-transform-emscripten-esm-library/src/index.ts @@ -15,8 +15,9 @@ import type { } from 'typescript' import { EOL } from 'os' +import { normalize } from 'path' -import ts = require('typescript') +import * as ts from 'typescript' export interface BaseTransformOptions { /** @default 'emscripten:runtime' */ @@ -54,7 +55,7 @@ class Transformer { transform (source: SourceFile): SourceFile { source = ts.visitNode(source, this.parseToolsVisitor) as SourceFile - ts.visitNode(source, this.collectExportedFunctionVisitor) as SourceFile + ts.visitNode(source, this.collectExportedFunctionVisitor) const result = ts.visitEachChild(source, this.finalVisitor, this.ctx) let statements = [ @@ -452,7 +453,7 @@ function transform (fileName: string, sourceText: string, options?: BaseTransfor } const source = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.ESNext, true, ts.ScriptKind.JS) const host = ts.createCompilerHost(compilerOptions, true) - host.getSourceFile = filePath => filePath === fileName ? source : undefined + host.getSourceFile = filePath => normalize(filePath) === fileName ? source : undefined const program = ts.createProgram({ rootNames: [fileName], options: compilerOptions, diff --git a/packages/ts-transform-emscripten-esm-library/test/index.js b/packages/ts-transform-emscripten-esm-library/test/index.js index 2480561c..e7321cf6 100644 --- a/packages/ts-transform-emscripten-esm-library/test/index.js +++ b/packages/ts-transform-emscripten-esm-library/test/index.js @@ -1,18 +1,22 @@ -const test = require('node:test') -const { strictEqual } = require('assert') -const { readFileSync, writeFileSync, mkdirSync } = require('fs') -const { join, dirname } = require('path') -const { rollup } = require('rollup') -const { transformWithOptions: transform } = require('..') +import test from 'node:test' +import { strictEqual } from 'assert' +import { readFileSync, writeFileSync, mkdirSync } from 'fs' +import { join, dirname } from 'path' +import { rollup } from 'rollup' +import { transformWithOptions as transform } from '@emnapi/ts-transform-emscripten-esm-library' function testTransform (file) { - const exportedFunction = join(__dirname, `input/${file}.js`) - const exportedFunctionExpected = join(__dirname, `expected/${file}.js`) - const actualFunctionExpected = join(__dirname, `actual/${file}.js`) + const exportedFunction = join(import.meta.dirname, `input/${file}.js`) + const exportedFunctionExpected = join(import.meta.dirname, `expected/${file}.js`) + const actualFunctionExpected = join(import.meta.dirname, `actual/${file}.js`) const transformed = transform(exportedFunction, readFileSync(exportedFunction, 'utf8')) mkdirSync(dirname(actualFunctionExpected), { recursive: true }) writeFileSync(actualFunctionExpected, transformed, 'utf8') - strictEqual(transformed, readFileSync(exportedFunctionExpected, 'utf8')) + let expected = readFileSync(exportedFunctionExpected, 'utf8') + if (process.platform === 'win32') { + expected = expected.replace(/\\n/g, '\\r\\n') + } + strictEqual(transformed, expected) } test('exported function', () => { @@ -55,5 +59,5 @@ test('rollup', async () => { const config = (await import('./rollup/rollup.config.mjs')).default const build = await rollup(config) await build.write(config.output) - strictEqual(readFileSync(config.output.file, 'utf8'), readFileSync(join(__dirname, './expected/bundle.js'), 'utf8')) + strictEqual(readFileSync(config.output.file, 'utf8'), readFileSync(join(import.meta.dirname, './expected/bundle.js'), 'utf8')) }) diff --git a/packages/ts-transform-emscripten-esm-library/tsconfig.json b/packages/ts-transform-emscripten-esm-library/tsconfig.json index e9e556f3..fc0bb43a 100644 --- a/packages/ts-transform-emscripten-esm-library/tsconfig.json +++ b/packages/ts-transform-emscripten-esm-library/tsconfig.json @@ -1,14 +1,14 @@ { "extends": "../shared/tsconfig.base.json", "compilerOptions": { - "target": "ES2019", + "target": "ES2021", "module": "NodeNext", "moduleResolution": "NodeNext", "strict": true, "declaration": true, "sourceMap": true, "declarationMap": true, - "outDir": "lib" + "outDir": "dist" }, "include": [ "./src/**/*", From e6248e2fd2bf56f69dccae3dca8662f8eacc308c Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Mon, 24 Mar 2025 00:36:11 +0800 Subject: [PATCH 13/14] wip --- CONTRIBUTING.md | 16 +++++++++++++--- packages/emnapi/README.md | 8 ++++---- .../api-extractor.json | 3 --- .../package.json | 16 +++++++--------- .../rollup.config.js | 8 -------- .../tsconfig.json | 8 +++----- .../package.json | 2 ++ packages/ts-transform-macro/package.json | 19 ++++++++++++++++--- packages/ts-transform-macro/tsconfig.json | 4 ++-- 9 files changed, 47 insertions(+), 37 deletions(-) delete mode 100644 packages/rollup-plugin-emscripten-esm-library/api-extractor.json delete mode 100644 packages/rollup-plugin-emscripten-esm-library/rollup.config.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 663569c7..21fbdecc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -55,7 +55,7 @@ This doc will explain the structure of this project and some points need to note Macros are powered by `packages/ts-transform-macro` -- `packages/core` (`dependencies`) +- `packages/core` (`dependencies`, follow emnapi version) This package is designed for using emnapi on non-Emscripten platform, it is a trasformed output of `packages/emnapi` by using `packages/ts-transform-emscripten-parse-tools`. @@ -64,15 +64,25 @@ This doc will explain the structure of this project and some points need to note We need to manually provide imported symbols to the second parameter of `WebAssembly.instantiate`, so this is the use case of this package. -- `packages/runtime` (`dependencies`) +- `packages/runtime` (`dependencies`, follow emnapi version) Provide runtime implementation of `napi_value` / `napi_handle_scope` / `napi_ref` etc. -- `packages/node` (`dependencies`) +- `packages/node` (`dependencies`, follow emnapi version) Some APIs make sense on Node.js only, such as `napi_async_init`, `napi_async_destroy` and `napi_make_callback`. This package provide native Node.js bindings for JavaScript implementation as bridge. +- `packages/rollup-plugin-emscripten-esm-library` (`devDependencies`, independent) + +- `packages/ts-transform-emscripten-esm-library` (`devDependencies`, independent) + +- `packages/ts-transform-emscripten-parse-tools` (`devDependencies`, follow emnapi version, private) + +- `packages/ts-transform-emscripten-parse-tools` (`devDependencies`, independent) + +- `packages/wasi-threads` (`dependencies`, independent) + ## Environment Requirements - Node.js `>= 16` diff --git a/packages/emnapi/README.md b/packages/emnapi/README.md index 64a48d2e..53dd62db 100644 --- a/packages/emnapi/README.md +++ b/packages/emnapi/README.md @@ -43,7 +43,7 @@ If you want to deep dive into WebAssembly, highly recommend you to visit [learn- You will need to install: -- Node.js `>= v16.15.0` +- Node.js `>= v22.12.0` for developing this repository on local machine, `>= v16.15.0` for user runtime. - npm `>= v8` - Emscripten `>= v3.1.9` / wasi-sdk / LLVM clang with wasm support - (Optional) CMake `>= v3.13` @@ -303,7 +303,7 @@ declare namespace Module { ``` ```html - + - + +