diff --git a/.changeset/friendly-radios-walk.md b/.changeset/friendly-radios-walk.md new file mode 100644 index 00000000..8532ea87 --- /dev/null +++ b/.changeset/friendly-radios-walk.md @@ -0,0 +1,5 @@ +--- +'@ice/pkg': minor +--- + +feat: add oxc-transoform as experimental declaration compiler diff --git a/packages/pkg/package.json b/packages/pkg/package.json index a8f9c03c..85faef7b 100644 --- a/packages/pkg/package.json +++ b/packages/pkg/package.json @@ -59,6 +59,7 @@ "gzip-size": "^7.0.0", "lodash.merge": "^4.6.2", "magic-string": "^0.25.7", + "oxc-transform": "^0.28.0", "picocolors": "^1.0.0", "postcss": "^8.4.6", "postcss-plugin-rpx2vw": "^1.0.0", @@ -67,7 +68,7 @@ "rollup-plugin-visualizer": "^5.8.3", "semver": "^7.0.0", "tsc-alias": "^1.8.2", - "typescript": "^4.9.4" + "typescript": "^5.5.0" }, "devDependencies": { "@types/babel__core": "^7.1.20", diff --git a/packages/pkg/src/helpers/dts.ts b/packages/pkg/src/helpers/dts.ts index e9d16750..f6428922 100644 --- a/packages/pkg/src/helpers/dts.ts +++ b/packages/pkg/src/helpers/dts.ts @@ -9,6 +9,7 @@ import { prepareSingleFileReplaceTscAliasPaths } from 'tsc-alias'; import fse from 'fs-extra'; import * as path from 'path'; import merge from 'lodash.merge'; +import oxc from 'oxc-transform'; export type FileExt = 'js' | 'ts' | 'tsx' | 'jsx' | 'cjs' | 'mjs' | 'mts' | 'cts'; @@ -45,16 +46,77 @@ interface DtsCompileOptions { alias: TaskConfig['alias']; rootDir: string; outputDir: string; - + usingOxc: boolean; } -export async function dtsCompile({ files, alias, rootDir, outputDir }: DtsCompileOptions): Promise { - if (!files.length) { +export async function dtsCompile(options: DtsCompileOptions): Promise { + if (!options.files.length) { return; } - const tsConfig = await getTSConfig(rootDir, outputDir, alias); + const tsConfig = await getTSConfig(options.rootDir, options.outputDir, options.alias); + const logger = createLogger('dts'); + + if (options.usingOxc) { + if (!tsConfig.options.isolatedDeclarations) { + logger.warn('[experimental.enableOxcIsolatedDeclaration] prefer to enable isolatedDeclaration in tsconfig.json'); + } + if (Object.keys(tsConfig.options.paths ?? {}).length !== 0) { + logger.warn('[experimental.enableOxcIsolatedDeclaration] not works with alias'); + } + return compileFromOxc(options); + } + + return compileFromTsc(options, tsConfig); +} +async function getTSConfig( + rootDir: string, + outputDir: string, + alias: TaskConfig['alias'], +) { + const defaultTSCompilerOptions: ts.CompilerOptions = { + allowJs: true, + declaration: true, + emitDeclarationOnly: true, + incremental: true, + skipLibCheck: true, + paths: formatAliasToTSPathsConfig(alias), // default add alias to paths + }; + const projectTSConfig = await getProjectTSConfig(rootDir); + const tsConfig: ts.ParsedCommandLine = merge( + { options: defaultTSCompilerOptions }, + projectTSConfig, + { + options: { + outDir: outputDir, + rootDir: path.join(rootDir, 'src'), + }, + }, + ); + + return tsConfig; +} + +async function getProjectTSConfig(rootDir: string): Promise { + const tsconfigPath = ts.findConfigFile(rootDir, ts.sys.fileExists); + if (tsconfigPath) { + const tsconfigFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile); + return ts.parseJsonConfigFileContent( + tsconfigFile.config, + ts.sys, + path.dirname(tsconfigPath), + ); + } + + return { + options: {}, + fileNames: [], + errors: [], + }; +} + +async function compileFromTsc({ files, rootDir, outputDir }: DtsCompileOptions, tsConfig: ts.ParsedCommandLine) { const logger = createLogger('dts'); logger.debug('Start Compiling typescript declarations...'); @@ -147,48 +209,29 @@ export async function dtsCompile({ files, alias, rootDir, outputDir }: DtsCompil return result; } -async function getTSConfig( - rootDir: string, - outputDir: string, - alias: TaskConfig['alias'], -) { - const defaultTSCompilerOptions: ts.CompilerOptions = { - allowJs: true, - declaration: true, - emitDeclarationOnly: true, - incremental: true, - skipLibCheck: true, - paths: formatAliasToTSPathsConfig(alias), // default add alias to paths - }; - const projectTSConfig = await getProjectTSConfig(rootDir); - const tsConfig: ts.ParsedCommandLine = merge( - { options: defaultTSCompilerOptions }, - projectTSConfig, - { - options: { - outDir: outputDir, - rootDir: path.join(rootDir, 'src'), - }, - }, - ); +async function compileFromOxc({ files, alias, rootDir, outputDir }: DtsCompileOptions) { + const _files = files + .map((file) => normalizeDtsInput(file, rootDir, outputDir)) + .map(({ filePath, dtsPath, ...rest }) => ({ + ...rest, + // Be compatible with Windows env. + filePath: normalizePath(filePath), + dtsPath: normalizePath(dtsPath), + })); - return tsConfig; -} + const dtsFiles: Record = {}; + for (const file of _files) { + const fileContent = fse.readFileSync(file.filePath, 'utf-8'); + const { code, map } = oxc.isolatedDeclaration(file.filePath, fileContent, { + sourcemap: true, + }); -async function getProjectTSConfig(rootDir: string): Promise { - const tsconfigPath = ts.findConfigFile(rootDir, ts.sys.fileExists); - if (tsconfigPath) { - const tsconfigFile = ts.readConfigFile(tsconfigPath, ts.sys.readFile); - return ts.parseJsonConfigFileContent( - tsconfigFile.config, - ts.sys, - path.dirname(tsconfigPath), - ); + dtsFiles[file.filePath] = code; + // fse.writeFileSync(file.dtsPath, code) } - return { - options: {}, - fileNames: [], - errors: [], - }; + return _files.map((file) => ({ + ...file, + dtsContent: dtsFiles[file.filePath], + })); } diff --git a/packages/pkg/src/helpers/getRollupOptions.ts b/packages/pkg/src/helpers/getRollupOptions.ts index df501f3a..5b2adc69 100644 --- a/packages/pkg/src/helpers/getRollupOptions.ts +++ b/packages/pkg/src/helpers/getRollupOptions.ts @@ -80,6 +80,7 @@ export function getRollupOptions( generateTypesForJs: userConfig.generateTypesForJs, alias: taskConfig.alias, outputDir: taskConfig.outputDir, + usingOxc: !!userConfig.experimental?.enableOxcIsolatedDeclaration, }), ); } diff --git a/packages/pkg/src/rollupPlugins/dts.ts b/packages/pkg/src/rollupPlugins/dts.ts index a5ba5651..11a795de 100644 --- a/packages/pkg/src/rollupPlugins/dts.ts +++ b/packages/pkg/src/rollupPlugins/dts.ts @@ -15,6 +15,7 @@ interface DtsPluginOptions { entry: Record; alias: TaskConfig['alias']; outputDir: string; + usingOxc: boolean; generateTypesForJs?: UserConfig['generateTypesForJs']; } @@ -24,6 +25,7 @@ function dtsPlugin({ alias, generateTypesForJs, outputDir, + usingOxc, }: DtsPluginOptions): Plugin { const includeFileRegexps = [/\.(?:[cm]?ts|tsx)$/]; if (generateTypesForJs) { @@ -67,7 +69,7 @@ function dtsPlugin({ filePath: id, srcCode: cachedContents[id].srcCode, })); - dtsFiles = await dtsCompile({ files, alias, rootDir, outputDir }); + dtsFiles = await dtsCompile({ files, alias, rootDir, outputDir, usingOxc }); } else { dtsFiles = Object.keys(cachedContents).map((id) => { const { updated, ...rest } = cachedContents[id]; diff --git a/packages/pkg/src/types.ts b/packages/pkg/src/types.ts index ebab8915..86ecfbcb 100644 --- a/packages/pkg/src/types.ts +++ b/packages/pkg/src/types.ts @@ -156,6 +156,19 @@ export interface UserConfig { * "bundle mode" means bundle everything up by using Rollup */ bundle?: BundleUserConfig; + + /** + * Experimental features + * Is not ready for procution. If you found any bugs, please report to https://github.com/ice-lab/icepkg/issues + */ + experimental?: ExperimentalUserConfig; +} + +export interface ExperimentalUserConfig { + /** + * Using oxc-transform to genreation [isolated declaration](https://www.typescriptlang.org/tsconfig/#isolatedDeclarations). + */ + enableOxcIsolatedDeclaration?: boolean; } interface _TaskConfig { diff --git a/packages/pkg/tests/projects/default.test.ts b/packages/pkg/tests/projects/default.test.ts index 225afab6..6f61e752 100644 --- a/packages/pkg/tests/projects/default.test.ts +++ b/packages/pkg/tests/projects/default.test.ts @@ -60,5 +60,5 @@ runProjectTest('default', [ config: { sourceMaps: true } - } + }, ]) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 73be233c..c1faeaff 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -423,6 +423,9 @@ importers: magic-string: specifier: ^0.25.7 version: 0.25.9 + oxc-transform: + specifier: ^0.28.0 + version: 0.28.0 picocolors: specifier: ^1.0.0 version: 1.0.0 @@ -448,8 +451,8 @@ importers: specifier: ^1.8.2 version: 1.8.2 typescript: - specifier: ^4.9.4 - version: 4.9.4 + specifier: ^5.5.0 + version: 5.6.2 devDependencies: '@types/babel__core': specifier: ^7.1.20 @@ -6623,6 +6626,70 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.13.0 + /@oxc-transform/binding-darwin-arm64@0.28.0: + resolution: {integrity: sha512-WBqUfFjr/6I5nrImc8Teo5lqM6SPCkxSjl59bJbSMNSeeDiO6TPqXNd8JmmLoFRIi834aPV0tcLNRs3R5k1cgA==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@oxc-transform/binding-darwin-x64@0.28.0: + resolution: {integrity: sha512-9ndgXbENCHmYhS5py40f2OG5v17INO72UI+KvHCztejm1E2D0mKYOt+ZTp4H8uDkU1LmyQWX+60U2dXTTHBgWQ==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@oxc-transform/binding-linux-arm64-gnu@0.28.0: + resolution: {integrity: sha512-5NZKi3DruTEtxUd/uHP1RXdnoB0vWZRZbOqTI96wf6RzWZ62djj1ywPb4fGESyPmsb+5I77p5o4yozVSs5LfAQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@oxc-transform/binding-linux-arm64-musl@0.28.0: + resolution: {integrity: sha512-ZSU18gGHzDhrs34FrF6i8+TUkOBhphHLUc5QAlm+Qu77b3m+Q1Drqri5vc96E+TvrYBybCLvryOG+WwILCavBQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@oxc-transform/binding-linux-x64-gnu@0.28.0: + resolution: {integrity: sha512-ozgoPjEUgU1UOHiZDwNzbNJQceDWBhsHYtzcNKkas7v5EPRegSLdSpQLJ8bj88wmS1XermL9/3vMe0+xfN3/nA==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@oxc-transform/binding-linux-x64-musl@0.28.0: + resolution: {integrity: sha512-HYMRAfsqjTDyN9bu8KhSMIF1mjRVogOgVkovW/Iz5G2JydzIse+ZEKR6lXx0lctIQxbFKW6TatQLWCoABGHQjw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@oxc-transform/binding-win32-arm64-msvc@0.28.0: + resolution: {integrity: sha512-9vTEGSj+ZcNGTkQu/0WdRrK1qqYgiBm47UWXmlmPSPnbiZmFZ+hvkFG/3qwwYaAnhe486w6el3Vc4VoHtzCiKQ==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@oxc-transform/binding-win32-x64-msvc@0.28.0: + resolution: {integrity: sha512-+RRend+n8iCULBVg1HyhPpXL2oD1UUuIgyY6R2IYQ3MDYHZ9pMvzgfZvr/qmYD5HbUUVK8RM8Ad4lVHa6Hp61g==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@polka/url@1.0.0-next.21: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} @@ -15284,6 +15351,19 @@ packages: resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} dev: true + /oxc-transform@0.28.0: + resolution: {integrity: sha512-TxJhypZ9V6pFmApi/hyP0pX5jrxxJBH/GgXU9SJ7bFbfiA6W0GG7l5D+WMXixy8MBrs8WxoWBX5FCABhRfVgig==} + optionalDependencies: + '@oxc-transform/binding-darwin-arm64': 0.28.0 + '@oxc-transform/binding-darwin-x64': 0.28.0 + '@oxc-transform/binding-linux-arm64-gnu': 0.28.0 + '@oxc-transform/binding-linux-arm64-musl': 0.28.0 + '@oxc-transform/binding-linux-x64-gnu': 0.28.0 + '@oxc-transform/binding-linux-x64-musl': 0.28.0 + '@oxc-transform/binding-win32-arm64-msvc': 0.28.0 + '@oxc-transform/binding-win32-x64-msvc': 0.28.0 + dev: false + /p-cancelable@1.1.0: resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==} engines: {node: '>=6'} @@ -18882,6 +18962,13 @@ packages: resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} engines: {node: '>=4.2.0'} hasBin: true + dev: true + + /typescript@5.6.2: + resolution: {integrity: sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==} + engines: {node: '>=14.17'} + hasBin: true + dev: false /typical@4.0.0: resolution: {integrity: sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==} diff --git a/website/docs/reference/config.md b/website/docs/reference/config.md index d612bfb5..7368c4b6 100644 --- a/website/docs/reference/config.md +++ b/website/docs/reference/config.md @@ -508,3 +508,19 @@ export default defineConfig({ - index.esm.es2017.development.js # 输出未压缩产物 (ES module + es2017) - index.esm.es2017.production.js # 输出未压缩产物 (ES module + es2017) ``` + +### experimental + +实验性参数,如果遇到问题,请提交到[此处](https://github.com/ice-lab/icepkg/issues)。 + +#### enableOxcIsolatedDeclaration + ++ 类型:`boolean` ++ 可用版本:`1.6.0` + +使用 `oxc-transform` 替代 `tsc` 去生成 [isolated declaration](https://www.typescriptlang.org/tsconfig/#isolatedDeclarations),可以获得数十倍的构建性能提升。 + +开启此选项需要注意以下内容: + +- `isolated declaration` 是 TypeScript 5.5 引入的新功能,需要开启此功能,请保证你的代码对此兼容 +- `oxc-transform` 目前不支持 alias 能力