Skip to content

Commit

Permalink
feat: webworker ssr target (vitejs#3151)
Browse files Browse the repository at this point in the history
  • Loading branch information
patak-dev authored and fi3ework committed May 22, 2021
1 parent 75e5854 commit 70c862d
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 41 deletions.
7 changes: 7 additions & 0 deletions docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -616,3 +616,10 @@ SSR options may be adjusted in minor releases.
- **Type:** `string[]`

Prevent listed dependencies from being externalized for SSR.

### ssr.target

- **Type:** `'node' | 'webworker'`
- **Default:** `node`

Build target for the SSR server.
4 changes: 4 additions & 0 deletions docs/guide/ssr.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,7 @@ export function mySSRPlugin() {
}
}
```
## SSR Target
The default target for the SSR build is a node environment, but you can also run the server in a Web Worker. Packages entry resolution is different for each platform. You can configure the target to be Web Worker using the `ssr.target` set to `'webworker'`.
9 changes: 9 additions & 0 deletions packages/vite/src/node/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,17 @@ export interface UserConfig {
dedupe?: string[]
}

export type SSRTarget = 'node' | 'webworker'

export interface SSROptions {
external?: string[]
noExternal?: 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
}

export interface InlineConfig extends UserConfig {
Expand Down Expand Up @@ -348,6 +356,7 @@ export async function resolveConfig(
root: resolvedRoot,
isProduction,
isBuild: command === 'build',
ssrTarget: resolved.ssr?.target,
asSrc: true,
preferRelative: false,
tryIndex: true,
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export async function resolvePlugins(
root: config.root,
isProduction: config.isProduction,
isBuild,
ssrTarget: config.ssr?.target,
asSrc: true
}),
htmlInlineScriptProxyPlugin(),
Expand Down
91 changes: 50 additions & 41 deletions packages/vite/src/node/plugins/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
cleanUrl,
slash
} from '../utils'
import { ViteDevServer } from '..'
import { ViteDevServer, SSRTarget } from '..'
import { createFilter } from '@rollup/pluginutils'
import { PartialResolvedId } from 'rollup'
import { resolve as _resolveExports } from 'resolve.exports'
Expand All @@ -50,6 +50,7 @@ export interface InternalResolveOptions extends ResolveOptions {
root: string
isBuild: boolean
isProduction: boolean
ssrTarget?: SSRTarget
/**
* src code mode also attempts the following:
* - resolving /xxx as URLs
Expand All @@ -63,7 +64,13 @@ export interface InternalResolveOptions extends ResolveOptions {
}

export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
const { root, isProduction, asSrc, preferRelative = false } = baseOptions
const {
root,
isProduction,
asSrc,
ssrTarget,
preferRelative = false
} = baseOptions
const requireOptions: InternalResolveOptions = {
...baseOptions,
isRequire: true
Expand All @@ -87,6 +94,8 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
return
}

const targetWeb = !ssr || ssrTarget === 'webworker'

// this is passed by @rollup/plugin-commonjs
const isRequire =
resolveOpts &&
Expand Down Expand Up @@ -145,7 +154,7 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
}

if (
!ssr &&
targetWeb &&
(res = tryResolveBrowserMapping(fsPath, importer, options, true))
) {
return res
Expand Down Expand Up @@ -197,13 +206,13 @@ export function resolvePlugin(baseOptions: InternalResolveOptions): Plugin {
}

if (
!ssr &&
targetWeb &&
(res = tryResolveBrowserMapping(id, importer, options, false))
) {
return res
}

if ((res = tryNodeResolve(id, importer, options, ssr, server))) {
if ((res = tryNodeResolve(id, importer, options, targetWeb, server))) {
return res
}

Expand Down Expand Up @@ -252,7 +261,7 @@ function tryFsResolve(
fsPath: string,
options: InternalResolveOptions,
tryIndex = true,
ssr?: boolean
targetWeb = true
): string | undefined {
let file = fsPath
let postfix = ''
Expand All @@ -273,7 +282,7 @@ function tryFsResolve(
postfix,
options,
false,
ssr,
targetWeb,
options.tryPrefix
))
) {
Expand All @@ -287,7 +296,7 @@ function tryFsResolve(
postfix,
options,
false,
ssr,
targetWeb,
options.tryPrefix
))
) {
Expand All @@ -301,7 +310,7 @@ function tryFsResolve(
postfix,
options,
tryIndex,
ssr,
targetWeb,
options.tryPrefix
))
) {
Expand All @@ -314,7 +323,7 @@ function tryResolveFile(
postfix: string,
options: InternalResolveOptions,
tryIndex: boolean,
ssr?: boolean,
targetWeb: boolean,
tryPrefix?: string
): string | undefined {
let isReadable = false
Expand All @@ -333,15 +342,15 @@ function tryResolveFile(
if (fs.existsSync(pkgPath)) {
// path points to a node package
const pkg = loadPackageData(pkgPath)
return resolvePackageEntry(file, pkg, options, ssr)
return resolvePackageEntry(file, pkg, options, targetWeb)
}
const index = tryFsResolve(file + '/index', options)
if (index) return index + postfix
}
}
if (tryPrefix) {
const prefixed = `${path.dirname(file)}/${tryPrefix}${path.basename(file)}`
return tryResolveFile(prefixed, postfix, options, tryIndex, ssr)
return tryResolveFile(prefixed, postfix, options, tryIndex, targetWeb)
}
}

Expand All @@ -351,7 +360,7 @@ export function tryNodeResolve(
id: string,
importer: string | undefined,
options: InternalResolveOptions,
ssr?: boolean,
targetWeb: boolean,
server?: ViteDevServer
): PartialResolvedId | undefined {
const { root, dedupe, isBuild } = options
Expand All @@ -378,8 +387,8 @@ export function tryNodeResolve(
}

let resolved = deepMatch
? resolveDeepImport(id, pkg, options, ssr)
: resolvePackageEntry(id, pkg, options, ssr)
? resolveDeepImport(id, pkg, options, targetWeb)
: resolvePackageEntry(id, pkg, options, targetWeb)
if (!resolved) {
return
}
Expand Down Expand Up @@ -451,10 +460,10 @@ export function tryOptimizedResolve(
export interface PackageData {
dir: string
hasSideEffects: (id: string) => boolean
resolvedImports: Record<string, string | undefined>
ssrResolvedImports: Record<string, string | undefined>
setResolvedCache: (key: string, entry: string, ssr?: boolean) => void
getResolvedCache: (key: string, ssr?: boolean) => string | undefined
webResolvedImports: Record<string, string | undefined>
nodeResolvedImports: Record<string, string | undefined>
setResolvedCache: (key: string, entry: string, targetWeb: boolean) => void
getResolvedCache: (key: string, targetWeb: boolean) => string | undefined
data: {
[field: string]: any
version: string
Expand Down Expand Up @@ -501,20 +510,20 @@ function loadPackageData(pkgPath: string, cacheKey = pkgPath) {
dir: pkgDir,
data,
hasSideEffects,
resolvedImports: {},
ssrResolvedImports: {},
setResolvedCache(key: string, entry: string, ssr?: boolean) {
if (ssr) {
pkg.ssrResolvedImports[key] = entry
webResolvedImports: {},
nodeResolvedImports: {},
setResolvedCache(key: string, entry: string, targetWeb: boolean) {
if (targetWeb) {
pkg.webResolvedImports[key] = entry
} else {
pkg.resolvedImports[key] = entry
pkg.nodeResolvedImports[key] = entry
}
},
getResolvedCache(key: string, ssr?: boolean) {
if (ssr) {
return pkg.ssrResolvedImports[key]
getResolvedCache(key: string, targetWeb: boolean) {
if (targetWeb) {
return pkg.webResolvedImports[key]
} else {
return pkg.resolvedImports[key]
return pkg.nodeResolvedImports[key]
}
}
}
Expand All @@ -526,9 +535,9 @@ export function resolvePackageEntry(
id: string,
{ dir, data, setResolvedCache, getResolvedCache }: PackageData,
options: InternalResolveOptions,
ssr?: boolean
targetWeb: boolean
): string | undefined {
const cached = getResolvedCache('.', ssr)
const cached = getResolvedCache('.', targetWeb)
if (cached) {
return cached
}
Expand All @@ -544,7 +553,7 @@ export function resolvePackageEntry(
// This is because .mjs files can technically import .cjs files which would
// make them invalid for pure ESM environments - so if other module/browser
// fields are present, prioritize those instead.
if (!ssr && (!entryPoint || entryPoint.endsWith('.mjs'))) {
if (targetWeb && (!entryPoint || entryPoint.endsWith('.mjs'))) {
// check browser field
// https://github.com/defunctzombie/package-browser-field-spec
const browserEntry =
Expand Down Expand Up @@ -594,7 +603,7 @@ export function resolvePackageEntry(

// resolve object browser field in package.json
const { browser: browserField } = data
if (!ssr && isObject(browserField)) {
if (targetWeb && isObject(browserField)) {
entryPoint = mapWithBrowserField(entryPoint, browserField) || entryPoint
}

Expand All @@ -606,7 +615,7 @@ export function resolvePackageEntry(
debug(
`[package entry] ${chalk.cyan(id)} -> ${chalk.dim(resolvedEntryPoint)}`
)
setResolvedCache('.', resolvedEntryPoint, ssr)
setResolvedCache('.', resolvedEntryPoint, targetWeb)
return resolvedEntryPoint
} else {
throw new Error(
Expand Down Expand Up @@ -638,17 +647,17 @@ function resolveExports(
function resolveDeepImport(
id: string,
{
resolvedImports,
webResolvedImports,
setResolvedCache,
getResolvedCache,
dir,
data
}: PackageData,
options: InternalResolveOptions,
ssr?: boolean
targetWeb: boolean
): string | undefined {
id = '.' + id.slice(data.name.length)
const cache = getResolvedCache(id, ssr)
const cache = getResolvedCache(id, targetWeb)
if (cache) {
return cache
}
Expand All @@ -670,12 +679,12 @@ function resolveDeepImport(
`${path.join(dir, 'package.json')}.`
)
}
} else if (!ssr && isObject(browserField)) {
} else if (targetWeb && isObject(browserField)) {
const mapped = mapWithBrowserField(relativeId, browserField)
if (mapped) {
relativeId = mapped
} else if (mapped === false) {
return (resolvedImports[id] = browserExternalId)
return (webResolvedImports[id] = browserExternalId)
}
}

Expand All @@ -684,12 +693,12 @@ function resolveDeepImport(
path.join(dir, relativeId),
options,
!exportsField, // try index only if no exports field
ssr
targetWeb
)
if (resolved) {
isDebug &&
debug(`[node/deep-import] ${chalk.cyan(id)} -> ${chalk.dim(resolved)}`)
setResolvedCache(id, resolved, ssr)
setResolvedCache(id, resolved, targetWeb)
return resolved
}
}
Expand Down

0 comments on commit 70c862d

Please sign in to comment.