feat(schema,webpack): allow $client and $server overrides (#22304)

This commit is contained in:
Daniel Roe 2023-07-24 20:46:09 +01:00 committed by GitHub
parent 1b5a8bb924
commit 491ebff3b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 135 additions and 157 deletions

View File

@ -68,6 +68,10 @@ export interface NuxtConfig extends DeepPartial<Omit<ConfigSchema, 'vite' | 'run
// Avoid DeepPartial for vite config interface (#4772)
vite?: ConfigSchema['vite']
runtimeConfig?: Overrideable<RuntimeConfig>
webpack?: ConfigSchema['webpack'] & {
$client?: ConfigSchema['webpack']
$server?: ConfigSchema['webpack']
}
/**
* Experimental custom config schema
@ -89,9 +93,13 @@ export type NuxtConfigLayer = ConfigLayer<NuxtConfig & {
}>
/** Normalized Nuxt options available as `nuxt.options.*` */
export interface NuxtOptions extends Omit<ConfigSchema, 'builder'> {
export interface NuxtOptions extends Omit<ConfigSchema, 'builder' | 'webpack'> {
sourcemap: Required<Exclude<ConfigSchema['sourcemap'], boolean>>
builder: '@nuxt/vite-builder' | '@nuxt/webpack-builder' | { bundle: (nuxt: Nuxt) => Promise<void> }
webpack: ConfigSchema['webpack'] & {
$client: ConfigSchema['webpack']
$server: ConfigSchema['webpack']
}
_layers: NuxtConfigLayer[]
$schema: SchemaDefinition
}

View File

@ -25,6 +25,7 @@
"css-loader": "^6.8.1",
"css-minimizer-webpack-plugin": "^5.0.1",
"cssnano": "^6.0.1",
"defu": "^6.1.2",
"esbuild-loader": "^3.0.1",
"escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3",

View File

@ -47,17 +47,15 @@ function clientPerformance (ctx: WebpackConfigContext) {
}
function clientHMR (ctx: WebpackConfigContext) {
const { options, config } = ctx
if (!ctx.isDev) {
return
}
const clientOptions = options.webpack.hotMiddleware?.client || {}
const clientOptions = ctx.userConfig.hotMiddleware?.client || {}
const hotMiddlewareClientOptions = {
reload: true,
timeout: 30000,
path: joinURL(options.app.baseURL, '__webpack_hmr', ctx.name),
path: joinURL(ctx.options.app.baseURL, '__webpack_hmr', ctx.name),
...clientOptions,
ansiColors: JSON.stringify(clientOptions.ansiColors || {}),
overlayStyles: JSON.stringify(clientOptions.overlayStyles || {}),
@ -66,14 +64,14 @@ function clientHMR (ctx: WebpackConfigContext) {
const hotMiddlewareClientOptionsStr = querystring.stringify(hotMiddlewareClientOptions)
// Add HMR support
const app = (config.entry as any).app as any
const app = (ctx.config.entry as any).app as any
app.unshift(
// https://github.com/glenjamin/webpack-hot-middleware#config
`webpack-hot-middleware/client?${hotMiddlewareClientOptionsStr}`
)
config.plugins = config.plugins || []
config.plugins.push(new webpack.HotModuleReplacementPlugin())
ctx.config.plugins = ctx.config.plugins || []
ctx.config.plugins.push(new webpack.HotModuleReplacementPlugin())
}
function clientOptimization (_ctx: WebpackConfigContext) {
@ -81,21 +79,19 @@ function clientOptimization (_ctx: WebpackConfigContext) {
}
function clientPlugins (ctx: WebpackConfigContext) {
const { options, config } = ctx
// webpack Bundle Analyzer
// https://github.com/webpack-contrib/webpack-bundle-analyzer
if (!ctx.isDev && ctx.name === 'client' && options.webpack.analyze) {
const statsDir = resolve(options.analyzeDir)
if (!ctx.isDev && ctx.name === 'client' && ctx.userConfig.analyze) {
const statsDir = resolve(ctx.options.analyzeDir)
config.plugins!.push(new BundleAnalyzerPlugin({
ctx.config.plugins!.push(new BundleAnalyzerPlugin({
analyzerMode: 'static',
defaultSizes: 'gzip',
generateStatsFile: true,
openAnalyzer: true,
reportFilename: resolve(statsDir, `${ctx.name}.html`),
statsFilename: resolve(statsDir, `${ctx.name}.json`),
...options.webpack.analyze === true ? {} : options.webpack.analyze
...ctx.userConfig.analyze === true ? {} : ctx.userConfig.analyze
}))
}
@ -103,7 +99,7 @@ function clientPlugins (ctx: WebpackConfigContext) {
// no server build, so we inject here instead.
if (!ctx.nuxt.options.ssr) {
if (ctx.nuxt.options.typescript.typeCheck === true || (ctx.nuxt.options.typescript.typeCheck === 'build' && !ctx.nuxt.options.dev)) {
config.plugins!.push(new ForkTSCheckerWebpackPlugin({
ctx.config.plugins!.push(new ForkTSCheckerWebpackPlugin({
logger
}))
}

View File

@ -25,13 +25,11 @@ export function server (ctx: WebpackConfigContext) {
}
function serverPreset (ctx: WebpackConfigContext) {
const { config } = ctx
ctx.config.output!.filename = 'server.mjs'
config.output!.filename = 'server.mjs'
ctx.config.devtool = ctx.nuxt.options.sourcemap.server ? ctx.isDev ? 'cheap-module-source-map' : 'source-map' : false
config.devtool = ctx.nuxt.options.sourcemap.server ? ctx.isDev ? 'cheap-module-source-map' : 'source-map' : false
config.optimization = {
ctx.config.optimization = {
splitChunks: false,
minimize: false
}
@ -76,21 +74,19 @@ function serverStandalone (ctx: WebpackConfigContext) {
}
function serverPlugins (ctx: WebpackConfigContext) {
const { config, options } = ctx
config.plugins = config.plugins || []
ctx.config.plugins = ctx.config.plugins || []
// Server polyfills
if (options.webpack.serverURLPolyfill) {
config.plugins.push(new webpack.ProvidePlugin({
URL: [options.webpack.serverURLPolyfill, 'URL'],
URLSearchParams: [options.webpack.serverURLPolyfill, 'URLSearchParams']
if (ctx.userConfig.serverURLPolyfill) {
ctx.config.plugins.push(new webpack.ProvidePlugin({
URL: [ctx.userConfig.serverURLPolyfill, 'URL'],
URLSearchParams: [ctx.userConfig.serverURLPolyfill, 'URLSearchParams']
}))
}
// Add type-checking
if (ctx.nuxt.options.typescript.typeCheck === true || (ctx.nuxt.options.typescript.typeCheck === 'build' && !ctx.nuxt.options.dev)) {
config.plugins!.push(new ForkTSCheckerWebpackPlugin({
ctx.config.plugins!.push(new ForkTSCheckerWebpackPlugin({
logger
}))
}

View File

@ -8,7 +8,7 @@ export function assets (ctx: WebpackConfigContext) {
use: [{
loader: 'url-loader',
options: {
...ctx.options.webpack.loaders.imgUrl,
...ctx.userConfig.loaders.imgUrl,
name: fileName(ctx, 'img')
}
}]
@ -18,7 +18,7 @@ export function assets (ctx: WebpackConfigContext) {
use: [{
loader: 'url-loader',
options: {
...ctx.options.webpack.loaders.fontUrl,
...ctx.userConfig.loaders.fontUrl,
name: fileName(ctx, 'font')
}
}]
@ -28,7 +28,7 @@ export function assets (ctx: WebpackConfigContext) {
use: [{
loader: 'file-loader',
options: {
...ctx.options.webpack.loaders.file,
...ctx.userConfig.loaders.file,
name: fileName(ctx, 'video')
}
}]

View File

@ -27,20 +27,18 @@ export function base (ctx: WebpackConfigContext) {
}
function baseConfig (ctx: WebpackConfigContext) {
const { options } = ctx
ctx.config = {
name: ctx.name,
entry: { app: [resolve(options.appDir, options.experimental.asyncEntry ? 'entry.async' : 'entry')] },
entry: { app: [resolve(ctx.options.appDir, ctx.options.experimental.asyncEntry ? 'entry.async' : 'entry')] },
module: { rules: [] },
plugins: [],
externals: [],
optimization: {
...options.webpack.optimization,
...ctx.userConfig.optimization,
minimizer: []
},
experiments: {
...options.webpack.experiments
...ctx.userConfig.experiments
},
mode: ctx.isDev ? 'development' : 'production',
cache: getCache(ctx),
@ -51,27 +49,25 @@ function baseConfig (ctx: WebpackConfigContext) {
}
function basePlugins (ctx: WebpackConfigContext) {
const { config, options, nuxt } = ctx
config.plugins = config.plugins || []
ctx.config.plugins = ctx.config.plugins || []
// Add timefix-plugin before other plugins
if (options.dev) {
config.plugins.push(new TimeFixPlugin())
if (ctx.options.dev) {
ctx.config.plugins.push(new TimeFixPlugin())
}
// User plugins
config.plugins.push(...(options.webpack.plugins || []))
ctx.config.plugins.push(...(ctx.userConfig.plugins || []))
// Ignore empty warnings
config.plugins.push(new WarningIgnorePlugin(getWarningIgnoreFilter(ctx)))
ctx.config.plugins.push(new WarningIgnorePlugin(getWarningIgnoreFilter(ctx)))
// Provide env via DefinePlugin
config.plugins.push(new webpack.DefinePlugin(getEnv(ctx)))
ctx.config.plugins.push(new webpack.DefinePlugin(getEnv(ctx)))
// Friendly errors
if (ctx.isServer || (ctx.isDev && options.webpack.friendlyErrors)) {
config.plugins.push(
if (ctx.isServer || (ctx.isDev && ctx.userConfig.friendlyErrors)) {
ctx.config.plugins.push(
new FriendlyErrorsWebpackPlugin({
clearConsole: false,
reporter: 'consola',
@ -80,14 +76,14 @@ function basePlugins (ctx: WebpackConfigContext) {
)
}
if (nuxt.options.webpack.profile) {
if (ctx.nuxt.options.webpack.profile) {
// Webpackbar
const colors = {
client: 'green',
server: 'orange',
modern: 'blue'
}
config.plugins.push(new WebpackBar({
ctx.config.plugins.push(new WebpackBar({
name: ctx.name,
color: colors[ctx.name as keyof typeof colors],
reporters: ['stats'],
@ -97,21 +93,21 @@ function basePlugins (ctx: WebpackConfigContext) {
reporter: {
change: (_, { shortPath }) => {
if (!ctx.isServer) {
nuxt.callHook('webpack:change', shortPath)
ctx.nuxt.callHook('webpack:change', shortPath)
}
},
done: ({ state }) => {
if (state.hasErrors) {
nuxt.callHook('webpack:error')
ctx.nuxt.callHook('webpack:error')
} else {
logger.success(`${state.name} ${state.message}`)
}
},
allDone: () => {
nuxt.callHook('webpack:done')
ctx.nuxt.callHook('webpack:done')
},
progress ({ statesArray }) {
nuxt.callHook('webpack:progress', statesArray)
ctx.nuxt.callHook('webpack:progress', statesArray)
}
}
}
@ -120,13 +116,11 @@ function basePlugins (ctx: WebpackConfigContext) {
}
function baseAlias (ctx: WebpackConfigContext) {
const { options } = ctx
ctx.alias = {
'#app': options.appDir,
'#build/plugins': resolve(options.buildDir, 'plugins', ctx.isClient ? 'client' : 'server'),
'#build': options.buildDir,
...options.alias,
'#app': ctx.options.appDir,
'#build/plugins': resolve(ctx.options.buildDir, 'plugins', ctx.isClient ? 'client' : 'server'),
'#build': ctx.options.buildDir,
...ctx.options.alias,
...ctx.alias
}
if (ctx.isClient) {
@ -135,29 +129,25 @@ function baseAlias (ctx: WebpackConfigContext) {
}
function baseResolve (ctx: WebpackConfigContext) {
const { options, config } = ctx
// Prioritize nested node_modules in webpack search path (#2558)
// TODO: this might be refactored as default modulesDir?
const webpackModulesDir = ['node_modules'].concat(options.modulesDir)
const webpackModulesDir = ['node_modules'].concat(ctx.options.modulesDir)
config.resolve = {
ctx.config.resolve = {
extensions: ['.wasm', '.mjs', '.js', '.ts', '.json', '.vue', '.jsx', '.tsx'],
alias: ctx.alias,
modules: webpackModulesDir,
fullySpecified: false,
...config.resolve
...ctx.config.resolve
}
config.resolveLoader = {
ctx.config.resolveLoader = {
modules: webpackModulesDir,
...config.resolveLoader
...ctx.config.resolveLoader
}
}
function baseTranspile (ctx: WebpackConfigContext) {
const { options } = ctx
const transpile = [
/\.vue\.js/i, // include SFCs in node_modules
/consola\/src/,
@ -165,7 +155,7 @@ function baseTranspile (ctx: WebpackConfigContext) {
/(^|\/)nuxt\/(dist\/)?(app|[^/]+\/runtime)($|\/)/
]
for (let pattern of options.build.transpile) {
for (let pattern of ctx.options.build.transpile) {
if (typeof pattern === 'function') {
const result = pattern(ctx)
if (result) { pattern = result }
@ -182,9 +172,7 @@ function baseTranspile (ctx: WebpackConfigContext) {
}
function getCache (ctx: WebpackConfigContext): webpack.Configuration['cache'] {
const { options } = ctx
if (!options.dev) {
if (!ctx.options.dev) {
return false
}
@ -205,37 +193,31 @@ function getCache (ctx: WebpackConfigContext): webpack.Configuration['cache'] {
}
function getOutput (ctx: WebpackConfigContext): webpack.Configuration['output'] {
const { options } = ctx
return {
path: resolve(options.buildDir, 'dist', ctx.isServer ? 'server' : joinURL('client', options.app.buildAssetsDir)),
path: resolve(ctx.options.buildDir, 'dist', ctx.isServer ? 'server' : joinURL('client', ctx.options.app.buildAssetsDir)),
filename: fileName(ctx, 'app'),
chunkFilename: fileName(ctx, 'chunk'),
publicPath: joinURL(options.app.baseURL, options.app.buildAssetsDir)
publicPath: joinURL(ctx.options.app.baseURL, ctx.options.app.buildAssetsDir)
}
}
function getWarningIgnoreFilter (ctx: WebpackConfigContext): WarningFilter {
const { options } = ctx
const filters: WarningFilter[] = [
// Hide warnings about plugins without a default export (#1179)
warn => warn.name === 'ModuleDependencyWarning' &&
warn.message.includes('export \'default\'') &&
warn.message.includes('nuxt_plugin_'),
...(options.webpack.warningIgnoreFilters || [])
...(ctx.userConfig.warningIgnoreFilters || [])
]
return warn => !filters.some(ignoreFilter => ignoreFilter(warn))
}
function getEnv (ctx: WebpackConfigContext) {
const { options } = ctx
const _env: Record<string, string | boolean> = {
'process.env.NODE_ENV': JSON.stringify(ctx.config.mode),
'process.mode': JSON.stringify(ctx.config.mode),
'process.dev': options.dev,
'process.dev': ctx.options.dev,
'process.test': isTest,
__NUXT_VERSION__: JSON.stringify(ctx.nuxt._version),
'process.env.VUE_ENV': JSON.stringify(ctx.name),
@ -244,7 +226,7 @@ function getEnv (ctx: WebpackConfigContext) {
'process.server': ctx.isServer
}
if (options.webpack.aggressiveCodeRemoval) {
if (ctx.userConfig.aggressiveCodeRemoval) {
_env['typeof process'] = JSON.stringify(ctx.isServer ? 'object' : 'undefined')
_env['typeof window'] = _env['typeof document'] = JSON.stringify(!ctx.isServer ? 'object' : 'undefined')
}

View File

@ -2,17 +2,15 @@ import { EsbuildPlugin } from 'esbuild-loader'
import type { WebpackConfigContext } from '../utils/config'
export function esbuild (ctx: WebpackConfigContext) {
const { config } = ctx
// https://esbuild.github.io/getting-started/#bundling-for-the-browser
// https://gs.statcounter.com/browser-version-market-share
// https://nodejs.org/en/
const target = ctx.isServer ? 'es2019' : 'chrome85'
// https://github.com/nuxt/nuxt/issues/13052
config.optimization!.minimizer!.push(new EsbuildPlugin())
ctx.config.optimization!.minimizer!.push(new EsbuildPlugin())
config.module!.rules!.push(
ctx.config.module!.rules!.push(
{
test: /\.m?[jt]s$/i,
loader: 'esbuild-loader',

View File

@ -1,15 +1,13 @@
import type { WebpackConfigContext } from '../utils/config'
export function node (ctx: WebpackConfigContext) {
const { config } = ctx
ctx.config.target = 'node'
ctx.config.node = false
config.target = 'node'
config.node = false
ctx.config.experiments!.outputModule = true
config.experiments!.outputModule = true
config.output = {
...config.output,
ctx.config.output = {
...ctx.config.output,
chunkFilename: '[name].mjs',
chunkFormat: 'module',
chunkLoading: 'import',
@ -28,8 +26,8 @@ export function node (ctx: WebpackConfigContext) {
}
}
config.performance = {
...config.performance,
ctx.config.performance = {
...ctx.config.performance,
hints: false,
maxEntrypointSize: Infinity,
maxAssetSize: Infinity

View File

@ -8,7 +8,7 @@ export function pug (ctx: WebpackConfigContext) {
resourceQuery: /^\?vue/i,
use: [{
loader: 'pug-plain-loader',
options: ctx.options.webpack.loaders.pugPlain
options: ctx.userConfig.loaders.pugPlain
}]
},
{
@ -16,7 +16,7 @@ export function pug (ctx: WebpackConfigContext) {
'raw-loader',
{
loader: 'pug-plain-loader',
options: ctx.options.webpack.loaders.pugPlain
options: ctx.userConfig.loaders.pugPlain
}
]
}

View File

@ -13,67 +13,59 @@ export function style (ctx: WebpackConfigContext) {
}
function minimizer (ctx: WebpackConfigContext) {
const { options, config } = ctx
if (options.webpack.optimizeCSS && Array.isArray(config.optimization!.minimizer)) {
config.optimization!.minimizer.push(new CssMinimizerPlugin({
...options.webpack.optimizeCSS
if (ctx.userConfig.optimizeCSS && Array.isArray(ctx.config.optimization!.minimizer)) {
ctx.config.optimization!.minimizer.push(new CssMinimizerPlugin({
...ctx.userConfig.optimizeCSS
}))
}
}
function extractCSS (ctx: WebpackConfigContext) {
const { options, config } = ctx
// CSS extraction
if (options.webpack.extractCSS) {
config.plugins!.push(new MiniCssExtractPlugin({
if (ctx.userConfig.extractCSS) {
ctx.config.plugins!.push(new MiniCssExtractPlugin({
filename: fileName(ctx, 'css'),
chunkFilename: fileName(ctx, 'css'),
...options.webpack.extractCSS === true ? {} : options.webpack.extractCSS
...ctx.userConfig.extractCSS === true ? {} : ctx.userConfig.extractCSS
}))
}
}
function loaders (ctx: WebpackConfigContext) {
const { config, options } = ctx
// CSS
config.module!.rules!.push(createdStyleRule('css', /\.css$/i, null, ctx))
ctx.config.module!.rules!.push(createdStyleRule('css', /\.css$/i, null, ctx))
// PostCSS
config.module!.rules!.push(createdStyleRule('postcss', /\.p(ost)?css$/i, null, ctx))
ctx.config.module!.rules!.push(createdStyleRule('postcss', /\.p(ost)?css$/i, null, ctx))
// Less
const lessLoader = { loader: 'less-loader', options: options.webpack.loaders.less }
config.module!.rules!.push(createdStyleRule('less', /\.less$/i, lessLoader, ctx))
const lessLoader = { loader: 'less-loader', options: ctx.userConfig.loaders.less }
ctx.config.module!.rules!.push(createdStyleRule('less', /\.less$/i, lessLoader, ctx))
// Sass (TODO: optional dependency)
const sassLoader = { loader: 'sass-loader', options: options.webpack.loaders.sass }
config.module!.rules!.push(createdStyleRule('sass', /\.sass$/i, sassLoader, ctx))
const sassLoader = { loader: 'sass-loader', options: ctx.userConfig.loaders.sass }
ctx.config.module!.rules!.push(createdStyleRule('sass', /\.sass$/i, sassLoader, ctx))
const scssLoader = { loader: 'sass-loader', options: options.webpack.loaders.scss }
config.module!.rules!.push(createdStyleRule('scss', /\.scss$/i, scssLoader, ctx))
const scssLoader = { loader: 'sass-loader', options: ctx.userConfig.loaders.scss }
ctx.config.module!.rules!.push(createdStyleRule('scss', /\.scss$/i, scssLoader, ctx))
// Stylus
const stylusLoader = { loader: 'stylus-loader', options: options.webpack.loaders.stylus }
config.module!.rules!.push(createdStyleRule('stylus', /\.styl(us)?$/i, stylusLoader, ctx))
const stylusLoader = { loader: 'stylus-loader', options: ctx.userConfig.loaders.stylus }
ctx.config.module!.rules!.push(createdStyleRule('stylus', /\.styl(us)?$/i, stylusLoader, ctx))
}
function createdStyleRule (lang: string, test: RegExp, processorLoader: any, ctx: WebpackConfigContext) {
const { options } = ctx
const styleLoaders = [
createPostcssLoadersRule(ctx),
processorLoader
].filter(Boolean)
options.webpack.loaders.css.importLoaders =
options.webpack.loaders.cssModules.importLoaders =
ctx.userConfig.loaders.css.importLoaders =
ctx.userConfig.loaders.cssModules.importLoaders =
styleLoaders.length
const cssLoaders = createCssLoadersRule(ctx, options.webpack.loaders.css)
const cssModuleLoaders = createCssLoadersRule(ctx, options.webpack.loaders.cssModules)
const cssLoaders = createCssLoadersRule(ctx, ctx.userConfig.loaders.css)
const cssModuleLoaders = createCssLoadersRule(ctx, ctx.userConfig.loaders.cssModules)
return {
test,
@ -92,11 +84,9 @@ function createdStyleRule (lang: string, test: RegExp, processorLoader: any, ctx
}
function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any) {
const { options } = ctx
const cssLoader = { loader: 'css-loader', options: cssLoaderOptions }
if (options.webpack.extractCSS) {
if (ctx.userConfig.extractCSS) {
if (ctx.isServer) {
// https://webpack.js.org/loaders/css-loader/#exportonlylocals
if (cssLoader.options.modules) {
@ -124,11 +114,9 @@ function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions: any)
}
function createPostcssLoadersRule (ctx: WebpackConfigContext) {
const { options, nuxt } = ctx
if (!ctx.options.postcss) { return }
if (!options.postcss) { return }
const config = getPostcssConfig(nuxt)
const config = getPostcssConfig(ctx.nuxt)
if (!config) {
return

View File

@ -6,27 +6,25 @@ import VueSSRServerPlugin from '../plugins/vue/server'
import type { WebpackConfigContext } from '../utils/config'
export function vue (ctx: WebpackConfigContext) {
const { options, config } = ctx
// @ts-expect-error de-default vue-loader
config.plugins!.push(new (VueLoaderPlugin.default || VueLoaderPlugin)())
ctx.config.plugins!.push(new (VueLoaderPlugin.default || VueLoaderPlugin)())
config.module!.rules!.push({
ctx.config.module!.rules!.push({
test: /\.vue$/i,
loader: 'vue-loader',
options: {
reactivityTransform: ctx.nuxt.options.experimental.reactivityTransform,
...options.webpack.loaders.vue
...ctx.userConfig.loaders.vue
}
})
if (ctx.isClient) {
config.plugins!.push(new VueSSRClientPlugin({
filename: resolve(options.buildDir, 'dist/server', `${ctx.name}.manifest.json`),
ctx.config.plugins!.push(new VueSSRClientPlugin({
filename: resolve(ctx.options.buildDir, 'dist/server', `${ctx.name}.manifest.json`),
nuxt: ctx.nuxt
}))
} else {
config.plugins!.push(new VueSSRServerPlugin({
ctx.config.plugins!.push(new VueSSRServerPlugin({
filename: `${ctx.name}.manifest.json`
}))
}
@ -34,7 +32,7 @@ export function vue (ctx: WebpackConfigContext) {
// Feature flags
// https://github.com/vuejs/vue-next/tree/master/packages/vue#bundler-build-feature-flags
// TODO: Provide options to toggle
config.plugins!.push(new webpack.DefinePlugin({
ctx.config.plugins!.push(new webpack.DefinePlugin({
__VUE_OPTIONS_API__: 'true',
__VUE_PROD_DEVTOOLS__: 'false'
}))

View File

@ -1,26 +1,38 @@
import { cloneDeep } from 'lodash-es'
import type { Configuration } from 'webpack'
import type { Nuxt } from '@nuxt/schema'
import type { Nuxt, NuxtOptions } from '@nuxt/schema'
import { logger } from '@nuxt/kit'
export interface WebpackConfigContext extends ReturnType<typeof createWebpackConfigContext> {}
export interface WebpackConfigContext {
nuxt: Nuxt
options: NuxtOptions
userConfig: Omit<NuxtOptions['webpack'], '$client' | '$server'>
config: Configuration
name: string
isDev: boolean
isServer: boolean
isClient: boolean
alias: { [index: string]: string | false | string[] }
transpile: RegExp[]
}
type WebpackConfigPreset = (ctx: WebpackConfigContext, options?: object) => void
type WebpackConfigPresetItem = WebpackConfigPreset | [WebpackConfigPreset, any]
export function createWebpackConfigContext (nuxt: Nuxt) {
export function createWebpackConfigContext (nuxt: Nuxt): WebpackConfigContext {
return {
nuxt,
options: nuxt.options,
config: {} as Configuration,
userConfig: nuxt.options.webpack,
config: {},
name: 'base',
isDev: nuxt.options.dev,
isServer: false,
isClient: false,
alias: {} as { [index: string]: string | false | string[] },
transpile: [] as RegExp[]
alias: {},
transpile: []
}
}
@ -38,15 +50,13 @@ export function applyPresets (ctx: WebpackConfigContext, presets: WebpackConfigP
}
export function fileName (ctx: WebpackConfigContext, key: string) {
const { options } = ctx
let fileName = options.webpack.filenames[key]
let fileName = ctx.userConfig.filenames[key]
if (typeof fileName === 'function') {
fileName = fileName(ctx)
}
if (typeof fileName === 'string' && options.dev) {
if (typeof fileName === 'string' && ctx.options.dev) {
const hash = /\[(chunkhash|contenthash|hash)(?::(\d+))?]/.exec(fileName)
if (hash) {
logger.warn(`Notice: Please do not use ${hash[1]} in dev mode to prevent memory leak`)

View File

@ -6,10 +6,11 @@ import type { OutputFileSystem } from 'webpack-dev-middleware'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import type { Compiler, Watching } from 'webpack'
import { defu } from 'defu'
import type { Nuxt } from '@nuxt/schema'
import { joinURL } from 'ufo'
import { logger, useNuxt } from '@nuxt/kit'
import { composableKeysPlugin } from '../../vite/src/plugins/composable-keys'
import { DynamicBasePlugin } from './plugins/dynamic-base'
import { ChunkErrorPlugin } from './plugins/chunk'
@ -26,6 +27,7 @@ export async function bundle (nuxt: Nuxt) {
const webpackConfigs = [client, ...nuxt.options.ssr ? [server] : []].map((preset) => {
const ctx = createWebpackConfigContext(nuxt)
ctx.userConfig = defu(nuxt.options.webpack[`$${preset.name as 'client' | 'server'}`], ctx.userConfig)
applyPresets(ctx, preset)
return getWebpackConfig(ctx)
})
@ -119,13 +121,11 @@ async function createDevMiddleware (compiler: Compiler) {
async function compile (compiler: Compiler) {
const nuxt = useNuxt()
const { name } = compiler.options
await nuxt.callHook('webpack:compile', { name: name!, compiler })
await nuxt.callHook('webpack:compile', { name: compiler.options.name!, compiler })
// Load renderer resources after build
compiler.hooks.done.tap('load-resources', async (stats) => {
await nuxt.callHook('webpack:compiled', { name: name!, compiler, stats })
await nuxt.callHook('webpack:compiled', { name: compiler.options.name!, compiler, stats })
})
// --- Dev Build ---
@ -137,7 +137,7 @@ async function compile (compiler: Compiler) {
})
// Client build
if (name === 'client') {
if (compiler.options.name === 'client') {
return new Promise((resolve, reject) => {
compiler.hooks.done.tap('nuxt-dev', () => { resolve(null) })
compiler.hooks.failed.tap('nuxt-errorlog', (err) => { reject(err) })

View File

@ -806,6 +806,9 @@ importers:
cssnano:
specifier: ^6.0.1
version: 6.0.1(postcss@8.4.27)
defu:
specifier: ^6.1.2
version: 6.1.2
esbuild-loader:
specifier: ^3.0.1
version: 3.0.1(webpack@5.88.2)