From ac854dd2e3aaf30ccf973fa9bd26d78c3161d59e Mon Sep 17 00:00:00 2001 From: luhc228 Date: Mon, 16 Oct 2023 14:24:31 +0800 Subject: [PATCH] fix: compile all deps when specify deps in compileDependencies (#602) * fix: compile all deps when specify deps in compileDependencies * chore: changeset * refactor: compileDependencies * chore: remove comment * feat: optimize * fix: test * feat: add test * fix: not compile polyfills and helpers * fix: type * fix: comment * fix: include node_modules scripts --- .changeset/giant-wolves-press.md | 5 ++ packages/pkg/src/rollupPlugins/babel.ts | 6 +- packages/pkg/src/rollupPlugins/swc.ts | 8 ++- packages/pkg/src/types.ts | 2 +- packages/pkg/src/utils.ts | 64 ++++++++++++++++--- packages/pkg/tests/babelPlugin.test.ts | 4 +- .../pkg/tests/formatCnpmDepFilepath.test.ts | 23 +++++++ website/docs/reference/config.md | 4 +- 8 files changed, 95 insertions(+), 21 deletions(-) create mode 100644 .changeset/giant-wolves-press.md create mode 100644 packages/pkg/tests/formatCnpmDepFilepath.test.ts diff --git a/.changeset/giant-wolves-press.md b/.changeset/giant-wolves-press.md new file mode 100644 index 00000000..f7f032f1 --- /dev/null +++ b/.changeset/giant-wolves-press.md @@ -0,0 +1,5 @@ +--- +'@ice/pkg': patch +--- + +fix: compile all deps when specify deps in compileDependencies diff --git a/packages/pkg/src/rollupPlugins/babel.ts b/packages/pkg/src/rollupPlugins/babel.ts index 19bde436..084610ec 100644 --- a/packages/pkg/src/rollupPlugins/babel.ts +++ b/packages/pkg/src/rollupPlugins/babel.ts @@ -4,7 +4,7 @@ import * as babel from '@babel/core'; import type { ParserPlugin } from '@babel/parser'; import { Plugin } from 'rollup'; -import { createScriptsFilter } from '../utils.js'; +import { createScriptsFilter, formatCnpmDepFilepath, getIncludeNodeModuleScripts } from '../utils.js'; import type { BundleTaskConfig } from '../types.js'; import { TransformOptions } from '@babel/core'; import getBabelOptions from '../helpers/getBabelOptions.js'; @@ -43,12 +43,12 @@ const babelPlugin = ( ): Plugin => { // https://babeljs.io/docs/en/babel-preset-react#usage const babelOptions = getBabelOptions(plugins, options, modifyBabelOptions); - const scriptsFilter = createScriptsFilter(compileDependencies); + const scriptsFilter = createScriptsFilter(getIncludeNodeModuleScripts(compileDependencies)); return { name: 'ice-pkg:babel', transform(source, id) { - if (!scriptsFilter(id)) { + if (!scriptsFilter(formatCnpmDepFilepath(id))) { return null; } diff --git a/packages/pkg/src/rollupPlugins/swc.ts b/packages/pkg/src/rollupPlugins/swc.ts index 9d5d0718..9b74a125 100644 --- a/packages/pkg/src/rollupPlugins/swc.ts +++ b/packages/pkg/src/rollupPlugins/swc.ts @@ -2,7 +2,7 @@ import { extname, basename, relative, sep } from 'path'; import * as swc from '@swc/core'; import deepmerge from 'deepmerge'; import { isTypescriptOnly } from '../helpers/suffix.js'; -import { checkDependencyExists, createScriptsFilter } from '../utils.js'; +import { checkDependencyExists, createScriptsFilter, formatCnpmDepFilepath, getIncludeNodeModuleScripts } from '../utils.js'; import type { Options as swcCompileOptions, Config, TsParserConfig, EsParserConfig } from '@swc/core'; import type { TaskConfig, OutputFile, BundleTaskConfig } from '../types.js'; @@ -65,12 +65,14 @@ const swcPlugin = ( extraSwcOptions?: Config, compileDependencies?: BundleTaskConfig['compileDependencies'], ): Plugin => { - const scriptsFilter = createScriptsFilter(compileDependencies); + const scriptsFilter = createScriptsFilter( + getIncludeNodeModuleScripts(compileDependencies), + ); return { name: 'ice-pkg:swc', async transform(source, id) { - if (!scriptsFilter(id)) { + if (!scriptsFilter(formatCnpmDepFilepath(id))) { return null; } diff --git a/packages/pkg/src/types.ts b/packages/pkg/src/types.ts index 8c74318d..2b9f85d8 100644 --- a/packages/pkg/src/types.ts +++ b/packages/pkg/src/types.ts @@ -95,7 +95,7 @@ export interface BundleUserConfig { /** * Weather or not compile the dependencies in node_modules. */ - compileDependencies?: boolean | RegExp[]; + compileDependencies?: boolean | Array; } export interface UserConfig { diff --git a/packages/pkg/src/utils.ts b/packages/pkg/src/utils.ts index f000086d..92dd9945 100644 --- a/packages/pkg/src/utils.ts +++ b/packages/pkg/src/utils.ts @@ -286,18 +286,62 @@ export const stringifyObject = (obj: PlainObject) => { }, {}); }; -export const createScriptsFilter = (compileDependencies?: boolean | RegExp[]) => { - const exclude = [/\.d\.ts$/]; - if (Array.isArray(compileDependencies)) { - exclude.push(...compileDependencies); - } else if (!compileDependencies) { - exclude.push(/node_modules/); +// @ref: It will pass to createScriptFilter function +export function getIncludeNodeModuleScripts(compileDependencies: boolean | Array): RegExp[] { + if (compileDependencies === true || (Array.isArray(compileDependencies) && compileDependencies.length === 0)) { + return [/node_modules/]; } - return createFilter( - /\.m?[jt]sx?$/, // include - exclude, - ); + if (Array.isArray(compileDependencies) && compileDependencies.length > 0) { + // compile all deps in node_modules except compileDependencies + // for example: now only want to compile abc and @ice/abc deps. + // will generate the regular expression: /node_modules(?:\/|\\\\)(abc|@ice\/abc)(?:\/|\\\\)(?!node_modules).*/ + // will match: + // 1. node_modules/abc/index.js + // 2. node_modules/def/node_modules/abc/index.js + // 3. node_modules/@ice/abc/index.js + // 4. node_modules/def/node_modules/@ice/abc/index.js + // will not match: + // node_modules/abc/node_modules/def/index.js + // node_modules/def/index.js + return [new RegExp(`node_modules/(${compileDependencies.map((dep: string | RegExp) => (`${typeof dep === 'string' ? dep : dep.source}`)).join('|')})/(?!node_modules).*.m?[jt]sx?$`)]; + } + // default + return []; +} + +/** + * @reason cnpm node_modules path is different from npm/pnpm, it will not match the compileDependencies + * + * @example transform react/node_modules/_idb@7.1.1@idb/build/index.js to react/node_modules/idb/build/index.js + */ +export function formatCnpmDepFilepath(filepath: string) { + const reg = /(.*(?:\/|\\\\))(?:_.*@(?:\d+)\.(?:\d+)\.(?:\d+)(?:-(?:(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?:[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?@)(.*)/; + const matchedResult = filepath.match(reg); + if (!matchedResult) { + return filepath; + } + const [, p1, p2] = matchedResult; + return p1 + p2; +} + +/** + * default include src/**.m?[jt]sx? but exclude .d.ts file + * + * @param extraInclude include other file types + * @param extraExclude exclude other file types + * + * @example exclude node_modules createScriptsFilter([], [/node_modules/]) + */ +export const createScriptsFilter = ( + extraIncludes: RegExp[] = [], + extraExcludes: RegExp[] = [], +) => { + const includes = [/src\/.*\.m?[jt]sx?$/].concat(extraIncludes); + const excludes = [/\.d\.ts$/, /core-js/, /core-js-pure/, /tslib/, /@swc\/helpers/, /@babel\/runtime/, /babel-runtime/].concat(extraExcludes); + + return createFilter(includes, excludes); }; + export const cwd = process.cwd(); export function normalizeSlashes(file: string) { diff --git a/packages/pkg/tests/babelPlugin.test.ts b/packages/pkg/tests/babelPlugin.test.ts index e1721de0..5bf32dab 100644 --- a/packages/pkg/tests/babelPlugin.test.ts +++ b/packages/pkg/tests/babelPlugin.test.ts @@ -34,7 +34,7 @@ describe('transform', () => { }); expect(babelPlugin.name).toBe('ice-pkg:babel'); // @ts-ignore it's callable - const ret = babelPlugin.transform('
', 'test.tsx'); + const ret = babelPlugin.transform('
', 'src/test.tsx'); expect(cleanCode(ret.code)).toBe( cleanCode(`import { createCondition as __create_condition__ } from "babel-runtime-jsx-plus"; import { jsx as _jsx } from "react/jsx-runtime"; @@ -55,7 +55,7 @@ describe('transform', () => { }); expect(babelPlugin.name).toBe('ice-pkg:babel'); // @ts-ignore it's callable - const ret = babelPlugin.transform('
', 'test.tsx'); + const ret = babelPlugin.transform('
', 'src/test.tsx'); expect(cleanCode(ret.code)).toBe( cleanCode(`import { createCondition as __create_condition__ } from "babel-runtime-jsx-plus"; __create_condition__([[() => false, () => /*#__PURE__*/React.createElement("div", null)]]);`), diff --git a/packages/pkg/tests/formatCnpmDepFilepath.test.ts b/packages/pkg/tests/formatCnpmDepFilepath.test.ts new file mode 100644 index 00000000..3e6b8ee8 --- /dev/null +++ b/packages/pkg/tests/formatCnpmDepFilepath.test.ts @@ -0,0 +1,23 @@ +import { expect, it, describe } from 'vitest'; +import { formatCnpmDepFilepath } from '../src/utils'; + +describe('formatCnpmDepFilepath function', () => { + it('pnpm path', () => { + expect(formatCnpmDepFilepath('/workspace/node_modules/.pnpm/classnames@2.3.2/node_modules/classnames/index.js')).toBe('/workspace/node_modules/.pnpm/classnames@2.3.2/node_modules/classnames/index.js'); + }) + it('pnpm path with scope', () => { + expect(formatCnpmDepFilepath('/workspace/node_modules/.pnpm/@actions+exec@1.1.1/node_modules/@actions/exec/lib/exec.js')).toBe('/workspace/node_modules/.pnpm/@actions+exec@1.1.1/node_modules/@actions/exec/lib/exec.js'); + }) + it('cnpm path', () => { + expect(formatCnpmDepFilepath('/workspace/node_modules/_idb@7.1.1@idb/build/index.js')).toBe('/workspace/node_modules/idb/build/index.js'); + }) + it('cnpm path with npm scope', () => { + expect(formatCnpmDepFilepath('/workspace/node_modules/_@swc_helpers@0.5.3@@swc/helpers/esm/_extends.js')).toBe('/workspace/node_modules/@swc/helpers/esm/_extends.js'); + }) + it('npm path', () => { + expect(formatCnpmDepFilepath('/workspace/node_modules/idb/build/index.js')).toBe('/workspace/node_modules/idb/build/index.js'); + }) + it('npm path with npm scope', () => { + expect(formatCnpmDepFilepath('/workspace/node_modules/@ice/idb/build/index.js')).toBe('/workspace/node_modules/@ice/idb/build/index.js'); + }) +}) diff --git a/website/docs/reference/config.md b/website/docs/reference/config.md index 0d81be36..41f0ad3a 100644 --- a/website/docs/reference/config.md +++ b/website/docs/reference/config.md @@ -443,7 +443,7 @@ export default defineConfig({ #### compileDependencies -+ 类型:`boolean | RegExp[]` ++ 类型:`boolean | RegExp[] | string[]` + 默认值:`false` 配置是否编译 node_modules 中的依赖。如果值为 `true`,则 node_modules 中的依赖都会编译;如果值为 false 则都不编译;如果值为数组,则只会编译对应的依赖。 @@ -453,7 +453,7 @@ import { defineConfig } from '@ice/pkg'; export default defineConfig({ bundle: { - compileDependencies: [/antd/], + compileDependencies: ['antd'], }, }); ```