From 802359282d76850318c82b969c92feebeaa2e2a3 Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 15 Nov 2022 16:41:46 +0800 Subject: [PATCH 1/8] feat(ssr): support external true --- docs/config/ssr-options.md | 6 ++--- .../__tests__/fixtures/cjs-ssr-dep/index.js | 3 +++ .../fixtures/cjs-ssr-dep/package.json | 5 ++++ .../vite/src/node/ssr/__tests__/package.json | 8 ++++++ .../node/ssr/__tests__/ssrExternal.spec.ts | 26 +++++++++++++++++-- packages/vite/src/node/ssr/index.ts | 2 +- packages/vite/src/node/ssr/ssrExternal.ts | 17 +++++++----- 7 files changed, 55 insertions(+), 12 deletions(-) create mode 100644 packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/index.js create mode 100644 packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/package.json create mode 100644 packages/vite/src/node/ssr/__tests__/package.json diff --git a/docs/config/ssr-options.md b/docs/config/ssr-options.md index 886b5f4bb4fca3..475fd4526074a1 100644 --- a/docs/config/ssr-options.md +++ b/docs/config/ssr-options.md @@ -2,17 +2,17 @@ ## ssr.external -- **Type:** `string[]` +- **Type:** `string[] | true` - **Related:** [SSR Externals](/guide/ssr#ssr-externals) -Force externalize dependencies for SSR. +Externalize dependencies for SSR. By default, all dependencies are externalized, except linked dependencies for HMR. This can opted-out by adding the dependency to this option, or set `true` to force externalize all dependencies. ## ssr.noExternal - **Type:** `string | RegExp | (string | RegExp)[] | true` - **Related:** [SSR Externals](/guide/ssr#ssr-externals) -Prevent listed dependencies from being externalized for SSR. If `true`, no dependencies are externalized. +Prevent listed dependencies from being externalized for SSR. If `true`, no dependencies are externalized. This option has a higher priority than `ssr.external` except if a dependency is explicitly specified in the `ssr.external` array. ## ssr.target diff --git a/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/index.js b/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/index.js new file mode 100644 index 00000000000000..5b6184b5e89fb9 --- /dev/null +++ b/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/index.js @@ -0,0 +1,3 @@ +module.exports = { + hello: () => 'world' +} diff --git a/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/package.json b/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/package.json new file mode 100644 index 00000000000000..73a3f598a18dfd --- /dev/null +++ b/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/package.json @@ -0,0 +1,5 @@ +{ + "name": "@vitejs/cjs-ssr-dep", + "private": true, + "version": "0.0.0" +} diff --git a/packages/vite/src/node/ssr/__tests__/package.json b/packages/vite/src/node/ssr/__tests__/package.json new file mode 100644 index 00000000000000..a5f6e053817561 --- /dev/null +++ b/packages/vite/src/node/ssr/__tests__/package.json @@ -0,0 +1,8 @@ +{ + "name": "@vitejs/unit-ssr", + "private": true, + "version": "0.0.0", + "dependencies": { + "@vitejs/cjs-ssr-dep": "link:./fixtures/cjs-ssr-dep" + } +} diff --git a/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts index 579ba997da5272..ebc8e4e1064b1e 100644 --- a/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts +++ b/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts @@ -1,6 +1,28 @@ -import { expect, test } from 'vitest' -import { stripNesting } from '../ssrExternal' +import { describe, expect, test } from 'vitest' +import type { SSROptions } from '..' +import { resolveConfig } from '../../config' +import { createIsConfiguredAsSsrExternal, stripNesting } from '../ssrExternal' test('stripNesting', async () => { expect(stripNesting(['c', 'p1>c1', 'p2 > c2'])).toEqual(['c', 'c1', 'c2']) }) + +describe('createIsConfiguredAsSsrExternal', () => { + test('default', async () => { + const isExternal = await createIsExternal() + expect(isExternal('@vitejs/cjs-ssr-dep')).toBe(false) + }) + + test('force external', async () => { + const isExternal = await createIsExternal({ external: true }) + expect(isExternal('@vitejs/cjs-ssr-dep')).toBe(true) + }) +}) + +async function createIsExternal(ssrConfig?: SSROptions) { + const resolvedConfig = await resolveConfig( + { configFile: false, ssr: ssrConfig }, + 'serve' + ) + return createIsConfiguredAsSsrExternal(resolvedConfig) +} diff --git a/packages/vite/src/node/ssr/index.ts b/packages/vite/src/node/ssr/index.ts index d23e78b18cae5f..13a065c1ad0c0a 100644 --- a/packages/vite/src/node/ssr/index.ts +++ b/packages/vite/src/node/ssr/index.ts @@ -7,7 +7,7 @@ export type SsrDepOptimizationOptions = DepOptimizationConfig export interface SSROptions { noExternal?: string | RegExp | (string | RegExp)[] | true - external?: string[] + external?: string[] | true /** * Define the target for the ssr build. The browser field in package.json * is ignored for node but used if webworker is the target diff --git a/packages/vite/src/node/ssr/ssrExternal.ts b/packages/vite/src/node/ssr/ssrExternal.ts index 9281c8ebebc9b8..a93760c681e576 100644 --- a/packages/vite/src/node/ssr/ssrExternal.ts +++ b/packages/vite/src/node/ssr/ssrExternal.ts @@ -46,10 +46,12 @@ export function cjsSsrResolveExternals( const ssrExternals: Set = new Set() const seen: Set = new Set() - ssrConfig?.external?.forEach((id) => { - ssrExternals.add(id) - seen.add(id) - }) + if (Array.isArray(ssrConfig?.external)) { + ssrConfig.external.forEach((id) => { + ssrExternals.add(id) + seen.add(id) + }) + } cjsSsrCollectExternals( config.root, @@ -156,11 +158,11 @@ export function createIsConfiguredAsSsrExternal( // Returns true if it is configured as external, false if it is filtered // by noExternal and undefined if it isn't affected by the explicit config return (id: string) => { - const { ssr } = config if (ssr) { if ( // If this id is defined as external, force it as external // Note that individual package entries are allowed in ssr.external + ssr.external !== true && ssr.external?.includes(id) ) { return true @@ -172,6 +174,7 @@ export function createIsConfiguredAsSsrExternal( if ( // A package name in ssr.external externalizes every // externalizable package entry + ssr.external !== true && ssr.external?.includes(pkgName) ) { return isExternalizable(id, true) @@ -183,7 +186,9 @@ export function createIsConfiguredAsSsrExternal( return false } } - return isExternalizable(id) + // If `ssr.external: true`, all will be externalized by default, regardless if + // it's a linked package + return ssr.external === true || isExternalizable(id) } } From c81ab082d74bded0fdf9c376f64a06a4028dd369 Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 15 Nov 2022 22:10:30 +0800 Subject: [PATCH 2/8] chore: fix test setup --- .eslintrc.cjs | 2 +- .../node/ssr/__tests__/ssrExternal.spec.ts | 7 ++- packages/vite/src/node/ssr/ssrExternal.ts | 54 +++++++++---------- pnpm-lock.yaml | 36 +++++++++++++ pnpm-workspace.yaml | 1 + 5 files changed, 70 insertions(+), 30 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 59a3579c80fc2e..ca2ce959b8ecda 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -148,7 +148,7 @@ module.exports = defineConfig({ } }, { - files: ['playground/**'], + files: ['playground/**', '**/__tests__/**'], rules: { 'node/no-extraneous-import': 'off', 'node/no-extraneous-require': 'off', diff --git a/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts index ebc8e4e1064b1e..48b86fe8c5d9ac 100644 --- a/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts +++ b/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts @@ -1,3 +1,4 @@ +import { fileURLToPath } from 'node:url' import { describe, expect, test } from 'vitest' import type { SSROptions } from '..' import { resolveConfig } from '../../config' @@ -21,7 +22,11 @@ describe('createIsConfiguredAsSsrExternal', () => { async function createIsExternal(ssrConfig?: SSROptions) { const resolvedConfig = await resolveConfig( - { configFile: false, ssr: ssrConfig }, + { + configFile: false, + root: fileURLToPath(new URL('./', import.meta.url)), + ssr: ssrConfig + }, 'serve' ) return createIsConfiguredAsSsrExternal(resolvedConfig) diff --git a/packages/vite/src/node/ssr/ssrExternal.ts b/packages/vite/src/node/ssr/ssrExternal.ts index a93760c681e576..af08f2a29bd634 100644 --- a/packages/vite/src/node/ssr/ssrExternal.ts +++ b/packages/vite/src/node/ssr/ssrExternal.ts @@ -158,37 +158,35 @@ export function createIsConfiguredAsSsrExternal( // Returns true if it is configured as external, false if it is filtered // by noExternal and undefined if it isn't affected by the explicit config return (id: string) => { - if (ssr) { - if ( - // If this id is defined as external, force it as external - // Note that individual package entries are allowed in ssr.external - ssr.external !== true && - ssr.external?.includes(id) - ) { - return true - } - const pkgName = getNpmPackageName(id) - if (!pkgName) { - return isExternalizable(id) - } - if ( - // A package name in ssr.external externalizes every - // externalizable package entry - ssr.external !== true && - ssr.external?.includes(pkgName) - ) { - return isExternalizable(id, true) - } - if (typeof noExternal === 'boolean') { - return !noExternal - } - if (noExternalFilter && !noExternalFilter(pkgName)) { - return false - } + if ( + // If this id is defined as external, force it as external + // Note that individual package entries are allowed in ssr.external + ssr.external !== true && + ssr.external?.includes(id) + ) { + return true + } + const pkgName = getNpmPackageName(id) + if (!pkgName) { + return isExternalizable(id) + } + if ( + // A package name in ssr.external externalizes every + // externalizable package entry + ssr.external !== true && + ssr.external?.includes(pkgName) + ) { + return isExternalizable(id, true) + } + if (typeof noExternal === 'boolean') { + return !noExternal + } + if (noExternalFilter && !noExternalFilter(pkgName)) { + return false } // If `ssr.external: true`, all will be externalized by default, regardless if // it's a linked package - return ssr.external === true || isExternalizable(id) + return isExternalizable(id, ssr.external === true) } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a7f8770e4973ee..a50418b4ff039c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -335,6 +335,42 @@ importers: ufo: 0.8.6 ws: 8.11.0 + packages/vite/src/node/__tests__/packages/module: + specifiers: {} + + packages/vite/src/node/__tests__/packages/name: + specifiers: {} + + packages/vite/src/node/__tests__/packages/noname: + specifiers: {} + + packages/vite/src/node/server/__tests__/fixtures/lerna/nested: + specifiers: {} + + packages/vite/src/node/server/__tests__/fixtures/none/nested: + specifiers: {} + + packages/vite/src/node/server/__tests__/fixtures/pnpm: + specifiers: {} + + packages/vite/src/node/server/__tests__/fixtures/pnpm/nested: + specifiers: {} + + packages/vite/src/node/server/__tests__/fixtures/yarn: + specifiers: {} + + packages/vite/src/node/server/__tests__/fixtures/yarn/nested: + specifiers: {} + + packages/vite/src/node/ssr/__tests__: + specifiers: + '@vitejs/cjs-ssr-dep': link:./fixtures/cjs-ssr-dep + dependencies: + '@vitejs/cjs-ssr-dep': link:fixtures/cjs-ssr-dep + + packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep: + specifiers: {} + playground: specifiers: convert-source-map: ^1.9.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7c6523c6cbb288..9a42b455d0ae09 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,4 @@ packages: - 'packages/*' - 'playground/**' + - '**/__tests__/**' From d4806b37d1bae432d59f43939e5c061e5d852fb2 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Thu, 17 Nov 2022 13:19:44 +0800 Subject: [PATCH 3/8] docs: update external priority explanation Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com> --- docs/config/ssr-options.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config/ssr-options.md b/docs/config/ssr-options.md index 475fd4526074a1..a3f6413f982b58 100644 --- a/docs/config/ssr-options.md +++ b/docs/config/ssr-options.md @@ -12,7 +12,7 @@ Externalize dependencies for SSR. By default, all dependencies are externalized, - **Type:** `string | RegExp | (string | RegExp)[] | true` - **Related:** [SSR Externals](/guide/ssr#ssr-externals) -Prevent listed dependencies from being externalized for SSR. If `true`, no dependencies are externalized. This option has a higher priority than `ssr.external` except if a dependency is explicitly specified in the `ssr.external` array. +Prevent listed dependencies from being externalized for SSR. If `true`, no dependencies are externalized. If a dependency is explicitly defined in `ssr.external`, it will take priority and be externalized along with its transitive dependencies. ## ssr.target From 47c51487f4821eaed3d825eff8a112ea04a7e0f4 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 6 Dec 2023 17:58:45 +0800 Subject: [PATCH 4/8] chore: fix lint --- .eslintrc.cjs | 2 +- .../vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/index.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 227be213e46c78..a01ce9b38982b9 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -169,7 +169,7 @@ module.exports = defineConfig({ }, }, { - files: ['playground/**', '**/__tests__/**'], + files: ['playground/**'], rules: { 'n/no-extraneous-import': 'off', 'n/no-extraneous-require': 'off', diff --git a/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/index.js b/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/index.js index 5b6184b5e89fb9..8f862a9f08875d 100644 --- a/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/index.js +++ b/packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep/index.js @@ -1,3 +1,4 @@ +// eslint-disable-next-line no-undef module.exports = { - hello: () => 'world' + hello: () => 'world', } From eb969a92b7ffabee286a65f808e7850cc5337634 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 6 Dec 2023 18:21:36 +0800 Subject: [PATCH 5/8] docs: update options explanation Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com> --- docs/config/ssr-options.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/config/ssr-options.md b/docs/config/ssr-options.md index 6599c969c0c4c4..0111aa56031e15 100644 --- a/docs/config/ssr-options.md +++ b/docs/config/ssr-options.md @@ -5,14 +5,22 @@ - **Type:** `string[] | true` - **Related:** [SSR Externals](/guide/ssr#ssr-externals) -Externalize dependencies for SSR. By default, all dependencies are externalized, except linked dependencies for HMR. This can opted-out by adding the dependency to this option, or set `true` to force externalize all dependencies. +Externalize the given dependencies and their transitive dependencies for SSR. By default, all dependencies are externalized except for linked dependencies (for HMR). If you prefer to externalize the linked dependency, you can pass its name to this option. + +If `true`, all dependencies including linked dependencies are externalized. + +Note that the explicitly listed dependencies (using `string[]` type) will always take priority if they're also listed in `ssr.noExternal` (using any type). ## ssr.noExternal - **Type:** `string | RegExp | (string | RegExp)[] | true` - **Related:** [SSR Externals](/guide/ssr#ssr-externals) -Prevent listed dependencies from being externalized for SSR. If `true`, no dependencies are externalized. If a dependency is explicitly defined in `ssr.external`, it will take priority and be externalized along with its transitive dependencies. +Prevent listed dependencies from being externalized for SSR, which they will get bundled in build. By default, only linked dependencies are not externalized (for HMR). If you prefer to externalize the linked dependency, you can pass its name to the `ssr.external` option. + +If `true`, no dependencies are externalized. However, dependencies explicitly listed in `ssr.external` (using `string[]` type) can take priority and still be externalized. + +Note that if both `ssr.noExternal: true` and `ssr.external: true` are configured, `ssr.noExternal` takes priority and no dependencies are externalized. ## ssr.target From f097f9f0252ea1a61a26d3b4116ed3f6791338cc Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 6 Dec 2023 18:27:29 +0800 Subject: [PATCH 6/8] chore: fix lockfile --- pnpm-lock.yaml | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 497665abf0b87c..a91135481b2916 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -424,41 +424,31 @@ importers: specifier: ^8.14.2 version: 8.14.2 - packages/vite/src/node/__tests__/packages/module: - specifiers: {} + packages/vite/src/node/__tests__/packages/module: {} - packages/vite/src/node/__tests__/packages/name: - specifiers: {} + packages/vite/src/node/__tests__/packages/name: {} - packages/vite/src/node/__tests__/packages/noname: - specifiers: {} + packages/vite/src/node/__tests__/packages/noname: {} - packages/vite/src/node/server/__tests__/fixtures/lerna/nested: - specifiers: {} + packages/vite/src/node/server/__tests__/fixtures/lerna/nested: {} - packages/vite/src/node/server/__tests__/fixtures/none/nested: - specifiers: {} + packages/vite/src/node/server/__tests__/fixtures/none/nested: {} - packages/vite/src/node/server/__tests__/fixtures/pnpm: - specifiers: {} + packages/vite/src/node/server/__tests__/fixtures/pnpm: {} - packages/vite/src/node/server/__tests__/fixtures/pnpm/nested: - specifiers: {} + packages/vite/src/node/server/__tests__/fixtures/pnpm/nested: {} - packages/vite/src/node/server/__tests__/fixtures/yarn: - specifiers: {} + packages/vite/src/node/server/__tests__/fixtures/yarn: {} - packages/vite/src/node/server/__tests__/fixtures/yarn/nested: - specifiers: {} + packages/vite/src/node/server/__tests__/fixtures/yarn/nested: {} packages/vite/src/node/ssr/__tests__: - specifiers: - '@vitejs/cjs-ssr-dep': link:./fixtures/cjs-ssr-dep dependencies: - '@vitejs/cjs-ssr-dep': link:fixtures/cjs-ssr-dep + '@vitejs/cjs-ssr-dep': + specifier: link:./fixtures/cjs-ssr-dep + version: link:fixtures/cjs-ssr-dep - packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep: - specifiers: {} + packages/vite/src/node/ssr/__tests__/fixtures/cjs-ssr-dep: {} playground: devDependencies: @@ -1928,7 +1918,6 @@ packages: /@babel/highlight@7.23.4: resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} engines: {node: '>=6.9.0'} - requiresBuild: true dependencies: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 From e75c4d3a51494be74a06e03b6209b030d3a47a34 Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 6 Dec 2023 18:28:35 +0800 Subject: [PATCH 7/8] chore: update workspace config --- pnpm-workspace.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 9a42b455d0ae09..19efe2ba1fc494 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,4 +1,4 @@ packages: - 'packages/*' - 'playground/**' - - '**/__tests__/**' + - 'packages/**/__tests__/**' From a561663761fe6660fb6554703564afd1f9b30d8b Mon Sep 17 00:00:00 2001 From: bluwy Date: Wed, 6 Dec 2023 18:42:58 +0800 Subject: [PATCH 8/8] chore: format --- packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts index 7d6467a7f6893e..68e753af703ce2 100644 --- a/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts +++ b/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts @@ -21,9 +21,9 @@ async function createIsExternal(ssrConfig?: SSROptions) { { configFile: false, root: fileURLToPath(new URL('./', import.meta.url)), - ssr: ssrConfig + ssr: ssrConfig, }, - 'serve' + 'serve', ) return createIsConfiguredAsSsrExternal(resolvedConfig) }