2023-06-20 18:55:20 +00:00
|
|
|
import { existsSync, promises as fsp, readFileSync } from 'node:fs'
|
2023-06-28 14:17:19 +00:00
|
|
|
import { cpus } from 'node:os'
|
2023-10-31 18:05:06 +00:00
|
|
|
import { join, normalize, relative, resolve } from 'pathe'
|
2023-09-19 21:31:18 +00:00
|
|
|
import { createRouter as createRadixRouter, exportMatcher, toRouteMatcher } from 'radix3'
|
|
|
|
import { randomUUID } from 'uncrypto'
|
2023-09-22 07:25:52 +00:00
|
|
|
import { joinURL, withTrailingSlash } from 'ufo'
|
2023-04-07 16:02:47 +00:00
|
|
|
import { build, copyPublicAssets, createDevServer, createNitro, prepare, prerender, scanHandlers, writeTypes } from 'nitropack'
|
|
|
|
import type { Nitro, NitroConfig } from 'nitropack'
|
2023-12-13 11:54:56 +00:00
|
|
|
import { findPath, logger, resolveIgnorePatterns, resolveNuxtModule } from '@nuxt/kit'
|
2022-11-15 13:52:16 +00:00
|
|
|
import escapeRE from 'escape-string-regexp'
|
2023-01-30 12:09:48 +00:00
|
|
|
import { defu } from 'defu'
|
2022-04-07 11:28:04 +00:00
|
|
|
import fsExtra from 'fs-extra'
|
2022-10-15 18:42:57 +00:00
|
|
|
import { dynamicEventHandler } from 'h3'
|
2023-10-21 18:17:53 +00:00
|
|
|
import type { Nuxt, RuntimeConfig } from 'nuxt/schema'
|
2023-06-20 18:55:20 +00:00
|
|
|
// @ts-expect-error TODO: add legacy type support for subpath imports
|
|
|
|
import { template as defaultSpaLoadingTemplate } from '@nuxt/ui-templates/templates/spa-loading-icon.mjs'
|
2023-11-16 15:16:42 +00:00
|
|
|
import { version as nuxtVersion } from '../../package.json'
|
2022-04-07 11:28:04 +00:00
|
|
|
import { distDir } from '../dirs'
|
|
|
|
import { ImportProtectionPlugin } from './plugins/import-protection'
|
|
|
|
|
2022-09-15 16:10:50 +00:00
|
|
|
export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
2022-04-07 11:28:04 +00:00
|
|
|
// Resolve config
|
|
|
|
const _nitroConfig = ((nuxt.options as any).nitro || {}) as NitroConfig
|
2023-02-07 17:18:47 +00:00
|
|
|
|
|
|
|
const excludePaths = nuxt.options._layers
|
|
|
|
.flatMap(l => [
|
|
|
|
l.cwd.match(/(?<=\/)node_modules\/(.+)$/)?.[1],
|
|
|
|
l.cwd.match(/\.pnpm\/.+\/node_modules\/(.+)$/)?.[1]
|
|
|
|
])
|
|
|
|
.filter((dir): dir is string => Boolean(dir))
|
|
|
|
.map(dir => escapeRE(dir))
|
|
|
|
const excludePattern = excludePaths.length
|
|
|
|
? [new RegExp(`node_modules\\/(?!${excludePaths.join('|')})`)]
|
|
|
|
: [/node_modules/]
|
|
|
|
|
2023-09-22 07:25:52 +00:00
|
|
|
const rootDirWithSlash = withTrailingSlash(nuxt.options.rootDir)
|
|
|
|
|
|
|
|
const modules = await resolveNuxtModule(rootDirWithSlash,
|
|
|
|
nuxt.options._installedModules
|
|
|
|
.filter(m => m.entryPath)
|
|
|
|
.map(m => m.entryPath)
|
|
|
|
)
|
|
|
|
|
2023-06-22 10:49:14 +00:00
|
|
|
const nitroConfig: NitroConfig = defu(_nitroConfig, {
|
2022-10-15 10:56:15 +00:00
|
|
|
debug: nuxt.options.debug,
|
2022-04-07 11:28:04 +00:00
|
|
|
rootDir: nuxt.options.rootDir,
|
2022-09-12 20:06:17 +00:00
|
|
|
workspaceDir: nuxt.options.workspaceDir,
|
2022-10-10 10:49:44 +00:00
|
|
|
srcDir: nuxt.options.serverDir,
|
2022-04-07 11:28:04 +00:00
|
|
|
dev: nuxt.options.dev,
|
|
|
|
buildDir: nuxt.options.buildDir,
|
2023-07-14 13:46:40 +00:00
|
|
|
experimental: {
|
2023-08-23 07:30:53 +00:00
|
|
|
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'
|
2023-07-14 13:46:40 +00:00
|
|
|
},
|
2023-11-16 15:16:42 +00:00
|
|
|
framework: {
|
|
|
|
name: 'nuxt',
|
|
|
|
version: nuxtVersion
|
|
|
|
},
|
2023-01-14 01:27:06 +00:00
|
|
|
imports: {
|
2023-06-22 10:49:14 +00:00
|
|
|
autoImport: nuxt.options.imports.autoImport as boolean,
|
2023-01-14 01:27:06 +00:00
|
|
|
imports: [
|
|
|
|
{
|
|
|
|
as: '__buildAssetsURL',
|
|
|
|
name: 'buildAssetsURL',
|
|
|
|
from: resolve(distDir, 'core/runtime/nitro/paths')
|
|
|
|
},
|
|
|
|
{
|
|
|
|
as: '__publicAssetsURL',
|
|
|
|
name: 'publicAssetsURL',
|
|
|
|
from: resolve(distDir, 'core/runtime/nitro/paths')
|
2023-03-14 09:54:59 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
// TODO: Remove after https://github.com/unjs/nitro/issues/1049
|
|
|
|
as: 'defineAppConfig',
|
|
|
|
name: 'defineAppConfig',
|
|
|
|
from: resolve(distDir, 'core/runtime/nitro/config'),
|
|
|
|
priority: -1
|
2023-01-14 01:27:06 +00:00
|
|
|
}
|
2023-02-07 17:18:47 +00:00
|
|
|
],
|
|
|
|
exclude: [...excludePattern, /[\\/]\.git[\\/]/]
|
2023-01-14 01:27:06 +00:00
|
|
|
},
|
2022-11-15 13:52:16 +00:00
|
|
|
esbuild: {
|
2023-02-07 17:18:47 +00:00
|
|
|
options: { exclude: excludePattern }
|
2022-11-15 13:52:16 +00:00
|
|
|
},
|
2023-12-05 17:09:46 +00:00
|
|
|
analyze: !nuxt.options.test && nuxt.options.build.analyze && (nuxt.options.build.analyze === true || nuxt.options.build.analyze.enabled)
|
2023-10-23 11:19:16 +00:00
|
|
|
? {
|
|
|
|
template: 'treemap',
|
|
|
|
projectRoot: nuxt.options.rootDir,
|
|
|
|
filename: join(nuxt.options.analyzeDir, '{name}.html')
|
|
|
|
}
|
|
|
|
: false,
|
2022-10-10 10:49:44 +00:00
|
|
|
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),
|
2022-04-07 11:28:04 +00:00
|
|
|
renderer: resolve(distDir, 'core/runtime/nitro/renderer'),
|
2022-04-12 20:37:32 +00:00
|
|
|
errorHandler: resolve(distDir, 'core/runtime/nitro/error'),
|
2022-04-07 11:28:04 +00:00
|
|
|
nodeModulesDirs: nuxt.options.modulesDir,
|
2022-10-27 10:36:37 +00:00
|
|
|
handlers: nuxt.options.serverHandlers,
|
2022-04-07 11:28:04 +00:00
|
|
|
devHandlers: [],
|
|
|
|
baseURL: nuxt.options.app.baseURL,
|
2022-11-10 11:41:02 +00:00
|
|
|
virtual: {
|
2023-06-20 18:55:20 +00:00
|
|
|
'#internal/nuxt.config.mjs': () => nuxt.vfs['#build/nuxt.config'],
|
2023-12-13 11:54:56 +00:00
|
|
|
'#spa-template': async () => `export const template = ${JSON.stringify(await spaLoadingTemplate(nuxt))}`
|
2022-11-10 11:41:02 +00:00
|
|
|
},
|
2022-10-18 18:01:23 +00:00
|
|
|
routeRules: {
|
|
|
|
'/__nuxt_error': { cache: false }
|
|
|
|
},
|
2022-04-07 11:28:04 +00:00
|
|
|
runtimeConfig: {
|
2022-04-11 14:34:23 +00:00
|
|
|
...nuxt.options.runtimeConfig,
|
2023-10-21 18:17:53 +00:00
|
|
|
app: {
|
|
|
|
...nuxt.options.runtimeConfig.app,
|
|
|
|
baseURL: nuxt.options.runtimeConfig.app.baseURL.startsWith('./')
|
|
|
|
? nuxt.options.runtimeConfig.app.baseURL.slice(1)
|
|
|
|
: nuxt.options.runtimeConfig.app.baseURL
|
2023-11-20 20:31:29 +00:00
|
|
|
},
|
2022-04-07 11:28:04 +00:00
|
|
|
nitro: {
|
2022-04-11 14:34:23 +00:00
|
|
|
envPrefix: 'NUXT_',
|
2023-11-20 20:31:29 +00:00
|
|
|
// TODO: address upstream issue with defu types...?
|
|
|
|
...nuxt.options.runtimeConfig.nitro satisfies RuntimeConfig['nitro'] as any
|
2022-04-07 11:28:04 +00:00
|
|
|
}
|
2023-11-20 20:31:29 +00:00
|
|
|
} ,
|
2023-03-14 09:54:59 +00:00
|
|
|
appConfig: nuxt.options.appConfig,
|
|
|
|
appConfigFiles: nuxt.options._layers.map(
|
|
|
|
layer => resolve(layer.config.srcDir, 'app.config')
|
|
|
|
),
|
2022-04-07 11:28:04 +00:00
|
|
|
typescript: {
|
2023-05-15 15:36:30 +00:00
|
|
|
strict: true,
|
|
|
|
generateTsConfig: true,
|
2023-06-22 10:49:14 +00:00
|
|
|
tsconfigPath: 'tsconfig.server.json',
|
|
|
|
tsConfig: {
|
|
|
|
include: [
|
2023-09-22 07:25:52 +00:00
|
|
|
join(nuxt.options.buildDir, 'types/nitro-nuxt.d.ts'),
|
|
|
|
...modules.map(m => join(relativeWithDot(nuxt.options.buildDir, m), 'runtime/server'))
|
2023-08-23 20:36:33 +00:00
|
|
|
],
|
|
|
|
exclude: [
|
|
|
|
...nuxt.options.modulesDir.map(m => relativeWithDot(nuxt.options.buildDir, m)),
|
|
|
|
// nitro generate output: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/nitro.ts#L186
|
|
|
|
relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, 'dist'))
|
2023-06-22 10:49:14 +00:00
|
|
|
]
|
|
|
|
}
|
2022-04-07 11:28:04 +00:00
|
|
|
},
|
|
|
|
publicAssets: [
|
2023-02-09 06:02:07 +00:00
|
|
|
nuxt.options.dev
|
|
|
|
? { dir: resolve(nuxt.options.buildDir, 'dist/client') }
|
|
|
|
: {
|
|
|
|
dir: join(nuxt.options.buildDir, 'dist/client', nuxt.options.app.buildAssetsDir),
|
2023-02-28 13:06:31 +00:00
|
|
|
maxAge: 31536000 /* 1 year */,
|
2023-02-09 06:02:07 +00:00
|
|
|
baseURL: nuxt.options.app.buildAssetsDir
|
|
|
|
},
|
2022-04-07 11:28:04 +00:00
|
|
|
...nuxt.options._layers
|
2023-09-12 14:27:28 +00:00
|
|
|
.map(layer => join(layer.config.srcDir, (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options : layer.config).dir?.public || 'public'))
|
2022-04-07 11:28:04 +00:00
|
|
|
.filter(dir => existsSync(dir))
|
|
|
|
.map(dir => ({ dir }))
|
|
|
|
],
|
|
|
|
prerender: {
|
2023-06-28 14:17:19 +00:00
|
|
|
failOnError: true,
|
|
|
|
concurrency: cpus().length * 4 || 4,
|
2023-06-29 09:14:35 +00:00
|
|
|
routes: ([] as string[]).concat(nuxt.options.generate.routes)
|
2022-04-07 11:28:04 +00:00
|
|
|
},
|
2022-09-07 11:32:10 +00:00
|
|
|
sourceMap: nuxt.options.sourcemap.server,
|
2022-04-07 11:28:04 +00:00
|
|
|
externals: {
|
2022-04-07 12:57:57 +00:00
|
|
|
inline: [
|
2022-06-10 14:31:36 +00:00
|
|
|
...(nuxt.options.dev
|
|
|
|
? []
|
|
|
|
: [
|
|
|
|
...nuxt.options.experimental.externalVue ? [] : ['vue', '@vue/'],
|
|
|
|
'@nuxt/',
|
|
|
|
nuxt.options.buildDir
|
|
|
|
]),
|
2023-06-22 10:49:14 +00:00
|
|
|
...nuxt.options.build.transpile.filter((i): i is string => typeof i === 'string'),
|
2022-04-07 12:57:57 +00:00
|
|
|
'nuxt/dist',
|
2022-09-15 11:24:43 +00:00
|
|
|
'nuxt3/dist',
|
2023-10-12 14:17:38 +00:00
|
|
|
'nuxt-nightly/dist',
|
2022-09-15 11:24:43 +00:00
|
|
|
distDir
|
2023-04-06 11:51:32 +00:00
|
|
|
],
|
|
|
|
traceInclude: [
|
|
|
|
// force include files used in generated code from the runtime-compiler
|
2023-05-01 16:39:07 +00:00
|
|
|
...(nuxt.options.vue.runtimeCompiler && !nuxt.options.experimental.externalVue)
|
2023-04-06 11:51:32 +00:00
|
|
|
? [
|
|
|
|
...nuxt.options.modulesDir.reduce<string[]>((targets, path) => {
|
|
|
|
const serverRendererPath = resolve(path, 'vue/server-renderer/index.js')
|
|
|
|
if (existsSync(serverRendererPath)) { targets.push(serverRendererPath) }
|
|
|
|
return targets
|
|
|
|
}, [])
|
|
|
|
]
|
|
|
|
: []
|
2022-04-07 12:57:57 +00:00
|
|
|
]
|
2022-04-07 11:28:04 +00:00
|
|
|
},
|
|
|
|
alias: {
|
|
|
|
// Vue 3 mocks
|
2023-05-01 16:39:07 +00:00
|
|
|
...nuxt.options.vue.runtimeCompiler || nuxt.options.experimental.externalVue
|
2023-04-06 11:51:32 +00:00
|
|
|
? {}
|
|
|
|
: {
|
|
|
|
'estree-walker': 'unenv/runtime/mock/proxy',
|
|
|
|
'@babel/parser': 'unenv/runtime/mock/proxy',
|
|
|
|
'@vue/compiler-core': 'unenv/runtime/mock/proxy',
|
|
|
|
'@vue/compiler-dom': 'unenv/runtime/mock/proxy',
|
|
|
|
'@vue/compiler-ssr': 'unenv/runtime/mock/proxy'
|
|
|
|
},
|
2022-08-17 14:44:36 +00:00
|
|
|
'@vue/devtools-api': 'vue-devtools-stub',
|
2022-04-07 11:28:04 +00:00
|
|
|
|
|
|
|
// Paths
|
2022-04-08 00:05:27 +00:00
|
|
|
'#paths': resolve(distDir, 'core/runtime/nitro/paths'),
|
|
|
|
|
|
|
|
// Nuxt aliases
|
|
|
|
...nuxt.options.alias
|
2022-04-07 11:28:04 +00:00
|
|
|
},
|
|
|
|
replace: {
|
2022-07-12 12:32:07 +00:00
|
|
|
'process.env.NUXT_NO_SSR': nuxt.options.ssr === false,
|
2022-10-17 20:20:13 +00:00
|
|
|
'process.env.NUXT_EARLY_HINTS': nuxt.options.experimental.writeEarlyHints !== false,
|
2022-09-26 09:52:43 +00:00
|
|
|
'process.env.NUXT_NO_SCRIPTS': !!nuxt.options.experimental.noScripts && !nuxt.options.dev,
|
2022-09-03 13:03:30 +00:00
|
|
|
'process.env.NUXT_INLINE_STYLES': !!nuxt.options.experimental.inlineSSRStyles,
|
2023-04-07 10:34:35 +00:00
|
|
|
'process.env.NUXT_JSON_PAYLOADS': !!nuxt.options.experimental.renderJsonPayloads,
|
2022-11-24 12:24:14 +00:00
|
|
|
'process.env.NUXT_COMPONENT_ISLANDS': !!nuxt.options.experimental.componentIslands,
|
2023-08-07 22:57:35 +00:00
|
|
|
'process.env.NUXT_ASYNC_CONTEXT': !!nuxt.options.experimental.asyncContext,
|
2022-08-11 22:33:21 +00:00
|
|
|
'process.dev': nuxt.options.dev,
|
|
|
|
__VUE_PROD_DEVTOOLS__: false
|
2022-05-06 08:33:56 +00:00
|
|
|
},
|
|
|
|
rollupConfig: {
|
2022-12-12 15:22:04 +00:00
|
|
|
output: {},
|
2022-05-06 08:33:56 +00:00
|
|
|
plugins: []
|
2022-04-07 11:28:04 +00:00
|
|
|
}
|
2023-06-22 10:49:14 +00:00
|
|
|
} satisfies NitroConfig)
|
2022-04-07 11:28:04 +00:00
|
|
|
|
2023-04-07 13:19:53 +00:00
|
|
|
// Resolve user-provided paths
|
|
|
|
nitroConfig.srcDir = resolve(nuxt.options.rootDir, nuxt.options.srcDir, nitroConfig.srcDir!)
|
2023-08-25 12:08:38 +00:00
|
|
|
nitroConfig.ignore = [...(nitroConfig.ignore || []), ...resolveIgnorePatterns(nitroConfig.srcDir)]
|
2023-04-07 13:19:53 +00:00
|
|
|
|
2023-09-19 21:31:18 +00:00
|
|
|
// Add app manifest handler and prerender configuration
|
|
|
|
if (nuxt.options.experimental.appManifest) {
|
|
|
|
// @ts-expect-error untyped nuxt property
|
2023-10-03 09:58:36 +00:00
|
|
|
const buildId = nuxt.options.appConfig.nuxt!.buildId ||=
|
2023-10-20 15:52:37 +00:00
|
|
|
(nuxt.options.dev ? 'dev' : nuxt.options.test ? 'test' : randomUUID())
|
2023-09-19 21:31:18 +00:00
|
|
|
const buildTimestamp = Date.now()
|
|
|
|
|
|
|
|
const manifestPrefix = joinURL(nuxt.options.app.buildAssetsDir, 'builds')
|
|
|
|
const tempDir = join(nuxt.options.buildDir, 'manifest')
|
|
|
|
|
2023-11-28 13:02:30 +00:00
|
|
|
nitroConfig.prerender ||= {}
|
|
|
|
nitroConfig.prerender.ignore ||= []
|
|
|
|
nitroConfig.prerender.ignore.push(manifestPrefix)
|
|
|
|
|
2023-09-19 21:31:18 +00:00
|
|
|
nitroConfig.publicAssets!.unshift(
|
|
|
|
// build manifest
|
|
|
|
{
|
|
|
|
dir: join(tempDir, 'meta'),
|
|
|
|
maxAge: 31536000 /* 1 year */,
|
|
|
|
baseURL: joinURL(manifestPrefix, 'meta')
|
|
|
|
},
|
|
|
|
// latest build
|
|
|
|
{
|
|
|
|
dir: tempDir,
|
|
|
|
maxAge: 1,
|
|
|
|
baseURL: manifestPrefix
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
2023-10-30 20:56:34 +00:00
|
|
|
nuxt.hook('nitro:init', (nitro) => {
|
|
|
|
nitro.hooks.hook('rollup:before', async (nitro) => {
|
|
|
|
const routeRules = {} as Record<string, any>
|
|
|
|
const _routeRules = nitro.options.routeRules
|
|
|
|
for (const key in _routeRules) {
|
|
|
|
if (key === '/__nuxt_error') { continue }
|
|
|
|
const filteredRules = Object.entries(_routeRules[key])
|
|
|
|
.filter(([key, value]) => ['prerender', 'redirect'].includes(key) && value)
|
|
|
|
.map(([key, value]: any) => {
|
|
|
|
if (key === 'redirect') {
|
|
|
|
return [key, typeof value === 'string' ? value : value.to]
|
|
|
|
}
|
|
|
|
return [key, value]
|
|
|
|
})
|
|
|
|
if (filteredRules.length > 0) {
|
|
|
|
routeRules[key] = Object.fromEntries(filteredRules)
|
|
|
|
}
|
2023-09-19 21:31:18 +00:00
|
|
|
}
|
|
|
|
|
2023-10-30 20:56:34 +00:00
|
|
|
// Add pages prerendered but not covered by route rules
|
|
|
|
const prerenderedRoutes = new Set<string>()
|
|
|
|
const routeRulesMatcher = toRouteMatcher(
|
|
|
|
createRadixRouter({ routes: routeRules })
|
|
|
|
)
|
|
|
|
const payloadSuffix = nuxt.options.experimental.renderJsonPayloads ? '/_payload.json' : '/_payload.js'
|
|
|
|
for (const route of nitro._prerenderedRoutes || []) {
|
|
|
|
if (!route.error && route.route.endsWith(payloadSuffix)) {
|
|
|
|
const url = route.route.slice(0, -payloadSuffix.length) || '/'
|
|
|
|
const rules = defu({}, ...routeRulesMatcher.matchAll(url).reverse()) as Record<string, any>
|
|
|
|
if (!rules.prerender) {
|
|
|
|
prerenderedRoutes.add(url)
|
|
|
|
}
|
2023-09-19 21:31:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-30 20:56:34 +00:00
|
|
|
const manifest = {
|
|
|
|
id: buildId,
|
|
|
|
timestamp: buildTimestamp,
|
|
|
|
matcher: exportMatcher(routeRulesMatcher),
|
|
|
|
prerendered: nuxt.options.dev ? [] : [...prerenderedRoutes]
|
|
|
|
}
|
2023-09-19 21:31:18 +00:00
|
|
|
|
2023-10-30 20:56:34 +00:00
|
|
|
await fsp.mkdir(join(tempDir, 'meta'), { recursive: true })
|
|
|
|
await fsp.writeFile(join(tempDir, 'latest.json'), JSON.stringify({
|
|
|
|
id: buildId,
|
|
|
|
timestamp: buildTimestamp
|
|
|
|
}))
|
|
|
|
await fsp.writeFile(join(tempDir, `meta/${buildId}.json`), JSON.stringify(manifest))
|
|
|
|
})
|
2023-09-19 21:31:18 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-07-07 16:51:42 +00:00
|
|
|
// Add fallback server for `ssr: false`
|
|
|
|
if (!nuxt.options.ssr) {
|
2022-08-12 17:47:58 +00:00
|
|
|
nitroConfig.virtual!['#build/dist/server/server.mjs'] = 'export default () => {}'
|
2023-02-09 06:02:07 +00:00
|
|
|
// In case a non-normalized absolute path is called for on Windows
|
|
|
|
if (process.platform === 'win32') {
|
|
|
|
nitroConfig.virtual!['#build/dist/server/server.mjs'.replace(/\//g, '\\')] = 'export default () => {}'
|
|
|
|
}
|
2022-07-07 16:51:42 +00:00
|
|
|
}
|
|
|
|
|
2023-05-11 22:33:17 +00:00
|
|
|
if (nuxt.options.builder === '@nuxt/webpack-builder' || nuxt.options.dev) {
|
2022-09-03 13:03:30 +00:00
|
|
|
nitroConfig.virtual!['#build/dist/server/styles.mjs'] = 'export default {}'
|
2023-02-09 06:02:07 +00:00
|
|
|
// In case a non-normalized absolute path is called for on Windows
|
|
|
|
if (process.platform === 'win32') {
|
|
|
|
nitroConfig.virtual!['#build/dist/server/styles.mjs'.replace(/\//g, '\\')] = 'export default {}'
|
|
|
|
}
|
2022-09-03 13:03:30 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 10:39:01 +00:00
|
|
|
// Add backward-compatible middleware to respect `x-nuxt-no-ssr` header
|
|
|
|
if (nuxt.options.experimental.respectNoSSRHeader) {
|
|
|
|
nitroConfig.handlers = nitroConfig.handlers || []
|
|
|
|
nitroConfig.handlers.push({
|
|
|
|
handler: resolve(distDir, 'core/runtime/nitro/no-ssr'),
|
|
|
|
middleware: true
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-07-12 10:55:32 +00:00
|
|
|
// Register nuxt protection patterns
|
2022-12-12 15:22:04 +00:00
|
|
|
nitroConfig.rollupConfig!.plugins = await nitroConfig.rollupConfig!.plugins || []
|
|
|
|
nitroConfig.rollupConfig!.plugins = Array.isArray(nitroConfig.rollupConfig!.plugins) ? nitroConfig.rollupConfig!.plugins : [nitroConfig.rollupConfig!.plugins]
|
2022-10-18 09:36:06 +00:00
|
|
|
nitroConfig.rollupConfig!.plugins!.push(
|
2023-11-20 18:10:58 +00:00
|
|
|
// @ts-expect-error rollup 4 types
|
2022-10-18 09:36:06 +00:00
|
|
|
ImportProtectionPlugin.rollup({
|
|
|
|
rootDir: nuxt.options.rootDir,
|
|
|
|
patterns: [
|
|
|
|
...['#app', /^#build(\/|$)/]
|
|
|
|
.map(p => [p, 'Vue app aliases are not allowed in server routes.']) as [RegExp | string, string][]
|
|
|
|
],
|
|
|
|
exclude: [/core[\\/]runtime[\\/]nitro[\\/]renderer/]
|
2023-02-05 12:31:53 +00:00
|
|
|
})
|
2022-10-18 09:36:06 +00:00
|
|
|
)
|
2022-07-12 10:55:32 +00:00
|
|
|
|
2022-04-07 11:28:04 +00:00
|
|
|
// Extend nitro config with hook
|
|
|
|
await nuxt.callHook('nitro:config', nitroConfig)
|
|
|
|
|
2023-06-22 10:49:14 +00:00
|
|
|
// TODO: extract to shared utility?
|
|
|
|
const excludedAlias = [/^@vue\/.*$/, '#imports', '#vue-router', 'vue-demi', /^#app/]
|
|
|
|
const basePath = nitroConfig.typescript!.tsConfig!.compilerOptions?.baseUrl ? resolve(nuxt.options.buildDir, nitroConfig.typescript!.tsConfig!.compilerOptions?.baseUrl) : nuxt.options.buildDir
|
|
|
|
const aliases = nitroConfig.alias!
|
|
|
|
const tsConfig = nitroConfig.typescript!.tsConfig!
|
|
|
|
tsConfig.compilerOptions = tsConfig.compilerOptions || {}
|
|
|
|
tsConfig.compilerOptions.paths = tsConfig.compilerOptions.paths || {}
|
|
|
|
for (const _alias in aliases) {
|
|
|
|
const alias = _alias as keyof typeof aliases
|
|
|
|
if (excludedAlias.some(pattern => typeof pattern === 'string' ? alias === pattern : pattern.test(alias))) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if (alias in tsConfig.compilerOptions.paths) { continue }
|
|
|
|
|
|
|
|
const absolutePath = resolve(basePath, aliases[alias]!)
|
|
|
|
const stats = await fsp.stat(absolutePath).catch(() => null /* file does not exist */)
|
|
|
|
if (stats?.isDirectory()) {
|
|
|
|
tsConfig.compilerOptions.paths[alias] = [absolutePath]
|
|
|
|
tsConfig.compilerOptions.paths[`${alias}/*`] = [`${absolutePath}/*`]
|
|
|
|
} else {
|
|
|
|
tsConfig.compilerOptions.paths[alias] = [absolutePath.replace(/(?<=\w)\.\w+$/g, '')] /* remove extension */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-07 11:28:04 +00:00
|
|
|
// Init nitro
|
|
|
|
const nitro = await createNitro(nitroConfig)
|
|
|
|
|
2023-10-31 18:05:06 +00:00
|
|
|
// Trigger Nitro reload when SPA loading template changes
|
2023-12-13 11:54:56 +00:00
|
|
|
const spaLoadingTemplateFilePath = await spaLoadingTemplatePath(nuxt)
|
2023-10-31 18:05:06 +00:00
|
|
|
nuxt.hook('builder:watch', async (_event, path) => {
|
2023-12-13 11:54:56 +00:00
|
|
|
if (normalize(path) === spaLoadingTemplateFilePath) {
|
2023-10-31 18:05:06 +00:00
|
|
|
await nitro.hooks.callHook('rollup:reload')
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2023-08-04 07:47:42 +00:00
|
|
|
// Set prerender-only options
|
|
|
|
nitro.options._config.storage ||= {}
|
2023-08-04 07:54:09 +00:00
|
|
|
nitro.options._config.storage['internal:nuxt:prerender'] = { driver: 'memory' }
|
|
|
|
nitro.options._config.storage['internal:nuxt:prerender:island'] = { driver: 'lruCache', max: 1000 }
|
|
|
|
nitro.options._config.storage['internal:nuxt:prerender:payload'] = { driver: 'lruCache', max: 1000 }
|
2023-08-04 07:47:42 +00:00
|
|
|
|
2022-09-15 16:10:50 +00:00
|
|
|
// Expose nitro to modules and kit
|
|
|
|
nuxt._nitro = nitro
|
2022-04-07 11:28:04 +00:00
|
|
|
await nuxt.callHook('nitro:init', nitro)
|
|
|
|
|
|
|
|
// Connect vfs storages
|
|
|
|
nitro.vfs = nuxt.vfs = nitro.vfs || nuxt.vfs || {}
|
|
|
|
|
|
|
|
// Connect hooks
|
|
|
|
nuxt.hook('close', () => nitro.hooks.callHook('close'))
|
2022-11-03 21:03:12 +00:00
|
|
|
nitro.hooks.hook('prerender:routes', (routes) => {
|
2023-07-20 13:22:10 +00:00
|
|
|
return nuxt.callHook('prerender:routes', { routes })
|
2022-11-03 21:03:12 +00:00
|
|
|
})
|
2022-04-07 11:28:04 +00:00
|
|
|
|
2023-04-06 11:51:32 +00:00
|
|
|
// Enable runtime compiler client side
|
2023-05-01 16:39:07 +00:00
|
|
|
if (nuxt.options.vue.runtimeCompiler) {
|
2023-04-06 11:51:32 +00:00
|
|
|
nuxt.hook('vite:extendConfig', (config, { isClient }) => {
|
|
|
|
if (isClient) {
|
|
|
|
if (Array.isArray(config.resolve!.alias)) {
|
|
|
|
config.resolve!.alias.push({
|
|
|
|
find: 'vue',
|
|
|
|
replacement: 'vue/dist/vue.esm-bundler'
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
config.resolve!.alias = {
|
|
|
|
...config.resolve!.alias,
|
|
|
|
vue: 'vue/dist/vue.esm-bundler'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
nuxt.hook('webpack:config', (configuration) => {
|
|
|
|
const clientConfig = configuration.find(config => config.name === 'client')
|
|
|
|
if (!clientConfig!.resolve) { clientConfig!.resolve!.alias = {} }
|
|
|
|
if (Array.isArray(clientConfig!.resolve!.alias)) {
|
|
|
|
clientConfig!.resolve!.alias.push({
|
|
|
|
name: 'vue',
|
|
|
|
alias: 'vue/dist/vue.esm-bundler'
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
clientConfig!.resolve!.alias!.vue = 'vue/dist/vue.esm-bundler'
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-04-07 11:28:04 +00:00
|
|
|
// Setup handlers
|
2022-08-26 10:09:29 +00:00
|
|
|
const devMiddlewareHandler = dynamicEventHandler()
|
|
|
|
nitro.options.devHandlers.unshift({ handler: devMiddlewareHandler })
|
2022-10-27 10:36:37 +00:00
|
|
|
nitro.options.devHandlers.push(...nuxt.options.devServerHandlers)
|
2022-04-07 11:28:04 +00:00
|
|
|
nitro.options.handlers.unshift({
|
2022-04-09 09:52:42 +00:00
|
|
|
route: '/__nuxt_error',
|
2022-04-07 11:28:04 +00:00
|
|
|
lazy: true,
|
|
|
|
handler: resolve(distDir, 'core/runtime/nitro/renderer')
|
|
|
|
})
|
|
|
|
|
2023-06-11 20:41:22 +00:00
|
|
|
if (!nuxt.options.dev && nuxt.options.experimental.noVueServer) {
|
2023-03-23 09:04:40 +00:00
|
|
|
nitro.hooks.hook('rollup:before', (nitro) => {
|
|
|
|
if (nitro.options.preset === 'nitro-prerender') { return }
|
|
|
|
const nuxtErrorHandler = nitro.options.handlers.findIndex(h => h.route === '/__nuxt_error')
|
|
|
|
if (nuxtErrorHandler >= 0) {
|
|
|
|
nitro.options.handlers.splice(nuxtErrorHandler, 1)
|
|
|
|
}
|
2023-03-23 13:03:21 +00:00
|
|
|
|
2023-03-23 09:04:40 +00:00
|
|
|
nitro.options.renderer = undefined
|
|
|
|
nitro.options.errorHandler = '#internal/nitro/error'
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-04-07 11:28:04 +00:00
|
|
|
// Add typed route responses
|
|
|
|
nuxt.hook('prepare:types', async (opts) => {
|
2022-07-21 13:50:41 +00:00
|
|
|
if (!nuxt.options.dev) {
|
2022-04-07 11:28:04 +00:00
|
|
|
await scanHandlers(nitro)
|
|
|
|
await writeTypes(nitro)
|
|
|
|
}
|
2023-03-08 21:14:06 +00:00
|
|
|
// Exclude nitro output dir from typescript
|
|
|
|
opts.tsConfig.exclude = opts.tsConfig.exclude || []
|
|
|
|
opts.tsConfig.exclude.push(relative(nuxt.options.buildDir, resolve(nuxt.options.rootDir, nitro.options.output.dir)))
|
2022-04-07 11:28:04 +00:00
|
|
|
opts.references.push({ path: resolve(nuxt.options.buildDir, 'types/nitro.d.ts') })
|
|
|
|
})
|
|
|
|
|
2023-06-29 09:14:35 +00:00
|
|
|
if (nitro.options.static) {
|
|
|
|
nitro.hooks.hook('prerender:routes', (routes) => {
|
|
|
|
for (const route of [nuxt.options.ssr ? '/' : '/index.html', '/200.html', '/404.html']) {
|
|
|
|
routes.add(route)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-10-30 20:56:34 +00:00
|
|
|
// Copy public assets after prerender so app manifest can be present
|
|
|
|
if (!nuxt.options.dev) {
|
|
|
|
nitro.hooks.hook('rollup:before', async (nitro) => {
|
|
|
|
await copyPublicAssets(nitro)
|
|
|
|
await nuxt.callHook('nitro:build:public-assets', nitro)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-04-07 11:28:04 +00:00
|
|
|
// nuxt build/dev
|
|
|
|
nuxt.hook('build:done', async () => {
|
2022-05-02 20:15:47 +00:00
|
|
|
await nuxt.callHook('nitro:build:before', nitro)
|
2022-04-07 11:28:04 +00:00
|
|
|
if (nuxt.options.dev) {
|
|
|
|
await build(nitro)
|
|
|
|
} else {
|
|
|
|
await prepare(nitro)
|
2022-04-15 16:31:19 +00:00
|
|
|
await prerender(nitro)
|
2023-06-22 10:00:50 +00:00
|
|
|
|
|
|
|
logger.restoreAll()
|
|
|
|
await build(nitro)
|
|
|
|
logger.wrapAll()
|
|
|
|
|
2023-06-29 09:14:35 +00:00
|
|
|
if (nitro.options.static) {
|
2022-04-20 19:12:04 +00:00
|
|
|
const distDir = resolve(nuxt.options.rootDir, 'dist')
|
|
|
|
if (!existsSync(distDir)) {
|
2023-03-23 09:04:40 +00:00
|
|
|
await fsp.symlink(nitro.options.output.publicDir, distDir, 'junction').catch(() => {})
|
2022-04-20 19:12:04 +00:00
|
|
|
}
|
|
|
|
}
|
2022-04-07 11:28:04 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
// nuxt dev
|
|
|
|
if (nuxt.options.dev) {
|
2022-10-27 10:36:37 +00:00
|
|
|
nuxt.hook('webpack:compile', ({ compiler }) => { compiler.outputFileSystem = { ...fsExtra, join } as any })
|
|
|
|
nuxt.hook('webpack:compiled', () => { nuxt.server.reload() })
|
|
|
|
nuxt.hook('vite:compiled', () => { nuxt.server.reload() })
|
|
|
|
|
2022-10-15 18:42:57 +00:00
|
|
|
nuxt.hook('server:devHandler', (h) => { devMiddlewareHandler.set(h) })
|
2022-04-07 11:28:04 +00:00
|
|
|
nuxt.server = createDevServer(nitro)
|
2022-10-27 10:36:37 +00:00
|
|
|
|
2022-04-19 19:10:32 +00:00
|
|
|
const waitUntilCompile = new Promise<void>(resolve => nitro.hooks.hook('compiled', () => resolve()))
|
2022-04-07 11:28:04 +00:00
|
|
|
nuxt.hook('build:done', () => waitUntilCompile)
|
|
|
|
}
|
|
|
|
}
|
2023-08-23 20:36:33 +00:00
|
|
|
|
|
|
|
function relativeWithDot (from: string, to: string) {
|
|
|
|
return relative(from, to).replace(/^([^.])/, './$1') || '.'
|
|
|
|
}
|
2023-09-11 11:02:28 +00:00
|
|
|
|
2023-12-13 11:54:56 +00:00
|
|
|
async function spaLoadingTemplatePath (nuxt: Nuxt) {
|
|
|
|
if (typeof nuxt.options.spaLoadingTemplate === 'string') {
|
|
|
|
return resolve(nuxt.options.srcDir, nuxt.options.spaLoadingTemplate)
|
|
|
|
}
|
|
|
|
|
|
|
|
const possiblePaths = nuxt.options._layers.map(layer => join(layer.config.srcDir, 'app/spa-loading-template.html'))
|
|
|
|
|
|
|
|
return await findPath(possiblePaths) ?? resolve(nuxt.options.srcDir, 'app/spa-loading-template.html')
|
2023-10-31 18:05:06 +00:00
|
|
|
}
|
|
|
|
|
2023-12-13 11:54:56 +00:00
|
|
|
async function spaLoadingTemplate (nuxt: Nuxt) {
|
2023-09-11 11:02:28 +00:00
|
|
|
if (nuxt.options.spaLoadingTemplate === false) { return '' }
|
|
|
|
|
2023-12-13 11:54:56 +00:00
|
|
|
const spaLoadingTemplate = await spaLoadingTemplatePath(nuxt)
|
2023-09-11 11:02:28 +00:00
|
|
|
|
|
|
|
try {
|
|
|
|
if (existsSync(spaLoadingTemplate)) {
|
|
|
|
return readFileSync(spaLoadingTemplate, 'utf-8')
|
|
|
|
}
|
2023-11-09 17:01:13 +00:00
|
|
|
} catch {
|
|
|
|
// fall through if we have issues reading the file
|
|
|
|
}
|
2023-09-11 11:02:28 +00:00
|
|
|
|
|
|
|
if (nuxt.options.spaLoadingTemplate === true) {
|
|
|
|
return defaultSpaLoadingTemplate({})
|
|
|
|
}
|
|
|
|
|
2023-09-11 12:07:28 +00:00
|
|
|
if (nuxt.options.spaLoadingTemplate) {
|
2023-09-19 21:26:15 +00:00
|
|
|
logger.warn(`Could not load custom \`spaLoadingTemplate\` path as it does not exist: \`${nuxt.options.spaLoadingTemplate}\`.`)
|
2023-09-11 12:07:28 +00:00
|
|
|
}
|
|
|
|
|
2023-09-11 11:02:28 +00:00
|
|
|
return ''
|
|
|
|
}
|