From 520139cdff88ae3a0bf89692133cce3e453cb29a Mon Sep 17 00:00:00 2001 From: patak Date: Wed, 18 Oct 2023 10:31:54 +0200 Subject: [PATCH] feat(ssr): backport ssr.resolve.conditions and ssr.resolve.externalConditions (#14498) (#14668) Co-authored-by: Marc MacLeod --- docs/config/ssr-options.md | 16 +++++ docs/guide/ssr.md | 4 ++ packages/vite/src/node/plugins/resolve.ts | 7 ++ packages/vite/src/node/ssr/index.ts | 20 ++++++ packages/vite/src/node/ssr/ssrExternal.ts | 3 + packages/vite/src/node/ssr/ssrModuleLoader.ts | 8 ++- playground/ssr-conditions/__tests__/serve.ts | 35 ++++++++++ .../__tests__/ssr-conditions.spec.ts | 27 +++++++ playground/ssr-conditions/external/browser.js | 1 + playground/ssr-conditions/external/default.js | 1 + playground/ssr-conditions/external/edge.js | 1 + playground/ssr-conditions/external/node.js | 1 + .../ssr-conditions/external/node.unbundled.js | 1 + .../ssr-conditions/external/package.json | 21 ++++++ playground/ssr-conditions/index.html | 29 ++++++++ .../ssr-conditions/no-external/browser.js | 1 + .../ssr-conditions/no-external/default.js | 1 + playground/ssr-conditions/no-external/edge.js | 1 + playground/ssr-conditions/no-external/node.js | 1 + .../no-external/node.unbundled.js | 1 + .../ssr-conditions/no-external/package.json | 21 ++++++ playground/ssr-conditions/package.json | 18 +++++ playground/ssr-conditions/server.js | 70 +++++++++++++++++++ playground/ssr-conditions/src/app.js | 16 +++++ playground/ssr-conditions/vite.config.js | 12 ++++ .../__tests__/ssr-webworker.spec.ts | 12 ++++ .../ssr-webworker/browser-exports/browser.js | 1 + .../ssr-webworker/browser-exports/node.js | 1 + .../browser-exports/package.json | 12 ++++ playground/ssr-webworker/package.json | 4 +- playground/ssr-webworker/src/entry-worker.jsx | 4 ++ playground/ssr-webworker/vite.config.js | 1 + .../ssr-webworker/worker-exports/browser.js | 2 + .../ssr-webworker/worker-exports/node.js | 1 + .../ssr-webworker/worker-exports/package.json | 13 ++++ .../ssr-webworker/worker-exports/worker.js | 1 + playground/test-utils.ts | 2 + pnpm-lock.yaml | 47 +++++++++++++ 38 files changed, 416 insertions(+), 2 deletions(-) create mode 100644 playground/ssr-conditions/__tests__/serve.ts create mode 100644 playground/ssr-conditions/__tests__/ssr-conditions.spec.ts create mode 100644 playground/ssr-conditions/external/browser.js create mode 100644 playground/ssr-conditions/external/default.js create mode 100644 playground/ssr-conditions/external/edge.js create mode 100644 playground/ssr-conditions/external/node.js create mode 100644 playground/ssr-conditions/external/node.unbundled.js create mode 100644 playground/ssr-conditions/external/package.json create mode 100644 playground/ssr-conditions/index.html create mode 100644 playground/ssr-conditions/no-external/browser.js create mode 100644 playground/ssr-conditions/no-external/default.js create mode 100644 playground/ssr-conditions/no-external/edge.js create mode 100644 playground/ssr-conditions/no-external/node.js create mode 100644 playground/ssr-conditions/no-external/node.unbundled.js create mode 100644 playground/ssr-conditions/no-external/package.json create mode 100644 playground/ssr-conditions/package.json create mode 100644 playground/ssr-conditions/server.js create mode 100644 playground/ssr-conditions/src/app.js create mode 100644 playground/ssr-conditions/vite.config.js create mode 100644 playground/ssr-webworker/browser-exports/browser.js create mode 100644 playground/ssr-webworker/browser-exports/node.js create mode 100644 playground/ssr-webworker/browser-exports/package.json create mode 100644 playground/ssr-webworker/worker-exports/browser.js create mode 100644 playground/ssr-webworker/worker-exports/node.js create mode 100644 playground/ssr-webworker/worker-exports/package.json create mode 100644 playground/ssr-webworker/worker-exports/worker.js diff --git a/docs/config/ssr-options.md b/docs/config/ssr-options.md index d8b65f1ea1c910..fb120569fabbc7 100644 --- a/docs/config/ssr-options.md +++ b/docs/config/ssr-options.md @@ -29,3 +29,19 @@ Build target for the SSR server. - **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. + +## ssr.resolve.conditions + +- **Type:** `string[]` +- **Related:** [Resolve Conditions](./shared-options.md#resolve-conditions) + +Defaults to the the root [`resolve.conditions`](./shared-options.md#resolve-conditions). + +These conditions are used in the plugin pipeline, and only affect non-externalized dependencies during the SSR build. Use `ssr.resolve.externalConditions` to affect externalized imports. + +## ssr.resolve.externalConditions + +- **Type:** `string[]` +- **Default:** `[]` + +Conditions that are used during ssr import (including `ssrLoadModule`) of externalized dependencies. diff --git a/docs/guide/ssr.md b/docs/guide/ssr.md index f70b0385a4096a..5828637fb4acb6 100644 --- a/docs/guide/ssr.md +++ b/docs/guide/ssr.md @@ -259,6 +259,10 @@ In some cases like `webworker` runtimes, you might want to bundle your SSR build - Treat all dependencies as `noExternal` - Throw an error if any Node.js built-ins are imported +## SSR Resolve Conditions + +By default package entry resolution will use the conditions set in [`resolve.conditions`](../config/shared-options.md#resolve-conditions) for the SSR build. You can use [`ssr.resolve.conditions`](../config/ssr-options.md#ssr-resolve-conditions) and [`ssr.resolve.externalConditions`](../config/ssr-options.md#ssr-resolve-externalconditions) to customize this behavior. + ## Vite CLI The CLI commands `$ vite dev` and `$ vite preview` can also be used for SSR apps. You can add your SSR middlewares to the development server with [`configureServer`](/guide/api-plugin#configureserver) and to the preview server with [`configurePreviewServer`](/guide/api-plugin#configurepreviewserver). diff --git a/packages/vite/src/node/plugins/resolve.ts b/packages/vite/src/node/plugins/resolve.ts index 5932b720875bef..1bf7b504d6e1f3 100644 --- a/packages/vite/src/node/plugins/resolve.ts +++ b/packages/vite/src/node/plugins/resolve.ts @@ -173,10 +173,17 @@ export function resolvePlugin(resolveOptions: InternalResolveOptions): Plugin { const isRequire: boolean = resolveOpts?.custom?.['node-resolve']?.isRequire ?? false + // end user can configure different conditions for ssr and client. + // falls back to client conditions if no ssr conditions supplied + const ssrConditions = + resolveOptions.ssrConfig?.resolve?.conditions || + resolveOptions.conditions + const options: InternalResolveOptions = { isRequire, ...resolveOptions, scan: resolveOpts?.scan ?? resolveOptions.scan, + conditions: ssr ? ssrConditions : resolveOptions.conditions, } const resolvedImports = resolveSubpathImports( diff --git a/packages/vite/src/node/ssr/index.ts b/packages/vite/src/node/ssr/index.ts index ba4597177170c0..8a17ed8625ca53 100644 --- a/packages/vite/src/node/ssr/index.ts +++ b/packages/vite/src/node/ssr/index.ts @@ -8,12 +8,14 @@ export type SsrDepOptimizationOptions = DepOptimizationConfig export interface SSROptions { noExternal?: string | RegExp | (string | RegExp)[] | true external?: string[] + /** * Define the target for the ssr build. The browser field in package.json * is ignored for node but used if webworker is the target * @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 @@ -33,6 +35,24 @@ export interface SSROptions { * @experimental */ optimizeDeps?: SsrDepOptimizationOptions + + resolve?: { + /** + * Conditions that are used in the plugin pipeline. The default value is the root config's `resolve.conditions`. + * + * Use this to override the default ssr conditions for the ssr build. + * + * @default rootConfig.resolve.conditions + */ + conditions?: string[] + + /** + * Conditions that are used during ssr import (including `ssrLoadModule`) of externalized dependencies. + * + * @default [] + */ + externalConditions?: string[] + } } export interface ResolvedSSROptions extends SSROptions { diff --git a/packages/vite/src/node/ssr/ssrExternal.ts b/packages/vite/src/node/ssr/ssrExternal.ts index 99001f3614f330..6fb0ce28805b13 100644 --- a/packages/vite/src/node/ssr/ssrExternal.ts +++ b/packages/vite/src/node/ssr/ssrExternal.ts @@ -119,11 +119,14 @@ export function createIsConfiguredAsSsrExternal( typeof noExternal !== 'boolean' && createFilter(undefined, noExternal, { resolve: false }) + const targetConditions = config.ssr.resolve?.externalConditions || [] + const resolveOptions: InternalResolveOptions = { ...config.resolve, root, isProduction: false, isBuild: true, + conditions: targetConditions, } const isExternalizable = ( diff --git a/packages/vite/src/node/ssr/ssrModuleLoader.ts b/packages/vite/src/node/ssr/ssrModuleLoader.ts index 129d91b5f0a428..90375c8498f3ba 100644 --- a/packages/vite/src/node/ssr/ssrModuleLoader.ts +++ b/packages/vite/src/node/ssr/ssrModuleLoader.ts @@ -123,19 +123,23 @@ async function instantiateModule( isProduction, resolve: { dedupe, preserveSymlinks }, root, + ssr, } = server.config + const overrideConditions = ssr.resolve?.externalConditions || [] + const resolveOptions: InternalResolveOptionsWithOverrideConditions = { mainFields: ['main'], browserField: true, conditions: [], - overrideConditions: ['production', 'development'], + overrideConditions: [...overrideConditions, 'production', 'development'], extensions: ['.js', '.cjs', '.json'], dedupe, preserveSymlinks, isBuild: false, isProduction, root, + ssrConfig: ssr, } // Since dynamic imports can happen in parallel, we need to @@ -281,6 +285,8 @@ async function nodeImport( ? { ...resolveOptions, tryEsmOnly: true } : resolveOptions, false, + undefined, + true, ) if (!resolved) { const err: any = new Error( diff --git a/playground/ssr-conditions/__tests__/serve.ts b/playground/ssr-conditions/__tests__/serve.ts new file mode 100644 index 00000000000000..5e0546db2bd1a5 --- /dev/null +++ b/playground/ssr-conditions/__tests__/serve.ts @@ -0,0 +1,35 @@ +// this is automatically detected by playground/vitestSetup.ts and will replace +// the default e2e test serve behavior + +import path from 'node:path' +import kill from 'kill-port' +import { hmrPorts, ports, rootDir } from '~utils' + +export const port = ports['ssr-conditions'] + +export async function serve(): Promise<{ close(): Promise }> { + await kill(port) + + const { createServer } = await import(path.resolve(rootDir, 'server.js')) + const { app, vite } = await createServer(rootDir, hmrPorts['ssr-conditions']) + + return new Promise((resolve, reject) => { + try { + const server = app.listen(port, () => { + resolve({ + // for test teardown + async close() { + await new Promise((resolve) => { + server.close(resolve) + }) + if (vite) { + await vite.close() + } + }, + }) + }) + } catch (e) { + reject(e) + } + }) +} diff --git a/playground/ssr-conditions/__tests__/ssr-conditions.spec.ts b/playground/ssr-conditions/__tests__/ssr-conditions.spec.ts new file mode 100644 index 00000000000000..76ec36363f1309 --- /dev/null +++ b/playground/ssr-conditions/__tests__/ssr-conditions.spec.ts @@ -0,0 +1,27 @@ +import { expect, test } from 'vitest' +import { port } from './serve' +import { page } from '~utils' + +const url = `http://localhost:${port}` + +test('ssr.resolve.conditions affect non-externalized imports during ssr', async () => { + await page.goto(url) + expect(await page.textContent('.no-external-react-server')).toMatch( + 'node.unbundled.js', + ) +}) + +test('ssr.resolve.externalConditions affect externalized imports during ssr', async () => { + await page.goto(url) + expect(await page.textContent('.external-react-server')).toMatch('edge.js') +}) + +test('ssr.resolve settings do not affect non-ssr imports', async () => { + await page.goto(url) + expect(await page.textContent('.browser-no-external-react-server')).toMatch( + 'default.js', + ) + expect(await page.textContent('.browser-external-react-server')).toMatch( + 'default.js', + ) +}) diff --git a/playground/ssr-conditions/external/browser.js b/playground/ssr-conditions/external/browser.js new file mode 100644 index 00000000000000..a02fa8e63243a7 --- /dev/null +++ b/playground/ssr-conditions/external/browser.js @@ -0,0 +1 @@ +export default 'browser.js' diff --git a/playground/ssr-conditions/external/default.js b/playground/ssr-conditions/external/default.js new file mode 100644 index 00000000000000..6d647f59df1b54 --- /dev/null +++ b/playground/ssr-conditions/external/default.js @@ -0,0 +1 @@ +export default 'default.js' diff --git a/playground/ssr-conditions/external/edge.js b/playground/ssr-conditions/external/edge.js new file mode 100644 index 00000000000000..358f21d00905b2 --- /dev/null +++ b/playground/ssr-conditions/external/edge.js @@ -0,0 +1 @@ +export default 'edge.js' diff --git a/playground/ssr-conditions/external/node.js b/playground/ssr-conditions/external/node.js new file mode 100644 index 00000000000000..758a33e2709d32 --- /dev/null +++ b/playground/ssr-conditions/external/node.js @@ -0,0 +1 @@ +export default 'node.js' diff --git a/playground/ssr-conditions/external/node.unbundled.js b/playground/ssr-conditions/external/node.unbundled.js new file mode 100644 index 00000000000000..5ea769de6bd97f --- /dev/null +++ b/playground/ssr-conditions/external/node.unbundled.js @@ -0,0 +1 @@ +export default 'node.unbundled.js' diff --git a/playground/ssr-conditions/external/package.json b/playground/ssr-conditions/external/package.json new file mode 100644 index 00000000000000..55b77e3670c375 --- /dev/null +++ b/playground/ssr-conditions/external/package.json @@ -0,0 +1,21 @@ +{ + "name": "@vitejs/test-ssr-conditions-external", + "private": true, + "version": "0.0.0", + "type": "module", + "exports": { + "./server": { + "react-server": { + "workerd": "./edge.js", + "deno": "./browser.js", + "node": { + "webpack": "./node.js", + "default": "./node.unbundled.js" + }, + "edge-light": "./edge.js", + "browser": "./browser.js" + }, + "default": "./default.js" + } + } +} diff --git a/playground/ssr-conditions/index.html b/playground/ssr-conditions/index.html new file mode 100644 index 00000000000000..d2fec18916c81f --- /dev/null +++ b/playground/ssr-conditions/index.html @@ -0,0 +1,29 @@ + + + + + + SSR Resolve Conditions + + +

SSR Resolve Conditions

+
+ + + + diff --git a/playground/ssr-conditions/no-external/browser.js b/playground/ssr-conditions/no-external/browser.js new file mode 100644 index 00000000000000..a02fa8e63243a7 --- /dev/null +++ b/playground/ssr-conditions/no-external/browser.js @@ -0,0 +1 @@ +export default 'browser.js' diff --git a/playground/ssr-conditions/no-external/default.js b/playground/ssr-conditions/no-external/default.js new file mode 100644 index 00000000000000..6d647f59df1b54 --- /dev/null +++ b/playground/ssr-conditions/no-external/default.js @@ -0,0 +1 @@ +export default 'default.js' diff --git a/playground/ssr-conditions/no-external/edge.js b/playground/ssr-conditions/no-external/edge.js new file mode 100644 index 00000000000000..358f21d00905b2 --- /dev/null +++ b/playground/ssr-conditions/no-external/edge.js @@ -0,0 +1 @@ +export default 'edge.js' diff --git a/playground/ssr-conditions/no-external/node.js b/playground/ssr-conditions/no-external/node.js new file mode 100644 index 00000000000000..758a33e2709d32 --- /dev/null +++ b/playground/ssr-conditions/no-external/node.js @@ -0,0 +1 @@ +export default 'node.js' diff --git a/playground/ssr-conditions/no-external/node.unbundled.js b/playground/ssr-conditions/no-external/node.unbundled.js new file mode 100644 index 00000000000000..5ea769de6bd97f --- /dev/null +++ b/playground/ssr-conditions/no-external/node.unbundled.js @@ -0,0 +1 @@ +export default 'node.unbundled.js' diff --git a/playground/ssr-conditions/no-external/package.json b/playground/ssr-conditions/no-external/package.json new file mode 100644 index 00000000000000..45b1d5f706a286 --- /dev/null +++ b/playground/ssr-conditions/no-external/package.json @@ -0,0 +1,21 @@ +{ + "name": "@vitejs/test-ssr-conditions-no-external", + "private": true, + "version": "0.0.0", + "type": "module", + "exports": { + "./server": { + "react-server": { + "workerd": "./edge.js", + "deno": "./browser.js", + "node": { + "webpack": "./node.js", + "default": "./node.unbundled.js" + }, + "edge-light": "./edge.js", + "browser": "./browser.js" + }, + "default": "./default.js" + } + } +} diff --git a/playground/ssr-conditions/package.json b/playground/ssr-conditions/package.json new file mode 100644 index 00000000000000..f30e73cb1731de --- /dev/null +++ b/playground/ssr-conditions/package.json @@ -0,0 +1,18 @@ +{ + "name": "@vitejs/test-ssr-conditions", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "node server", + "serve": "NODE_ENV=production node server", + "debug": "node --inspect-brk server" + }, + "dependencies": { + "@vitejs/test-ssr-conditions-external": "file:./external", + "@vitejs/test-ssr-conditions-no-external": "file:./no-external" + }, + "devDependencies": { + "express": "^4.18.2" + } +} diff --git a/playground/ssr-conditions/server.js b/playground/ssr-conditions/server.js new file mode 100644 index 00000000000000..aa26dfb0cb8607 --- /dev/null +++ b/playground/ssr-conditions/server.js @@ -0,0 +1,70 @@ +import fs from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import express from 'express' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const isTest = process.env.VITEST + +export async function createServer(root = process.cwd(), hmrPort) { + const resolve = (p) => path.resolve(__dirname, p) + + const app = express() + + /** + * @type {import('vite').ViteDevServer} + */ + const vite = await ( + await import('vite') + ).createServer({ + root, + logLevel: isTest ? 'error' : 'info', + server: { + middlewareMode: true, + watch: { + // During tests we edit the files too fast and sometimes chokidar + // misses change events, so enforce polling for consistency + usePolling: true, + interval: 100, + }, + hmr: { + port: hmrPort, + }, + }, + appType: 'custom', + }) + + app.use(vite.middlewares) + + app.use('*', async (req, res) => { + try { + const url = req.originalUrl + + let template + template = fs.readFileSync(resolve('index.html'), 'utf-8') + template = await vite.transformIndexHtml(url, template) + const render = (await vite.ssrLoadModule('/src/app.js')).render + + const appHtml = await render(url, __dirname) + + const html = template.replace(``, appHtml) + + res.status(200).set({ 'Content-Type': 'text/html' }).end(html) + } catch (e) { + vite && vite.ssrFixStacktrace(e) + console.log(e.stack) + res.status(500).end(e.stack) + } + }) + + return { app, vite } +} + +if (!isTest) { + createServer().then(({ app }) => + app.listen(5173, () => { + console.log('http://localhost:5173') + }), + ) +} diff --git a/playground/ssr-conditions/src/app.js b/playground/ssr-conditions/src/app.js new file mode 100644 index 00000000000000..43f109c37ea7a9 --- /dev/null +++ b/playground/ssr-conditions/src/app.js @@ -0,0 +1,16 @@ +import noExternalReactServerMessage from '@vitejs/test-ssr-conditions-no-external/server' +import externalReactServerMessage from '@vitejs/test-ssr-conditions-external/server' + +export async function render(url) { + let html = '' + + html += `\n

${noExternalReactServerMessage}

` + + html += `\n

` + + html += `\n

${externalReactServerMessage}

` + + html += `\n

` + + return html + '\n' +} diff --git a/playground/ssr-conditions/vite.config.js b/playground/ssr-conditions/vite.config.js new file mode 100644 index 00000000000000..41727adaf5f811 --- /dev/null +++ b/playground/ssr-conditions/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' + +export default defineConfig({ + ssr: { + external: ['@vitejs/test-ssr-conditions-external'], + noExternal: ['@vitejs/test-ssr-conditions-no-external'], + resolve: { + conditions: ['react-server'], + externalConditions: ['workerd', 'react-server'], + }, + }, +}) diff --git a/playground/ssr-webworker/__tests__/ssr-webworker.spec.ts b/playground/ssr-webworker/__tests__/ssr-webworker.spec.ts index e215abe862825b..bd0bc25f3074f8 100644 --- a/playground/ssr-webworker/__tests__/ssr-webworker.spec.ts +++ b/playground/ssr-webworker/__tests__/ssr-webworker.spec.ts @@ -11,6 +11,18 @@ test('/', async () => { expect(await page.textContent('.external')).toMatch('object') }) +test('supports resolve.conditions', async () => { + await page.goto(url) + expect(await page.textContent('.worker-exports')).toMatch('[success] worker') +}) + +test('respects browser export', async () => { + await page.goto(url) + expect(await page.textContent('.browser-exports')).toMatch( + '[success] browser', + ) +}) + test.runIf(isBuild)('inlineDynamicImports', () => { const dynamicJsContent = findAssetFile(/dynamic-\w+\.js/, 'worker') expect(dynamicJsContent).toBe('') diff --git a/playground/ssr-webworker/browser-exports/browser.js b/playground/ssr-webworker/browser-exports/browser.js new file mode 100644 index 00000000000000..a2f54551f2dc4a --- /dev/null +++ b/playground/ssr-webworker/browser-exports/browser.js @@ -0,0 +1 @@ +export default '[success] browser' diff --git a/playground/ssr-webworker/browser-exports/node.js b/playground/ssr-webworker/browser-exports/node.js new file mode 100644 index 00000000000000..b55d59fc6c4b95 --- /dev/null +++ b/playground/ssr-webworker/browser-exports/node.js @@ -0,0 +1 @@ +export default '[fail] should not load me' diff --git a/playground/ssr-webworker/browser-exports/package.json b/playground/ssr-webworker/browser-exports/package.json new file mode 100644 index 00000000000000..daabadafafc095 --- /dev/null +++ b/playground/ssr-webworker/browser-exports/package.json @@ -0,0 +1,12 @@ +{ + "name": "@vitejs/test-browser-exports", + "private": true, + "version": "0.0.0", + "exports": { + ".": { + "browser": "./browser.js", + "node": "./node.js", + "default": "./node.js" + } + } +} diff --git a/playground/ssr-webworker/package.json b/playground/ssr-webworker/package.json index 6be45e0d653668..41ca845b7e8476 100644 --- a/playground/ssr-webworker/package.json +++ b/playground/ssr-webworker/package.json @@ -8,7 +8,9 @@ "build:worker": "vite build --ssr src/entry-worker.jsx --outDir dist/worker" }, "dependencies": { - "react": "^18.2.0" + "react": "^18.2.0", + "@vitejs/test-browser-exports": "file:./browser-exports", + "@vitejs/test-worker-exports": "file:./worker-exports" }, "devDependencies": { "miniflare": "^1.4.1", diff --git a/playground/ssr-webworker/src/entry-worker.jsx b/playground/ssr-webworker/src/entry-worker.jsx index 9210d7e708e0d7..2b58c6f17a6e0c 100644 --- a/playground/ssr-webworker/src/entry-worker.jsx +++ b/playground/ssr-webworker/src/entry-worker.jsx @@ -1,4 +1,6 @@ import { msg as linkedMsg } from '@vitejs/test-resolve-linked' +import browserExportsMessage from '@vitejs/test-browser-exports' +import workerExportsMessage from '@vitejs/test-worker-exports' import React from 'react' let loaded = false @@ -14,6 +16,8 @@ addEventListener('fetch', function (event) {

${linkedMsg}

${typeof React}

dynamic: ${loaded}

+

${browserExportsMessage}

+

${workerExportsMessage}

`, { headers: { diff --git a/playground/ssr-webworker/vite.config.js b/playground/ssr-webworker/vite.config.js index 034cc512606df4..b0b922d7d1b97e 100644 --- a/playground/ssr-webworker/vite.config.js +++ b/playground/ssr-webworker/vite.config.js @@ -6,6 +6,7 @@ export default defineConfig({ }, resolve: { dedupe: ['react'], + conditions: ['worker'], }, ssr: { target: 'webworker', diff --git a/playground/ssr-webworker/worker-exports/browser.js b/playground/ssr-webworker/worker-exports/browser.js new file mode 100644 index 00000000000000..819b0ae6e9556f --- /dev/null +++ b/playground/ssr-webworker/worker-exports/browser.js @@ -0,0 +1,2 @@ +// conditions are set to worker, and worker is higher up in the exports object in package.json, so should be preferred +export default '[fail] should not load me' diff --git a/playground/ssr-webworker/worker-exports/node.js b/playground/ssr-webworker/worker-exports/node.js new file mode 100644 index 00000000000000..b55d59fc6c4b95 --- /dev/null +++ b/playground/ssr-webworker/worker-exports/node.js @@ -0,0 +1 @@ +export default '[fail] should not load me' diff --git a/playground/ssr-webworker/worker-exports/package.json b/playground/ssr-webworker/worker-exports/package.json new file mode 100644 index 00000000000000..c8e1a93163d5c6 --- /dev/null +++ b/playground/ssr-webworker/worker-exports/package.json @@ -0,0 +1,13 @@ +{ + "name": "@vitejs/test-worker-exports", + "private": true, + "version": "0.0.0", + "exports": { + ".": { + "worker": "./worker.js", + "browser": "./browser.js", + "node": "./node.js", + "default": "./node.js" + } + } +} diff --git a/playground/ssr-webworker/worker-exports/worker.js b/playground/ssr-webworker/worker-exports/worker.js new file mode 100644 index 00000000000000..8cd0fa65046d76 --- /dev/null +++ b/playground/ssr-webworker/worker-exports/worker.js @@ -0,0 +1 @@ +export default '[success] worker' diff --git a/playground/test-utils.ts b/playground/test-utils.ts index df68dce9c5e66f..7389d2aed1d7a6 100644 --- a/playground/test-utils.ts +++ b/playground/test-utils.ts @@ -32,6 +32,7 @@ export const ports = { 'ssr-webworker': 9605, 'proxy-hmr': 9606, // not imported but used in `proxy-hmr/vite.config.js` 'proxy-hmr/other-app': 9607, // not imported but used in `proxy-hmr/other-app/vite.config.js` + 'ssr-conditions': 9608, 'css/postcss-caching': 5005, 'css/postcss-plugins-different-dir': 5006, 'css/dynamic-import': 5007, @@ -45,6 +46,7 @@ export const hmrPorts = { 'ssr-noexternal': 24684, 'ssr-pug': 24685, 'css/lightningcss-proxy': 24686, + 'ssr-conditions': 24688, } const hexToNameMap: Record = {} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 02d818d0ed8896..3ec5f476ea6317 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1185,6 +1185,23 @@ importers: specifier: ^4.18.2 version: 4.18.2 + playground/ssr-conditions: + dependencies: + '@vitejs/test-ssr-conditions-external': + specifier: file:./external + version: file:playground/ssr-conditions/external + '@vitejs/test-ssr-conditions-no-external': + specifier: file:./no-external + version: file:playground/ssr-conditions/no-external + devDependencies: + express: + specifier: ^4.18.2 + version: 4.18.2 + + playground/ssr-conditions/external: {} + + playground/ssr-conditions/no-external: {} + playground/ssr-deps: dependencies: '@vitejs/test-css-lib': @@ -1386,6 +1403,12 @@ importers: playground/ssr-webworker: dependencies: + '@vitejs/test-browser-exports': + specifier: file:./browser-exports + version: file:playground/ssr-webworker/browser-exports + '@vitejs/test-worker-exports': + specifier: file:./worker-exports + version: file:playground/ssr-webworker/worker-exports react: specifier: ^18.2.0 version: 18.2.0 @@ -1397,6 +1420,10 @@ importers: specifier: ^1.4.1 version: 1.4.1 + playground/ssr-webworker/browser-exports: {} + + playground/ssr-webworker/worker-exports: {} + playground/tailwind: dependencies: autoprefixer: @@ -11032,6 +11059,16 @@ packages: dep-a: file:playground/preload/dep-a dev: true + file:playground/ssr-conditions/external: + resolution: {directory: playground/ssr-conditions/external, type: directory} + name: '@vitejs/test-ssr-conditions-external' + dev: false + + file:playground/ssr-conditions/no-external: + resolution: {directory: playground/ssr-conditions/no-external, type: directory} + name: '@vitejs/test-ssr-conditions-no-external' + dev: false + file:playground/ssr-deps/css-lib: resolution: {directory: playground/ssr-deps/css-lib, type: directory} name: '@vitejs/test-css-lib' @@ -11166,6 +11203,16 @@ packages: name: '@vitejs/test-resolve-pkg-exports' dev: false + file:playground/ssr-webworker/browser-exports: + resolution: {directory: playground/ssr-webworker/browser-exports, type: directory} + name: '@vitejs/test-browser-exports' + dev: false + + file:playground/ssr-webworker/worker-exports: + resolution: {directory: playground/ssr-webworker/worker-exports, type: directory} + name: '@vitejs/test-worker-exports' + dev: false + file:playground/worker/dep-to-optimize: resolution: {directory: playground/worker/dep-to-optimize, type: directory} name: '@vitejs/test-dep-to-optimize'