Skip to content

Commit

Permalink
refactor: remove CJS ssr output format (#13944)
Browse files Browse the repository at this point in the history
Co-authored-by: sapphi-red <[email protected]>
  • Loading branch information
patak-dev and sapphi-red authored Sep 17, 2023
1 parent 2947af7 commit 2f60b9e
Show file tree
Hide file tree
Showing 12 changed files with 15 additions and 378 deletions.
9 changes: 0 additions & 9 deletions docs/config/ssr-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,3 @@ Prevent listed dependencies from being externalized for SSR. If `true`, no depen
- **Default:** `node`

Build target for the SSR server.

## ssr.format

- **Experimental:** [CJS support to be removed in Vite 5](https://github.com/vitejs/vite/discussions/13816)
- **Deprecated** Only ESM output will be supported in Vite 5.
- **Type:** `'esm' | 'cjs'`
- **Default:** `esm`

Build format for the SSR server. Since Vite v3 the SSR build generates ESM by default. `'cjs'` can be selected to generate a CJS build, but it isn't recommended. The option is left marked as experimental to give users more time to update to ESM. CJS builds require complex externalization heuristics that aren't present in the ESM format.
8 changes: 0 additions & 8 deletions docs/guide/ssr.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,11 +266,3 @@ The CLI commands `$ vite dev` and `$ vite preview` can also be used for SSR apps
:::tip Note
Use a post hook so that your SSR middleware runs _after_ Vite's middlewares.
:::
## SSR Format
By default, Vite generates the SSR bundle in ESM. There is experimental support for configuring `ssr.format`, but it isn't recommended. Future efforts around SSR development will be based on ESM, and CommonJS remains available for backward compatibility. If using ESM for SSR isn't possible in your project, you can set `legacy.buildSsrCjsExternalHeuristics: true` to generate a CJS bundle using the same [externalization heuristics of Vite v2](https://v2.vitejs.dev/guide/ssr.html#ssr-externals).
:::warning Warning
Experimental `legacy.buildSsrCjsExternalHeuristics` and `ssr.format: 'cjs'` are going to be removed in Vite 5. Find more information and give feedback [in this discussion](https://github.com/vitejs/vite/discussions/13816).
:::
58 changes: 4 additions & 54 deletions packages/vite/src/node/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,8 @@ import { manifestPlugin } from './plugins/manifest'
import type { Logger } from './logger'
import { dataURIPlugin } from './plugins/dataUri'
import { buildImportAnalysisPlugin } from './plugins/importAnalysisBuild'
import {
cjsShouldExternalizeForSSR,
cjsSsrResolveExternals,
} from './ssr/ssrExternal'
import { ssrManifestPlugin } from './ssr/ssrManifestPlugin'
import type { DepOptimizationMetadata } from './optimizer'
import {
findKnownImports,
getDepsCacheDir,
initDepsOptimizer,
} from './optimizer'
import { initDepsOptimizer } from './optimizer'
import { loadFallbackPlugin } from './plugins/loadFallback'
import { findNearestPackageData } from './packages'
import type { PackageCache } from './packages'
Expand Down Expand Up @@ -517,16 +508,6 @@ export async function build(
ssr ? config.plugins.map((p) => injectSsrFlagToHooks(p)) : config.plugins
) as Plugin[]

const userExternal = options.rollupOptions?.external
let external = userExternal

// In CJS, we can pass the externals to rollup as is. In ESM, we need to
// do it in the resolve plugin so we can add the resolved extension for
// deep node_modules imports
if (ssr && config.legacy?.buildSsrCjsExternalHeuristics) {
external = await cjsSsrResolveExternal(config, userExternal)
}

if (isDepsOptimizerEnabled(config, ssr)) {
await initDepsOptimizer(config)
}
Expand All @@ -541,7 +522,7 @@ export async function build(
...options.rollupOptions,
input,
plugins,
external,
external: options.rollupOptions?.external,
onwarn(warning, warn) {
onRollupWarning(warning, warn, config)
},
Expand Down Expand Up @@ -574,9 +555,8 @@ export async function build(

const ssrNodeBuild = ssr && config.ssr.target === 'node'
const ssrWorkerBuild = ssr && config.ssr.target === 'webworker'
const cjsSsrBuild = ssr && config.ssr.format === 'cjs'

const format = output.format || (cjsSsrBuild ? 'cjs' : 'es')
const format = output.format || 'es'
const jsExt =
ssrNodeBuild || libOptions
? resolveOutputJsExtension(
Expand All @@ -589,7 +569,7 @@ export async function build(
dir: outDir,
// Default format is 'es' for regular and for SSR builds
format,
exports: cjsSsrBuild ? 'named' : 'auto',
exports: 'auto',
sourcemap: options.sourcemap,
name: libOptions ? libOptions.name : undefined,
// es2015 enables `generatedCode.symbols`
Expand Down Expand Up @@ -944,36 +924,6 @@ export function onRollupWarning(
}
}

async function cjsSsrResolveExternal(
config: ResolvedConfig,
user: ExternalOption | undefined,
): Promise<ExternalOption> {
// see if we have cached deps data available
let knownImports: string[] | undefined
const dataPath = path.join(getDepsCacheDir(config, false), '_metadata.json')
try {
const data = JSON.parse(
fs.readFileSync(dataPath, 'utf-8'),
) as DepOptimizationMetadata
knownImports = Object.keys(data.optimized)
} catch (e) {}
if (!knownImports) {
// no dev deps optimization data, do a fresh scan
knownImports = await findKnownImports(config, false) // needs to use non-ssr
}
const ssrExternals = cjsSsrResolveExternals(config, knownImports)

return (id, parentId, isResolved) => {
const isExternal = cjsShouldExternalizeForSSR(id, ssrExternals)
if (isExternal) {
return true
}
if (user) {
return resolveUserExternal(user, id, parentId, isResolved)
}
}
}

export function resolveUserExternal(
user: ExternalOption,
id: string,
Expand Down
19 changes: 6 additions & 13 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -322,13 +322,8 @@ export interface ExperimentalOptions {

export interface LegacyOptions {
/**
* Revert vite build --ssr to the v2.9 strategy. Use CJS SSR build and v2.9 externalization heuristics
*
* @experimental
* @deprecated
* @default false
* No longer needed for now, but kept for backwards compatibility.
*/
buildSsrCjsExternalHeuristics?: boolean
}

export interface ResolveWorkerOptions extends PluginHookUtils {
Expand Down Expand Up @@ -651,11 +646,7 @@ export async function resolveConfig(
: ''

const server = resolveServerOptions(resolvedRoot, config.server, logger)
const ssr = resolveSSROptions(
config.ssr,
resolveOptions.preserveSymlinks,
config.legacy?.buildSsrCjsExternalHeuristics,
)
const ssr = resolveSSROptions(config.ssr, resolveOptions.preserveSymlinks)

const middlewareMode = config?.server?.middlewareMode

Expand Down Expand Up @@ -860,13 +851,15 @@ assetFileNames isn't equal for every build.rollupOptions.output. A single patter

// Warn about removal of experimental features
if (
// @ts-expect-error Option removed
config.legacy?.buildSsrCjsExternalHeuristics ||
// @ts-expect-error Option removed
config.ssr?.format === 'cjs'
) {
resolved.logger.warn(
colors.yellow(`
(!) Experimental legacy.buildSsrCjsExternalHeuristics and ssr.format: 'cjs' are going to be removed in Vite 5.
Find more information and give feedback at https://github.com/vitejs/vite/discussions/13816.
(!) Experimental legacy.buildSsrCjsExternalHeuristics and ssr.format were be removed in Vite 5.
The only SSR Output format is ESM. Find more information at https://github.com/vitejs/vite/discussions/13816.
`),
)
}
Expand Down
1 change: 0 additions & 1 deletion packages/vite/src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ export type {
ResolvedSSROptions,
SsrDepOptimizationOptions,
SSROptions,
SSRFormat,
SSRTarget,
} from './ssr'
export type { Plugin, HookHandler } from './plugin'
Expand Down
9 changes: 0 additions & 9 deletions packages/vite/src/node/optimizer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -822,15 +822,6 @@ async function prepareEsbuildOptimizerRun(
return { context, idToExports }
}

export async function findKnownImports(
config: ResolvedConfig,
ssr: boolean,
): Promise<string[]> {
const { deps } = await scanImports(config).result
await addManuallyIncludedOptimizeDeps(deps, config, ssr)
return Object.keys(deps)
}

export async function addManuallyIncludedOptimizeDeps(
deps: Record<string, string>,
config: ResolvedConfig,
Expand Down
13 changes: 2 additions & 11 deletions packages/vite/src/node/plugins/importAnalysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,7 @@ import {
import { getDepOptimizationConfig } from '../config'
import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import {
cjsShouldExternalizeForSSR,
shouldExternalizeForSSR,
} from '../ssr/ssrExternal'
import { shouldExternalizeForSSR } from '../ssr/ssrExternal'
import { getDepsOptimizer, optimizedDepNeedsInterop } from '../optimizer'
import { ERR_CLOSED_SERVER } from '../server/pluginContainer'
import { checkPublicFile, urlRE } from './asset'
Expand Down Expand Up @@ -487,13 +484,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
}
// skip ssr external
if (ssr) {
if (config.legacy?.buildSsrCjsExternalHeuristics) {
if (
cjsShouldExternalizeForSSR(specifier, server._ssrExternals)
) {
return
}
} else if (shouldExternalizeForSSR(specifier, importer, config)) {
if (shouldExternalizeForSSR(specifier, importer, config)) {
return
}
if (isBuiltin(specifier)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/vite/src/node/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export async function resolvePlugins(
asSrc: true,
getDepsOptimizer: (ssr: boolean) => getDepsOptimizer(config, ssr),
shouldExternalize:
isBuild && config.build.ssr && config.ssr?.format !== 'cjs'
isBuild && config.build.ssr
? (id, importer) => shouldExternalizeForSSR(id, importer, config)
: undefined,
}),
Expand Down
33 changes: 0 additions & 33 deletions packages/vite/src/node/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
resolveServerUrls,
} from '../utils'
import { ssrLoadModule } from '../ssr/ssrModuleLoader'
import { cjsSsrResolveExternals } from '../ssr/ssrExternal'
import { ssrFixStacktrace, ssrRewriteStacktrace } from '../ssr/ssrStacktrace'
import { ssrTransform } from '../ssr/ssrTransform'
import {
Expand Down Expand Up @@ -290,11 +289,6 @@ export interface ViteDevServer {
* @internal
*/
_importGlobMap: Map<string, { affirmed: string[]; negated: string[] }[]>
/**
* Deps that are externalized
* @internal
*/
_ssrExternals: string[] | null
/**
* @internal
*/
Expand Down Expand Up @@ -400,9 +394,6 @@ export async function _createServer(
if (isDepsOptimizerEnabled(config, true)) {
await initDevSsrDepsOptimizer(config, server)
}
if (config.legacy?.buildSsrCjsExternalHeuristics) {
await updateCjsSsrExternals(server)
}
return ssrLoadModule(
url,
server,
Expand Down Expand Up @@ -508,7 +499,6 @@ export async function _createServer(
return server._restartPromise
},

_ssrExternals: null,
_restartPromise: null,
_importGlobMap: new Map(),
_forceOptimizeOnRestart: false,
Expand Down Expand Up @@ -886,26 +876,3 @@ async function restartServer(server: ViteDevServer) {
bindCLIShortcuts(newServer, shortcutsOptions)
}
}

async function updateCjsSsrExternals(server: ViteDevServer) {
if (!server._ssrExternals) {
let knownImports: string[] = []

// Important! We use the non-ssr optimized deps to find known imports
// Only the explicitly defined deps are optimized during dev SSR, so
// we use the generated list from the scanned deps in regular dev.
// This is part of the v2 externalization heuristics and it is kept
// for backwards compatibility in case user needs to fallback to the
// legacy scheme. It may be removed in a future v3 minor.
const depsOptimizer = getDepsOptimizer(server.config, false) // non-ssr

if (depsOptimizer) {
await depsOptimizer.scanProcessing
knownImports = [
...Object.keys(depsOptimizer.metadata.optimized),
...Object.keys(depsOptimizer.metadata.discovered),
]
}
server._ssrExternals = cjsSsrResolveExternals(server.config, knownImports)
}
}
6 changes: 0 additions & 6 deletions packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts

This file was deleted.

15 changes: 0 additions & 15 deletions packages/vite/src/node/ssr/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { DepOptimizationConfig } from '../optimizer'

export type SSRTarget = 'node' | 'webworker'
export type SSRFormat = 'esm' | 'cjs'

export type SsrDepOptimizationOptions = DepOptimizationConfig

Expand All @@ -14,16 +13,6 @@ export interface SSROptions {
* @default 'node'
*/
target?: SSRTarget
/**
* Define the format for the ssr build. Since Vite v3 the SSR build generates ESM by default.
* `'cjs'` can be selected to generate a CJS build, but it isn't recommended. This option is
* left marked as experimental to give users more time to update to ESM. CJS builds requires
* complex externalization heuristics that aren't present in the ESM format.
* @experimental
* @deprecated
* @default 'esm'
*/
format?: SSRFormat
/**
* Control over which dependencies are optimized during SSR and esbuild options
* During build:
Expand All @@ -37,21 +26,17 @@ export interface SSROptions {

export interface ResolvedSSROptions extends SSROptions {
target: SSRTarget
format: SSRFormat
optimizeDeps: SsrDepOptimizationOptions
}

export function resolveSSROptions(
ssr: SSROptions | undefined,
preserveSymlinks: boolean,
buildSsrCjsExternalHeuristics?: boolean,
): ResolvedSSROptions {
ssr ??= {}
const optimizeDeps = ssr.optimizeDeps ?? {}
const format: SSRFormat = buildSsrCjsExternalHeuristics ? 'cjs' : 'esm'
const target: SSRTarget = 'node'
return {
format,
target,
...ssr,
optimizeDeps: {
Expand Down
Loading

0 comments on commit 2f60b9e

Please sign in to comment.