Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server): add warmupRequest api #14787

Merged
merged 3 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 2 additions & 19 deletions packages/vite/src/node/plugins/importAnalysis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,8 @@ import type { ResolvedConfig } from '../config'
import type { Plugin } from '../plugin'
import { shouldExternalizeForSSR } from '../ssr/ssrExternal'
import { getDepsOptimizer, optimizedDepNeedsInterop } from '../optimizer'
import { ERR_CLOSED_SERVER } from '../server/pluginContainer'
import { checkPublicFile, urlRE } from './asset'
import {
ERR_OUTDATED_OPTIMIZED_DEP,
throwOutdatedRequest,
} from './optimizedDeps'
import { throwOutdatedRequest } from './optimizedDeps'
import { isCSSRequest, isDirectCSSRequest } from './css'
import { browserExternalId } from './resolve'
import { serializeDefine } from './define'
Expand Down Expand Up @@ -625,20 +621,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin {
// These requests will also be registered in transformRequest to be awaited
// by the deps optimizer
const url = removeImportQuery(hmrUrl)
server.transformRequest(url, { ssr }).catch((e) => {
if (
e?.code === ERR_OUTDATED_OPTIMIZED_DEP ||
e?.code === ERR_CLOSED_SERVER
) {
// these are expected errors
return
}
// Unexpected error, log the issue but avoid an unhandled exception
config.logger.error(`Pre-transform error: ${e.message}`, {
error: e,
timestamp: true,
})
})
server.warmupRequest(url, { ssr })
}
} else if (!importer.startsWith(withTrailingSlash(clientDir))) {
if (!isInNodeModules(importer)) {
Expand Down
25 changes: 24 additions & 1 deletion packages/vite/src/node/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
import { ssrLoadModule } from '../ssr/ssrModuleLoader'
import { ssrFixStacktrace, ssrRewriteStacktrace } from '../ssr/ssrStacktrace'
import { ssrTransform } from '../ssr/ssrTransform'
import { ERR_OUTDATED_OPTIMIZED_DEP } from '../plugins/optimizedDeps'
import {
getDepsOptimizer,
initDepsOptimizer,
Expand All @@ -47,7 +48,7 @@ import type { Logger } from '../logger'
import { printServerUrls } from '../logger'
import { createNoopWatcher, resolveChokidarOptions } from '../watch'
import type { PluginContainer } from './pluginContainer'
import { createPluginContainer } from './pluginContainer'
import { ERR_CLOSED_SERVER, createPluginContainer } from './pluginContainer'
import type { WebSocketServer } from './ws'
import { createWebSocketServer } from './ws'
import { baseMiddleware } from './middlewares/base'
Expand Down Expand Up @@ -231,6 +232,12 @@ export interface ViteDevServer {
url: string,
options?: TransformOptions,
): Promise<TransformResult | null>
/**
* Same as `transformRequest` but only warm up the URLs so the next request
* will already be cached. The function will never throw as it handles and
* reports errors internally.
*/
warmupRequest(url: string, options?: TransformOptions): Promise<void>
/**
* Apply vite built-in HTML transforms and any plugin HTML transforms.
*/
Expand Down Expand Up @@ -403,6 +410,22 @@ export async function _createServer(
transformRequest(url, options) {
return transformRequest(url, server, options)
},
async warmupRequest(url, options) {
await transformRequest(url, server, options).catch((e) => {
if (
e?.code === ERR_OUTDATED_OPTIMIZED_DEP ||
e?.code === ERR_CLOSED_SERVER
) {
// these are expected errors
return
}
// Unexpected error, log the issue but avoid an unhandled exception
server.config.logger.error(`Pre-transform error: ${e.message}`, {
error: e,
timestamp: true,
})
})
},
transformIndexHtml: null!, // to be immediately set
async ssrLoadModule(url, opts?: { fixStacktrace?: boolean }) {
if (isDepsOptimizerEnabled(config, true)) {
Expand Down
20 changes: 2 additions & 18 deletions packages/vite/src/node/server/middlewares/indexHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ import {
unwrapId,
wrapId,
} from '../../utils'
import { ERR_CLOSED_SERVER } from '../pluginContainer'
import { ERR_OUTDATED_OPTIMIZED_DEP } from '../../plugins/optimizedDeps'
import { isCSSRequest } from '../../plugins/css'
import { checkPublicFile } from '../../plugins/asset'
import { getCodeWithSourcemap, injectSourcesContent } from '../sourcemap'
Expand Down Expand Up @@ -422,21 +420,7 @@ export function indexHtmlMiddleware(
function preTransformRequest(server: ViteDevServer, url: string, base: string) {
if (!server.config.server.preTransformRequests) return

url = unwrapId(stripBase(url, base))

// transform all url as non-ssr as html includes client-side assets only
server.transformRequest(url).catch((e) => {
if (
e?.code === ERR_OUTDATED_OPTIMIZED_DEP ||
e?.code === ERR_CLOSED_SERVER
) {
// these are expected errors
return
}
// Unexpected error, log the issue but avoid an unhandled exception
server.config.logger.error(`Pre-transform error: ${e.message}`, {
error: e,
timestamp: true,
})
})
url = unwrapId(stripBase(url, base))
server.warmupRequest(url)
}
17 changes: 9 additions & 8 deletions packages/vite/src/node/server/transformRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,7 @@ async function doTransform(
// returns a boolean true is successful, or false if no handling is needed
const softInvalidatedTransformResult =
module &&
(await handleModuleSoftInvalidation(
module,
ssr,
timestamp,
server.config.base,
))
(await handleModuleSoftInvalidation(module, ssr, timestamp, server))
if (softInvalidatedTransformResult) {
debugCache?.(`[memory-hmr] ${prettyUrl}`)
return softInvalidatedTransformResult
Expand Down Expand Up @@ -384,7 +379,7 @@ async function handleModuleSoftInvalidation(
mod: ModuleNode,
ssr: boolean,
timestamp: number,
base: string,
server: ViteDevServer,
) {
const transformResult = ssr ? mod.ssrInvalidationState : mod.invalidationState

Expand Down Expand Up @@ -425,7 +420,7 @@ async function handleModuleSoftInvalidation(
const urlWithoutTimestamp = removeTimestampQuery(rawUrl)
// hmrUrl must be derived the same way as importAnalysis
const hmrUrl = unwrapId(
stripBase(removeImportQuery(urlWithoutTimestamp), base),
stripBase(removeImportQuery(urlWithoutTimestamp), server.config.base),
)
for (const importedMod of mod.clientImportedModules) {
if (importedMod.url !== hmrUrl) continue
Expand All @@ -438,6 +433,12 @@ async function handleModuleSoftInvalidation(
const end = hasQuotes ? imp.e - 1 : imp.e
s.overwrite(start, end, replacedUrl)
}

if (imp.d === -1 && server.config.server.preTransformRequests) {
// pre-transform known direct imports
server.warmupRequest(hmrUrl, { ssr })
}

break
}
}
Expand Down
38 changes: 21 additions & 17 deletions packages/vite/src/node/server/warmup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,31 @@ export function warmupFiles(server: ViteDevServer): void {
}

async function warmupFile(server: ViteDevServer, file: string, ssr: boolean) {
try {
// transform html with the `transformIndexHtml` hook as Vite internals would
// pre-transform the imported JS modules linked. this may cause `transformIndexHtml`
// plugins to be executed twice, but that's probably fine.
if (file.endsWith('.html')) {
const url = htmlFileToUrl(file, server.config.root)
if (url) {
// transform html with the `transformIndexHtml` hook as Vite internals would
// pre-transform the imported JS modules linked. this may cause `transformIndexHtml`
// plugins to be executed twice, but that's probably fine.
if (file.endsWith('.html')) {
const url = htmlFileToUrl(file, server.config.root)
if (url) {
try {
const html = await fs.readFile(file, 'utf-8')
await server.transformIndexHtml(url, html)
} catch (e) {
// Unexpected error, log the issue but avoid an unhandled exception
server.config.logger.error(
`Pre-transform error (${colors.cyan(file)}): ${e.message}`,
{
error: e,
timestamp: true,
},
)
}
}
// for other files, pass it through `transformRequest`. this is what Vite uses
// for it's `server.preTransformRequests` option.
else {
const url = fileToUrl(file, server.config.root)
await server.transformRequest(url, { ssr })
}
} catch (e) {
server.config.logger.error(
colors.red(`Failed to warm up ${colors.cyan(file)}:\n`) + e.message,
)
}
// for other files, pass it through `transformRequest` with warmup
else {
const url = fileToUrl(file, server.config.root)
await server.warmupRequest(url, { ssr })
}
}

Expand Down