feat(kit,nuxt,schema,vite,webpack): nitropack v3 nightly (#27702)

This commit is contained in:
Daniel Roe 2024-06-26 15:18:05 +02:00 committed by GitHub
parent 5f819ab88e
commit 8f95cac34c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
48 changed files with 953 additions and 202 deletions

View File

@ -90,7 +90,7 @@ declare module '#app' {
} }
} }
declare module 'nitropack' { declare module 'nitro/types' {
interface NitroRuntimeHooks { interface NitroRuntimeHooks {
'your-nitro-hook': () => void; 'your-nitro-hook': () => void;
} }

View File

@ -583,7 +583,7 @@ export default defineNuxtModule({
interface MyModuleNitroRules { interface MyModuleNitroRules {
myModule?: { foo: 'bar' } myModule?: { foo: 'bar' }
} }
declare module 'nitropack' { declare module 'nitro/types' {
interface NitroRouteRules extends MyModuleNitroRules {} interface NitroRouteRules extends MyModuleNitroRules {}
interface NitroRouteConfig extends MyModuleNitroRules {} interface NitroRouteConfig extends MyModuleNitroRules {}
} }

View File

@ -34,6 +34,9 @@
"typecheck:docs": "DOCS_TYPECHECK=true pnpm nuxi prepare && nuxt-content-twoslash verify --content-dir docs" "typecheck:docs": "DOCS_TYPECHECK=true pnpm nuxi prepare && nuxt-content-twoslash verify --content-dir docs"
}, },
"resolutions": { "resolutions": {
"nitro": "npm:nitro-nightly@3.0.0-beta-28648657.9a717203",
"typescript": "5.5.2",
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"@nuxt/kit": "workspace:*", "@nuxt/kit": "workspace:*",
"@nuxt/schema": "workspace:*", "@nuxt/schema": "workspace:*",
"@nuxt/ui-templates": "workspace:*", "@nuxt/ui-templates": "workspace:*",
@ -69,11 +72,11 @@
"eslint-typegen": "0.2.4", "eslint-typegen": "0.2.4",
"execa": "9.3.0", "execa": "9.3.0",
"globby": "14.0.1", "globby": "14.0.1",
"h3": "1.12.0", "h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"happy-dom": "14.12.3", "happy-dom": "14.12.3",
"jiti": "1.21.6", "jiti": "1.21.6",
"markdownlint-cli": "0.41.0", "markdownlint-cli": "0.41.0",
"nitropack": "2.9.6", "nitro": "npm:nitro-nightly@3.0.0-beta-28648657.9a717203",
"nuxi": "3.12.0", "nuxi": "3.12.0",
"nuxt": "workspace:*", "nuxt": "workspace:*",
"nuxt-content-twoslash": "0.0.10", "nuxt-content-twoslash": "0.0.10",
@ -95,5 +98,10 @@
"engines": { "engines": {
"node": "^16.10.0 || >=18.0.0" "node": "^16.10.0 || >=18.0.0"
}, },
"version": "" "version": "",
"pnpm": {
"patchedDependencies": {
"ofetch@1.3.4": "patches/ofetch@1.3.4.patch"
}
}
} }

View File

@ -8,6 +8,7 @@ export default defineBuildConfig({
externals: [ externals: [
'@nuxt/schema', '@nuxt/schema',
'nitropack', 'nitropack',
'nitro',
'webpack', 'webpack',
'vite', 'vite',
'h3', 'h3',

View File

@ -49,7 +49,7 @@
"devDependencies": { "devDependencies": {
"@types/hash-sum": "1.0.2", "@types/hash-sum": "1.0.2",
"@types/semver": "7.5.8", "@types/semver": "7.5.8",
"nitropack": "2.9.6", "nitro": "npm:nitro-nightly@3.0.0-beta-28648657.9a717203",
"unbuild": "latest", "unbuild": "latest",
"vite": "5.3.1", "vite": "5.3.1",
"vitest": "1.6.0", "vitest": "1.6.0",

View File

@ -1,4 +1,4 @@
import type { Nitro, NitroDevEventHandler, NitroEventHandler } from 'nitropack' import type { Nitro, NitroDevEventHandler, NitroEventHandler } from 'nitro/types'
import type { Import } from 'unimport' import type { Import } from 'unimport'
import { normalize } from 'pathe' import { normalize } from 'pathe'
import { useNuxt } from './context' import { useNuxt } from './context'
@ -12,7 +12,7 @@ function normalizeHandlerMethod (handler: NitroEventHandler) {
// retrieve method from handler file name // retrieve method from handler file name
const [, method = undefined] = handler.handler.match(/\.(get|head|patch|post|put|delete|connect|options|trace)(\.\w+)*$/) || [] const [, method = undefined] = handler.handler.match(/\.(get|head|patch|post|put|delete|connect|options|trace)(\.\w+)*$/) || []
return { return {
method, method: method as 'get' | 'head' | 'patch' | 'post' | 'put' | 'delete' | 'connect' | 'options' | 'trace' | undefined,
...handler, ...handler,
handler: normalize(handler.handler), handler: normalize(handler.handler),
} }

View File

@ -1,5 +1,5 @@
import type { NuxtHooks, NuxtMiddleware } from '@nuxt/schema' import type { NuxtHooks, NuxtMiddleware } from '@nuxt/schema'
import type { NitroRouteConfig } from 'nitropack' import type { NitroRouteConfig } from 'nitro/types'
import { defu } from 'defu' import { defu } from 'defu'
import { useNuxt } from './context' import { useNuxt } from './context'
import { logger } from './logger' import { logger } from './logger'

View File

@ -80,7 +80,7 @@
"escape-string-regexp": "^5.0.0", "escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3", "estree-walker": "^3.0.3",
"globby": "^14.0.1", "globby": "^14.0.1",
"h3": "^1.12.0", "h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"hookable": "^5.5.3", "hookable": "^5.5.3",
"ignore": "^5.3.1", "ignore": "^5.3.1",
"jiti": "^1.21.6", "jiti": "^1.21.6",
@ -88,7 +88,7 @@
"knitwork": "^1.1.0", "knitwork": "^1.1.0",
"magic-string": "^0.30.10", "magic-string": "^0.30.10",
"mlly": "^1.7.1", "mlly": "^1.7.1",
"nitropack": "^2.9.6", "nitro": "npm:nitro-nightly@3.0.0-beta-28648657.9a717203",
"nuxi": "^3.12.0", "nuxi": "^3.12.0",
"nypm": "^0.3.8", "nypm": "^0.3.8",
"ofetch": "^1.3.4", "ofetch": "^1.3.4",

View File

@ -1,5 +1,5 @@
import type { FetchError, FetchOptions } from 'ofetch' import type { FetchError, FetchOptions } from 'ofetch'
import type { NitroFetchRequest, TypedInternalResponse, AvailableRouterMethod as _AvailableRouterMethod } from 'nitropack' import type { NitroFetchRequest, TypedInternalResponse, AvailableRouterMethod as _AvailableRouterMethod } from 'nitro/types'
import type { MaybeRef, Ref } from 'vue' import type { MaybeRef, Ref } from 'vue'
import { computed, reactive, toValue } from 'vue' import { computed, reactive, toValue } from 'vue'
import { hash } from 'ohash' import { hash } from 'ohash'

View File

@ -1,7 +1,7 @@
import type { Ref } from 'vue' import type { Ref } from 'vue'
import { getCurrentScope, onScopeDispose, ref } from 'vue' import { getCurrentScope, onScopeDispose, ref } from 'vue'
import { injectHead } from '@unhead/vue' import { injectHead } from '@unhead/vue'
import { useNuxtApp } from '#app' import { useNuxtApp } from '../nuxt'
export type Politeness = 'assertive' | 'polite' | 'off' export type Politeness = 'assertive' | 'polite' | 'off'

View File

@ -7,7 +7,7 @@ import { getContext } from 'unctx'
import type { SSRContext, createRenderer } from 'vue-bundle-renderer/runtime' import type { SSRContext, createRenderer } from 'vue-bundle-renderer/runtime'
import type { EventHandlerRequest, H3Event } from 'h3' import type { EventHandlerRequest, H3Event } from 'h3'
import type { AppConfig, AppConfigInput, RuntimeConfig } from 'nuxt/schema' import type { AppConfig, AppConfigInput, RuntimeConfig } from 'nuxt/schema'
import type { RenderResponse } from 'nitropack' import type { RenderResponse } from 'nitro/types'
import type { LogObject } from 'consola' import type { LogObject } from 'consola'
import type { MergeHead, VueHeadClient } from '@unhead/vue' import type { MergeHead, VueHeadClient } from '@unhead/vue'

View File

@ -4,8 +4,8 @@ import { cpus } from 'node:os'
import { join, relative, resolve } from 'pathe' import { join, relative, resolve } from 'pathe'
import { createRouter as createRadixRouter, exportMatcher, toRouteMatcher } from 'radix3' import { createRouter as createRadixRouter, exportMatcher, toRouteMatcher } from 'radix3'
import { joinURL, withTrailingSlash } from 'ufo' import { joinURL, withTrailingSlash } from 'ufo'
import { build, copyPublicAssets, createDevServer, createNitro, prepare, prerender, scanHandlers, writeTypes } from 'nitropack' import { build, copyPublicAssets, createDevServer, createNitro, prepare, prerender, writeTypes } from 'nitro'
import type { Nitro, NitroConfig, NitroOptions } from 'nitropack' import type { Nitro, NitroConfig, NitroOptions } from 'nitro/types'
import { findPath, logger, resolveAlias, resolveIgnorePatterns, resolveNuxtModule, resolvePath } from '@nuxt/kit' import { findPath, logger, resolveAlias, resolveIgnorePatterns, resolveNuxtModule, resolvePath } from '@nuxt/kit'
import escapeRE from 'escape-string-regexp' import escapeRE from 'escape-string-regexp'
import { defu } from 'defu' import { defu } from 'defu'
@ -95,22 +95,18 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
: false, : false,
scanDirs: nuxt.options._layers.map(layer => (layer.config.serverDir || layer.config.srcDir) && resolve(layer.cwd, layer.config.serverDir || resolve(layer.config.srcDir, 'server'))).filter(Boolean), scanDirs: nuxt.options._layers.map(layer => (layer.config.serverDir || layer.config.srcDir) && resolve(layer.cwd, layer.config.serverDir || resolve(layer.config.srcDir, 'server'))).filter(Boolean),
renderer: resolve(distDir, 'core/runtime/nitro/renderer'), renderer: resolve(distDir, 'core/runtime/nitro/renderer'),
errorHandler: resolve(distDir, 'core/runtime/nitro/error'),
nodeModulesDirs: nuxt.options.modulesDir, nodeModulesDirs: nuxt.options.modulesDir,
handlers: nuxt.options.serverHandlers, handlers: nuxt.options.serverHandlers,
devHandlers: [], devHandlers: [],
baseURL: nuxt.options.app.baseURL, baseURL: nuxt.options.app.baseURL,
virtual: { virtual: {
'#internal/nuxt.config.mjs': () => nuxt.vfs['#build/nuxt.config'], '#internal/nuxt.config.mjs': () => nuxt.vfs['#build/nuxt.config'],
'#internal/nuxt/app-config': () => nuxt.vfs['#build/app.config'].replace(/\/\*\* client \*\*\/[\s\S]*\/\*\* client-end \*\*\//, ''),
'#spa-template': async () => `export const template = ${JSON.stringify(await spaLoadingTemplate(nuxt))}`, '#spa-template': async () => `export const template = ${JSON.stringify(await spaLoadingTemplate(nuxt))}`,
}, },
routeRules: { routeRules: {
'/__nuxt_error': { cache: false }, '/__nuxt_error': { cache: false },
}, },
appConfig: nuxt.options.appConfig,
appConfigFiles: nuxt.options._layers.map(
layer => resolve(layer.config.srcDir, 'app.config'),
),
typescript: { typescript: {
strict: true, strict: true,
generateTsConfig: true, generateTsConfig: true,
@ -213,6 +209,19 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
logLevel: logLevelMapReverse[nuxt.options.logLevel], logLevel: logLevelMapReverse[nuxt.options.logLevel],
} satisfies NitroConfig) } satisfies NitroConfig)
if (nuxt.options.experimental.serverAppConfig && nitroConfig.imports) {
nitroConfig.imports.imports ||= []
nitroConfig.imports.imports.push({
name: 'useAppConfig',
from: resolve(distDir, 'core/runtime/nitro/app-config'),
})
}
// add error handler
if (!nitroConfig.errorHandler && (nuxt.options.dev || !nuxt.options.experimental.noVueServer)) {
nitroConfig.errorHandler = resolve(distDir, 'core/runtime/nitro/error')
}
// Resolve user-provided paths // Resolve user-provided paths
nitroConfig.srcDir = resolve(nuxt.options.rootDir, nuxt.options.srcDir, nitroConfig.srcDir!) nitroConfig.srcDir = resolve(nuxt.options.rootDir, nuxt.options.srcDir, nitroConfig.srcDir!)
nitroConfig.ignore = [...(nitroConfig.ignore || []), ...resolveIgnorePatterns(nitroConfig.srcDir), `!${join(nuxt.options.buildDir, 'dist/client', nuxt.options.app.buildAssetsDir, '**/*')}`] nitroConfig.ignore = [...(nitroConfig.ignore || []), ...resolveIgnorePatterns(nitroConfig.srcDir), `!${join(nuxt.options.buildDir, 'dist/client', nuxt.options.app.buildAssetsDir, '**/*')}`]
@ -383,7 +392,6 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
// Init nitro // Init nitro
const nitro = await createNitro(nitroConfig, { const nitro = await createNitro(nitroConfig, {
// @ts-expect-error this will be valid in a future version of Nitro
compatibilityDate: nuxt.options.compatibilityDate, compatibilityDate: nuxt.options.compatibilityDate,
}) })
@ -463,21 +471,22 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
if (!nuxt.options.dev && nuxt.options.experimental.noVueServer) { if (!nuxt.options.dev && nuxt.options.experimental.noVueServer) {
nitro.hooks.hook('rollup:before', (nitro) => { nitro.hooks.hook('rollup:before', (nitro) => {
if (nitro.options.preset === 'nitro-prerender') { return } if (nitro.options.preset === 'nitro-prerender') {
nitro.options.errorHandler = resolve(distDir, 'core/runtime/nitro/error')
return
}
const nuxtErrorHandler = nitro.options.handlers.findIndex(h => h.route === '/__nuxt_error') const nuxtErrorHandler = nitro.options.handlers.findIndex(h => h.route === '/__nuxt_error')
if (nuxtErrorHandler >= 0) { if (nuxtErrorHandler >= 0) {
nitro.options.handlers.splice(nuxtErrorHandler, 1) nitro.options.handlers.splice(nuxtErrorHandler, 1)
} }
nitro.options.renderer = undefined nitro.options.renderer = undefined
nitro.options.errorHandler = '#internal/nitro/error'
}) })
} }
// Add typed route responses // Add typed route responses
nuxt.hook('prepare:types', async (opts) => { nuxt.hook('prepare:types', async (opts) => {
if (!nuxt.options.dev) { if (!nuxt.options.dev) {
await scanHandlers(nitro)
await writeTypes(nitro) await writeTypes(nitro)
} }
// Exclude nitro output dir from typescript // Exclude nitro output dir from typescript

View File

@ -62,6 +62,7 @@ export function createNuxt (options: NuxtOptions): Nuxt {
const nightlies = { const nightlies = {
'nitropack': 'nitropack-nightly', 'nitropack': 'nitropack-nightly',
'nitro': 'nitro-nightly',
'h3': 'h3-nightly', 'h3': 'h3-nightly',
'nuxt': 'nuxt-nightly', 'nuxt': 'nuxt-nightly',
'@nuxt/schema': '@nuxt/schema-nightly', '@nuxt/schema': '@nuxt/schema-nightly',

View File

@ -34,7 +34,7 @@ export const nuxtImportProtections = (nuxt: { options: NuxtOptions }, options: {
]) ])
} }
for (const i of [/(^|node_modules\/)@nuxt\/(kit|test-utils)/, /(^|node_modules\/)nuxi/, /(^|node_modules\/)nuxt\/(config|kit|schema)/, 'nitropack']) { for (const i of [/(^|node_modules\/)@nuxt\/(kit|test-utils)/, /(^|node_modules\/)nuxi/, /(^|node_modules\/)nitro(?:pack)?(?:-nightly)?(?:$|\/)(?!(?:dist\/)?runtime|types)/, /(^|node_modules\/)nuxt\/(config|kit|schema)/]) {
patterns.push([i, 'This module cannot be imported' + (options.isNitro ? ' in server runtime.' : ' in the Vue part of your app.')]) patterns.push([i, 'This module cannot be imported' + (options.isNitro ? ' in server runtime.' : ' in the Vue part of your app.')])
} }

View File

@ -0,0 +1,38 @@
import type { H3Event } from 'h3'
import { klona } from 'klona'
// @ts-expect-error virtual file
import _inlineAppConfig from '#internal/nuxt/app-config'
// App config
const _sharedAppConfig = _deepFreeze(klona(_inlineAppConfig))
export function useAppConfig (event?: H3Event) {
// Backwards compatibility with ambient context
if (!event) {
return _sharedAppConfig
}
if (!event.context.nuxt) {
event.context.nuxt = {}
}
// Reuse cached app config from event context
if (event.context.nuxt.appConfig) {
return event.context.nuxt.appConfig
}
// Prepare app config for event context
const appConfig = klona(_inlineAppConfig)
event.context.nuxt.appConfig = appConfig
return appConfig
}
// --- Utils ---
function _deepFreeze (object: Record<string, any>) {
const propNames = Object.getOwnPropertyNames(object)
for (const name of propNames) {
const value = object[name]
if (value && typeof value === 'object') {
_deepFreeze(value)
}
}
return Object.freeze(object)
}

View File

@ -7,7 +7,7 @@ import { withTrailingSlash } from 'ufo'
import { getContext } from 'unctx' import { getContext } from 'unctx'
import { isVNode } from 'vue' import { isVNode } from 'vue'
import type { NitroApp } from '#internal/nitro/app' import type { NitroApp } from 'nitro/types'
// @ts-expect-error virtual file // @ts-expect-error virtual file
import { rootDir } from '#internal/dev-server-logs-options' import { rootDir } from '#internal/dev-server-logs-options'

View File

@ -1,10 +1,8 @@
import { joinURL, withQuery } from 'ufo' import { joinURL, withQuery } from 'ufo'
import type { NitroErrorHandler } from 'nitropack' import type { NitroErrorHandler } from 'nitro/types'
import type { H3Error } from 'h3' import type { H3Error, H3Event } from 'h3'
import { getRequestHeaders, send, setResponseHeader, setResponseStatus } from 'h3' import { getRequestHeader, getRequestHeaders, send, setResponseHeader, setResponseStatus } from 'h3'
import { useRuntimeConfig } from '#internal/nitro' import { useNitroApp, useRuntimeConfig } from 'nitro/runtime'
import { useNitroApp } from '#internal/nitro/app'
import { isJsonRequest, normalizeError } from '#internal/nitro/utils'
import type { NuxtPayload } from '#app' import type { NuxtPayload } from '#app'
export default <NitroErrorHandler> async function errorhandler (error: H3Error, event) { export default <NitroErrorHandler> async function errorhandler (error: H3Error, event) {
@ -86,3 +84,65 @@ export default <NitroErrorHandler> async function errorhandler (error: H3Error,
return send(event, html) return send(event, html)
} }
/**
* Nitro internal functions extracted from https://github.com/unjs/nitro/blob/main/src/runtime/internal/utils.ts
*/
function isJsonRequest (event: H3Event) {
// If the client specifically requests HTML, then avoid classifying as JSON.
if (hasReqHeader(event, 'accept', 'text/html')) {
return false
}
return (
hasReqHeader(event, 'accept', 'application/json') ||
hasReqHeader(event, 'user-agent', 'curl/') ||
hasReqHeader(event, 'user-agent', 'httpie/') ||
hasReqHeader(event, 'sec-fetch-mode', 'cors') ||
event.path.startsWith('/api/') ||
event.path.endsWith('.json')
)
}
function hasReqHeader (event: H3Event, name: string, includes: string) {
const value = getRequestHeader(event, name)
return (
value && typeof value === 'string' && value.toLowerCase().includes(includes)
)
}
function normalizeError (error: any) {
// temp fix for https://github.com/unjs/nitro/issues/759
// TODO: investigate vercel-edge not using unenv pollyfill
const cwd = typeof process.cwd === 'function' ? process.cwd() : '/'
const stack = ((error.stack as string) || '')
.split('\n')
.splice(1)
.filter(line => line.includes('at '))
.map((line) => {
const text = line
.replace(cwd + '/', './')
.replace('webpack:/', '')
.replace('file://', '')
.trim()
return {
text,
internal:
(line.includes('node_modules') && !line.includes('.cache')) ||
line.includes('internal') ||
line.includes('new Promise'),
}
})
const statusCode = error.statusCode || 500
const statusMessage =
error.statusMessage ?? (statusCode === 404 ? 'Not Found' : '')
const message = error.message || error.toString()
return {
stack,
statusCode,
statusMessage,
message,
}
}

View File

@ -1,5 +1,5 @@
import { joinRelativeURL } from 'ufo' import { joinRelativeURL } from 'ufo'
import { useRuntimeConfig } from '#internal/nitro' import { useRuntimeConfig } from 'nitro/runtime'
export function baseURL (): string { export function baseURL (): string {
// TODO: support passing event to `useRuntimeConfig` // TODO: support passing event to `useRuntimeConfig`

View File

@ -6,7 +6,7 @@ import {
getRequestDependencies, getRequestDependencies,
renderResourceHeaders, renderResourceHeaders,
} from 'vue-bundle-renderer/runtime' } from 'vue-bundle-renderer/runtime'
import type { RenderResponse } from 'nitropack' import type { RenderResponse } from 'nitro/types'
import type { Manifest } from 'vite' import type { Manifest } from 'vite'
import type { H3Event } from 'h3' import type { H3Event } from 'h3'
import { appendResponseHeader, createError, getQuery, getResponseStatus, getResponseStatusText, readBody, writeEarlyHints } from 'h3' import { appendResponseHeader, createError, getQuery, getResponseStatus, getResponseStatusText, readBody, writeEarlyHints } from 'h3'
@ -21,8 +21,7 @@ import type { HeadEntryOptions } from '@unhead/schema'
import type { Link, Script, Style } from '@unhead/vue' import type { Link, Script, Style } from '@unhead/vue'
import { createServerHead } from '@unhead/vue' import { createServerHead } from '@unhead/vue'
import { defineRenderHandler, getRouteRules, useRuntimeConfig, useStorage } from '#internal/nitro' import { defineRenderHandler, getRouteRules, useNitroApp, useRuntimeConfig, useStorage } from 'nitro/runtime'
import { useNitroApp } from '#internal/nitro/app'
// @ts-expect-error virtual file // @ts-expect-error virtual file
import unheadPlugins from '#internal/unhead-plugins.mjs' import unheadPlugins from '#internal/unhead-plugins.mjs'

View File

@ -239,7 +239,28 @@ import type { H3Event } from 'h3'
import type { LogObject } from 'consola' import type { LogObject } from 'consola'
import type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from 'nuxt/app' import type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from 'nuxt/app'
declare module 'nitropack' { declare module 'nitro/types' {
interface NitroRuntimeConfigApp {
buildAssetsDir: string
cdnURL: string
}
interface NitroRuntimeConfig extends RuntimeConfig {}
interface NitroRouteConfig {
ssr?: boolean
experimentalNoScripts?: boolean
}
interface NitroRouteRules {
ssr?: boolean
experimentalNoScripts?: boolean
appMiddleware?: Record<string, boolean>
}
interface NitroRuntimeHooks {
'dev:ssr-logs': (ctx: { logs: LogObject[], path: string }) => void | Promise<void>
'render:html': (htmlContext: NuxtRenderHTMLContext, context: { event: H3Event }) => void | Promise<void>
'render:island': (islandResponse: NuxtIslandResponse, context: { event: H3Event, islandContext: NuxtIslandContext }) => void | Promise<void>
}
}
declare module 'nitropack/types' {
interface NitroRuntimeConfigApp { interface NitroRuntimeConfigApp {
buildAssetsDir: string buildAssetsDir: string
cdnURL: string cdnURL: string
@ -315,17 +336,19 @@ export const appConfigTemplate: NuxtTemplate = {
write: true, write: true,
getContents ({ app, nuxt }) { getContents ({ app, nuxt }) {
return ` return `
import { updateAppConfig } from '#app/config'
import { defuFn } from 'defu' import { defuFn } from 'defu'
const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)} const inlineConfig = ${JSON.stringify(nuxt.options.appConfig, null, 2)}
/** client **/
// Vite - webpack is handled directly in #app/config // Vite - webpack is handled directly in #app/config
if (import.meta.hot) { if (import.meta.dev && !import.meta.nitro && import.meta.hot) {
const { updateAppConfig } = await import('#app/config')
import.meta.hot.accept((newModule) => { import.meta.hot.accept((newModule) => {
updateAppConfig(newModule.default) updateAppConfig(newModule.default)
}) })
} }
/** client-end **/
${app.configs.map((id: string, index: number) => `import ${`cfg${index}`} from ${JSON.stringify(id)}`).join('\n')} ${app.configs.map((id: string, index: number) => `import ${`cfg${index}`} from ${JSON.stringify(id)}`).join('\n')}
@ -339,7 +362,7 @@ export const publicPathTemplate: NuxtTemplate = {
getContents ({ nuxt }) { getContents ({ nuxt }) {
return [ return [
'import { joinRelativeURL } from \'ufo\'', 'import { joinRelativeURL } from \'ufo\'',
!nuxt.options.dev && 'import { useRuntimeConfig } from \'#internal/nitro\'', !nuxt.options.dev && 'import { useRuntimeConfig } from \'nitro/runtime\'',
nuxt.options.dev nuxt.options.dev
? `const appConfig = ${JSON.stringify(nuxt.options.app)}` ? `const appConfig = ${JSON.stringify(nuxt.options.app)}`

View File

@ -8,7 +8,7 @@ import { createRoutesContext } from 'unplugin-vue-router'
import { resolveOptions } from 'unplugin-vue-router/options' import { resolveOptions } from 'unplugin-vue-router/options'
import type { EditableTreeNode, Options as TypedRouterOptions } from 'unplugin-vue-router' import type { EditableTreeNode, Options as TypedRouterOptions } from 'unplugin-vue-router'
import type { NitroRouteConfig } from 'nitropack' import type { NitroRouteConfig } from 'nitro/types'
import { defu } from 'defu' import { defu } from 'defu'
import { distDir } from '../dirs' import { distDir } from '../dirs'
import { normalizeRoutes, resolvePagesRoutes, resolveRoutePaths } from './utils' import { normalizeRoutes, resolvePagesRoutes, resolveRoutePaths } from './utils'
@ -117,7 +117,12 @@ export default defineNuxtModule({
addTypeTemplate({ addTypeTemplate({
filename: 'types/middleware.d.ts', filename: 'types/middleware.d.ts',
getContents: () => [ getContents: () => [
'declare module \'nitropack\' {', 'declare module \'nitropack/types\' {',
' interface NitroRouteConfig {',
' appMiddleware?: string | string[] | Record<string, boolean>',
' }',
'}',
'declare module \'nitro/types\' {',
' interface NitroRouteConfig {', ' interface NitroRouteConfig {',
' appMiddleware?: string | string[] | Record<string, boolean>', ' appMiddleware?: string | string[] | Record<string, boolean>',
' }', ' }',
@ -442,7 +447,12 @@ export default defineNuxtModule({
' middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard>', ' middleware?: MiddlewareKey | NavigationGuard | Array<MiddlewareKey | NavigationGuard>',
' }', ' }',
'}', '}',
'declare module \'nitropack\' {', 'declare module \'nitropack/types\' {',
' interface NitroRouteConfig {',
' appMiddleware?: MiddlewareKey | MiddlewareKey[] | Record<MiddlewareKey, boolean>',
' }',
'}',
'declare module \'nitro/types\' {',
' interface NitroRouteConfig {', ' interface NitroRouteConfig {',
' appMiddleware?: MiddlewareKey | MiddlewareKey[] | Record<MiddlewareKey, boolean>', ' appMiddleware?: MiddlewareKey | MiddlewareKey[] | Record<MiddlewareKey, boolean>',
' }', ' }',

View File

@ -5,7 +5,7 @@ import { walk } from 'estree-walker'
import { transform } from 'esbuild' import { transform } from 'esbuild'
import { parse } from 'acorn' import { parse } from 'acorn'
import type { NuxtPage } from '@nuxt/schema' import type { NuxtPage } from '@nuxt/schema'
import type { NitroRouteConfig } from 'nitropack' import type { NitroRouteConfig } from 'nitro/types'
import { normalize } from 'pathe' import { normalize } from 'pathe'
import { extractScriptContent, pathToNitroGlob } from './utils' import { extractScriptContent, pathToNitroGlob } from './utils'

View File

@ -2,7 +2,7 @@ import type { KeepAliveProps, TransitionProps, UnwrapRef } from 'vue'
import { getCurrentInstance } from 'vue' import { getCurrentInstance } from 'vue'
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded, RouteRecordRedirectOption } from 'vue-router' import type { RouteLocationNormalized, RouteLocationNormalizedLoaded, RouteRecordRedirectOption } from 'vue-router'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import type { NitroRouteConfig } from 'nitropack' import type { NitroRouteConfig } from 'nitro/types'
import { useNuxtApp } from '#app/nuxt' import { useNuxtApp } from '#app/nuxt'
import type { NuxtError } from '#app' import type { NuxtError } from '#app'

View File

@ -1,4 +1,4 @@
/// <reference types="nitropack" /> /// <reference types="nitro/types" />
import type { DefineNuxtConfig } from 'nuxt/config' import type { DefineNuxtConfig } from 'nuxt/config'
import type { RuntimeConfig, SchemaDefinition } from 'nuxt/schema' import type { RuntimeConfig, SchemaDefinition } from 'nuxt/schema'
@ -14,7 +14,28 @@ declare global {
} }
// Note: Keep in sync with packages/nuxt/src/core/templates.ts // Note: Keep in sync with packages/nuxt/src/core/templates.ts
declare module 'nitropack' { declare module 'nitro/types' {
interface NitroRuntimeConfigApp {
buildAssetsDir: string
cdnURL: string
}
interface NitroRuntimeConfig extends RuntimeConfig {}
interface NitroRouteConfig {
ssr?: boolean
experimentalNoScripts?: boolean
}
interface NitroRouteRules {
ssr?: boolean
experimentalNoScripts?: boolean
appMiddleware?: Record<string, boolean>
}
interface NitroRuntimeHooks {
'dev:ssr-logs': (ctx: { logs: LogObject[], path: string }) => void | Promise<void>
'render:html': (htmlContext: NuxtRenderHTMLContext, context: { event: H3Event }) => void | Promise<void>
'render:island': (islandResponse: NuxtIslandResponse, context: { event: H3Event, islandContext: NuxtIslandContext }) => void | Promise<void>
}
}
declare module 'nitropack/types' {
interface NitroRuntimeConfigApp { interface NitroRuntimeConfigApp {
buildAssetsDir: string buildAssetsDir: string
cdnURL: string cdnURL: string

View File

@ -1,4 +1,4 @@
/// <reference types="nitropack" /> /// <reference types="nitro/types" />
import type { DefineNuxtConfig } from 'nuxt/config' import type { DefineNuxtConfig } from 'nuxt/config'
import type { RuntimeConfig, SchemaDefinition } from 'nuxt/schema' import type { RuntimeConfig, SchemaDefinition } from 'nuxt/schema'
import type { H3Event } from 'h3' import type { H3Event } from 'h3'
@ -13,7 +13,28 @@ declare global {
} }
// Note: Keep in sync with packages/nuxt/src/core/templates.ts // Note: Keep in sync with packages/nuxt/src/core/templates.ts
declare module 'nitropack' { declare module 'nitro/types' {
interface NitroRuntimeConfigApp {
buildAssetsDir: string
cdnURL: string
}
interface NitroRuntimeConfig extends RuntimeConfig {}
interface NitroRouteConfig {
ssr?: boolean
experimentalNoScripts?: boolean
}
interface NitroRouteRules {
ssr?: boolean
experimentalNoScripts?: boolean
appMiddleware?: Record<string, boolean>
}
interface NitroRuntimeHooks {
'dev:ssr-logs': (ctx: { logs: LogObject[], path: string }) => void | Promise<void>
'render:html': (htmlContext: NuxtRenderHTMLContext, context: { event: H3Event }) => void | Promise<void>
'render:island': (islandResponse: NuxtIslandResponse, context: { event: H3Event, islandContext: NuxtIslandContext }) => void | Promise<void>
}
}
declare module 'nitropack/types' {
interface NitroRuntimeConfigApp { interface NitroRuntimeConfigApp {
buildAssetsDir: string buildAssetsDir: string
cdnURL: string cdnURL: string

View File

@ -31,6 +31,7 @@ export default defineBuildConfig({
'vue', 'vue',
'unctx', 'unctx',
'hookable', 'hookable',
'nitro',
'nitropack', 'nitropack',
'webpack', 'webpack',
'webpack-bundle-analyzer', 'webpack-bundle-analyzer',

View File

@ -47,9 +47,9 @@
"@vue/language-core": "2.0.22", "@vue/language-core": "2.0.22",
"c12": "1.11.1", "c12": "1.11.1",
"esbuild-loader": "4.2.0", "esbuild-loader": "4.2.0",
"h3": "1.12.0", "h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"ignore": "5.3.1", "ignore": "5.3.1",
"nitropack": "2.9.6", "nitro": "npm:nitro-nightly@3.0.0-beta-28648657.9a717203",
"ofetch": "1.3.4", "ofetch": "1.3.4",
"unbuild": "latest", "unbuild": "latest",
"unctx": "2.3.1", "unctx": "2.3.1",

View File

@ -106,6 +106,12 @@ export default defineUntypedSchema({
*/ */
externalVue: true, externalVue: true,
/**
* Enable accessing `appConfig` from server routes.
*
* @deprecated This option is not recommended.
*/
serverAppConfig: false,
/** /**
* Emit `app:chunkError` hook when there is an error loading vite/webpack * Emit `app:chunkError` hook when there is an error loading vite/webpack
* chunks. * chunks.

View File

@ -5,7 +5,7 @@ export default defineUntypedSchema({
/** /**
* Configuration for Nitro. * Configuration for Nitro.
* @see https://nitro.unjs.io/config/ * @see https://nitro.unjs.io/config/
* @type {typeof import('nitropack')['NitroConfig']} * @type {typeof import('nitro/types')['NitroConfig']}
*/ */
nitro: { nitro: {
runtimeConfig: { runtimeConfig: {
@ -38,7 +38,7 @@ export default defineUntypedSchema({
* Global route options applied to matching server routes. * Global route options applied to matching server routes.
* @experimental This is an experimental feature and API may change in the future. * @experimental This is an experimental feature and API may change in the future.
* @see https://nitro.unjs.io/config/#routerules * @see https://nitro.unjs.io/config/#routerules
* @type {typeof import('nitropack')['NitroConfig']['routeRules']} * @type {typeof import('nitro/types')['NitroConfig']['routeRules']}
*/ */
routeRules: {}, routeRules: {},
@ -61,14 +61,14 @@ export default defineUntypedSchema({
* { route: '/path/foo/**:name', handler: '~/server/foohandler.ts' } * { route: '/path/foo/**:name', handler: '~/server/foohandler.ts' }
* ] * ]
* ``` * ```
* @type {typeof import('nitropack')['NitroEventHandler'][]} * @type {typeof import('nitro/types')['NitroEventHandler'][]}
*/ */
serverHandlers: [], serverHandlers: [],
/** /**
* Nitro development-only server handlers. * Nitro development-only server handlers.
* @see https://nitro.unjs.io/guide/routing * @see https://nitro.unjs.io/guide/routing
* @type {typeof import('nitropack')['NitroDevEventHandler'][]} * @type {typeof import('nitro/types')['NitroDevEventHandler'][]}
*/ */
devServerHandlers: [], devServerHandlers: [],
}) })

View File

@ -34,7 +34,7 @@ export default defineUntypedSchema({
$resolve: (val) => { $resolve: (val) => {
const defaults = [ const defaults = [
// Nitro auto-imported/augmented dependencies // Nitro auto-imported/augmented dependencies
'nitropack', 'nitro/types',
'defu', 'defu',
'h3', 'h3',
'consola', 'consola',

View File

@ -3,7 +3,7 @@ import type { ServerOptions as ViteServerOptions, UserConfig as ViteUserConfig }
import type { Options as VuePluginOptions } from '@vitejs/plugin-vue' import type { Options as VuePluginOptions } from '@vitejs/plugin-vue'
import type { Options as VueJsxPluginOptions } from '@vitejs/plugin-vue-jsx' import type { Options as VueJsxPluginOptions } from '@vitejs/plugin-vue-jsx'
import type { SchemaDefinition } from 'untyped' import type { SchemaDefinition } from 'untyped'
import type { NitroRuntimeConfig, NitroRuntimeConfigApp } from 'nitropack' import type { NitroRuntimeConfig, NitroRuntimeConfigApp } from 'nitro/types'
import type { SnakeCase } from 'scule' import type { SnakeCase } from 'scule'
import type { ConfigSchema } from '../../schema/config' import type { ConfigSchema } from '../../schema/config'
import type { Nuxt } from './nuxt' import type { Nuxt } from './nuxt'

View File

@ -6,7 +6,7 @@ import type { Manifest } from 'vue-bundle-renderer'
import type { EventHandler } from 'h3' import type { EventHandler } from 'h3'
import type { Import, InlinePreset, Unimport } from 'unimport' import type { Import, InlinePreset, Unimport } from 'unimport'
import type { Compiler, Configuration, Stats } from 'webpack' import type { Compiler, Configuration, Stats } from 'webpack'
import type { Nitro, NitroConfig } from 'nitropack' import type { Nitro, NitroConfig } from 'nitro/types'
import type { Schema, SchemaDefinition } from 'untyped' import type { Schema, SchemaDefinition } from 'untyped'
import type { RouteLocationRaw } from 'vue-router' import type { RouteLocationRaw } from 'vue-router'
import type { VueCompilerOptions } from '@vue/language-core' import type { VueCompilerOptions } from '@vue/language-core'

View File

@ -46,7 +46,7 @@
"estree-walker": "^3.0.3", "estree-walker": "^3.0.3",
"externality": "^1.0.2", "externality": "^1.0.2",
"get-port-please": "^3.1.2", "get-port-please": "^3.1.2",
"h3": "^1.12.0", "h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"knitwork": "^1.1.0", "knitwork": "^1.1.0",
"magic-string": "^0.30.10", "magic-string": "^0.30.10",
"mlly": "^1.7.1", "mlly": "^1.7.1",

View File

@ -112,7 +112,7 @@ export async function buildClient (ctx: ViteBuildContext) {
...ctx.config.resolve?.alias, ...ctx.config.resolve?.alias,
'#internal/nuxt/paths': resolve(ctx.nuxt.options.buildDir, 'paths.mjs'), '#internal/nuxt/paths': resolve(ctx.nuxt.options.buildDir, 'paths.mjs'),
'#build/plugins': resolve(ctx.nuxt.options.buildDir, 'plugins/client'), '#build/plugins': resolve(ctx.nuxt.options.buildDir, 'plugins/client'),
'#internal/nitro': resolve(ctx.nuxt.options.buildDir, 'nitro.client.mjs'), 'nitro/runtime': resolve(ctx.nuxt.options.buildDir, 'nitro.client.mjs'),
}, },
dedupe: [ dedupe: [
'vue', 'vue',

View File

@ -61,7 +61,7 @@ export async function buildServer (ctx: ViteBuildContext) {
}, },
ssr: { ssr: {
external: [ external: [
'#internal/nitro', '#internal/nitro/utils', 'nitro/runtime',
], ],
noExternal: [ noExternal: [
...transpile({ isServer: true, isDev: ctx.nuxt.options.dev }), ...transpile({ isServer: true, isDev: ctx.nuxt.options.dev }),
@ -80,7 +80,7 @@ export async function buildServer (ctx: ViteBuildContext) {
ssr: true, ssr: true,
rollupOptions: { rollupOptions: {
input: { server: entry }, input: { server: entry },
external: ['#internal/nitro', '#internal/nuxt/paths'], external: ['nitro/runtime', '#internal/nuxt/paths', '#internal/nuxt/app-config'],
output: { output: {
entryFileNames: '[name].mjs', entryFileNames: '[name].mjs',
format: 'module', format: 'module',
@ -104,8 +104,8 @@ export async function buildServer (ctx: ViteBuildContext) {
} satisfies vite.InlineConfig, ctx.nuxt.options.vite.$server || {})) } satisfies vite.InlineConfig, ctx.nuxt.options.vite.$server || {}))
if (!ctx.nuxt.options.dev) { if (!ctx.nuxt.options.dev) {
const nitroDependencies = await tryResolveModule('nitropack/package.json', ctx.nuxt.options.modulesDir) const nitroDependencies = await tryResolveModule('nitro/runtime/meta', ctx.nuxt.options.modulesDir)
.then(r => import(r!)).then(r => r.dependencies ? Object.keys(r.dependencies) : []).catch(() => []) .then(r => import(r!)).then(r => r.runtimeDependencies || []).catch(() => [])
if (Array.isArray(serverConfig.ssr!.external)) { if (Array.isArray(serverConfig.ssr!.external)) {
serverConfig.ssr!.external.push( serverConfig.ssr!.external.push(
// explicit dependencies we use in our ssr renderer - these can be inlined (if necessary) in the nitro build // explicit dependencies we use in our ssr renderer - these can be inlined (if necessary) in the nitro build

View File

@ -37,8 +37,10 @@
"estree-walker": "^3.0.3", "estree-walker": "^3.0.3",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "^9.0.2", "fork-ts-checker-webpack-plugin": "^9.0.2",
"h3": "^1.12.0", "globby": "^14.0.1",
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"hash-sum": "^2.0.0", "hash-sum": "^2.0.0",
"knitwork": "^1.1.0",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"magic-string": "^0.30.10", "magic-string": "^0.30.10",
"memfs": "^4.9.3", "memfs": "^4.9.3",
@ -75,6 +77,7 @@
"@types/pify": "5.0.4", "@types/pify": "5.0.4",
"@types/webpack-bundle-analyzer": "4.7.0", "@types/webpack-bundle-analyzer": "4.7.0",
"@types/webpack-hot-middleware": "2.25.9", "@types/webpack-hot-middleware": "2.25.9",
"rollup": "4.18.0",
"unbuild": "latest", "unbuild": "latest",
"vue": "3.4.30" "vue": "3.4.30"
}, },

View File

@ -53,9 +53,9 @@ function serverStandalone (ctx: WebpackConfigContext) {
'#', '#',
...ctx.options.build.transpile, ...ctx.options.build.transpile,
] ]
const external = ['#internal/nitro'] const external = ['nitro/runtime']
if (!ctx.nuxt.options.dev) { if (!ctx.nuxt.options.dev) {
external.push('#internal/nuxt/paths') external.push('#internal/nuxt/paths', '#internal/nuxt/app-config')
} }
if (!Array.isArray(ctx.config.externals)) { return } if (!Array.isArray(ctx.config.externals)) { return }

View File

@ -0,0 +1,128 @@
import { pathToFileURL } from 'node:url'
import { globby } from 'globby'
import { genSafeVariableName } from 'knitwork'
import { resolve } from 'pathe'
import type { Plugin } from 'rollup'
const PLUGIN_NAME = 'dynamic-require'
const HELPER_DYNAMIC = `\0${PLUGIN_NAME}.mjs`
const DYNAMIC_REQUIRE_RE = /import\("\.\/" ?\+(.*)\).then/g
interface Options {
dir: string
inline: boolean
ignore: string[]
outDir?: string
prefix?: string
}
interface Chunk {
id: string
src: string
name: string
meta?: {
id?: string
ids?: string[]
moduleIds?: string[]
}
}
interface TemplateContext {
chunks: Chunk[]
}
export function dynamicRequire ({ dir, ignore, inline }: Options): Plugin {
return {
name: PLUGIN_NAME,
transform (code: string, _id: string) {
return {
code: code.replace(
DYNAMIC_REQUIRE_RE,
`import('${HELPER_DYNAMIC}').then(r => r.default || r).then(dynamicRequire => dynamicRequire($1)).then`,
),
map: null,
}
},
resolveId (id: string) {
return id === HELPER_DYNAMIC ? id : null
},
// TODO: Async chunk loading over network!
// renderDynamicImport () {
// return {
// left: 'fetch(', right: ')'
// }
// },
async load (_id: string) {
if (_id !== HELPER_DYNAMIC) {
return null
}
// Scan chunks
let files = []
try {
const wpManifest = resolve(dir, './server.manifest.json')
files = await import(pathToFileURL(wpManifest).href).then(r =>
Object.keys(r.files).filter(file => !ignore.includes(file)),
)
} catch {
files = await globby('**/*.{cjs,mjs,js}', {
cwd: dir,
absolute: false,
ignore,
})
}
const chunks = (
await Promise.all(
files.map(async id => ({
id,
src: resolve(dir, id).replace(/\\/g, '/'),
name: genSafeVariableName(id),
meta: await getWebpackChunkMeta(resolve(dir, id)),
})),
)
).filter(chunk => chunk.meta) as Chunk[]
return inline ? TMPL_INLINE({ chunks }) : TMPL_LAZY({ chunks })
},
}
}
async function getWebpackChunkMeta (src: string) {
const chunk = await import(pathToFileURL(src).href).then(
r => r.default || r || {},
)
const { id, ids, modules } = chunk
if (!id && !ids) {
return null // Not a webpack chunk
}
return {
id,
ids,
moduleIds: Object.keys(modules || {}),
}
}
function TMPL_INLINE ({ chunks }: TemplateContext) {
return `${chunks
.map(i => `import * as ${i.name} from '${i.src}'`)
.join('\n')}
const dynamicChunks = {
${chunks.map(i => ` ['${i.id}']: ${i.name}`).join(',\n')}
};
export default function dynamicRequire(id) {
return Promise.resolve(dynamicChunks[id]);
};`
}
function TMPL_LAZY ({ chunks }: TemplateContext) {
return `
const dynamicChunks = {
${chunks.map(i => ` ['${i.id}']: () => import('${i.src}')`).join(',\n')}
};
export default function dynamicRequire(id) {
return dynamicChunks[id]();
};`
}

View File

@ -125,7 +125,7 @@ function baseAlias (ctx: WebpackConfigContext) {
...ctx.alias, ...ctx.alias,
} }
if (ctx.isClient) { if (ctx.isClient) {
ctx.alias['#internal/nitro'] = resolve(ctx.nuxt.options.buildDir, 'nitro.client.mjs') ctx.alias['nitro/runtime'] = resolve(ctx.nuxt.options.buildDir, 'nitro.client.mjs')
} }
} }

View File

@ -1,6 +1,7 @@
import pify from 'pify' import pify from 'pify'
import webpack from 'webpack' import webpack from 'webpack'
import type { NodeMiddleware } from 'h3' import type { NodeMiddleware } from 'h3'
import { resolve } from 'pathe'
import { defineEventHandler, fromNodeMiddleware } from 'h3' import { defineEventHandler, fromNodeMiddleware } from 'h3'
import type { MultiWatching } from 'webpack-dev-middleware' import type { MultiWatching } from 'webpack-dev-middleware'
import webpackDevMiddleware from 'webpack-dev-middleware' import webpackDevMiddleware from 'webpack-dev-middleware'
@ -9,7 +10,8 @@ import type { Compiler, Stats, Watching } from 'webpack'
import { defu } from 'defu' import { defu } from 'defu'
import type { NuxtBuilder } from '@nuxt/schema' import type { NuxtBuilder } from '@nuxt/schema'
import { joinURL } from 'ufo' import { joinURL } from 'ufo'
import { logger, useNuxt } from '@nuxt/kit' import { logger, useNitro, useNuxt } from '@nuxt/kit'
import type { InputPluginOption } from 'rollup'
import { composableKeysPlugin } from '../../vite/src/plugins/composable-keys' import { composableKeysPlugin } from '../../vite/src/plugins/composable-keys'
import { DynamicBasePlugin } from './plugins/dynamic-base' import { DynamicBasePlugin } from './plugins/dynamic-base'
@ -18,6 +20,7 @@ import { createMFS } from './utils/mfs'
import { registerVirtualModules } from './virtual-modules' import { registerVirtualModules } from './virtual-modules'
import { client, server } from './configs' import { client, server } from './configs'
import { applyPresets, createWebpackConfigContext, getWebpackConfig } from './utils/config' import { applyPresets, createWebpackConfigContext, getWebpackConfig } from './utils/config'
import { dynamicRequire } from './nitro/plugins/dynamic-require'
// TODO: Support plugins // TODO: Support plugins
// const plugins: string[] = [] // const plugins: string[] = []
@ -32,6 +35,26 @@ export const bundle: NuxtBuilder['bundle'] = async (nuxt) => {
return getWebpackConfig(ctx) return getWebpackConfig(ctx)
}) })
/** Inject rollup plugin for Nitro to handle dynamic imports from webpack chunks */
const nitro = useNitro()
const dynamicRequirePlugin = dynamicRequire({
dir: resolve(nuxt.options.buildDir, 'dist/server'),
inline:
nitro.options.node === false || nitro.options.inlineDynamicImports,
ignore: [
'client.manifest.mjs',
'server.js',
'server.cjs',
'server.mjs',
'server.manifest.mjs',
],
})
const prerenderRollupPlugins = nitro.options._config.rollupConfig!.plugins as InputPluginOption[]
const rollupPlugins = nitro.options.rollupConfig!.plugins as InputPluginOption[]
prerenderRollupPlugins.push(dynamicRequirePlugin)
rollupPlugins.push(dynamicRequirePlugin)
await nuxt.callHook('webpack:config', webpackConfigs) await nuxt.callHook('webpack:config', webpackConfigs)
// Initialize shared MFS for dev // Initialize shared MFS for dev

View File

@ -0,0 +1,33 @@
diff --git a/dist/node.d.cts b/dist/node.d.cts
index d3a39ff53717d267ff4581af714533ff7229799c..4e3db1f3d6defb7b0c40d11589c0ff6cb8391ad5 100644
--- a/dist/node.d.cts
+++ b/dist/node.d.cts
@@ -1,5 +1,5 @@
import { $ as $Fetch } from './shared/ofetch.8459ad38.cjs';
-export { F as FetchError, c as createFetch, a as createFetchError } from './shared/ofetch.8459ad38.cjs';
+export { C as CreateFetchOptions, g as Fetch, b as FetchContext, F as FetchError, d as FetchOptions, h as FetchRequest, f as FetchResponse, G as GlobalOptions, I as IFetchError, M as MappedResponseType, R as ResponseMap, e as ResponseType, S as SearchParameters, c as createFetch, a as createFetchError } from './shared/ofetch.8459ad38.mjs';
declare function createNodeFetch(): (input: RequestInfo, init?: RequestInit) => any;
declare const fetch: typeof globalThis.fetch;
diff --git a/dist/node.d.mts b/dist/node.d.mts
index 3d8b330375ce60178c05292179ec8bac764ae516..bdcc322bd8554fc7e61d5d9760cb9991560560eb 100644
--- a/dist/node.d.mts
+++ b/dist/node.d.mts
@@ -1,5 +1,5 @@
import { $ as $Fetch } from './shared/ofetch.8459ad38.mjs';
-export { F as FetchError, c as createFetch, a as createFetchError } from './shared/ofetch.8459ad38.mjs';
+export { C as CreateFetchOptions, g as Fetch, b as FetchContext, F as FetchError, d as FetchOptions, h as FetchRequest, f as FetchResponse, G as GlobalOptions, I as IFetchError, M as MappedResponseType, R as ResponseMap, e as ResponseType, S as SearchParameters, c as createFetch, a as createFetchError } from './shared/ofetch.8459ad38.mjs';
declare function createNodeFetch(): (input: RequestInfo, init?: RequestInit) => any;
declare const fetch: typeof globalThis.fetch;
diff --git a/dist/node.d.ts b/dist/node.d.ts
index 6a5419d1939000a15958b362f44bf49fb1800207..4b319d2c3051e966274268670e243c5f99e2904d 100644
--- a/dist/node.d.ts
+++ b/dist/node.d.ts
@@ -1,5 +1,5 @@
import { $ as $Fetch } from './shared/ofetch.8459ad38.js';
-export { F as FetchError, c as createFetch, a as createFetchError } from './shared/ofetch.8459ad38.js';
+export { C as CreateFetchOptions, g as Fetch, b as FetchContext, F as FetchError, d as FetchOptions, h as FetchRequest, f as FetchResponse, G as GlobalOptions, I as IFetchError, M as MappedResponseType, R as ResponseMap, e as ResponseType, S as SearchParameters, c as createFetch, a as createFetchError } from './shared/ofetch.8459ad38.mjs';
declare function createNodeFetch(): (input: RequestInfo, init?: RequestInit) => any;
declare const fetch: typeof globalThis.fetch;

File diff suppressed because it is too large Load Diff

View File

@ -4,8 +4,8 @@ import { consola } from 'consola'
import { determineBumpType, loadWorkspace } from './_utils' import { determineBumpType, loadWorkspace } from './_utils'
const nightlyPackages = { const nightlyPackages = {
nitropack: 'nitropack-nightly', // nitro: 'nitro-nightly',
h3: 'h3-nightly', // h3: 'h3-nightly',
nuxi: 'nuxi-nightly', nuxi: 'nuxi-nightly',
} }

View File

@ -4,13 +4,16 @@ import { describe, expect, it } from 'vitest'
import { joinURL, withQuery } from 'ufo' import { joinURL, withQuery } from 'ufo'
import { isCI, isWindows } from 'std-env' import { isCI, isWindows } from 'std-env'
import { join, normalize } from 'pathe' import { join, normalize } from 'pathe'
import { $fetch, createPage, fetch, isDev, setup, startServer, url, useTestContext } from '@nuxt/test-utils/e2e' import { $fetch as _$fetch, createPage, fetch, isDev, setup, startServer, url, useTestContext } from '@nuxt/test-utils/e2e'
import { $fetchComponent } from '@nuxt/test-utils/experimental' import { $fetchComponent } from '@nuxt/test-utils/experimental'
import { expectNoClientErrors, expectWithPolling, gotoPath, isRenderingJson, parseData, parsePayload, renderPage } from './utils' import { expectNoClientErrors, expectWithPolling, gotoPath, isRenderingJson, parseData, parsePayload, renderPage } from './utils'
import type { NuxtIslandResponse } from '#app' import type { NuxtIslandResponse } from '#app'
// TODO: update @nuxt/test-utils
const $fetch = _$fetch as import('nitro/types').$Fetch<unknown, import('nitro/types').NitroFetchRequest>
const isWebpack = process.env.TEST_BUILDER === 'webpack' const isWebpack = process.env.TEST_BUILDER === 'webpack'
const isTestingAppManifest = process.env.TEST_MANIFEST !== 'manifest-off' const isTestingAppManifest = process.env.TEST_MANIFEST !== 'manifest-off'

View File

@ -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(`"210k"`) expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"209k"`)
const modules = await analyzeSizes('node_modules/**/*', serverDir) const modules = await analyzeSizes('node_modules/**/*', serverDir)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1341k"`) expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"1345k"`)
const packages = modules.files const packages = modules.files
.filter(m => m.endsWith('package.json')) .filter(m => m.endsWith('package.json'))
@ -55,6 +55,7 @@ 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",
"db0",
"devalue", "devalue",
"entities", "entities",
"estree-walker", "estree-walker",
@ -72,10 +73,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(`"532k"`) expect.soft(roundToKilobytes(serverStats.totalBytes)).toMatchInlineSnapshot(`"531k"`)
const modules = await analyzeSizes('node_modules/**/*', serverDir) const modules = await analyzeSizes('node_modules/**/*', serverDir)
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"76.2k"`) expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot(`"80.3k"`)
const packages = modules.files const packages = modules.files
.filter(m => m.endsWith('package.json')) .filter(m => m.endsWith('package.json'))
@ -86,6 +87,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
"@unhead/dom", "@unhead/dom",
"@unhead/shared", "@unhead/shared",
"@unhead/ssr", "@unhead/ssr",
"db0",
"devalue", "devalue",
"hookable", "hookable",
"unhead", "unhead",

View File

@ -5,7 +5,7 @@ import { createUnplugin } from 'unplugin'
import { withoutLeadingSlash } from 'ufo' import { withoutLeadingSlash } from 'ufo'
// (defined in nuxt/src/core/nitro.ts) // (defined in nuxt/src/core/nitro.ts)
declare module 'nitropack' { declare module 'nitro/types' {
interface NitroRouteConfig { interface NitroRouteConfig {
ssr?: boolean ssr?: boolean
} }
@ -242,6 +242,7 @@ export default defineNuxtConfig({
inlineStyles: id => !!id && !id.includes('assets.vue'), inlineStyles: id => !!id && !id.includes('assets.vue'),
}, },
experimental: { experimental: {
serverAppConfig: true,
typedPages: true, typedPages: true,
clientFallback: true, clientFallback: true,
restoreState: true, restoreState: true,

View File

@ -3,10 +3,13 @@ import { fileURLToPath } from 'node:url'
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import { isWindows } from 'std-env' import { isWindows } from 'std-env'
import { join } from 'pathe' import { join } from 'pathe'
import { $fetch, fetch, setup } from '@nuxt/test-utils/e2e' import { $fetch as _$fetch, fetch, setup } from '@nuxt/test-utils/e2e'
import { expectWithPolling, renderPage } from './utils' import { expectWithPolling, renderPage } from './utils'
// TODO: update @nuxt/test-utils
const $fetch = _$fetch as import('nitro/types').$Fetch<unknown, import('nitro/types').NitroFetchRequest>
const isWebpack = process.env.TEST_BUILDER === 'webpack' const isWebpack = process.env.TEST_BUILDER === 'webpack'
// TODO: fix HMR on Windows // TODO: fix HMR on Windows

View File

@ -31,15 +31,6 @@
], ],
"#app/*": [ "#app/*": [
"./packages/nuxt/src/app/*" "./packages/nuxt/src/app/*"
],
"#internal/nitro": [
"./node_modules/nitropack/dist/runtime"
],
"#internal/nitro/app": [
"./node_modules/nitropack/dist/runtime/app"
],
"#internal/nitro/utils": [
"./node_modules/nitropack/dist/runtime/utils"
] ]
} }
}, },