mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-18 01:15:58 +00:00
feat: improve base url options (#2655)
This commit is contained in:
parent
05e75426ce
commit
d07d572263
@ -15,6 +15,13 @@ export function setupNitroBridge () {
|
|||||||
throw new Error('[nitro] Please use `nuxt generate` for static target')
|
throw new Error('[nitro] Please use `nuxt generate` for static target')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle legacy property name `assetsPath`
|
||||||
|
nuxt.options.app.buildAssetsDir = nuxt.options.app.buildAssetsDir || nuxt.options.app.assetsPath
|
||||||
|
nuxt.options.app.assetsPath = nuxt.options.app.buildAssetsDir
|
||||||
|
// Nitro expects app config on `config.app` rather than `config._app`
|
||||||
|
nuxt.options.publicRuntimeConfig.app = nuxt.options.publicRuntimeConfig.app || {}
|
||||||
|
Object.assign(nuxt.options.publicRuntimeConfig.app, nuxt.options.publicRuntimeConfig._app)
|
||||||
|
|
||||||
// Disable loading-screen
|
// Disable loading-screen
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
nuxt.options.build.loadingScreen = false
|
nuxt.options.build.loadingScreen = false
|
||||||
|
@ -3,6 +3,7 @@ import * as vite from 'vite'
|
|||||||
import { createVuePlugin } from 'vite-plugin-vue2'
|
import { createVuePlugin } from 'vite-plugin-vue2'
|
||||||
import PluginLegacy from '@vitejs/plugin-legacy'
|
import PluginLegacy from '@vitejs/plugin-legacy'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
import { joinURL } from 'ufo'
|
||||||
import { devStyleSSRPlugin } from '../../../vite/src/plugins/dev-ssr-css'
|
import { devStyleSSRPlugin } from '../../../vite/src/plugins/dev-ssr-css'
|
||||||
import { jsxPlugin } from './plugins/jsx'
|
import { jsxPlugin } from './plugins/jsx'
|
||||||
import { ViteBuildContext, ViteOptions } from './types'
|
import { ViteBuildContext, ViteOptions } from './types'
|
||||||
@ -28,7 +29,6 @@ export async function buildClient (ctx: ViteBuildContext) {
|
|||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: resolve(ctx.nuxt.options.buildDir, 'dist/client'),
|
outDir: resolve(ctx.nuxt.options.buildDir, 'dist/client'),
|
||||||
assetsDir: '.',
|
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: resolve(ctx.nuxt.options.buildDir, 'client.js')
|
input: resolve(ctx.nuxt.options.buildDir, 'client.js')
|
||||||
},
|
},
|
||||||
@ -39,7 +39,10 @@ export async function buildClient (ctx: ViteBuildContext) {
|
|||||||
jsxPlugin(),
|
jsxPlugin(),
|
||||||
createVuePlugin(ctx.config.vue),
|
createVuePlugin(ctx.config.vue),
|
||||||
PluginLegacy(),
|
PluginLegacy(),
|
||||||
devStyleSSRPlugin(ctx.nuxt.options.rootDir)
|
devStyleSSRPlugin({
|
||||||
|
rootDir: ctx.nuxt.options.rootDir,
|
||||||
|
buildAssetsURL: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir)
|
||||||
|
})
|
||||||
],
|
],
|
||||||
server: {
|
server: {
|
||||||
middlewareMode: true
|
middlewareMode: true
|
||||||
|
@ -46,7 +46,6 @@ export async function prepareManifests (ctx: ViteBuildContext) {
|
|||||||
export async function generateBuildManifest (ctx: ViteBuildContext) {
|
export async function generateBuildManifest (ctx: ViteBuildContext) {
|
||||||
const rDist = (...args: string[]): string => resolve(ctx.nuxt.options.buildDir, 'dist', ...args)
|
const rDist = (...args: string[]): string => resolve(ctx.nuxt.options.buildDir, 'dist', ...args)
|
||||||
|
|
||||||
const publicPath = ctx.nuxt.options.app.assetsPath // Default: /nuxt/
|
|
||||||
const viteClientManifest = await fse.readJSON(rDist('client/manifest.json'))
|
const viteClientManifest = await fse.readJSON(rDist('client/manifest.json'))
|
||||||
const clientEntries = Object.entries(viteClientManifest)
|
const clientEntries = Object.entries(viteClientManifest)
|
||||||
|
|
||||||
@ -59,12 +58,13 @@ export async function generateBuildManifest (ctx: ViteBuildContext) {
|
|||||||
const polyfillName = initialEntries.find(id => id.startsWith('polyfills-legacy.'))
|
const polyfillName = initialEntries.find(id => id.startsWith('polyfills-legacy.'))
|
||||||
|
|
||||||
// @vitejs/plugin-legacy uses SystemJS which need to call `System.import` to load modules
|
// @vitejs/plugin-legacy uses SystemJS which need to call `System.import` to load modules
|
||||||
const clientImports = initialJs.filter(id => id !== polyfillName).map(id => publicPath + id)
|
const clientImports = initialJs.filter(id => id !== polyfillName)
|
||||||
const clientEntryCode = `var imports = ${JSON.stringify(clientImports)}\nimports.reduce((p, id) => p.then(() => System.import(id)), Promise.resolve())`
|
const clientEntryCode = `var imports = ${JSON.stringify(clientImports)}\nimports.reduce((p, id) => p.then(() => System.import(id)), Promise.resolve())`
|
||||||
const clientEntryName = 'entry-legacy.' + hash(clientEntryCode) + '.js'
|
const clientEntryName = 'entry-legacy.' + hash(clientEntryCode) + '.js'
|
||||||
|
|
||||||
const clientManifest = {
|
const clientManifest = {
|
||||||
publicPath,
|
// This publicPath will be ignored by Nitro and computed dynamically
|
||||||
|
publicPath: ctx.nuxt.options.app.buildAssetsDir,
|
||||||
all: uniq([
|
all: uniq([
|
||||||
polyfillName,
|
polyfillName,
|
||||||
clientEntryName,
|
clientEntryName,
|
||||||
@ -74,12 +74,12 @@ export async function generateBuildManifest (ctx: ViteBuildContext) {
|
|||||||
polyfillName,
|
polyfillName,
|
||||||
clientEntryName,
|
clientEntryName,
|
||||||
...initialAssets
|
...initialAssets
|
||||||
],
|
].filter(Boolean),
|
||||||
async: [
|
async: [
|
||||||
// We move initial entries to the client entry
|
// We move initial entries to the client entry
|
||||||
...initialJs,
|
...initialJs,
|
||||||
...asyncEntries
|
...asyncEntries
|
||||||
],
|
].filter(Boolean),
|
||||||
modules: {},
|
modules: {},
|
||||||
assetsMapping: {}
|
assetsMapping: {}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,6 @@ export async function buildServer (ctx: ViteBuildContext) {
|
|||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
outDir: resolve(ctx.nuxt.options.buildDir, 'dist/server'),
|
outDir: resolve(ctx.nuxt.options.buildDir, 'dist/server'),
|
||||||
assetsDir: ctx.nuxt.options.app.assetsPath.replace(/^\/|\/$/, ''),
|
|
||||||
ssr: true,
|
ssr: true,
|
||||||
ssrManifest: true,
|
ssrManifest: true,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { resolve } from 'pathe'
|
import { resolve } from 'pathe'
|
||||||
import * as vite from 'vite'
|
import * as vite from 'vite'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
import { withoutLeadingSlash } from 'ufo'
|
||||||
import { distDir } from '../dirs'
|
import { distDir } from '../dirs'
|
||||||
import { warmupViteServer } from '../../../vite/src/utils/warmup'
|
import { warmupViteServer } from '../../../vite/src/utils/warmup'
|
||||||
import { buildClient } from './client'
|
import { buildClient } from './client'
|
||||||
@ -73,6 +74,7 @@ async function bundle (nuxt: Nuxt, builder: any) {
|
|||||||
publicDir: resolve(nuxt.options.srcDir, nuxt.options.dir.static),
|
publicDir: resolve(nuxt.options.srcDir, nuxt.options.dir.static),
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
build: {
|
build: {
|
||||||
|
assetsDir: withoutLeadingSlash(nuxt.options.app.buildAssetsDir),
|
||||||
emptyOutDir: false
|
emptyOutDir: false
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
@ -4,7 +4,7 @@ import * as rollup from 'rollup'
|
|||||||
import fse from 'fs-extra'
|
import fse from 'fs-extra'
|
||||||
import { printFSTree } from './utils/tree'
|
import { printFSTree } from './utils/tree'
|
||||||
import { getRollupConfig } from './rollup/config'
|
import { getRollupConfig } from './rollup/config'
|
||||||
import { hl, prettyPath, serializeTemplate, writeFile, isDirectory, readDirRecursively, replaceAll } from './utils'
|
import { hl, prettyPath, serializeTemplate, writeFile, isDirectory, replaceAll } from './utils'
|
||||||
import { NitroContext } from './context'
|
import { NitroContext } from './context'
|
||||||
import { scanMiddleware } from './server/middleware'
|
import { scanMiddleware } from './server/middleware'
|
||||||
|
|
||||||
@ -30,20 +30,17 @@ async function cleanupDir (dir: string) {
|
|||||||
export async function generate (nitroContext: NitroContext) {
|
export async function generate (nitroContext: NitroContext) {
|
||||||
consola.start('Generating public...')
|
consola.start('Generating public...')
|
||||||
|
|
||||||
|
await nitroContext._internal.hooks.callHook('nitro:generate', nitroContext)
|
||||||
|
|
||||||
const publicDir = nitroContext._nuxt.publicDir
|
const publicDir = nitroContext._nuxt.publicDir
|
||||||
let publicFiles: string[] = []
|
|
||||||
if (await isDirectory(publicDir)) {
|
if (await isDirectory(publicDir)) {
|
||||||
publicFiles = readDirRecursively(publicDir).map(r => r.replace(publicDir, ''))
|
|
||||||
await fse.copy(publicDir, nitroContext.output.publicDir)
|
await fse.copy(publicDir, nitroContext.output.publicDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
const clientDist = resolve(nitroContext._nuxt.buildDir, 'dist/client')
|
const clientDist = resolve(nitroContext._nuxt.buildDir, 'dist/client')
|
||||||
if (await isDirectory(clientDist)) {
|
if (await isDirectory(clientDist)) {
|
||||||
await fse.copy(clientDist, join(nitroContext.output.publicDir, nitroContext._nuxt.publicPath), {
|
const buildAssetsDir = join(nitroContext.output.publicDir, nitroContext._nuxt.buildAssetsDir)
|
||||||
// TODO: Workaround vite's issue that duplicates public files
|
await fse.copy(clientDist, buildAssetsDir)
|
||||||
// https://github.com/nuxt/framework/issues/1192
|
|
||||||
filter: src => !publicFiles.includes(src.replace(clientDist, ''))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
consola.success('Generated public ' + prettyPath(nitroContext.output.publicDir))
|
consola.success('Generated public ' + prettyPath(nitroContext.output.publicDir))
|
||||||
|
@ -19,6 +19,7 @@ export interface NitroHooks {
|
|||||||
'nitro:document': (htmlTemplate: { src: string, contents: string, dst: string }) => void
|
'nitro:document': (htmlTemplate: { src: string, contents: string, dst: string }) => void
|
||||||
'nitro:rollup:before': (context: NitroContext) => void | Promise<void>
|
'nitro:rollup:before': (context: NitroContext) => void | Promise<void>
|
||||||
'nitro:compiled': (context: NitroContext) => void
|
'nitro:compiled': (context: NitroContext) => void
|
||||||
|
'nitro:generate': (context: NitroContext) => void | Promise<void>
|
||||||
'close': () => void
|
'close': () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +72,8 @@ export interface NitroContext {
|
|||||||
generateDir: string
|
generateDir: string
|
||||||
publicDir: string
|
publicDir: string
|
||||||
serverDir: string
|
serverDir: string
|
||||||
routerBase: string
|
baseURL: string
|
||||||
publicPath: string
|
buildAssetsDir: string
|
||||||
isStatic: boolean
|
isStatic: boolean
|
||||||
fullStatic: boolean
|
fullStatic: boolean
|
||||||
staticAssets: any
|
staticAssets: any
|
||||||
@ -139,8 +140,8 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
|
|||||||
generateDir: nuxtOptions.generate.dir,
|
generateDir: nuxtOptions.generate.dir,
|
||||||
publicDir: resolve(nuxtOptions.srcDir, nuxtOptions.dir.public || nuxtOptions.dir.static),
|
publicDir: resolve(nuxtOptions.srcDir, nuxtOptions.dir.public || nuxtOptions.dir.static),
|
||||||
serverDir: resolve(nuxtOptions.srcDir, (nuxtOptions.dir as any).server || 'server'),
|
serverDir: resolve(nuxtOptions.srcDir, (nuxtOptions.dir as any).server || 'server'),
|
||||||
routerBase: nuxtOptions.router.base,
|
baseURL: nuxtOptions.app.baseURL,
|
||||||
publicPath: nuxtOptions.app.assetsPath,
|
buildAssetsDir: nuxtOptions.app.buildAssetsDir,
|
||||||
isStatic: nuxtOptions.target === 'static' && !nuxtOptions.dev,
|
isStatic: nuxtOptions.target === 'static' && !nuxtOptions.dev,
|
||||||
fullStatic: nuxtOptions.target === 'static' && !nuxtOptions._legacyGenerate,
|
fullStatic: nuxtOptions.target === 'static' && !nuxtOptions._legacyGenerate,
|
||||||
staticAssets: nuxtOptions.generate.staticAssets,
|
staticAssets: nuxtOptions.generate.staticAssets,
|
||||||
|
@ -1,17 +1,19 @@
|
|||||||
import { existsSync, promises as fsp } from 'fs'
|
import { existsSync, promises as fsp } from 'fs'
|
||||||
import { resolve } from 'pathe'
|
import { resolve } from 'pathe'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
import { joinURL } from 'ufo'
|
||||||
import { extendPreset, prettyPath } from '../utils'
|
import { extendPreset, prettyPath } from '../utils'
|
||||||
import { NitroPreset, NitroContext, NitroInput } from '../context'
|
import { NitroPreset, NitroContext, NitroInput } from '../context'
|
||||||
import { worker } from './worker'
|
import { worker } from './worker'
|
||||||
|
|
||||||
export const browser: NitroPreset = extendPreset(worker, (input: NitroInput) => {
|
export const browser: NitroPreset = extendPreset(worker, (input: NitroInput) => {
|
||||||
const routerBase = input._nuxt.routerBase
|
// TODO: Join base at runtime
|
||||||
|
const baseURL = input._nuxt.baseURL
|
||||||
|
|
||||||
const script = `<script>
|
const script = `<script>
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
window.addEventListener('load', function () {
|
window.addEventListener('load', function () {
|
||||||
navigator.serviceWorker.register('${routerBase}sw.js');
|
navigator.serviceWorker.register('${joinURL(baseURL, 'sw.js')}');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
</script>`
|
</script>`
|
||||||
@ -21,11 +23,11 @@ if ('serviceWorker' in navigator) {
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<link rel="prefetch" href="${routerBase}sw.js">
|
<link rel="prefetch" href="${joinURL(baseURL, 'sw.js')}">
|
||||||
<link rel="prefetch" href="${routerBase}_server/index.mjs">
|
<link rel="prefetch" href="${joinURL(baseURL, '_server/index.mjs')}">
|
||||||
<script>
|
<script>
|
||||||
async function register () {
|
async function register () {
|
||||||
const registration = await navigator.serviceWorker.register('${routerBase}sw.js')
|
const registration = await navigator.serviceWorker.register('${joinURL(baseURL, 'sw.js')}')
|
||||||
await navigator.serviceWorker.ready
|
await navigator.serviceWorker.ready
|
||||||
registration.active.addEventListener('statechange', (event) => {
|
registration.active.addEventListener('statechange', (event) => {
|
||||||
if (event.target.state === 'activated') {
|
if (event.target.state === 'activated') {
|
||||||
@ -62,7 +64,7 @@ if ('serviceWorker' in navigator) {
|
|||||||
tmpl.contents = tmpl.contents.replace('</body>', script + '</body>')
|
tmpl.contents = tmpl.contents.replace('</body>', script + '</body>')
|
||||||
},
|
},
|
||||||
async 'nitro:compiled' ({ output }: NitroContext) {
|
async 'nitro:compiled' ({ output }: NitroContext) {
|
||||||
await fsp.writeFile(resolve(output.publicDir, 'sw.js'), `self.importScripts('${input._nuxt.routerBase}_server/index.mjs');`, 'utf8')
|
await fsp.writeFile(resolve(output.publicDir, 'sw.js'), `self.importScripts('${joinURL(baseURL, '_server/index.mjs')}');`, 'utf8')
|
||||||
|
|
||||||
// Temp fix
|
// Temp fix
|
||||||
if (!existsSync(resolve(output.publicDir, 'index.html'))) {
|
if (!existsSync(resolve(output.publicDir, 'index.html'))) {
|
||||||
|
@ -159,8 +159,6 @@ export const getRollupConfig = (nitroContext: NitroContext) => {
|
|||||||
'process.server': 'true',
|
'process.server': 'true',
|
||||||
'process.client': 'false',
|
'process.client': 'false',
|
||||||
'process.env.NUXT_NO_SSR': JSON.stringify(!nitroContext._nuxt.ssr),
|
'process.env.NUXT_NO_SSR': JSON.stringify(!nitroContext._nuxt.ssr),
|
||||||
'process.env.ROUTER_BASE': JSON.stringify(nitroContext._nuxt.routerBase),
|
|
||||||
'process.env.PUBLIC_PATH': JSON.stringify(nitroContext._nuxt.publicPath),
|
|
||||||
'process.env.NUXT_STATIC_BASE': JSON.stringify(nitroContext._nuxt.staticAssets.base),
|
'process.env.NUXT_STATIC_BASE': JSON.stringify(nitroContext._nuxt.staticAssets.base),
|
||||||
'process.env.NUXT_STATIC_VERSION': JSON.stringify(nitroContext._nuxt.staticAssets.version),
|
'process.env.NUXT_STATIC_VERSION': JSON.stringify(nitroContext._nuxt.staticAssets.version),
|
||||||
'process.env.NUXT_FULL_STATIC': nitroContext._nuxt.fullStatic as unknown as string,
|
'process.env.NUXT_FULL_STATIC': nitroContext._nuxt.fullStatic as unknown as string,
|
||||||
@ -227,6 +225,7 @@ export const getRollupConfig = (nitroContext: NitroContext) => {
|
|||||||
entries: {
|
entries: {
|
||||||
'#nitro': nitroContext._internal.runtimeDir,
|
'#nitro': nitroContext._internal.runtimeDir,
|
||||||
'#nitro-renderer': resolve(nitroContext._internal.runtimeDir, 'app', renderer),
|
'#nitro-renderer': resolve(nitroContext._internal.runtimeDir, 'app', renderer),
|
||||||
|
'#paths': resolve(nitroContext._internal.runtimeDir, 'app/paths'),
|
||||||
'#config': resolve(nitroContext._internal.runtimeDir, 'app/config'),
|
'#config': resolve(nitroContext._internal.runtimeDir, 'app/config'),
|
||||||
'#nitro-vue-renderer': vue2ServerRenderer,
|
'#nitro-vue-renderer': vue2ServerRenderer,
|
||||||
// Only file and data URLs are supported by the default ESM loader on Windows (#427)
|
// Only file and data URLs are supported by the default ESM loader on Windows (#427)
|
||||||
|
@ -11,6 +11,12 @@ for (const type of ['private', 'public']) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load dynamic app configuration
|
||||||
|
const appConfig = _runtimeConfig.public.app
|
||||||
|
appConfig.baseURL = process.env.NUXT_APP_BASE_URL || appConfig.baseURL
|
||||||
|
appConfig.cdnURL = process.env.NUXT_APP_CDN_URL || appConfig.cdnURL
|
||||||
|
appConfig.buildAssetsDir = process.env.NUXT_APP_BUILD_ASSETS_DIR || appConfig.buildAssetsDir
|
||||||
|
|
||||||
// Named exports
|
// Named exports
|
||||||
export const privateConfig = deepFreeze(defu(_runtimeConfig.private, _runtimeConfig.public))
|
export const privateConfig = deepFreeze(defu(_runtimeConfig.private, _runtimeConfig.public))
|
||||||
export const publicConfig = deepFreeze(_runtimeConfig.public)
|
export const publicConfig = deepFreeze(_runtimeConfig.public)
|
||||||
|
19
packages/nitro/src/runtime/app/paths.ts
Normal file
19
packages/nitro/src/runtime/app/paths.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { joinURL } from 'ufo'
|
||||||
|
import config from '#config'
|
||||||
|
|
||||||
|
export function baseURL () {
|
||||||
|
return config.app.baseURL
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildAssetsDir () {
|
||||||
|
return config.app.buildAssetsDir
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildAssetsURL (...path: string[]) {
|
||||||
|
return joinURL(publicAssetsURL(), config.app.buildAssetsDir, ...path)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function publicAssetsURL (...path: string[]) {
|
||||||
|
const publicBase = config.app.cdnURL || config.app.baseURL
|
||||||
|
return path.length ? joinURL(publicBase, ...path) : publicBase
|
||||||
|
}
|
@ -2,6 +2,7 @@ import type { ServerResponse } from 'http'
|
|||||||
import { createRenderer } from 'vue-bundle-renderer'
|
import { createRenderer } from 'vue-bundle-renderer'
|
||||||
import devalue from '@nuxt/devalue'
|
import devalue from '@nuxt/devalue'
|
||||||
import { privateConfig, publicConfig } from './config'
|
import { privateConfig, publicConfig } from './config'
|
||||||
|
import { buildAssetsURL } from './paths'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import htmlTemplate from '#build/views/document.template.mjs'
|
import htmlTemplate from '#build/views/document.template.mjs'
|
||||||
|
|
||||||
@ -12,8 +13,6 @@ const PAYLOAD_JS = '/payload.js'
|
|||||||
const getClientManifest = cachedImport(() => import('#build/dist/server/client.manifest.mjs'))
|
const getClientManifest = cachedImport(() => import('#build/dist/server/client.manifest.mjs'))
|
||||||
const getSSRApp = !process.env.NUXT_NO_SSR && cachedImport(() => import('#build/dist/server/server.mjs'))
|
const getSSRApp = !process.env.NUXT_NO_SSR && cachedImport(() => import('#build/dist/server/server.mjs'))
|
||||||
|
|
||||||
const publicPath = (publicConfig.app && publicConfig.app.assetsPath) || process.env.PUBLIC_PATH || '/_nuxt'
|
|
||||||
|
|
||||||
const getSSRRenderer = cachedResult(async () => {
|
const getSSRRenderer = cachedResult(async () => {
|
||||||
// Load client manifest
|
// Load client manifest
|
||||||
const clientManifest = await getClientManifest()
|
const clientManifest = await getClientManifest()
|
||||||
@ -23,7 +22,7 @@ const getSSRRenderer = cachedResult(async () => {
|
|||||||
if (!createSSRApp) { throw new Error('Server bundle is not available') }
|
if (!createSSRApp) { throw new Error('Server bundle is not available') }
|
||||||
// Create renderer
|
// Create renderer
|
||||||
const { renderToString } = await import('#nitro-renderer')
|
const { renderToString } = await import('#nitro-renderer')
|
||||||
return createRenderer((createSSRApp), { clientManifest, renderToString, publicPath }).renderToString
|
return createRenderer((createSSRApp), { clientManifest, renderToString, publicPath: buildAssetsURL() }).renderToString
|
||||||
})
|
})
|
||||||
|
|
||||||
const getSPARenderer = cachedResult(async () => {
|
const getSPARenderer = cachedResult(async () => {
|
||||||
@ -50,13 +49,13 @@ const getSPARenderer = cachedResult(async () => {
|
|||||||
entryFiles
|
entryFiles
|
||||||
.flatMap(({ css }) => css)
|
.flatMap(({ css }) => css)
|
||||||
.filter(css => css != null)
|
.filter(css => css != null)
|
||||||
.map(file => `<link rel="stylesheet" href="${publicPath}${file}">`)
|
.map(file => `<link rel="stylesheet" href="${buildAssetsURL(file)}">`)
|
||||||
.join(''),
|
.join(''),
|
||||||
renderScripts: () =>
|
renderScripts: () =>
|
||||||
entryFiles
|
entryFiles
|
||||||
.map(({ file }) => {
|
.map(({ file }) => {
|
||||||
const isMJS = !file.endsWith('.js')
|
const isMJS = !file.endsWith('.js')
|
||||||
return `<script ${isMJS ? 'type="module"' : ''} src="${publicPath}${file}"></script>`
|
return `<script ${isMJS ? 'type="module"' : ''} src="${buildAssetsURL(file)}"></script>`
|
||||||
})
|
})
|
||||||
.join('')
|
.join('')
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import '#polyfill'
|
import '#polyfill'
|
||||||
import { getAssetFromKV } from '@cloudflare/kv-asset-handler'
|
import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler'
|
||||||
|
import { withoutBase } from 'ufo'
|
||||||
import { localCall } from '../server'
|
import { localCall } from '../server'
|
||||||
import { requestHasBody, useRequestBody } from '../server/utils'
|
import { requestHasBody, useRequestBody } from '../server/utils'
|
||||||
|
import { buildAssetsURL, baseURL } from '#paths'
|
||||||
const PUBLIC_PATH = process.env.PUBLIC_PATH // Default: /_nuxt/
|
|
||||||
|
|
||||||
addEventListener('fetch', (event: any) => {
|
addEventListener('fetch', (event: any) => {
|
||||||
event.respondWith(handleEvent(event))
|
event.respondWith(handleEvent(event))
|
||||||
@ -11,7 +11,7 @@ addEventListener('fetch', (event: any) => {
|
|||||||
|
|
||||||
async function handleEvent (event) {
|
async function handleEvent (event) {
|
||||||
try {
|
try {
|
||||||
return await getAssetFromKV(event, { cacheControl: assetsCacheControl })
|
return await getAssetFromKV(event, { cacheControl: assetsCacheControl, mapRequestToAsset: baseURLModifier })
|
||||||
} catch (_err) {
|
} catch (_err) {
|
||||||
// Ignore
|
// Ignore
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ async function handleEvent (event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function assetsCacheControl (request) {
|
function assetsCacheControl (request) {
|
||||||
if (request.url.includes(PUBLIC_PATH) /* TODO: Check with routerBase */) {
|
if (request.url.startsWith(buildAssetsURL())) {
|
||||||
return {
|
return {
|
||||||
browserTTL: 31536000,
|
browserTTL: 31536000,
|
||||||
edgeTTL: 31536000
|
edgeTTL: 31536000
|
||||||
@ -50,3 +50,8 @@ function assetsCacheControl (request) {
|
|||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const baseURLModifier = (request: Request) => {
|
||||||
|
const url = withoutBase(request.url, baseURL())
|
||||||
|
return mapRequestToAsset(new Request(url, request))
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { Server as HttpServer } from 'http'
|
|||||||
import { Server as HttpsServer } from 'https'
|
import { Server as HttpsServer } from 'https'
|
||||||
import destr from 'destr'
|
import destr from 'destr'
|
||||||
import { handle } from '../server'
|
import { handle } from '../server'
|
||||||
|
import { baseURL } from '#paths'
|
||||||
|
|
||||||
const cert = process.env.NITRO_SSL_CERT
|
const cert = process.env.NITRO_SSL_CERT
|
||||||
const key = process.env.NITRO_SSL_KEY
|
const key = process.env.NITRO_SSL_KEY
|
||||||
@ -19,7 +20,7 @@ server.listen(port, hostname, (err) => {
|
|||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
const protocol = cert && key ? 'https' : 'http'
|
const protocol = cert && key ? 'https' : 'http'
|
||||||
console.log(`Listening on ${protocol}://${hostname}:${port}`)
|
console.log(`Listening on ${protocol}://${hostname}:${port}${baseURL()}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
export default {}
|
export default {}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import '../app/config'
|
|
||||||
import { createApp, useBase } from 'h3'
|
import { createApp, useBase } from 'h3'
|
||||||
import { createFetch, Headers } from 'ohmyfetch'
|
import { createFetch, Headers } from 'ohmyfetch'
|
||||||
import destr from 'destr'
|
import destr from 'destr'
|
||||||
import { createCall, createFetch as createLocalFetch } from 'unenv/runtime/fetch/index'
|
import { createCall, createFetch as createLocalFetch } from 'unenv/runtime/fetch/index'
|
||||||
|
import { baseURL } from '../app/paths'
|
||||||
import { timingMiddleware } from './timing'
|
import { timingMiddleware } from './timing'
|
||||||
import { handleError } from './error'
|
import { handleError } from './error'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -18,7 +18,7 @@ app.use(serverMiddleware)
|
|||||||
app.use(() => import('../app/render').then(e => e.renderMiddleware), { lazy: true })
|
app.use(() => import('../app/render').then(e => e.renderMiddleware), { lazy: true })
|
||||||
|
|
||||||
export const stack = app.stack
|
export const stack = app.stack
|
||||||
export const handle = useBase(process.env.ROUTER_BASE, app)
|
export const handle = useBase(baseURL(), app)
|
||||||
export const localCall = createCall(handle)
|
export const localCall = createCall(handle)
|
||||||
export const localFetch = createLocalFetch(localCall, globalThis.fetch)
|
export const localFetch = createLocalFetch(localCall, globalThis.fetch)
|
||||||
|
|
||||||
|
@ -2,9 +2,10 @@ import { createError } from 'h3'
|
|||||||
import { withoutTrailingSlash, withLeadingSlash, parseURL } from 'ufo'
|
import { withoutTrailingSlash, withLeadingSlash, parseURL } from 'ufo'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { getAsset, readAsset } from '#static'
|
import { getAsset, readAsset } from '#static'
|
||||||
|
import { buildAssetsDir } from '#paths'
|
||||||
|
|
||||||
const METHODS = ['HEAD', 'GET']
|
const METHODS = ['HEAD', 'GET']
|
||||||
const PUBLIC_PATH = process.env.PUBLIC_PATH // Default: /_nuxt/
|
|
||||||
const TWO_DAYS = 2 * 60 * 60 * 24
|
const TWO_DAYS = 2 * 60 * 60 * 24
|
||||||
const STATIC_ASSETS_BASE = process.env.NUXT_STATIC_BASE + '/' + process.env.NUXT_STATIC_VERSION
|
const STATIC_ASSETS_BASE = process.env.NUXT_STATIC_BASE + '/' + process.env.NUXT_STATIC_VERSION
|
||||||
|
|
||||||
@ -26,8 +27,10 @@ export default async function serveStatic (req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isBuildAsset = id.startsWith(buildAssetsDir())
|
||||||
|
|
||||||
if (!asset) {
|
if (!asset) {
|
||||||
if (id.startsWith(PUBLIC_PATH) && !id.startsWith(STATIC_ASSETS_BASE)) {
|
if (isBuildAsset && !id.startsWith(STATIC_ASSETS_BASE)) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusMessage: 'Cannot find static asset ' + id,
|
statusMessage: 'Cannot find static asset ' + id,
|
||||||
statusCode: 404
|
statusCode: 404
|
||||||
@ -62,7 +65,7 @@ export default async function serveStatic (req, res) {
|
|||||||
res.setHeader('Last-Modified', asset.mtime)
|
res.setHeader('Last-Modified', asset.mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id.startsWith(PUBLIC_PATH)) {
|
if (isBuildAsset) {
|
||||||
res.setHeader('Cache-Control', `max-age=${TWO_DAYS}, immutable`)
|
res.setHeader('Cache-Control', `max-age=${TWO_DAYS}, immutable`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import servePlaceholder from 'serve-placeholder'
|
|||||||
import serveStatic from 'serve-static'
|
import serveStatic from 'serve-static'
|
||||||
import { resolve } from 'pathe'
|
import { resolve } from 'pathe'
|
||||||
import connect from 'connect'
|
import connect from 'connect'
|
||||||
|
import { joinURL } from 'ufo'
|
||||||
import type { NitroContext } from '../context'
|
import type { NitroContext } from '../context'
|
||||||
import { handleVfs } from './vfs'
|
import { handleVfs } from './vfs'
|
||||||
|
|
||||||
@ -76,8 +77,9 @@ export function createDevServer (nitroContext: NitroContext) {
|
|||||||
const app = createApp()
|
const app = createApp()
|
||||||
|
|
||||||
// _nuxt and static
|
// _nuxt and static
|
||||||
app.use(nitroContext._nuxt.publicPath, serveStatic(resolve(nitroContext._nuxt.buildDir, 'dist/client')))
|
const buildAssetsURL = joinURL(nitroContext._nuxt.baseURL, nitroContext._nuxt.buildAssetsDir)
|
||||||
app.use(nitroContext._nuxt.routerBase, serveStatic(resolve(nitroContext._nuxt.publicDir)))
|
app.use(buildAssetsURL, serveStatic(resolve(nitroContext._nuxt.buildDir, 'dist/client')))
|
||||||
|
app.use(nitroContext._nuxt.baseURL, serveStatic(resolve(nitroContext._nuxt.publicDir)))
|
||||||
|
|
||||||
// debugging endpoint to view vfs
|
// debugging endpoint to view vfs
|
||||||
app.use('/_vfs', useBase('/_vfs', handleVfs(nitroContext)))
|
app.use('/_vfs', useBase('/_vfs', handleVfs(nitroContext)))
|
||||||
@ -89,7 +91,7 @@ export function createDevServer (nitroContext: NitroContext) {
|
|||||||
app.use(devMiddleware.middleware)
|
app.use(devMiddleware.middleware)
|
||||||
|
|
||||||
// serve placeholder 404 assets instead of hitting SSR
|
// serve placeholder 404 assets instead of hitting SSR
|
||||||
app.use(nitroContext._nuxt.publicPath, servePlaceholder())
|
app.use(buildAssetsURL, servePlaceholder())
|
||||||
|
|
||||||
// SSR Proxy
|
// SSR Proxy
|
||||||
const proxy = httpProxy.createProxy()
|
const proxy = httpProxy.createProxy()
|
||||||
|
@ -23,10 +23,10 @@ export interface ServerMiddleware {
|
|||||||
promisify?: boolean // Default is true
|
promisify?: boolean // Default is true
|
||||||
}
|
}
|
||||||
|
|
||||||
function filesToMiddleware (files: string[], baseDir: string, basePath: string, overrides?: Partial<ServerMiddleware>): ServerMiddleware[] {
|
function filesToMiddleware (files: string[], baseDir: string, baseURL: string, overrides?: Partial<ServerMiddleware>): ServerMiddleware[] {
|
||||||
return files.map((file) => {
|
return files.map((file) => {
|
||||||
const route = joinURL(
|
const route = joinURL(
|
||||||
basePath,
|
baseURL,
|
||||||
file
|
file
|
||||||
.slice(0, file.length - extname(file).length)
|
.slice(0, file.length - extname(file).length)
|
||||||
.replace(/\/index$/, '')
|
.replace(/\/index$/, '')
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createRequire } from 'module'
|
import { createRequire } from 'module'
|
||||||
import { relative, dirname, join, resolve } from 'pathe'
|
import { relative, dirname, resolve } from 'pathe'
|
||||||
import fse from 'fs-extra'
|
import fse from 'fs-extra'
|
||||||
import jiti from 'jiti'
|
import jiti from 'jiti'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
@ -152,11 +152,3 @@ export function readPackageJson (
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function readDirRecursively (dir: string) {
|
|
||||||
return fse.readdirSync(dir).reduce((files, file) => {
|
|
||||||
const name = join(dir, file)
|
|
||||||
const isDirectory = fse.statSync(name).isDirectory()
|
|
||||||
return isDirectory ? [...files, ...readDirRecursively(name)] : [...files, name]
|
|
||||||
}, [])
|
|
||||||
}
|
|
||||||
|
8
packages/nitro/types/shims.d.ts
vendored
8
packages/nitro/types/shims.d.ts
vendored
@ -21,3 +21,11 @@ declare module '#config' {
|
|||||||
const runtimeConfig: PrivateRuntimeConfig & PublicRuntimeConfig
|
const runtimeConfig: PrivateRuntimeConfig & PublicRuntimeConfig
|
||||||
export default runtimeConfig
|
export default runtimeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module '#paths' {
|
||||||
|
export const baseURL: () => string
|
||||||
|
export const buildAssetsDir: () => string
|
||||||
|
|
||||||
|
export const buildAssetsURL: (...path: string[]) => string
|
||||||
|
export const publicAssetsURL: (...path: string[]) => string
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@ export function initNitro (nuxt: Nuxt) {
|
|||||||
nuxt.hooks.addHooks(nitroContext.nuxtHooks)
|
nuxt.hooks.addHooks(nitroContext.nuxtHooks)
|
||||||
nuxt.hook('close', () => nitroContext._internal.hooks.callHook('close'))
|
nuxt.hook('close', () => nitroContext._internal.hooks.callHook('close'))
|
||||||
nitroContext._internal.hooks.hook('nitro:document', template => nuxt.callHook('nitro:document', template))
|
nitroContext._internal.hooks.hook('nitro:document', template => nuxt.callHook('nitro:document', template))
|
||||||
|
nitroContext._internal.hooks.hook('nitro:generate', ctx => nuxt.callHook('nitro:generate', ctx))
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
nuxt.hooks.addHooks(nitroDevContext.nuxtHooks)
|
nuxt.hooks.addHooks(nitroDevContext.nuxtHooks)
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
import NuxtNestedPage from './nested-page.vue'
|
import NuxtNestedPage from './nested-page.vue'
|
||||||
import NuxtPage from './page.vue'
|
import NuxtPage from './page.vue'
|
||||||
import NuxtLayout from './layout'
|
import NuxtLayout from './layout'
|
||||||
import { defineNuxtPlugin } from '#app'
|
import { defineNuxtPlugin, useRuntimeConfig } from '#app'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import routes from '#build/routes'
|
import routes from '#build/routes'
|
||||||
|
|
||||||
@ -29,9 +29,10 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|||||||
// TODO: remove before release - present for backwards compatibility & intentionally undocumented
|
// TODO: remove before release - present for backwards compatibility & intentionally undocumented
|
||||||
nuxtApp.vueApp.component('NuxtChild', NuxtNestedPage)
|
nuxtApp.vueApp.component('NuxtChild', NuxtNestedPage)
|
||||||
|
|
||||||
|
const { baseURL } = useRuntimeConfig().app
|
||||||
const routerHistory = process.client
|
const routerHistory = process.client
|
||||||
? createWebHistory()
|
? createWebHistory(baseURL)
|
||||||
: createMemoryHistory()
|
: createMemoryHistory(baseURL)
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
history: routerHistory,
|
history: routerHistory,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { resolve, join } from 'pathe'
|
import { resolve, join } from 'pathe'
|
||||||
import { existsSync, readdirSync } from 'fs'
|
import { existsSync, readdirSync } from 'fs'
|
||||||
import defu from 'defu'
|
import defu from 'defu'
|
||||||
import { isRelative, joinURL, hasProtocol } from 'ufo'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/** Vue.js config */
|
/** Vue.js config */
|
||||||
@ -29,16 +28,40 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Nuxt App configuration.
|
* Nuxt App configuration.
|
||||||
* @version 2
|
* @version 2
|
||||||
|
* @version 3
|
||||||
*/
|
*/
|
||||||
app: {
|
app: {
|
||||||
$resolve: (val, get) => {
|
/**
|
||||||
const useCDN = hasProtocol(get('build.publicPath'), true) && !get('dev')
|
* The base path of your Nuxt application.
|
||||||
const isRelativePublicPath = isRelative(get('build.publicPath'))
|
*
|
||||||
return defu(val, {
|
* This can be set at runtime by setting the BASE_PATH environment variable.
|
||||||
basePath: get('router.base'),
|
* @example
|
||||||
assetsPath: isRelativePublicPath ? get('build.publicPath') : useCDN ? '/' : joinURL(get('router.base'), get('build.publicPath')),
|
* ```bash
|
||||||
cdnURL: useCDN ? get('build.publicPath') : null
|
* BASE_PATH=/prefix/ node .output/server/index.mjs
|
||||||
})
|
* ```
|
||||||
|
*/
|
||||||
|
baseURL: '/',
|
||||||
|
/** The folder name for the built site assets, relative to `baseURL` (or `cdnURL` if set). This is set at build time and should not be customized at runtime. */
|
||||||
|
buildAssetsDir: '/_nuxt/',
|
||||||
|
/**
|
||||||
|
* The folder name for the built site assets, relative to `baseURL` (or `cdnURL` if set).
|
||||||
|
* @deprecated - use `buildAssetsDir` instead
|
||||||
|
* @version 2
|
||||||
|
*/
|
||||||
|
assetsPath: {
|
||||||
|
$resolve: (val, get) => val ?? get('buildAssetsDir')
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* An absolute URL to serve the public folder from (production-only).
|
||||||
|
*
|
||||||
|
* This can be set to a different value at runtime by setting the CDN_URL environment variable.
|
||||||
|
* @example
|
||||||
|
* ```bash
|
||||||
|
* CDN_URL=https://mycdn.org/ node .output/server/index.mjs
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
cdnURL: {
|
||||||
|
$resolve: (val, get) => get('dev') ? null : val || null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -302,7 +325,7 @@ export default {
|
|||||||
* @see [vue@3 documentation](https://v3.vuejs.org/guide/transitions-enterleave.html)
|
* @see [vue@3 documentation](https://v3.vuejs.org/guide/transitions-enterleave.html)
|
||||||
* @version 2
|
* @version 2
|
||||||
*/
|
*/
|
||||||
pageTransition: {
|
pageTransition: {
|
||||||
$resolve: (val, get) => {
|
$resolve: (val, get) => {
|
||||||
val = typeof val === 'string' ? { name: val } : val
|
val = typeof val === 'string' ? { name: val } : val
|
||||||
return defu(val, {
|
return defu(val, {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { isCI, isTest } from 'std-env'
|
import { isCI, isTest } from 'std-env'
|
||||||
import { hasProtocol } from 'ufo'
|
import { normalizeURL, withTrailingSlash } from 'ufo'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
/**
|
||||||
@ -153,13 +153,9 @@ export default {
|
|||||||
* }
|
* }
|
||||||
* ```
|
* ```
|
||||||
* @version 2
|
* @version 2
|
||||||
* @version 3
|
|
||||||
*/
|
*/
|
||||||
publicPath: {
|
publicPath: {
|
||||||
$resolve: (val, get) => {
|
$resolve: (val, get) => val ? withTrailingSlash(normalizeURL(val)) : get('app.buildAssetsDir')
|
||||||
if (hasProtocol(val, true) && get('dev')) { val = null }
|
|
||||||
return (val || '/_nuxt/').replace(/([^/])$/, '$1/')
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -160,7 +160,7 @@ export default {
|
|||||||
* The full path to the directory underneath `/_nuxt/` where static assets
|
* The full path to the directory underneath `/_nuxt/` where static assets
|
||||||
* (payload, state and manifest files) will live.
|
* (payload, state and manifest files) will live.
|
||||||
*/
|
*/
|
||||||
base: { $resolve: (val, get) => val || joinURL(get('app.assetsPath'), get('generate.dir')) },
|
base: { $resolve: (val, get) => val || joinURL(get('app.buildAssetsDir'), get('generate.dir')) },
|
||||||
/** The full path to the versioned directory where static assets for the current buidl are located. */
|
/** The full path to the versioned directory where static assets for the current buidl are located. */
|
||||||
versionBase: { $resolve: (val, get) => val || joinURL(get('generate.base'), get('generate.version')) },
|
versionBase: { $resolve: (val, get) => val || joinURL(get('generate.base'), get('generate.version')) },
|
||||||
/** A unique string to uniquely identify payload versions (defaults to the current timestamp). */
|
/** A unique string to uniquely identify payload versions (defaults to the current timestamp). */
|
||||||
|
@ -16,10 +16,9 @@ export default {
|
|||||||
* This can be useful if you need to serve Nuxt as a different context root, from
|
* This can be useful if you need to serve Nuxt as a different context root, from
|
||||||
* within a bigger web site.
|
* within a bigger web site.
|
||||||
* @version 2
|
* @version 2
|
||||||
* @version 3
|
|
||||||
*/
|
*/
|
||||||
base: {
|
base: {
|
||||||
$resolve: (val = '/') => withTrailingSlash(normalizeURL(val))
|
$resolve: (val, get) => val ? withTrailingSlash(normalizeURL(val)) : get('app.baseURL')
|
||||||
},
|
},
|
||||||
|
|
||||||
/** @private */
|
/** @private */
|
||||||
|
@ -80,6 +80,7 @@ export interface NuxtHooks {
|
|||||||
// @nuxt/nitro
|
// @nuxt/nitro
|
||||||
'nitro:document': (template: { src: string, contents: string }) => HookResult
|
'nitro:document': (template: { src: string, contents: string }) => HookResult
|
||||||
'nitro:context': (context: any) => HookResult
|
'nitro:context': (context: any) => HookResult
|
||||||
|
'nitro:generate': (context: any) => HookResult
|
||||||
|
|
||||||
// @nuxt/cli
|
// @nuxt/cli
|
||||||
'generate:cache:ignore': (ignore: string[]) => HookResult
|
'generate:cache:ignore': (ignore: string[]) => HookResult
|
||||||
|
@ -5,12 +5,14 @@ import vuePlugin from '@vitejs/plugin-vue'
|
|||||||
import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
|
import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
|
||||||
import type { Connect } from 'vite'
|
import type { Connect } from 'vite'
|
||||||
|
|
||||||
|
import { joinURL, withoutLeadingSlash } from 'ufo'
|
||||||
import { cacheDirPlugin } from './plugins/cache-dir'
|
import { cacheDirPlugin } from './plugins/cache-dir'
|
||||||
import { analyzePlugin } from './plugins/analyze'
|
import { analyzePlugin } from './plugins/analyze'
|
||||||
import { wpfs } from './utils/wpfs'
|
import { wpfs } from './utils/wpfs'
|
||||||
import type { ViteBuildContext, ViteOptions } from './vite'
|
import type { ViteBuildContext, ViteOptions } from './vite'
|
||||||
import { writeManifest } from './manifest'
|
import { writeManifest } from './manifest'
|
||||||
import { devStyleSSRPlugin } from './plugins/dev-ssr-css'
|
import { devStyleSSRPlugin } from './plugins/dev-ssr-css'
|
||||||
|
import { DynamicBasePlugin } from './plugins/dynamic-base'
|
||||||
|
|
||||||
export async function buildClient (ctx: ViteBuildContext) {
|
export async function buildClient (ctx: ViteBuildContext) {
|
||||||
const clientConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
|
const clientConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
|
||||||
@ -25,6 +27,7 @@ export async function buildClient (ctx: ViteBuildContext) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
assetsDir: ctx.nuxt.options.dev ? withoutLeadingSlash(ctx.nuxt.options.app.buildAssetsDir) : '.',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
output: {
|
output: {
|
||||||
chunkFileNames: ctx.nuxt.options.dev ? undefined : '[name]-[hash].mjs',
|
chunkFileNames: ctx.nuxt.options.dev ? undefined : '[name]-[hash].mjs',
|
||||||
@ -38,7 +41,11 @@ export async function buildClient (ctx: ViteBuildContext) {
|
|||||||
cacheDirPlugin(ctx.nuxt.options.rootDir, 'client'),
|
cacheDirPlugin(ctx.nuxt.options.rootDir, 'client'),
|
||||||
vuePlugin(ctx.config.vue),
|
vuePlugin(ctx.config.vue),
|
||||||
viteJsxPlugin(),
|
viteJsxPlugin(),
|
||||||
devStyleSSRPlugin(ctx.nuxt.options.rootDir)
|
DynamicBasePlugin.vite({ env: 'client', devAppConfig: ctx.nuxt.options.app }),
|
||||||
|
devStyleSSRPlugin({
|
||||||
|
rootDir: ctx.nuxt.options.rootDir,
|
||||||
|
buildAssetsURL: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir)
|
||||||
|
})
|
||||||
],
|
],
|
||||||
server: {
|
server: {
|
||||||
middlewareMode: true
|
middlewareMode: true
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import fse from 'fs-extra'
|
import fse from 'fs-extra'
|
||||||
import { resolve } from 'pathe'
|
import { resolve } from 'pathe'
|
||||||
|
import { joinURL } from 'ufo'
|
||||||
import type { ViteBuildContext } from './vite'
|
import type { ViteBuildContext } from './vite'
|
||||||
|
|
||||||
export async function writeManifest (ctx: ViteBuildContext, extraEntries: string[] = []) {
|
export async function writeManifest (ctx: ViteBuildContext, extraEntries: string[] = []) {
|
||||||
@ -15,7 +16,7 @@ export async function writeManifest (ctx: ViteBuildContext, extraEntries: string
|
|||||||
|
|
||||||
// Legacy dev manifest
|
// Legacy dev manifest
|
||||||
const devClientManifest = {
|
const devClientManifest = {
|
||||||
publicPath: ctx.nuxt.options.build.publicPath,
|
publicPath: joinURL(ctx.nuxt.options.app.baseURL, ctx.nuxt.options.app.buildAssetsDir),
|
||||||
all: entries,
|
all: entries,
|
||||||
initial: entries,
|
initial: entries,
|
||||||
async: [],
|
async: [],
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
|
import { joinURL } from 'ufo'
|
||||||
import { Plugin } from 'vite'
|
import { Plugin } from 'vite'
|
||||||
import { isCSS } from '../utils'
|
import { isCSS } from '../utils'
|
||||||
|
|
||||||
export function devStyleSSRPlugin (rootDir: string): Plugin {
|
export interface DevStyleSSRPluginOptions {
|
||||||
|
rootDir: string
|
||||||
|
buildAssetsURL: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function devStyleSSRPlugin (options: DevStyleSSRPluginOptions): Plugin {
|
||||||
return {
|
return {
|
||||||
name: 'nuxt:dev-style-ssr',
|
name: 'nuxt:dev-style-ssr',
|
||||||
apply: 'serve',
|
apply: 'serve',
|
||||||
@ -12,13 +18,13 @@ export function devStyleSSRPlugin (rootDir: string): Plugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let moduleId = id
|
let moduleId = id
|
||||||
if (moduleId.startsWith(rootDir)) {
|
if (moduleId.startsWith(options.rootDir)) {
|
||||||
moduleId = moduleId.slice(rootDir.length)
|
moduleId = moduleId.slice(options.rootDir.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
// When dev `<style>` is injected, remove the `<link>` styles from manifest
|
// When dev `<style>` is injected, remove the `<link>` styles from manifest
|
||||||
// TODO: Use `app.assetsPath` or unique hash
|
const selector = joinURL(options.buildAssetsURL, moduleId)
|
||||||
return code + `\ndocument.querySelectorAll(\`link[href="/_nuxt${moduleId}"]\`).forEach(i=>i.remove())`
|
return code + `\ndocument.querySelectorAll(\`link[href="${selector}"]\`).forEach(i=>i.remove())`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
57
packages/vite/src/plugins/dynamic-base.ts
Normal file
57
packages/vite/src/plugins/dynamic-base.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { createUnplugin } from 'unplugin'
|
||||||
|
|
||||||
|
interface DynamicBasePluginOptions {
|
||||||
|
env: 'dev' | 'server' | 'client'
|
||||||
|
devAppConfig?: Record<string, any>
|
||||||
|
globalPublicPath?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DynamicBasePlugin = createUnplugin(function (options: DynamicBasePluginOptions) {
|
||||||
|
return {
|
||||||
|
name: 'nuxt:dynamic-base-path',
|
||||||
|
resolveId (id) {
|
||||||
|
if (id.startsWith('/__NUXT_BASE__')) {
|
||||||
|
return id.replace('/__NUXT_BASE__', '')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enforce: 'post',
|
||||||
|
transform (code, id) {
|
||||||
|
if (options.globalPublicPath && id.includes('entry.ts')) {
|
||||||
|
code = 'import { joinURL } from "ufo";' +
|
||||||
|
`${options.globalPublicPath} = joinURL(NUXT_BASE, NUXT_CONFIG.app.buildAssetsDir);` + code
|
||||||
|
}
|
||||||
|
|
||||||
|
if (code.includes('NUXT_BASE') && !code.includes('const NUXT_BASE =')) {
|
||||||
|
code = 'const NUXT_BASE = NUXT_CONFIG.app.cdnURL || NUXT_CONFIG.app.baseURL;' + code
|
||||||
|
|
||||||
|
if (options.env === 'dev') {
|
||||||
|
code = `const NUXT_CONFIG = { app: ${JSON.stringify(options.devAppConfig)} };` + code
|
||||||
|
} else if (options.env === 'server') {
|
||||||
|
code = 'import NUXT_CONFIG from "#config";' + code
|
||||||
|
} else {
|
||||||
|
code = 'const NUXT_CONFIG = __NUXT__.config;' + code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id === 'vite/preload-helper') {
|
||||||
|
// Define vite base path as buildAssetsUrl (i.e. including _nuxt/)
|
||||||
|
code = code.replace(
|
||||||
|
/const base = ['"]\/__NUXT_BASE__\/['"]/,
|
||||||
|
'import { joinURL } from "ufo";' +
|
||||||
|
'const base = joinURL(NUXT_BASE, NUXT_CONFIG.app.buildAssetsDir);')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanitize imports
|
||||||
|
code = code.replace(/from *['"]\/__NUXT_BASE__(\/[^'"]*)['"]/g, 'from "$1"')
|
||||||
|
|
||||||
|
// Dynamically compute string URLs featuring baseURL
|
||||||
|
for (const delimiter of ['`', '"', "'"]) {
|
||||||
|
const delimiterRE = new RegExp(`${delimiter}([^${delimiter}]*)\\/__NUXT_BASE__\\/([^${delimiter}]*)${delimiter}`, 'g')
|
||||||
|
/* eslint-disable-next-line no-template-curly-in-string */
|
||||||
|
code = code.replace(delimiterRE, '`$1${NUXT_BASE}$2`')
|
||||||
|
}
|
||||||
|
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
@ -1,4 +1,4 @@
|
|||||||
import { resolve, normalize } from 'pathe'
|
import { join, resolve, normalize } from 'pathe'
|
||||||
import * as vite from 'vite'
|
import * as vite from 'vite'
|
||||||
import vuePlugin from '@vitejs/plugin-vue'
|
import vuePlugin from '@vitejs/plugin-vue'
|
||||||
import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
|
import viteJsxPlugin from '@vitejs/plugin-vue-jsx'
|
||||||
@ -6,12 +6,14 @@ import fse from 'fs-extra'
|
|||||||
import pDebounce from 'p-debounce'
|
import pDebounce from 'p-debounce'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
import { resolveModule } from '@nuxt/kit'
|
import { resolveModule } from '@nuxt/kit'
|
||||||
|
import { withoutTrailingSlash } from 'ufo'
|
||||||
import { ViteBuildContext, ViteOptions } from './vite'
|
import { ViteBuildContext, ViteOptions } from './vite'
|
||||||
import { wpfs } from './utils/wpfs'
|
import { wpfs } from './utils/wpfs'
|
||||||
import { cacheDirPlugin } from './plugins/cache-dir'
|
import { cacheDirPlugin } from './plugins/cache-dir'
|
||||||
|
import { DynamicBasePlugin } from './plugins/dynamic-base'
|
||||||
import { bundleRequest } from './dev-bundler'
|
import { bundleRequest } from './dev-bundler'
|
||||||
import { writeManifest } from './manifest'
|
import { writeManifest } from './manifest'
|
||||||
import { isCSS } from './utils'
|
import { isCSS, isDirectory, readDirRecursively } from './utils'
|
||||||
|
|
||||||
export async function buildServer (ctx: ViteBuildContext) {
|
export async function buildServer (ctx: ViteBuildContext) {
|
||||||
const _resolve = id => resolveModule(id, { paths: ctx.nuxt.options.modulesDir })
|
const _resolve = id => resolveModule(id, { paths: ctx.nuxt.options.modulesDir })
|
||||||
@ -38,7 +40,7 @@ export async function buildServer (ctx: ViteBuildContext) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
ssr: {
|
ssr: {
|
||||||
external: [],
|
external: ['#config'],
|
||||||
noExternal: [
|
noExternal: [
|
||||||
...ctx.nuxt.options.build.transpile,
|
...ctx.nuxt.options.build.transpile,
|
||||||
// TODO: Use externality for production (rollup) build
|
// TODO: Use externality for production (rollup) build
|
||||||
@ -75,12 +77,41 @@ export async function buildServer (ctx: ViteBuildContext) {
|
|||||||
plugins: [
|
plugins: [
|
||||||
cacheDirPlugin(ctx.nuxt.options.rootDir, 'server'),
|
cacheDirPlugin(ctx.nuxt.options.rootDir, 'server'),
|
||||||
vuePlugin(ctx.config.vue),
|
vuePlugin(ctx.config.vue),
|
||||||
|
DynamicBasePlugin.vite({ env: ctx.nuxt.options.dev ? 'dev' : 'server', devAppConfig: ctx.nuxt.options.app }),
|
||||||
viteJsxPlugin()
|
viteJsxPlugin()
|
||||||
]
|
]
|
||||||
} as ViteOptions)
|
} as ViteOptions)
|
||||||
|
|
||||||
await ctx.nuxt.callHook('vite:extendConfig', serverConfig, { isClient: false, isServer: true })
|
await ctx.nuxt.callHook('vite:extendConfig', serverConfig, { isClient: false, isServer: true })
|
||||||
|
|
||||||
|
ctx.nuxt.hook('nitro:generate', async () => {
|
||||||
|
const clientDist = resolve(ctx.nuxt.options.buildDir, 'dist/client')
|
||||||
|
|
||||||
|
// Remove public files that have been duplicated into buildAssetsDir
|
||||||
|
// TODO: Add option to configure this behaviour in vite
|
||||||
|
const publicDir = join(ctx.nuxt.options.srcDir, ctx.nuxt.options.dir.public)
|
||||||
|
let publicFiles: string[] = []
|
||||||
|
if (await isDirectory(publicDir)) {
|
||||||
|
publicFiles = readDirRecursively(publicDir).map(r => r.replace(publicDir, ''))
|
||||||
|
for (const file of publicFiles) {
|
||||||
|
try {
|
||||||
|
fse.rmSync(join(clientDist, file))
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy doubly-nested /_nuxt/_nuxt files into buildAssetsDir
|
||||||
|
// TODO: Workaround vite issue
|
||||||
|
if (await isDirectory(clientDist)) {
|
||||||
|
const nestedAssetsPath = withoutTrailingSlash(join(clientDist, ctx.nuxt.options.app.buildAssetsDir))
|
||||||
|
|
||||||
|
if (await isDirectory(nestedAssetsPath)) {
|
||||||
|
await fse.copy(nestedAssetsPath, clientDist, { recursive: true })
|
||||||
|
await fse.remove(nestedAssetsPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const onBuild = () => ctx.nuxt.callHook('build:resources', wpfs)
|
const onBuild = () => ctx.nuxt.callHook('build:resources', wpfs)
|
||||||
|
|
||||||
// Production build
|
// Production build
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { createHash } from 'crypto'
|
import { createHash } from 'crypto'
|
||||||
|
import { promises as fsp, readdirSync, statSync } from 'fs'
|
||||||
|
import { join } from 'pathe'
|
||||||
|
|
||||||
export function uniq<T> (arr: T[]): T[] {
|
export function uniq<T> (arr: T[]): T[] {
|
||||||
return Array.from(new Set(arr))
|
return Array.from(new Set(arr))
|
||||||
@ -32,3 +34,19 @@ export function hash (input: string, length = 8) {
|
|||||||
.digest('hex')
|
.digest('hex')
|
||||||
.slice(0, length)
|
.slice(0, length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function readDirRecursively (dir: string) {
|
||||||
|
return readdirSync(dir).reduce((files, file) => {
|
||||||
|
const name = join(dir, file)
|
||||||
|
const isDirectory = statSync(name).isDirectory()
|
||||||
|
return isDirectory ? [...files, ...readDirRecursively(name)] : [...files, name]
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function isDirectory (path: string) {
|
||||||
|
try {
|
||||||
|
return (await fsp.stat(path)).isDirectory()
|
||||||
|
} catch (_err) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,6 +5,7 @@ import type { Nuxt } from '@nuxt/schema'
|
|||||||
import type { InlineConfig, SSROptions } from 'vite'
|
import type { InlineConfig, SSROptions } from 'vite'
|
||||||
import type { Options } from '@vitejs/plugin-vue'
|
import type { Options } from '@vitejs/plugin-vue'
|
||||||
import { sanitizeFilePath } from 'mlly'
|
import { sanitizeFilePath } from 'mlly'
|
||||||
|
import { joinURL, withoutLeadingSlash } from 'ufo'
|
||||||
import { buildClient } from './client'
|
import { buildClient } from './client'
|
||||||
import { buildServer } from './server'
|
import { buildServer } from './server'
|
||||||
import virtual from './plugins/virtual'
|
import virtual from './plugins/virtual'
|
||||||
@ -47,7 +48,9 @@ export async function bundle (nuxt: Nuxt) {
|
|||||||
'abort-controller': 'unenv/runtime/mock/empty'
|
'abort-controller': 'unenv/runtime/mock/empty'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
base: nuxt.options.build.publicPath,
|
base: nuxt.options.dev
|
||||||
|
? joinURL(nuxt.options.app.baseURL, nuxt.options.app.buildAssetsDir)
|
||||||
|
: '/__NUXT_BASE__/',
|
||||||
publicDir: resolve(nuxt.options.srcDir, nuxt.options.dir.public),
|
publicDir: resolve(nuxt.options.srcDir, nuxt.options.dir.public),
|
||||||
// TODO: move to kit schema when it exists
|
// TODO: move to kit schema when it exists
|
||||||
vue: {
|
vue: {
|
||||||
@ -71,6 +74,7 @@ export async function bundle (nuxt: Nuxt) {
|
|||||||
},
|
},
|
||||||
clearScreen: false,
|
clearScreen: false,
|
||||||
build: {
|
build: {
|
||||||
|
assetsDir: withoutLeadingSlash(nuxt.options.app.buildAssetsDir),
|
||||||
emptyOutDir: false,
|
emptyOutDir: false,
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
input: resolve(nuxt.options.appDir, 'entry'),
|
input: resolve(nuxt.options.appDir, 'entry'),
|
||||||
|
@ -4,6 +4,7 @@ import webpack from 'webpack'
|
|||||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
|
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
|
||||||
|
|
||||||
import type { ClientOptions } from 'webpack-hot-middleware'
|
import type { ClientOptions } from 'webpack-hot-middleware'
|
||||||
|
import { joinURL } from 'ufo'
|
||||||
import { applyPresets, WebpackConfigContext } from '../utils/config'
|
import { applyPresets, WebpackConfigContext } from '../utils/config'
|
||||||
import { nuxt } from '../presets/nuxt'
|
import { nuxt } from '../presets/nuxt'
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ function clientHMR (ctx: WebpackConfigContext) {
|
|||||||
const hotMiddlewareClientOptions = {
|
const hotMiddlewareClientOptions = {
|
||||||
reload: true,
|
reload: true,
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
path: `${options.router.base}/__webpack_hmr/${ctx.name}`.replace(/\/\//g, '/'),
|
path: joinURL(options.app.baseURL, '__webpack_hmr', ctx.name),
|
||||||
...clientOptions,
|
...clientOptions,
|
||||||
ansiColors: JSON.stringify(clientOptions.ansiColors || {}),
|
ansiColors: JSON.stringify(clientOptions.ansiColors || {}),
|
||||||
overlayStyles: JSON.stringify(clientOptions.overlayStyles || {}),
|
overlayStyles: JSON.stringify(clientOptions.overlayStyles || {}),
|
||||||
|
@ -45,9 +45,13 @@ function serverStandalone (ctx: WebpackConfigContext) {
|
|||||||
'#',
|
'#',
|
||||||
...ctx.options.build.transpile
|
...ctx.options.build.transpile
|
||||||
]
|
]
|
||||||
|
const external = ['#config']
|
||||||
|
|
||||||
if (!Array.isArray(ctx.config.externals)) { return }
|
if (!Array.isArray(ctx.config.externals)) { return }
|
||||||
ctx.config.externals.push(({ request }, cb) => {
|
ctx.config.externals.push(({ request }, cb) => {
|
||||||
|
if (external.includes(request)) {
|
||||||
|
return cb(null, true)
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
request[0] === '.' ||
|
request[0] === '.' ||
|
||||||
isAbsolute(request) ||
|
isAbsolute(request) ||
|
||||||
|
@ -5,7 +5,7 @@ import consola from 'consola'
|
|||||||
import webpack from 'webpack'
|
import webpack from 'webpack'
|
||||||
import FriendlyErrorsWebpackPlugin from '@nuxt/friendly-errors-webpack-plugin'
|
import FriendlyErrorsWebpackPlugin from '@nuxt/friendly-errors-webpack-plugin'
|
||||||
import { escapeRegExp } from 'lodash-es'
|
import { escapeRegExp } from 'lodash-es'
|
||||||
import { hasProtocol, joinURL } from 'ufo'
|
import { joinURL } from 'ufo'
|
||||||
import WarningIgnorePlugin from '../plugins/warning-ignore'
|
import WarningIgnorePlugin from '../plugins/warning-ignore'
|
||||||
import { WebpackConfigContext, applyPresets, fileName } from '../utils/config'
|
import { WebpackConfigContext, applyPresets, fileName } from '../utils/config'
|
||||||
|
|
||||||
@ -194,9 +194,7 @@ function getOutput (ctx: WebpackConfigContext): webpack.Configuration['output']
|
|||||||
path: resolve(options.buildDir, 'dist', ctx.isServer ? 'server' : 'client'),
|
path: resolve(options.buildDir, 'dist', ctx.isServer ? 'server' : 'client'),
|
||||||
filename: fileName(ctx, 'app'),
|
filename: fileName(ctx, 'app'),
|
||||||
chunkFilename: fileName(ctx, 'chunk'),
|
chunkFilename: fileName(ctx, 'chunk'),
|
||||||
publicPath: hasProtocol(options.build.publicPath, true)
|
publicPath: joinURL(options.app.baseURL, options.app.buildAssetsDir)
|
||||||
? options.build.publicPath
|
|
||||||
: joinURL(options.router.base, options.build.publicPath)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ import type { Context as WebpackDevMiddlewareContext, Options as WebpackDevMiddl
|
|||||||
import type { MiddlewareOptions as WebpackHotMiddlewareOptions } from 'webpack-hot-middleware'
|
import type { MiddlewareOptions as WebpackHotMiddlewareOptions } from 'webpack-hot-middleware'
|
||||||
|
|
||||||
import type { Nuxt } from '@nuxt/schema'
|
import type { Nuxt } from '@nuxt/schema'
|
||||||
|
import { joinURL } from 'ufo'
|
||||||
|
import { DynamicBasePlugin } from '../../vite/src/plugins/dynamic-base'
|
||||||
import { createMFS } from './utils/mfs'
|
import { createMFS } from './utils/mfs'
|
||||||
import { client, server } from './configs'
|
import { client, server } from './configs'
|
||||||
import { createWebpackConfigContext, applyPresets, getWebpackConfig } from './utils/config'
|
import { createWebpackConfigContext, applyPresets, getWebpackConfig } from './utils/config'
|
||||||
@ -113,6 +115,11 @@ class WebpackBundler {
|
|||||||
this.compilers = webpackConfigs.map((config) => {
|
this.compilers = webpackConfigs.map((config) => {
|
||||||
// Support virtual modules (input)
|
// Support virtual modules (input)
|
||||||
config.plugins.push(this.virtualModules)
|
config.plugins.push(this.virtualModules)
|
||||||
|
config.plugins.push(DynamicBasePlugin.webpack({
|
||||||
|
env: this.nuxt.options.dev ? 'dev' : config.name as 'client',
|
||||||
|
devAppConfig: this.nuxt.options.app,
|
||||||
|
globalPublicPath: '__webpack_public_path__'
|
||||||
|
}))
|
||||||
|
|
||||||
// Create compiler
|
// Create compiler
|
||||||
const compiler = webpack(config)
|
const compiler = webpack(config)
|
||||||
@ -210,7 +217,7 @@ class WebpackBundler {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
compiler,
|
compiler,
|
||||||
{
|
{
|
||||||
publicPath: buildOptions.publicPath,
|
publicPath: joinURL(this.nuxt.options.app.baseURL, this.nuxt.options.app.buildAssetsDir),
|
||||||
outputFileSystem: this.mfs,
|
outputFileSystem: this.mfs,
|
||||||
stats: 'none',
|
stats: 'none',
|
||||||
...buildOptions.devMiddleware
|
...buildOptions.devMiddleware
|
||||||
@ -229,7 +236,7 @@ class WebpackBundler {
|
|||||||
{
|
{
|
||||||
log: false,
|
log: false,
|
||||||
heartbeat: 10000,
|
heartbeat: 10000,
|
||||||
path: `/__webpack_hmr/${name}`,
|
path: joinURL(this.nuxt.options.app.baseURL, '__webpack_hmr', name),
|
||||||
...hotMiddlewareOptions
|
...hotMiddlewareOptions
|
||||||
} as WebpackHotMiddlewareOptions
|
} as WebpackHotMiddlewareOptions
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user