From 8d7ce9e03fbcba4643ad1599bbdd9caa8e2e06bd Mon Sep 17 00:00:00 2001 From: ArcherGu <34826812+ArcherGu@users.noreply.github.com> Date: Thu, 6 Oct 2022 22:46:05 +0800 Subject: [PATCH] feat: allow to exclude dependencies from specific package.json (#717) --- docs/README.md | 2 +- src/cli-main.ts | 2 +- src/esbuild/index.ts | 43 ++++++++++++++++++++------- test/__snapshots__/index.test.ts.snap | 9 ++++-- test/index.test.ts | 6 +++- 5 files changed, 46 insertions(+), 16 deletions(-) diff --git a/docs/README.md b/docs/README.md index dfdd9bd7..21c45252 100644 --- a/docs/README.md +++ b/docs/README.md @@ -52,7 +52,7 @@ This will output `dist/index.js` and `dist/cli.js`. ### Excluding packages -By default tsup bundles all `import`-ed modules but `dependencies` and `peerDependencies` in your `packages.json` are always excluded, you can also use `--external ` flag to mark other packages as external. +By default tsup bundles all `import`-ed modules but `dependencies` and `peerDependencies` in your `packages.json` are always excluded, you can also use `--external ` flag to mark other packages or other special `package.json`'s `dependencies` and `peerDependencies` as external. ### Excluding all packages diff --git a/src/cli-main.ts b/src/cli-main.ts index 0ae381b7..92163444 100644 --- a/src/cli-main.ts +++ b/src/cli-main.ts @@ -58,7 +58,7 @@ export async function main(options: Options = {}) { 'Replace a global variable with an import from another file' ) .option('--define.* ', 'Define compile-time constants') - .option('--external ', 'Mark specific packages as external') + .option('--external ', 'Mark specific packages / package.json (dependencies and peerDependencies) as external') .option('--global-name ', 'Global variable name for iife format') .option('--jsxFactory ', 'Name of JSX factory function', { default: 'React.createElement', diff --git a/src/esbuild/index.ts b/src/esbuild/index.ts index ad3b4a03..8157f0bf 100644 --- a/src/esbuild/index.ts +++ b/src/esbuild/index.ts @@ -58,6 +58,27 @@ const getOutputExtensionMap = ( } } +/** + * Support to exclude special package.json + */ +const generateExternal = async (external: (string | RegExp)[]) => { + const result: (string | RegExp)[] = [] + + for (const item of external) { + if (typeof item !== 'string' || !item.endsWith('package.json')) { + result.push(item) + continue + } + + let pkgPath: string = path.isAbsolute(item) ? path.dirname(item) : path.dirname(path.resolve(process.cwd(), item)) + + const deps = await getDeps(pkgPath) + result.push(...deps) + } + + return result +} + export async function runEsbuild( options: NormalizedOptions, { @@ -79,7 +100,7 @@ export async function runEsbuild( const external = [ // Exclude dependencies, e.g. `lodash`, `lodash/get` ...deps.map((dep) => new RegExp(`^${dep}($|\\/|\\\\)`)), - ...(options.external || []), + ...(await generateExternal(options.external || [])), ] const outDir = options.outDir @@ -103,8 +124,8 @@ export async function runEsbuild( format === 'iife' ? false : typeof options.splitting === 'boolean' - ? options.splitting - : format === 'esm' + ? options.splitting + : format === 'esm' const platform = options.platform || 'node' const loader = options.loader || {} @@ -131,12 +152,12 @@ export async function runEsbuild( // esbuild's `external` option doesn't support RegExp // So here we use a custom plugin to implement it format !== 'iife' && - externalPlugin({ - external, - noExternal: options.noExternal, - skipNodeModulesBundle: options.skipNodeModulesBundle, - tsconfigResolvePaths: options.tsconfigResolvePaths, - }), + externalPlugin({ + external, + noExternal: options.noExternal, + skipNodeModulesBundle: options.skipNodeModulesBundle, + tsconfigResolvePaths: options.tsconfigResolvePaths, + }), options.tsconfigDecoratorMetadata && swcPlugin({ logger }), nativeNodeModulesPlugin(), postcssPlugin({ css, inject: options.injectStyle }), @@ -199,8 +220,8 @@ export async function runEsbuild( TSUP_FORMAT: JSON.stringify(format), ...(format === 'cjs' && injectShims ? { - 'import.meta.url': 'importMetaUrl', - } + 'import.meta.url': 'importMetaUrl', + } : {}), ...options.define, ...Object.keys(env).reduce((res, key) => { diff --git a/test/__snapshots__/index.test.ts.snap b/test/__snapshots__/index.test.ts.snap index 080f7e6e..e60dd5d4 100644 --- a/test/__snapshots__/index.test.ts.snap +++ b/test/__snapshots__/index.test.ts.snap @@ -74,7 +74,8 @@ var input_exports = {}; __export(input_exports, { bar: () => import_bar.bar, baz: () => baz, - foo: () => import_foo.foo + foo: () => import_foo.foo, + qux: () => import_qux.qux }); module.exports = __toCommonJS(input_exports); var import_foo = require(\\"foo\\"); @@ -82,11 +83,15 @@ var import_bar = require(\\"bar\\"); // node_modules/baz/index.ts var baz = \\"baz\\"; + +// input.ts +var import_qux = require(\\"qux\\"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { bar, baz, - foo + foo, + qux }); " `; diff --git a/test/index.test.ts b/test/index.test.ts index 7eaec1b1..a7faba3b 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -344,6 +344,7 @@ test('external', async () => { 'input.ts': `export {foo} from 'foo' export {bar} from 'bar' export {baz} from 'baz' + export {qux} from 'qux' `, 'node_modules/foo/index.ts': `export const foo = 'foo'`, 'node_modules/foo/package.json': `{"name":"foo","version":"0.0.0"}`, @@ -351,9 +352,12 @@ test('external', async () => { 'node_modules/bar/package.json': `{"name":"bar","version":"0.0.0"}`, 'node_modules/baz/index.ts': `export const baz = 'baz'`, 'node_modules/baz/package.json': `{"name":"baz","version":"0.0.0"}`, + 'node_modules/qux/index.ts': `export const qux = 'qux'`, + 'node_modules/qux/package.json': `{"name":"qux","version":"0.0.0"}`, + 'another/package.json': `{"name":"another-pkg","dependencies":{"qux":"0.0.0"}}`, 'tsup.config.ts': ` export default { - external: [/f/, 'bar'] + external: [/f/, 'bar', 'another/package.json'] } `, })