mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
feat(nuxt): upgrade nitro + reduce node-specific usage (#22515)
Co-authored-by: Heb <xsh4k3@gmail.com>
This commit is contained in:
parent
7b35a1fe4f
commit
a2f2a4748e
@ -14,7 +14,7 @@ Nuxt automatically scans files inside these directories to register API and serv
|
|||||||
|
|
||||||
Each file should export a default function defined with `defineEventHandler()` or `eventHandler()` (alias).
|
Each file should export a default function defined with `defineEventHandler()` or `eventHandler()` (alias).
|
||||||
|
|
||||||
The handler can directly return JSON data, a `Promise` or use `event.node.res.end()` to send a response.
|
The handler can directly return JSON data, a `Promise`, or use `event.node.res.end()` to send a response.
|
||||||
|
|
||||||
**Example:** Create the `/api/hello` route with `server/api/hello.ts` file:
|
**Example:** Create the `/api/hello` route with `server/api/hello.ts` file:
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ Within your pages, components, and plugins you can use `useRequestEvent` to acce
|
|||||||
const event = useRequestEvent()
|
const event = useRequestEvent()
|
||||||
|
|
||||||
// Get the URL
|
// Get the URL
|
||||||
const url = event.node.req.url
|
const url = event.path
|
||||||
```
|
```
|
||||||
|
|
||||||
::alert{icon=👉}
|
::alert{icon=👉}
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
"happy-dom": "10.10.4",
|
"happy-dom": "10.10.4",
|
||||||
"jiti": "1.19.3",
|
"jiti": "1.19.3",
|
||||||
"markdownlint-cli": "^0.33.0",
|
"markdownlint-cli": "^0.33.0",
|
||||||
"nitropack": "2.5.2",
|
"nitropack": "2.6.0",
|
||||||
"nuxi": "workspace:*",
|
"nuxi": "workspace:*",
|
||||||
"nuxt": "workspace:*",
|
"nuxt": "workspace:*",
|
||||||
"nuxt-vitest": "0.10.2",
|
"nuxt-vitest": "0.10.2",
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
"@types/lodash-es": "4.17.8",
|
"@types/lodash-es": "4.17.8",
|
||||||
"@types/semver": "7.5.0",
|
"@types/semver": "7.5.0",
|
||||||
"lodash-es": "4.17.21",
|
"lodash-es": "4.17.21",
|
||||||
"nitropack": "2.5.2",
|
"nitropack": "2.6.0",
|
||||||
"unbuild": "latest",
|
"unbuild": "latest",
|
||||||
"vite": "4.4.9",
|
"vite": "4.4.9",
|
||||||
"vitest": "0.33.0",
|
"vitest": "0.33.0",
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
"listhen": "1.3.0",
|
"listhen": "1.3.0",
|
||||||
"mlly": "1.4.0",
|
"mlly": "1.4.0",
|
||||||
"mri": "1.2.0",
|
"mri": "1.2.0",
|
||||||
"nitropack": "2.5.2",
|
"nitropack": "2.6.0",
|
||||||
"ohash": "1.1.3",
|
"ohash": "1.1.3",
|
||||||
"pathe": "1.1.1",
|
"pathe": "1.1.1",
|
||||||
"perfect-debounce": "1.0.0",
|
"perfect-debounce": "1.0.0",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { promises as fsp } from 'node:fs'
|
import { promises as fsp } from 'node:fs'
|
||||||
import { join, resolve } from 'pathe'
|
import { join, resolve } from 'pathe'
|
||||||
import { createApp, eventHandler, lazyEventHandler, toNodeListener } from 'h3'
|
import { createApp, eventHandler, lazyEventHandler, send, toNodeListener } from 'h3'
|
||||||
import { listen } from 'listhen'
|
import { listen } from 'listhen'
|
||||||
import type { NuxtAnalyzeMeta } from '@nuxt/schema'
|
import type { NuxtAnalyzeMeta } from '@nuxt/schema'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
@ -77,7 +77,7 @@ export default defineNuxtCommand({
|
|||||||
|
|
||||||
const serveFile = (filePath: string) => lazyEventHandler(async () => {
|
const serveFile = (filePath: string) => lazyEventHandler(async () => {
|
||||||
const contents = await fsp.readFile(filePath, 'utf-8')
|
const contents = await fsp.readFile(filePath, 'utf-8')
|
||||||
return eventHandler((event) => { event.node.res.end(contents) })
|
return eventHandler(event => send(event, contents))
|
||||||
})
|
})
|
||||||
|
|
||||||
console.info('Starting stats server...')
|
console.info('Starting stats server...')
|
||||||
|
@ -81,7 +81,7 @@
|
|||||||
"knitwork": "^1.0.0",
|
"knitwork": "^1.0.0",
|
||||||
"magic-string": "^0.30.2",
|
"magic-string": "^0.30.2",
|
||||||
"mlly": "^1.4.0",
|
"mlly": "^1.4.0",
|
||||||
"nitropack": "^2.5.2",
|
"nitropack": "^2.6.0",
|
||||||
"nuxi": "workspace:../nuxi",
|
"nuxi": "workspace:../nuxi",
|
||||||
"nypm": "^0.3.0",
|
"nypm": "^0.3.0",
|
||||||
"ofetch": "^1.1.1",
|
"ofetch": "^1.1.1",
|
||||||
|
@ -2,7 +2,7 @@ import type { Ref } from 'vue'
|
|||||||
import { getCurrentInstance, nextTick, onUnmounted, ref, toRaw, watch } from 'vue'
|
import { getCurrentInstance, nextTick, onUnmounted, ref, toRaw, watch } from 'vue'
|
||||||
import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es'
|
import type { CookieParseOptions, CookieSerializeOptions } from 'cookie-es'
|
||||||
import { parse, serialize } from 'cookie-es'
|
import { parse, serialize } from 'cookie-es'
|
||||||
import { deleteCookie, getCookie, setCookie } from 'h3'
|
import { deleteCookie, getCookie, getRequestHeader, setCookie } from 'h3'
|
||||||
import type { H3Event } from 'h3'
|
import type { H3Event } from 'h3'
|
||||||
import destr from 'destr'
|
import destr from 'destr'
|
||||||
import { isEqual } from 'ohash'
|
import { isEqual } from 'ohash'
|
||||||
@ -80,7 +80,7 @@ export function useCookie<T = string | null | undefined> (name: string, _opts?:
|
|||||||
|
|
||||||
function readRawCookies (opts: CookieOptions = {}): Record<string, string> | undefined {
|
function readRawCookies (opts: CookieOptions = {}): Record<string, string> | undefined {
|
||||||
if (import.meta.server) {
|
if (import.meta.server) {
|
||||||
return parse(useRequestEvent()?.node.req.headers.cookie || '', opts)
|
return parse(getRequestHeader(useRequestEvent(), 'cookie') || '', opts)
|
||||||
} else if (import.meta.client) {
|
} else if (import.meta.client) {
|
||||||
return parse(document.cookie, opts)
|
return parse(document.cookie, opts)
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import type { H3Event } from 'h3'
|
import type { H3Event } from 'h3'
|
||||||
import { setResponseStatus as _setResponseStatus } from 'h3'
|
import { setResponseStatus as _setResponseStatus, getRequestHeaders } from 'h3'
|
||||||
import type { NuxtApp } from '../nuxt'
|
import type { NuxtApp } from '../nuxt'
|
||||||
import { useNuxtApp } from '../nuxt'
|
import { useNuxtApp } from '../nuxt'
|
||||||
|
|
||||||
@ -7,7 +7,8 @@ export function useRequestHeaders<K extends string = string> (include: K[]): { [
|
|||||||
export function useRequestHeaders (): Readonly<Record<string, string>>
|
export function useRequestHeaders (): Readonly<Record<string, string>>
|
||||||
export function useRequestHeaders (include?: any[]) {
|
export function useRequestHeaders (include?: any[]) {
|
||||||
if (import.meta.client) { return {} }
|
if (import.meta.client) { return {} }
|
||||||
const headers = useNuxtApp().ssrContext?.event.node.req.headers ?? {}
|
const event = useNuxtApp().ssrContext?.event
|
||||||
|
const headers = event ? getRequestHeaders(event) : {}
|
||||||
if (!include) { return headers }
|
if (!include) { return headers }
|
||||||
return Object.fromEntries(include.map(key => key.toLowerCase()).filter(key => headers[key]).map(key => [key, headers[key]]))
|
return Object.fromEntries(include.map(key => key.toLowerCase()).filter(key => headers[key]).map(key => [key, headers[key]]))
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,6 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
console.warn(`[nuxt] Could not load custom \`spaLoadingTemplate\` path as it does not exist: \`${spaLoadingTemplate}\`.`)
|
console.warn(`[nuxt] Could not load custom \`spaLoadingTemplate\` path as it does not exist: \`${spaLoadingTemplate}\`.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-expect-error `typescriptBundlerResolution` coming in next nitro version
|
|
||||||
const nitroConfig: NitroConfig = defu(_nitroConfig, {
|
const nitroConfig: NitroConfig = defu(_nitroConfig, {
|
||||||
debug: nuxt.options.debug,
|
debug: nuxt.options.debug,
|
||||||
rootDir: nuxt.options.rootDir,
|
rootDir: nuxt.options.rootDir,
|
||||||
@ -44,9 +43,8 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
|||||||
dev: nuxt.options.dev,
|
dev: nuxt.options.dev,
|
||||||
buildDir: nuxt.options.buildDir,
|
buildDir: nuxt.options.buildDir,
|
||||||
experimental: {
|
experimental: {
|
||||||
// @ts-expect-error `typescriptBundlerResolution` coming in next nitro version
|
asyncContext: nuxt.options.experimental.asyncContext,
|
||||||
typescriptBundlerResolution: nuxt.options.experimental.typescriptBundlerResolution || nuxt.options.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' || _nitroConfig.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler',
|
typescriptBundlerResolution: nuxt.options.experimental.typescriptBundlerResolution || nuxt.options.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' || _nitroConfig.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler'
|
||||||
asyncContext: nuxt.options.experimental.asyncContext
|
|
||||||
},
|
},
|
||||||
imports: {
|
imports: {
|
||||||
autoImport: nuxt.options.imports.autoImport as boolean,
|
autoImport: nuxt.options.imports.autoImport as boolean,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { joinURL, withQuery } from 'ufo'
|
import { joinURL, withQuery } from 'ufo'
|
||||||
import type { NitroErrorHandler } from 'nitropack'
|
import type { NitroErrorHandler } from 'nitropack'
|
||||||
import type { H3Error } from 'h3'
|
import type { H3Error } from 'h3'
|
||||||
import { getRequestHeaders, setResponseHeader, setResponseStatus } from 'h3'
|
import { getRequestHeaders, send, setResponseHeader, setResponseStatus } from 'h3'
|
||||||
import { useNitroApp, useRuntimeConfig } from '#internal/nitro'
|
import { useNitroApp, useRuntimeConfig } from '#internal/nitro'
|
||||||
import { isJsonRequest, normalizeError } from '#internal/nitro/utils'
|
import { isJsonRequest, normalizeError } from '#internal/nitro/utils'
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ export default <NitroErrorHandler> async function errorhandler (error: H3Error,
|
|||||||
|
|
||||||
// Create an error object
|
// Create an error object
|
||||||
const errorObject = {
|
const errorObject = {
|
||||||
url: event.node.req.url,
|
url: event.path,
|
||||||
statusCode,
|
statusCode,
|
||||||
statusMessage,
|
statusMessage,
|
||||||
message,
|
message,
|
||||||
@ -41,12 +41,11 @@ export default <NitroErrorHandler> async function errorhandler (error: H3Error,
|
|||||||
// JSON response
|
// JSON response
|
||||||
if (isJsonRequest(event)) {
|
if (isJsonRequest(event)) {
|
||||||
setResponseHeader(event, 'Content-Type', 'application/json')
|
setResponseHeader(event, 'Content-Type', 'application/json')
|
||||||
event.node.res.end(JSON.stringify(errorObject))
|
return send(event, JSON.stringify(errorObject))
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HTML response (via SSR)
|
// HTML response (via SSR)
|
||||||
const isErrorPage = event.node.req.url?.startsWith('/__nuxt_error')
|
const isErrorPage = event.path.startsWith('/__nuxt_error')
|
||||||
const res = !isErrorPage
|
const res = !isErrorPage
|
||||||
? await useNitroApp().localFetch(withQuery(joinURL(useRuntimeConfig().app.baseURL, '/__nuxt_error'), errorObject), {
|
? await useNitroApp().localFetch(withQuery(joinURL(useRuntimeConfig().app.baseURL, '/__nuxt_error'), errorObject), {
|
||||||
headers: getRequestHeaders(event) as Record<string, string>,
|
headers: getRequestHeaders(event) as Record<string, string>,
|
||||||
@ -67,8 +66,7 @@ export default <NitroErrorHandler> async function errorhandler (error: H3Error,
|
|||||||
}
|
}
|
||||||
if (event.handled) { return }
|
if (event.handled) { return }
|
||||||
setResponseHeader(event, 'Content-Type', 'text/html;charset=UTF-8')
|
setResponseHeader(event, 'Content-Type', 'text/html;charset=UTF-8')
|
||||||
event.node.res.end(template(errorObject))
|
return send(event, template(errorObject))
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const html = await res.text()
|
const html = await res.text()
|
||||||
@ -79,5 +77,5 @@ export default <NitroErrorHandler> async function errorhandler (error: H3Error,
|
|||||||
}
|
}
|
||||||
setResponseStatus(event, res.status && res.status !== 200 ? res.status : undefined, res.statusText)
|
setResponseStatus(event, res.status && res.status !== 200 ? res.status : undefined, res.statusText)
|
||||||
|
|
||||||
event.node.res.end(html)
|
return send(event, html)
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
import type { RenderResponse } from 'nitropack'
|
import type { RenderResponse } from 'nitropack'
|
||||||
import type { Manifest } from 'vite'
|
import type { Manifest } from 'vite'
|
||||||
import type { H3Event } from 'h3'
|
import type { H3Event } from 'h3'
|
||||||
import { appendResponseHeader, createError, getQuery, readBody, writeEarlyHints } from 'h3'
|
import { appendResponseHeader, createError, getQuery, getResponseStatus, getResponseStatusText, readBody, writeEarlyHints } from 'h3'
|
||||||
import devalue from '@nuxt/devalue'
|
import devalue from '@nuxt/devalue'
|
||||||
import { stringify, uneval } from 'devalue'
|
import { stringify, uneval } from 'devalue'
|
||||||
import destr from 'destr'
|
import destr from 'destr'
|
||||||
@ -170,16 +170,16 @@ const islandPropCache = import.meta.prerender ? useStorage('internal:nuxt:preren
|
|||||||
|
|
||||||
async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
|
async function getIslandContext (event: H3Event): Promise<NuxtIslandContext> {
|
||||||
// TODO: Strict validation for url
|
// TODO: Strict validation for url
|
||||||
let url = event.node.req.url || ''
|
let url = event.path || ''
|
||||||
if (import.meta.prerender && event.node.req.url && await islandPropCache!.hasItem(event.node.req.url)) {
|
if (import.meta.prerender && event.path && await islandPropCache!.hasItem(event.path)) {
|
||||||
// rehydrate props from cache so we can rerender island if cache does not have it any more
|
// rehydrate props from cache so we can rerender island if cache does not have it any more
|
||||||
url = await islandPropCache!.getItem(event.node.req.url) as string
|
url = await islandPropCache!.getItem(event.path) as string
|
||||||
}
|
}
|
||||||
url = url.substring('/__nuxt_island'.length + 1) || ''
|
url = url.substring('/__nuxt_island'.length + 1) || ''
|
||||||
const [componentName, hashId] = url.split('?')[0].split('_')
|
const [componentName, hashId] = url.split('?')[0].split('_')
|
||||||
|
|
||||||
// TODO: Validate context
|
// TODO: Validate context
|
||||||
const context = event.node.req.method === 'GET' ? getQuery(event) : await readBody(event)
|
const context = event.method === 'GET' ? getQuery(event) : await readBody(event)
|
||||||
|
|
||||||
const ctx: NuxtIslandContext = {
|
const ctx: NuxtIslandContext = {
|
||||||
url: '/',
|
url: '/',
|
||||||
@ -202,7 +202,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
const nitroApp = useNitroApp()
|
const nitroApp = useNitroApp()
|
||||||
|
|
||||||
// Whether we're rendering an error page
|
// Whether we're rendering an error page
|
||||||
const ssrError = event.node.req.url?.startsWith('/__nuxt_error')
|
const ssrError = event.path.startsWith('/__nuxt_error')
|
||||||
? getQuery(event) as unknown as Exclude<NuxtPayload['error'], Error>
|
? getQuery(event) as unknown as Exclude<NuxtPayload['error'], Error>
|
||||||
: null
|
: null
|
||||||
|
|
||||||
@ -210,7 +210,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
ssrError.statusCode = parseInt(ssrError.statusCode as any)
|
ssrError.statusCode = parseInt(ssrError.statusCode as any)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ssrError && event.node.req.socket.readyState !== 'readOnly' /* direct request */) {
|
if (ssrError && !('__unenv__' in event.node.req) /* allow internal fetch */) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 404,
|
statusCode: 404,
|
||||||
statusMessage: 'Page Not Found: /__nuxt_error'
|
statusMessage: 'Page Not Found: /__nuxt_error'
|
||||||
@ -218,21 +218,23 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for island component rendering
|
// Check for island component rendering
|
||||||
const islandContext = (process.env.NUXT_COMPONENT_ISLANDS && event.node.req.url?.startsWith('/__nuxt_island'))
|
const islandContext = (process.env.NUXT_COMPONENT_ISLANDS && event.path.startsWith('/__nuxt_island'))
|
||||||
? await getIslandContext(event)
|
? await getIslandContext(event)
|
||||||
: undefined
|
: undefined
|
||||||
|
|
||||||
if (import.meta.prerender && islandContext && event.node.req.url && await islandCache!.hasItem(event.node.req.url)) {
|
if (import.meta.prerender && islandContext && event.path && await islandCache!.hasItem(event.path)) {
|
||||||
return islandCache!.getItem(event.node.req.url) as Promise<Partial<RenderResponse>>
|
return islandCache!.getItem(event.path) as Promise<Partial<RenderResponse>>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request url
|
// Request url
|
||||||
let url = ssrError?.url as string || islandContext?.url || event.node.req.url!
|
let url = ssrError?.url as string || islandContext?.url || event.path
|
||||||
|
|
||||||
// Whether we are rendering payload route
|
// Whether we are rendering payload route
|
||||||
const isRenderingPayload = PAYLOAD_URL_RE.test(url) && !islandContext
|
const isRenderingPayload = PAYLOAD_URL_RE.test(url) && !islandContext
|
||||||
if (isRenderingPayload) {
|
if (isRenderingPayload) {
|
||||||
url = url.substring(0, url.lastIndexOf('/')) || '/'
|
url = url.substring(0, url.lastIndexOf('/')) || '/'
|
||||||
|
|
||||||
|
event._path = url
|
||||||
event.node.req.url = url
|
event.node.req.url = url
|
||||||
if (import.meta.prerender && await payloadCache!.hasItem(url)) {
|
if (import.meta.prerender && await payloadCache!.hasItem(url)) {
|
||||||
return payloadCache!.getItem(url) as Promise<Partial<RenderResponse>>
|
return payloadCache!.getItem(url) as Promise<Partial<RenderResponse>>
|
||||||
@ -435,8 +437,8 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
body: JSON.stringify(islandResponse, null, 2),
|
body: JSON.stringify(islandResponse, null, 2),
|
||||||
statusCode: event.node.res.statusCode,
|
statusCode: getResponseStatus(event),
|
||||||
statusMessage: event.node.res.statusMessage,
|
statusMessage: getResponseStatusText(event),
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'application/json;charset=utf-8',
|
'content-type': 'application/json;charset=utf-8',
|
||||||
'x-powered-by': 'Nuxt'
|
'x-powered-by': 'Nuxt'
|
||||||
@ -444,7 +446,7 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
} satisfies RenderResponse
|
} satisfies RenderResponse
|
||||||
if (import.meta.prerender) {
|
if (import.meta.prerender) {
|
||||||
await islandCache!.setItem(`/__nuxt_island/${islandContext!.name}_${islandContext!.id}`, response)
|
await islandCache!.setItem(`/__nuxt_island/${islandContext!.name}_${islandContext!.id}`, response)
|
||||||
await islandPropCache!.setItem(`/__nuxt_island/${islandContext!.name}_${islandContext!.id}`, event.node.req.url!)
|
await islandPropCache!.setItem(`/__nuxt_island/${islandContext!.name}_${islandContext!.id}`, event.path)
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
@ -452,8 +454,8 @@ export default defineRenderHandler(async (event): Promise<Partial<RenderResponse
|
|||||||
// Construct HTML response
|
// Construct HTML response
|
||||||
const response = {
|
const response = {
|
||||||
body: renderHTMLDocument(htmlContext),
|
body: renderHTMLDocument(htmlContext),
|
||||||
statusCode: event.node.res.statusCode,
|
statusCode: getResponseStatus(event),
|
||||||
statusMessage: event.node.res.statusMessage,
|
statusMessage: getResponseStatusText(event),
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': 'text/html;charset=utf-8',
|
'content-type': 'text/html;charset=utf-8',
|
||||||
'x-powered-by': 'Nuxt'
|
'x-powered-by': 'Nuxt'
|
||||||
@ -511,8 +513,8 @@ function renderPayloadResponse (ssrContext: NuxtSSRContext) {
|
|||||||
body: process.env.NUXT_JSON_PAYLOADS
|
body: process.env.NUXT_JSON_PAYLOADS
|
||||||
? stringify(splitPayload(ssrContext).payload, ssrContext._payloadReducers)
|
? stringify(splitPayload(ssrContext).payload, ssrContext._payloadReducers)
|
||||||
: `export default ${devalue(splitPayload(ssrContext).payload)}`,
|
: `export default ${devalue(splitPayload(ssrContext).payload)}`,
|
||||||
statusCode: ssrContext.event.node.res.statusCode,
|
statusCode: getResponseStatus(ssrContext.event),
|
||||||
statusMessage: ssrContext.event.node.res.statusMessage,
|
statusMessage: getResponseStatusText(ssrContext.event),
|
||||||
headers: {
|
headers: {
|
||||||
'content-type': process.env.NUXT_JSON_PAYLOADS ? 'application/json;charset=utf-8' : 'text/javascript;charset=utf-8',
|
'content-type': process.env.NUXT_JSON_PAYLOADS ? 'application/json;charset=utf-8' : 'text/javascript;charset=utf-8',
|
||||||
'x-powered-by': 'Nuxt'
|
'x-powered-by': 'Nuxt'
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
"esbuild-loader": "4.0.1",
|
"esbuild-loader": "4.0.1",
|
||||||
"h3": "1.8.0",
|
"h3": "1.8.0",
|
||||||
"ignore": "5.2.4",
|
"ignore": "5.2.4",
|
||||||
"nitropack": "2.5.2",
|
"nitropack": "2.6.0",
|
||||||
"unbuild": "latest",
|
"unbuild": "latest",
|
||||||
"unctx": "2.3.1",
|
"unctx": "2.3.1",
|
||||||
"vite": "4.4.9",
|
"vite": "4.4.9",
|
||||||
|
@ -163,18 +163,17 @@ export async function buildClient (ctx: ViteBuildContext) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const viteMiddleware = defineEventHandler(async (event) => {
|
const viteMiddleware = defineEventHandler(async (event) => {
|
||||||
// Workaround: vite devmiddleware modifies req.url
|
|
||||||
const originalURL = event.node.req.url!
|
|
||||||
|
|
||||||
const viteRoutes = viteServer.middlewares.stack.map(m => m.route).filter(r => r.length > 1)
|
const viteRoutes = viteServer.middlewares.stack.map(m => m.route).filter(r => r.length > 1)
|
||||||
if (!originalURL.startsWith(clientConfig.base!) && !viteRoutes.some(route => originalURL.startsWith(route))) {
|
if (!event.path.startsWith(clientConfig.base!) && !viteRoutes.some(route => event.path.startsWith(route))) {
|
||||||
// @ts-expect-error _skip_transform is a private property
|
// @ts-expect-error _skip_transform is a private property
|
||||||
event.node.req._skip_transform = true
|
event.node.req._skip_transform = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Workaround: vite devmiddleware modifies req.url
|
||||||
|
const _originalPath = event.node.req.url
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
viteServer.middlewares.handle(event.node.req, event.node.res, (err: Error) => {
|
viteServer.middlewares.handle(event.node.req, event.node.res, (err: Error) => {
|
||||||
event.node.req.url = originalURL
|
event.node.req.url = _originalPath
|
||||||
return err ? reject(err) : resolve(null)
|
return err ? reject(err) : resolve(null)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -141,7 +141,7 @@ function createViteNodeApp (ctx: ViteBuildContext, invalidates: Set<string> = ne
|
|||||||
}
|
}
|
||||||
|
|
||||||
return eventHandler(async (event) => {
|
return eventHandler(async (event) => {
|
||||||
const moduleId = decodeURI(event.node.req.url!).substring(1)
|
const moduleId = decodeURI(event.path).substring(1)
|
||||||
if (moduleId === '/') {
|
if (moduleId === '/') {
|
||||||
throw createError({ statusCode: 400 })
|
throw createError({ statusCode: 400 })
|
||||||
}
|
}
|
||||||
|
582
pnpm-lock.yaml
582
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -19,7 +19,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
for (const outputDir of ['.output', '.output-inline']) {
|
for (const outputDir of ['.output', '.output-inline']) {
|
||||||
it('default client bundle size', async () => {
|
it('default client bundle size', async () => {
|
||||||
const clientStats = await analyzeSizes('**/*.js', join(rootDir, outputDir, 'public'))
|
const clientStats = await analyzeSizes('**/*.js', join(rootDir, outputDir, 'public'))
|
||||||
expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot('"95.7k"')
|
expect.soft(roundToKilobytes(clientStats.totalBytes)).toMatchInlineSnapshot('"96.4k"')
|
||||||
expect(clientStats.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
|
expect(clientStats.files.map(f => f.replace(/\..*\.js/, '.js'))).toMatchInlineSnapshot(`
|
||||||
[
|
[
|
||||||
"_nuxt/entry.js",
|
"_nuxt/entry.js",
|
||||||
@ -32,10 +32,10 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
const serverDir = join(rootDir, '.output/server')
|
const serverDir = join(rootDir, '.output/server')
|
||||||
|
|
||||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"64.6k"')
|
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"305k"')
|
||||||
|
|
||||||
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
||||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"2348k"')
|
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"1822k"')
|
||||||
|
|
||||||
const packages = modules.files
|
const packages = modules.files
|
||||||
.filter(m => m.endsWith('package.json'))
|
.filter(m => m.endsWith('package.json'))
|
||||||
@ -55,33 +55,12 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
"@vue/runtime-dom",
|
"@vue/runtime-dom",
|
||||||
"@vue/server-renderer",
|
"@vue/server-renderer",
|
||||||
"@vue/shared",
|
"@vue/shared",
|
||||||
"cookie-es",
|
|
||||||
"debug",
|
|
||||||
"defu",
|
|
||||||
"destr",
|
|
||||||
"devalue",
|
"devalue",
|
||||||
"estree-walker",
|
"estree-walker",
|
||||||
"h3",
|
|
||||||
"has-flag",
|
|
||||||
"hookable",
|
"hookable",
|
||||||
"http-graceful-shutdown",
|
|
||||||
"iron-webcrypto",
|
|
||||||
"klona",
|
|
||||||
"ms",
|
|
||||||
"node-fetch-native",
|
|
||||||
"ofetch",
|
|
||||||
"ohash",
|
|
||||||
"pathe",
|
|
||||||
"radix3",
|
|
||||||
"scule",
|
|
||||||
"source-map-js",
|
"source-map-js",
|
||||||
"supports-color",
|
|
||||||
"ufo",
|
"ufo",
|
||||||
"uncrypto",
|
|
||||||
"unctx",
|
|
||||||
"unenv",
|
|
||||||
"unhead",
|
"unhead",
|
||||||
"unstorage",
|
|
||||||
"vue",
|
"vue",
|
||||||
"vue-bundle-renderer",
|
"vue-bundle-renderer",
|
||||||
]
|
]
|
||||||
@ -92,10 +71,10 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
const serverDir = join(rootDir, '.output-inline/server')
|
const serverDir = join(rootDir, '.output-inline/server')
|
||||||
|
|
||||||
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
const serverStats = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||||
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"370k"')
|
expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot('"611k"')
|
||||||
|
|
||||||
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
||||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"613k"')
|
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"70.9k"')
|
||||||
|
|
||||||
const packages = modules.files
|
const packages = modules.files
|
||||||
.filter(m => m.endsWith('package.json'))
|
.filter(m => m.endsWith('package.json'))
|
||||||
@ -106,31 +85,9 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
|||||||
"@unhead/dom",
|
"@unhead/dom",
|
||||||
"@unhead/shared",
|
"@unhead/shared",
|
||||||
"@unhead/ssr",
|
"@unhead/ssr",
|
||||||
"cookie-es",
|
|
||||||
"debug",
|
|
||||||
"defu",
|
|
||||||
"destr",
|
|
||||||
"devalue",
|
"devalue",
|
||||||
"h3",
|
|
||||||
"has-flag",
|
|
||||||
"hookable",
|
"hookable",
|
||||||
"http-graceful-shutdown",
|
|
||||||
"iron-webcrypto",
|
|
||||||
"klona",
|
|
||||||
"ms",
|
|
||||||
"node-fetch-native",
|
|
||||||
"ofetch",
|
|
||||||
"ohash",
|
|
||||||
"pathe",
|
|
||||||
"radix3",
|
|
||||||
"scule",
|
|
||||||
"supports-color",
|
|
||||||
"ufo",
|
|
||||||
"uncrypto",
|
|
||||||
"unctx",
|
|
||||||
"unenv",
|
|
||||||
"unhead",
|
"unhead",
|
||||||
"unstorage",
|
|
||||||
]
|
]
|
||||||
`)
|
`)
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user