mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
feat(schema,webpack): allow $client
and $server
overrides (#22304)
This commit is contained in:
parent
1b5a8bb924
commit
491ebff3b6
@ -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
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
@ -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
|
||||
}))
|
||||
}
|
||||
|
@ -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')
|
||||
}
|
||||
}]
|
||||
|
@ -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')
|
||||
}
|
||||
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
}))
|
||||
|
@ -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`)
|
||||
|
@ -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) })
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user