refactor(schema,webpack)!: split out webpack and postcss build options (#2812)

* refactor: split out webpack and postcss build options

* feat(schema): set nuxt3 builder in config

* fix(schema): default postcss config file to false

* chore: update lockfile

* style: remove unused imports

* refactor(webpack): remove (previously disabled) babel config

* refactor: move shared vite options into schema

* fix(schema): omit __NUXT_BASE__ from defaults

* fix: move appDir-dependent options back to vite

* refactor: split out virtual modules

* refactor: extract compile/createDevMiddleware

* refactor: further improvements

* chore: remove `@nuxt/webpack-builder` dependency

* chore: update lockfile

* refactor: move `builder` option to top level

* fix: bind close to watcher instance

* chore: update lockfile

* fix: create portal between postcss & build.postcss.postcssOptions

* fix: remove duplicate

* fix: revert

* fix: use `postcss` directly

* fix: import builder from rootDir

* chore: dedupe webpack install

* test: update fixture to use `builder`

* fix: bind class in pify

Co-authored-by: Pooya Parsa <pyapar@gmail.com>
This commit is contained in:
Daniel Roe 2022-02-25 19:11:01 +00:00 committed by GitHub
parent 2b3dbed594
commit 73ba30fb69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 1363 additions and 1576 deletions

View File

@ -83,6 +83,10 @@ export function useModuleContainer (nuxt: Nuxt = useNuxt()): ModuleContainer {
extendBuild (fn) {
// @ts-ignore
nuxt.options.build.extend = chainFn(nuxt.options.build.extend, fn)
if (!isNuxt2(nuxt)) {
console.warn('[kit] [compat] Using `extendBuild` in Nuxt 3 has no effect. Instead call extendWebpackConfig and extendViteConfig.')
}
},
extendRoutes (fn) {

View File

@ -35,7 +35,6 @@
"@nuxt/nitro": "3.0.0",
"@nuxt/schema": "3.0.0",
"@nuxt/vite-builder": "3.0.0",
"@nuxt/webpack-builder": "3.0.0",
"@vue/reactivity": "^3.2.31",
"@vue/shared": "^3.2.31",
"@vueuse/head": "^0.7.5",

View File

@ -1,5 +1,6 @@
import chokidar from 'chokidar'
import type { Nuxt } from '@nuxt/schema'
import { tryImportModule } from '@nuxt/kit'
import { createApp, generateApp } from './app'
export async function build (nuxt: Nuxt) {
@ -48,8 +49,9 @@ function watch (nuxt: Nuxt) {
}
async function bundle (nuxt: Nuxt) {
const useVite = nuxt.options.vite !== false
const { bundle } = await (useVite ? import('@nuxt/vite-builder') : import('@nuxt/webpack-builder'))
const { bundle } = typeof nuxt.options.builder === 'string'
? await tryImportModule(nuxt.options.builder, { paths: nuxt.options.rootDir })
: nuxt.options.builder
try {
return bundle(nuxt)
} catch (error) {

View File

@ -9,7 +9,10 @@ export default defineBuildConfig({
name: 'config',
builder: 'untyped',
defaults: {
rootDir: '/<rootDir>/'
rootDir: '/<rootDir>/',
vite: {
base: '/'
}
}
},
'src/index'
@ -24,6 +27,12 @@ export default defineBuildConfig({
'webpack-bundle-analyzer',
'rollup-plugin-visualizer',
'vite',
'mini-css-extract-plugin',
'terser-webpack-plugin',
'css-minimizer-webpack-plugin',
'webpack-dev-middleware',
'webpack-hot-middleware',
'postcss',
'consola',
// Implicit
'@vue/compiler-core',

View File

@ -24,6 +24,7 @@
"defu": "^5.0.1",
"jiti": "^1.13.0",
"pathe": "^0.2.0",
"postcss-import-resolver": "^2.0.0",
"scule": "^0.2.1",
"std-env": "^3.0.1",
"ufo": "^0.7.9"

File diff suppressed because it is too large Load Diff

View File

@ -10,7 +10,10 @@ import router from './router'
import server from './server'
import cli from './cli'
import generate from './generate'
import postcss from './postcss'
import typescript from './typescript'
import vite from './vite'
import webpack from './webpack'
import nitro from './nitro'
import experimental from './experimental'
@ -37,25 +40,18 @@ export default {
..._app,
..._common,
..._internal,
...postcss,
...typescript,
...vite,
...webpack,
...nitro,
build,
// Legacy
...build,
messages,
render,
router,
server,
cli,
generate,
typescript,
experimental,
/**
* Configuration that will be passed directly to Vite.
*
* See https://vitejs.dev/config for more information.
* Please note that not all vite options are supported in Nuxt.
*
* @type {boolean | typeof import('vite').InlineConfig}
* @version 3
*/
vite: undefined,
}

View File

@ -0,0 +1,53 @@
import defu from 'defu'
import createResolver from 'postcss-import-resolver'
export default {
/** @version 3 */
postcss: {
/** Path to postcss config file. */
/** @type string | false */
config: false,
/**
* Options for configuring PostCSS plugins.
*
* https://postcss.org/
*/
plugins: {
/**
* https://github.com/postcss/postcss-import
*/
'postcss-import': {
$resolve: (val, get) => val !== false ? defu(val || {}, {
resolve: createResolver({
alias: { ...get('alias') },
modules: [
get('srcDir'),
get('rootDir'),
...get('modulesDir')
]
})
}) : val,
},
/**
* https://github.com/postcss/postcss-url
*/
'postcss-url': {},
/**
* https://github.com/postcss/autoprefixer
*/
autoprefixer: {},
cssnano: {
$resolve: (val, get) => val ?? (get('dev') && {
preset: ['default', {
// Keep quotes in font values to prevent from HEX conversion
// https://github.com/nuxt/nuxt.js/issues/6306
minifyFontValues: { removeQuotes: false }
}]
})
}
}
}
}

View File

@ -1,21 +1,23 @@
export default {
/**
typescript: {
/**
* TypeScript comes with certain checks to give you more safety and analysis of your program.
* Once youve converted your codebase to TypeScript, you can start enabling these checks for greater safety.
* [Read More](https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#getting-stricter-checks)
*/
strict: false,
strict: false,
/**
* You can extend generated `.nuxt/tsconfig.json` using this option
* @typedef {Awaited<ReturnType<typeof import('pkg-types')['readPackageJSON']>>}
*/
tsConfig: {},
/**
* You can extend generated `.nuxt/tsconfig.json` using this option
* @typedef {Awaited<ReturnType<typeof import('pkg-types')['readPackageJSON']>>}
*/
tsConfig: {},
/**
* Generate a `*.vue` shim.
*
* We recommend instead either enabling [**Take Over Mode**](https://github.com/johnsoncodehk/volar/discussions/471) or adding **TypeScript Vue Plugin (Volar)** 👉 [[Download](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.vscode-typescript-vue-plugin)].
*/
shim: true
/**
* Generate a `*.vue` shim.
*
* We recommend instead either enabling [**Take Over Mode**](https://github.com/johnsoncodehk/volar/discussions/471) or adding **TypeScript Vue Plugin (Volar)** 👉 [[Download](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.vscode-typescript-vue-plugin)].
*/
shim: true
}
}

View File

@ -0,0 +1,83 @@
import { resolve } from 'pathe'
import { joinURL, withoutLeadingSlash } from 'ufo'
export default {
/**
* Configuration that will be passed directly to Vite.
*
* See https://vitejs.dev/config for more information.
* Please note that not all vite options are supported in Nuxt.
*
* @type {typeof import('vite').InlineConfig}
* @version 3
*/
vite: {
root: {
$resolve: (val, get) => val ?? get('srcDir'),
},
mode: {
$resolve: (val, get) => val ?? get('dev') ? 'development' : 'production',
},
logLevel: 'warn',
define: {
$resolve: (val, get) => ({
'process.dev': get('dev'),
...val || {}
})
},
resolve: {
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
},
base: {
$resolve: (val, get) => val ?? get('dev')
? joinURL(get('app').baseURL, get('app').buildAssetsDir)
: '/__NUXT_BASE__/',
},
publicDir: {
$resolve: (val, get) => val ?? resolve(get('srcDir'), get('dir').public),
},
vue: {
isProduction: {
$resolve: (val, get) => val ?? !get('dev'),
},
template: { compilerOptions: {
$resolve: (val, get) => val ?? get('vue').compilerOptions }
},
},
optimizeDeps: {
exclude: {
$resolve: (val, get) => [
...val || [],
...get('build.transpile').filter(i => typeof i === 'string'),
'vue-demi'
],
},
},
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
tsconfigRaw: '{}'
},
clearScreen: false,
build: {
assetsDir: {
$resolve: (val, get) => val ?? get('dev') ? withoutLeadingSlash(get('app').buildAssetsDir) : '.',
},
emptyOutDir: false,
},
server: {
fs: {
strict: false,
allow: {
$resolve: (val, get) => [
get('buildDir'),
get('srcDir'),
get('rootDir'),
...get('modulesDir'),
...val ?? []
]
}
}
}
}
}

View File

@ -0,0 +1,294 @@
import { join } from 'pathe'
export default {
/** @version 3 */
webpack: {
/**
* Nuxt uses `webpack-bundle-analyzer` to visualize your bundles and how to optimize them.
*
* Set to `true` to enable bundle analysis, or pass an object with options: [for webpack](https://github.com/webpack-contrib/webpack-bundle-analyzer#options-for-plugin) or [for vite](https://github.com/btd/rollup-plugin-visualizer#options).
*
* @example
* ```js
* analyze: {
* analyzerMode: 'static'
* }
* ```
* @type {boolean | typeof import('webpack-bundle-analyzer').BundleAnalyzerPlugin.Options}
*/
analyze: {
$resolve: (val, get) => {
if(val !== true) {
return val ?? false
}
const rootDir = get('rootDir')
return {
template: 'treemap',
projectRoot: rootDir,
filename: join(rootDir, '.nuxt/stats', '{name}.html')
}
}
},
/**
* Enable the profiler in webpackbar.
*
* It is normally enabled by CLI argument `--profile`.
*
* @see [webpackbar](https://github.com/unjs/webpackbar#profile)
*/
profile: process.argv.includes('--profile'),
/**
* Enables Common CSS Extraction using
* [Vue Server Renderer guidelines](https://ssr.vuejs.org/guide/css.html).
*
* Using [extract-css-chunks-webpack-plugin](https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/) under the hood, your CSS will be extracted
* into separate files, usually one per component. This allows caching your CSS and
* JavaScript separately and is worth trying if you have a lot of global or shared CSS.
*
* @example
* ```js
* export default {
* build: {
* extractCSS: true,
* // or
* extractCSS: {
* ignoreOrder: true
* }
* }
* }
* ```
*
* If you want to extract all your CSS to a single file, there is a workaround for this.
* However, note that it is not recommended to extract everything into a single file.
* Extracting into multiple CSS files is better for caching and preload isolation. It
* can also improve page performance by downloading and resolving only those resources
* that are needed.
*
* @example
* ```js
* export default {
* build: {
* extractCSS: true,
* optimization: {
* splitChunks: {
* cacheGroups: {
* styles: {
* name: 'styles',
* test: /\.(css|vue)$/,
* chunks: 'all',
* enforce: true
* }
* }
* }
* }
* }
* }
* ```
* @type {false | typeof import('mini-css-extract-plugin').PluginOptions}
*/
extractCSS: false,
/**
* Enables CSS source map support (defaults to true in development)
*/
cssSourceMap: {
$resolve: (val, get) => val ?? get('dev')
},
/**
* The polyfill library to load to provide URL and URLSearchParams.
*
* Defaults to `'url'` ([see package](https://www.npmjs.com/package/url)).
*/
serverURLPolyfill: 'url',
/**
* Customize bundle filenames.
*
* To understand a bit more about the use of manifests, take a look at [this webpack documentation](https://webpack.js.org/guides/code-splitting/).
*
* @note Be careful when using non-hashed based filenames in production
* as most browsers will cache the asset and not detect the changes on first load.
*
* This example changes fancy chunk names to numerical ids:
*
* @example
* ```js
* filenames: {
* chunk: ({ isDev }) => (isDev ? '[name].js' : '[id].[contenthash].js')
* }
* ```
*/
filenames: {
app: ({ isDev }) => isDev ? `[name].js` : `[contenthash:7].js`,
chunk: ({ isDev }) => isDev ? `[name].js` : `[contenthash:7].js`,
css: ({ isDev }) => isDev ? '[name].css' : 'css/[contenthash:7].css',
img: ({ isDev }) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]',
font: ({ isDev }) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]',
video: ({ isDev }) => isDev ? '[path][name].[ext]' : 'videos/[name].[contenthash:7].[ext]'
},
/**
* Customize the options of Nuxt's integrated webpack loaders.
*/
loaders: {
$resolve: (val, get) => {
const styleLoaders = [
'css', 'cssModules', 'less',
'sass', 'scss', 'stylus', 'vueStyle'
]
for (const name of styleLoaders) {
const loader = val[name]
if (loader && loader.sourceMap === undefined) {
loader.sourceMap = Boolean(get('build.cssSourceMap'))
}
}
return val
},
file: { esModule: false },
fontUrl: { esModule: false, limit: 1000 },
imgUrl: { esModule: false, limit: 1000 },
pugPlain: {},
vue: {
productionMode: { $resolve: (val, get) => val ?? !get('dev') },
transformAssetUrls: {
video: 'src',
source: 'src',
object: 'src',
embed: 'src'
},
compilerOptions: { $resolve: (val, get) => val ?? get('vue.compilerOptions') },
},
css: {
importLoaders: 0,
esModule: false
},
cssModules: {
importLoaders: 0,
esModule: false,
modules: {
localIdentName: '[local]_[hash:base64:5]'
}
},
less: {},
sass: {
sassOptions: {
indentedSyntax: true
}
},
scss: {},
stylus: {},
vueStyle: {}
},
/**
* Add webpack plugins.
*
* @example
* ```js
* import webpack from 'webpack'
* import { version } from './package.json'
* // ...
* plugins: [
* new webpack.DefinePlugin({
* 'process.VERSION': version
* })
* ]
* ```
*/
plugins: [],
/**
* Terser plugin options.
*
* Set to false to disable this plugin, or pass an object of options.
*
* @see [terser-webpack-plugin documentation](https://github.com/webpack-contrib/terser-webpack-plugin)
*
* @note Enabling sourceMap will leave `//# sourceMappingURL` linking comment at
* the end of each output file if webpack `config.devtool` is set to `source-map`.
*
* @type {false | typeof import('terser-webpack-plugin').BasePluginOptions & typeof import('terser-webpack-plugin').DefinedDefaultMinimizerAndOptions<any>}
*/
terser: {
},
/**
* Hard-replaces `typeof process`, `typeof window` and `typeof document` to tree-shake bundle.
*/
aggressiveCodeRemoval: false,
/**
* OptimizeCSSAssets plugin options.
*
* Defaults to true when `extractCSS` is enabled.
*
* @see [css-minimizer-webpack-plugin documentation](https://github.com/webpack-contrib/css-minimizer-webpack-plugin).
*
* @type {false | typeof import('css-minimizer-webpack-plugin').BasePluginOptions & typeof import('css-minimizer-webpack-plugin').DefinedDefaultMinimizerAndOptions<any>}
*/
optimizeCSS: {
$resolve: (val, get) => val ?? (get('build.extractCSS') ? {} : false)
},
/**
* Configure [webpack optimization](https://webpack.js.org/configuration/optimization/).
* @type {false | typeof import('webpack').Configuration['optimization']}
*/
optimization: {
runtimeChunk: 'single',
/** Set minimize to false to disable all minimizers. (It is disabled in development by default) */
minimize: { $resolve: (val, get) => val ?? !get('dev') },
/** You can set minimizer to a customized array of plugins. */
minimizer: undefined,
splitChunks: {
chunks: 'all',
automaticNameDelimiter: '/',
cacheGroups: {}
}
},
/**
* Customize PostCSS Loader.
* Same options as https://github.com/webpack-contrib/postcss-loader#options
*/
postcss: {
execute: undefined,
postcssOptions: {
config: {
$resolve: (val, get) => val ?? get('postcss.config')
},
plugins: {
$resolve: (val, get) => val ?? get('postcss.plugins')
}
},
sourceMap: undefined,
implementation: undefined,
order: ''
},
/**
* See [webpack-dev-middleware](https://github.com/webpack/webpack-dev-middleware) for available options.
* @type {typeof import('webpack-dev-middleware').Options<typeof import('http').IncomingMessage, typeof import('http').ServerResponse>}
*/
devMiddleware: {
stats: 'none'
},
/**
* See [webpack-hot-middleware](https://github.com/webpack-contrib/webpack-hot-middleware) for available options.
* @type {typeof import('webpack-hot-middleware').MiddlewareOptions & { client?: typeof import('webpack-hot-middleware').ClientOptions }}
*/
hotMiddleware: {},
/**
* Set to `false` to disable the overlay provided by [FriendlyErrorsWebpackPlugin](https://github.com/nuxt/friendly-errors-webpack-plugin)
*/
friendlyErrors: true,
/**
* Filters to hide build warnings.
* @type {Array<(warn: typeof import('webpack').WebpackError) => boolean>}
*/
warningIgnoreFilters: [],
}
}

View File

@ -70,7 +70,7 @@ export interface ModuleContainer {
/** Allows extending webpack build config by chaining `options.build.extend` function. */
extendBuild(fn): void
/** Allows extending routes by chaining `options.build.extendRoutes` function. */
/** Allows extending routes by chaining `options.router.extendRoutes` function. */
extendRoutes(fn): void
/** Registers a module */

View File

@ -35,7 +35,6 @@
"p-debounce": "^4.0.0",
"pathe": "^0.2.0",
"postcss-import": "^14.0.2",
"postcss-import-resolver": "^2.0.0",
"postcss-url": "^10.1.3",
"rollup-plugin-visualizer": "^5.6.0",
"ufo": "^0.7.9",

View File

@ -1,8 +1,6 @@
import createResolver from 'postcss-import-resolver'
import defu from 'defu'
import { requireModule } from '@nuxt/kit'
import type { Nuxt } from '@nuxt/schema'
import { ViteOptions } from './vite'
import type { ViteOptions } from './vite'
import { distDir } from './dirs'
export function resolveCSSOptions (nuxt: Nuxt): ViteOptions['css'] {
@ -12,25 +10,7 @@ export function resolveCSSOptions (nuxt: Nuxt): ViteOptions['css'] {
}
}
const plugins = defu(nuxt.options.build.postcss.postcssOptions.plugins, {
// https://github.com/postcss/postcss-import
'postcss-import': {
resolve: createResolver({
alias: { ...nuxt.options.alias },
modules: [
nuxt.options.srcDir,
nuxt.options.rootDir,
...nuxt.options.modulesDir
]
})
},
// https://github.com/postcss/postcss-url
'postcss-url': {},
// https://github.com/postcss/autoprefixer
autoprefixer: {}
})
const plugins = nuxt.options.postcss.plugins
for (const name in plugins) {
const opts = plugins[name]

View File

@ -5,7 +5,6 @@ import type { InlineConfig, SSROptions } from 'vite'
import { logger } from '@nuxt/kit'
import type { Options } from '@vitejs/plugin-vue'
import { sanitizeFilePath } from 'mlly'
import { joinURL, withoutLeadingSlash } from 'ufo'
import { getPort } from 'get-port-please'
import { buildClient } from './client'
import { buildServer } from './server'
@ -35,14 +34,7 @@ export async function bundle (nuxt: Nuxt) {
nuxt,
config: vite.mergeConfig(
{
root: nuxt.options.srcDir,
mode: nuxt.options.dev ? 'development' : 'production',
logLevel: 'warn',
define: {
'process.dev': nuxt.options.dev
},
resolve: {
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue'],
alias: {
...nuxt.options.alias,
'#app': nuxt.options.appDir,
@ -56,37 +48,16 @@ export async function bundle (nuxt: Nuxt) {
'abort-controller': 'unenv/runtime/mock/empty'
}
},
base: nuxt.options.dev
? joinURL(nuxt.options.app.baseURL, nuxt.options.app.buildAssetsDir)
: '/__NUXT_BASE__/',
publicDir: resolve(nuxt.options.srcDir, nuxt.options.dir.public),
// TODO: move to kit schema when it exists
vue: {
isProduction: !nuxt.options.dev,
template: { compilerOptions: nuxt.options.vue.compilerOptions }
},
css: resolveCSSOptions(nuxt),
optimizeDeps: {
exclude: [
...nuxt.options.build.transpile.filter(i => typeof i === 'string'),
'vue-demi'
],
entries: [
resolve(nuxt.options.appDir, 'entry.ts')
]
},
esbuild: {
jsxFactory: 'h',
jsxFragment: 'Fragment',
tsconfigRaw: '{}'
},
clearScreen: false,
css: resolveCSSOptions(nuxt),
build: {
assetsDir: nuxt.options.dev ? withoutLeadingSlash(nuxt.options.app.buildAssetsDir) : '.',
emptyOutDir: false,
rollupOptions: {
input: resolve(nuxt.options.appDir, 'entry'),
output: { sanitizeFileName: sanitizeFilePath }
output: { sanitizeFileName: sanitizeFilePath },
input: resolve(nuxt.options.appDir, 'entry')
}
},
plugins: [
@ -98,18 +69,13 @@ export async function bundle (nuxt: Nuxt) {
port: hmrPort
},
fs: {
strict: false,
allow: [
nuxt.options.buildDir,
nuxt.options.appDir,
nuxt.options.srcDir,
nuxt.options.rootDir,
...nuxt.options.modulesDir
nuxt.options.appDir
]
}
}
} as ViteOptions,
nuxt.options.vite as any || {}
},
nuxt.options.vite
)
}

View File

@ -9,18 +9,14 @@ export default defineBuildConfig({
'@nuxt/kit',
'unplugin',
'webpack-virtual-modules',
'@vue/babel-preset-jsx',
'postcss',
'postcss-import-resolver',
'postcss-loader',
'babel-loader',
'vue-loader',
'css-loader',
'file-loader',
'style-resources-loader',
'url-loader',
'vue-style-loader',
'@babel/core',
'vue'
],
externals: [

View File

@ -19,9 +19,7 @@
"@babel/core": "^7.17.5",
"@nuxt/friendly-errors-webpack-plugin": "^2.5.2",
"@nuxt/kit": "3.0.0",
"@vue/babel-preset-jsx": "^1.2.4",
"autoprefixer": "^10.4.2",
"babel-loader": "^8.2.3",
"css-loader": "^6.6.0",
"css-minimizer-webpack-plugin": "^3.4.1",
"cssnano": "^5.0.17",
@ -29,7 +27,6 @@
"escape-string-regexp": "^5.0.0",
"file-loader": "^6.2.0",
"fs-extra": "^10.0.1",
"glob": "^7.2.0",
"hash-sum": "^2.0.0",
"lodash-es": "^4.17.21",
"memfs": "^3.4.1",
@ -39,7 +36,6 @@
"pify": "^5.0.0",
"postcss": "^8.4.7",
"postcss-import": "^14.0.2",
"postcss-import-resolver": "^2.0.0",
"postcss-loader": "^6.2.1",
"postcss-url": "^10.1.3",
"style-resources-loader": "^1.5.0",
@ -59,7 +55,6 @@
"devDependencies": {
"@nuxt/schema": "3.0.0",
"@types/pify": "^5.0.1",
"@types/terser-webpack-plugin": "^5.0.4",
"@types/webpack-bundle-analyzer": "^4.4.1",
"@types/webpack-dev-middleware": "^5.0.2",
"@types/webpack-hot-middleware": "^2.25.6",

View File

@ -3,7 +3,6 @@ import { resolve } from 'pathe'
import webpack from 'webpack'
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
import type { ClientOptions } from 'webpack-hot-middleware'
import { joinURL } from 'ufo'
import { applyPresets, WebpackConfigContext } from '../utils/config'
import { nuxt } from '../presets/nuxt'
@ -50,7 +49,7 @@ function clientHMR (ctx: WebpackConfigContext) {
return
}
const clientOptions = options.build.hotMiddleware?.client || {} as ClientOptions
const clientOptions = options.webpack.hotMiddleware?.client || {}
const hotMiddlewareClientOptions = {
reload: true,
timeout: 30000,
@ -81,7 +80,7 @@ function clientPlugins (ctx: WebpackConfigContext) {
// Webpack Bundle Analyzer
// https://github.com/webpack-contrib/webpack-bundle-analyzer
if (!ctx.isDev && ctx.name === 'client' && options.build.analyze) {
if (!ctx.isDev && ctx.name === 'client' && options.webpack.analyze) {
const statsDir = resolve(options.buildDir, 'stats')
// @ts-ignore
@ -92,7 +91,7 @@ function clientPlugins (ctx: WebpackConfigContext) {
openAnalyzer: !options.build.quiet,
reportFilename: resolve(statsDir, `${ctx.name}.html`),
statsFilename: resolve(statsDir, `${ctx.name}.json`),
...options.build.analyze as any
...options.webpack.analyze === true ? {} : options.webpack.analyze
}))
}
}

View File

@ -71,10 +71,10 @@ function serverPlugins (ctx: WebpackConfigContext) {
const { config, options } = ctx
// Server polyfills
if (options.build.serverURLPolyfill) {
if (options.webpack.serverURLPolyfill) {
config.plugins.push(new webpack.ProvidePlugin({
URL: [options.build.serverURLPolyfill, 'URL'],
URLSearchParams: [options.build.serverURLPolyfill, 'URLSearchParams']
URL: [options.webpack.serverURLPolyfill, 'URL'],
URLSearchParams: [options.webpack.serverURLPolyfill, 'URLSearchParams']
}))
}
}

View File

@ -1,12 +1,15 @@
import type { WebpackError } from 'webpack'
export default class WarningIgnorePlugin {
filter: (warn: WebpackError) => boolean
import type { Compiler, WebpackError } from 'webpack'
constructor (filter) {
export type WarningFilter = (warn: WebpackError) => boolean
export default class WarningIgnorePlugin {
filter: WarningFilter
constructor (filter: WarningFilter) {
this.filter = filter
}
apply (compiler) /* istanbul ignore next */ {
apply (compiler: Compiler) {
compiler.hooks.done.tap('warnfix-plugin', (stats) => {
stats.compilation.warnings = stats.compilation.warnings.filter(this.filter)
})

View File

@ -1,15 +1,13 @@
import { fileName, WebpackConfigContext } from '../utils/config'
export function assets (ctx: WebpackConfigContext) {
const { options } = ctx
ctx.config.module.rules.push(
{
test: /\.(png|jpe?g|gif|svg|webp)$/i,
use: [{
loader: 'url-loader',
options: {
...options.build.loaders.imgUrl,
...ctx.options.webpack.loaders.imgUrl,
name: fileName(ctx, 'img')
}
}]
@ -19,7 +17,7 @@ export function assets (ctx: WebpackConfigContext) {
use: [{
loader: 'url-loader',
options: {
...options.build.loaders.fontUrl,
...ctx.options.webpack.loaders.fontUrl,
name: fileName(ctx, 'font')
}
}]
@ -29,7 +27,7 @@ export function assets (ctx: WebpackConfigContext) {
use: [{
loader: 'file-loader',
options: {
...options.build.loaders.file,
...ctx.options.webpack.loaders.file,
name: fileName(ctx, 'video')
}
}]

View File

@ -1,84 +0,0 @@
import { createRequire } from 'module'
import { normalize } from 'pathe'
import TerserWebpackPlugin from 'terser-webpack-plugin'
import { reservedVueTags } from '../utils/reserved-tags'
import { WebpackConfigContext } from '../utils/config'
const _require = createRequire(import.meta.url)
export function babel (ctx: WebpackConfigContext) {
const { config, options } = ctx
const babelLoader = {
loader: normalize(_require.resolve('babel-loader')),
options: getBabelOptions(ctx)
}
config.module.rules.push({
test: /\.m?[jt]sx?$/i,
exclude: (file) => {
file = file.split('node_modules', 2)[1]
// not exclude files outside node_modules
if (!file) {
return false
}
// item in transpile can be string or regex object
return !ctx.transpile.some(module => module.test(file))
},
resolve: {
fullySpecified: false
},
use: babelLoader
})
// https://github.com/webpack-contrib/terser-webpack-plugin
if (options.build.terser) {
const terser = new TerserWebpackPlugin({
// cache, TODO
extractComments: {
condition: 'some',
filename: 'LICENSES'
},
terserOptions: {
compress: {
ecma: ctx.isModern ? 6 : undefined
},
mangle: {
reserved: reservedVueTags
}
},
...options.build.terser as any
})
config.plugins.push(terser as any)
}
}
function getBabelOptions (ctx: WebpackConfigContext) {
const { options } = ctx
const babelOptions: any = {
...options.build.babel,
envName: ctx.name
}
if (babelOptions.configFile || babelOptions.babelrc) {
return babelOptions
}
if (typeof babelOptions.plugins === 'function') {
babelOptions.plugins = babelOptions.plugins(ctx)
}
const defaultPreset = [normalize(_require.resolve('../../babel-preset-app')), {}]
if (typeof babelOptions.presets === 'function') {
babelOptions.presets = babelOptions.presets(ctx, defaultPreset)
}
if (!babelOptions.presets) {
babelOptions.presets = [defaultPreset]
}
return babelOptions
}

View File

@ -6,7 +6,7 @@ import { logger } from '@nuxt/kit'
import FriendlyErrorsWebpackPlugin from '@nuxt/friendly-errors-webpack-plugin'
import escapeRegExp from 'escape-string-regexp'
import { joinURL } from 'ufo'
import WarningIgnorePlugin from '../plugins/warning-ignore'
import WarningIgnorePlugin, { WarningFilter } from '../plugins/warning-ignore'
import { WebpackConfigContext, applyPresets, fileName } from '../utils/config'
export function base (ctx: WebpackConfigContext) {
@ -28,7 +28,7 @@ function baseConfig (ctx: WebpackConfigContext) {
plugins: [],
externals: [],
optimization: {
...options.build.optimization as any,
...options.webpack.optimization,
minimizer: []
},
experiments: {},
@ -43,13 +43,13 @@ function baseConfig (ctx: WebpackConfigContext) {
function basePlugins (ctx: WebpackConfigContext) {
const { config, options, nuxt } = ctx
// Add timefix-plugin before others plugins
// Add timefix-plugin before other plugins
if (options.dev) {
config.plugins.push(new TimeFixPlugin())
}
// User plugins
config.plugins.push(...(options.build.plugins || []))
config.plugins.push(...(options.webpack.plugins || []))
// Ignore empty warnings
config.plugins.push(new WarningIgnorePlugin(getWarningIgnoreFilter(ctx)))
@ -60,7 +60,7 @@ function basePlugins (ctx: WebpackConfigContext) {
// Friendly errors
if (
ctx.isServer ||
(ctx.isDev && !options.build.quiet && options.build.friendlyErrors)
(ctx.isDev && !options.build.quiet && options.webpack.friendlyErrors)
) {
ctx.config.plugins.push(
new FriendlyErrorsWebpackPlugin({
@ -71,39 +71,41 @@ function basePlugins (ctx: WebpackConfigContext) {
)
}
// Webpackbar
const colors = {
client: 'green',
server: 'orange',
modern: 'blue'
}
config.plugins.push(new WebpackBar({
name: ctx.name,
color: colors[ctx.name],
reporters: ['stats'],
stats: !ctx.isDev,
reporter: {
// @ts-ignore
change: (_, { shortPath }) => {
if (!ctx.isServer) {
nuxt.callHook('bundler:change', shortPath)
}
},
done: ({ state }) => {
if (state.hasErrors) {
nuxt.callHook('bundler:error')
} else {
logger.success(`${state.name} ${state.message}`)
}
},
allDone: () => {
nuxt.callHook('bundler:done')
},
progress ({ statesArray }) {
nuxt.callHook('bundler:progress', statesArray)
}
if (nuxt.options.webpack.profile) {
// Webpackbar
const colors = {
client: 'green',
server: 'orange',
modern: 'blue'
}
}))
config.plugins.push(new WebpackBar({
name: ctx.name,
color: colors[ctx.name],
reporters: ['stats'],
stats: !ctx.isDev,
reporter: {
// @ts-ignore
change: (_, { shortPath }) => {
if (!ctx.isServer) {
nuxt.callHook('bundler:change', shortPath)
}
},
done: ({ state }) => {
if (state.hasErrors) {
nuxt.callHook('bundler:error')
} else {
logger.success(`${state.name} ${state.message}`)
}
},
allDone: () => {
nuxt.callHook('bundler:done')
},
progress ({ statesArray }) {
nuxt.callHook('bundler:progress', statesArray)
}
}
}))
}
}
function baseAlias (ctx: WebpackConfigContext) {
@ -198,15 +200,15 @@ function getOutput (ctx: WebpackConfigContext): webpack.Configuration['output']
}
}
function getWarningIgnoreFilter (ctx: WebpackConfigContext) {
function getWarningIgnoreFilter (ctx: WebpackConfigContext): WarningFilter {
const { options } = ctx
const filters = [
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.build.warningIgnoreFilters || [])
...(options.webpack.warningIgnoreFilters || [])
]
return warn => !filters.some(ignoreFilter => ignoreFilter(warn))
@ -224,11 +226,10 @@ function getEnv (ctx: WebpackConfigContext) {
'process.env.VUE_ENV': JSON.stringify(ctx.name),
'process.browser': ctx.isClient,
'process.client': ctx.isClient,
'process.server': ctx.isServer,
'process.modern': ctx.isModern
'process.server': ctx.isServer
}
if (options.build.aggressiveCodeRemoval) {
if (options.webpack.aggressiveCodeRemoval) {
_env['typeof process'] = JSON.stringify(ctx.isServer ? 'object' : 'undefined')
_env['typeof window'] = _env['typeof document'] = JSON.stringify(!ctx.isServer ? 'object' : 'undefined')
}

View File

@ -17,14 +17,10 @@ export function esbuild (ctx: WebpackConfigContext) {
test: /\.m?[jt]s$/i,
loader: 'esbuild-loader',
exclude: (file) => {
file = file.split('node_modules', 2)[1]
// Not exclude files outside node_modules
if (!file) {
return false
}
file = file.split('node_modules', 2)[1]
if (!file) { return false }
// Item in transpile can be string or regex object
return !ctx.transpile.some(module => module.test(file))
},
resolve: {

View File

@ -1,4 +1,4 @@
import { WebpackConfigContext } from '../utils/config'
import type { WebpackConfigContext } from '../utils/config'
export function node (ctx: WebpackConfigContext) {
const { config } = ctx

View File

@ -11,7 +11,6 @@ export function nuxt (ctx: WebpackConfigContext) {
applyPresets(ctx, [
base,
assets,
// babel,
esbuild,
pug,
style,

View File

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

View File

@ -1,8 +1,7 @@
import { resolve } from 'pathe'
import MiniCssExtractPlugin from 'mini-css-extract-plugin'
import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'
import { fileName, WebpackConfigContext, applyPresets } from '../utils/config'
import { PostcssConfig } from '../utils/postcss'
import { getPostcssConfig } from '../utils/postcss'
export function style (ctx: WebpackConfigContext) {
applyPresets(ctx, [
@ -15,9 +14,9 @@ export function style (ctx: WebpackConfigContext) {
function minimizer (ctx: WebpackConfigContext) {
const { options, config } = ctx
if (options.build.optimizeCSS && Array.isArray(config.optimization.minimizer)) {
if (options.webpack.optimizeCSS && Array.isArray(config.optimization.minimizer)) {
config.optimization.minimizer.push(new CssMinimizerPlugin({
...options.build.optimizeCSS as any
...options.webpack.optimizeCSS
}))
}
}
@ -26,11 +25,11 @@ function extractCSS (ctx: WebpackConfigContext) {
const { options, config } = ctx
// CSS extraction
if (options.build.extractCSS) {
if (options.webpack.extractCSS) {
config.plugins.push(new MiniCssExtractPlugin({
filename: fileName(ctx, 'css'),
chunkFilename: fileName(ctx, 'css'),
...(options.build.extractCSS as any)
...options.webpack.extractCSS
}))
}
}
@ -45,18 +44,18 @@ function loaders (ctx: WebpackConfigContext) {
config.module.rules.push(createdStyleRule('postcss', /\.p(ost)?css$/i, null, ctx))
// Less
const lessLoader = { loader: 'less-loader', options: options.build.loaders.less }
const lessLoader = { loader: 'less-loader', options: options.webpack.loaders.less }
config.module.rules.push(createdStyleRule('less', /\.less$/i, lessLoader, ctx))
// Sass (TODO: optional dependency)
const sassLoader = { loader: 'sass-loader', options: options.build.loaders.sass }
const sassLoader = { loader: 'sass-loader', options: options.webpack.loaders.sass }
config.module.rules.push(createdStyleRule('sass', /\.sass$/i, sassLoader, ctx))
const scssLoader = { loader: 'sass-loader', options: options.build.loaders.scss }
const scssLoader = { loader: 'sass-loader', options: options.webpack.loaders.scss }
config.module.rules.push(createdStyleRule('scss', /\.scss$/i, scssLoader, ctx))
// Stylus
const stylusLoader = { loader: 'stylus-loader', options: options.build.loaders.stylus }
const stylusLoader = { loader: 'stylus-loader', options: options.webpack.loaders.stylus }
config.module.rules.push(createdStyleRule('stylus', /\.styl(us)?$/i, stylusLoader, ctx))
}
@ -65,16 +64,15 @@ function createdStyleRule (lang: string, test: RegExp, processorLoader, ctx: Web
const styleLoaders = [
createPostcssLoadersRule(ctx),
processorLoader,
createStyleResourcesLoaderRule(lang, options.build.styleResources, options.rootDir)
processorLoader
].filter(Boolean)
options.build.loaders.css.importLoaders =
options.build.loaders.cssModules.importLoaders =
options.webpack.loaders.css.importLoaders =
options.webpack.loaders.cssModules.importLoaders =
styleLoaders.length
const cssLoaders = createCssLoadersRule(ctx, options.build.loaders.css)
const cssModuleLoaders = createCssLoadersRule(ctx, options.build.loaders.cssModules)
const cssLoaders = createCssLoadersRule(ctx, options.webpack.loaders.css)
const cssModuleLoaders = createCssLoadersRule(ctx, options.webpack.loaders.cssModules)
return {
test,
@ -97,7 +95,7 @@ function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions) {
const cssLoader = { loader: 'css-loader', options: cssLoaderOptions }
if (options.build.extractCSS) {
if (options.webpack.extractCSS) {
if (ctx.isServer) {
return [cssLoader]
}
@ -113,37 +111,18 @@ function createCssLoadersRule (ctx: WebpackConfigContext, cssLoaderOptions) {
return [
{
loader: 'vue-style-loader',
options: options.build.loaders.vueStyle
options: options.webpack.loaders.vueStyle
},
cssLoader
]
}
function createStyleResourcesLoaderRule (styleLang, styleResources, rootDir) {
// style-resources-loader
// https://github.com/yenshih/style-resources-loader
if (!styleResources[styleLang]) {
return
}
return {
loader: 'style-resources-loader',
options: {
patterns: Array.from(styleResources[styleLang]).map(p => resolve(rootDir, p as string)),
...styleResources.options
}
}
}
function createPostcssLoadersRule (ctx: WebpackConfigContext) {
const { options, nuxt } = ctx
if (!options.build.postcss) {
return
}
if (!options.postcss) { return }
const postcssConfig = new PostcssConfig(nuxt)
const config = postcssConfig.config()
const config = getPostcssConfig(nuxt)
if (!config) {
return

View File

@ -14,7 +14,7 @@ export function vue (ctx: WebpackConfigContext) {
config.module.rules.push({
test: /\.vue$/i,
loader: 'vue-loader',
options: options.build.loaders.vue
options: options.webpack.loaders.vue
})
if (ctx.isClient) {

View File

@ -1,202 +0,0 @@
const coreJsMeta = {
2: {
prefixes: {
es6: 'es6',
es7: 'es7'
},
builtIns: '@babel/compat-data/corejs2-built-ins'
},
3: {
prefixes: {
es6: 'es',
es7: 'es'
},
builtIns: 'core-js-compat/data'
}
}
function getDefaultPolyfills (corejs) {
const { prefixes: { es6, es7 } } = coreJsMeta[corejs.version]
return [
// Promise polyfill alone doesn't work in IE,
// Needs this as well. see: #1642
`${es6}.array.iterator`,
// This is required for webpack code splitting, vuex etc.
`${es6}.promise`,
// this is needed for object rest spread support in templates
// as vue-template-es2015-compiler 1.8+ compiles it to Object.assign() calls.
`${es6}.object.assign`,
// #2012 es7.promise replaces native Promise in FF and causes missing finally
`${es7}.promise.finally`
]
}
function getPolyfills (targets, includes, { ignoreBrowserslistConfig, configPath, corejs }) {
const { default: getTargets, isRequired } = require('@babel/helper-compilation-targets')
const builtInsList = require(coreJsMeta[corejs.version].builtIns)
const builtInTargets = getTargets(targets, {
ignoreBrowserslistConfig,
configPath
})
return includes.filter(item => isRequired(
'nuxt-polyfills',
builtInTargets,
{
compatData: { 'nuxt-polyfills': builtInsList[item] }
}
))
}
function isPackageHoisted (packageName) {
const path = require('pathe')
const installedPath = path.normalize(require.resolve(packageName))
const relativePath = path.resolve(__dirname, '..', 'node_modules', packageName)
return installedPath !== relativePath
}
module.exports = (api, options = {}) => {
const presets = []
const plugins = []
const envName = api.env()
const {
bugfixes,
polyfills: userPolyfills,
loose = false,
debug = false,
useBuiltIns = 'usage',
modules = false,
spec,
ignoreBrowserslistConfig = envName === 'modern',
configPath,
include,
exclude,
shippedProposals,
forceAllTransforms,
decoratorsBeforeExport,
decoratorsLegacy,
absoluteRuntime
} = options
let { corejs = { version: 3 } } = options
if (typeof corejs !== 'object') {
corejs = { version: Number(corejs) }
}
const isCorejs3Hoisted = isPackageHoisted('core-js')
if (
(corejs.version === 3 && !isCorejs3Hoisted) ||
(corejs.version === 2 && isCorejs3Hoisted)
) {
// eslint-disable-next-line no-console
(console.fatal || console.error)(`babel corejs option is ${corejs.version}, please directly install core-js@${corejs.version}.`)
}
const defaultTargets = {
server: { node: 'current' },
client: { ie: 9 },
modern: { esmodules: true }
}
let { targets = defaultTargets[envName] } = options
// modern mode can only be { esmodules: true }
if (envName === 'modern') {
targets = defaultTargets.modern
}
const polyfills = []
if (envName === 'client' && useBuiltIns === 'usage') {
polyfills.push(
...getPolyfills(
targets,
userPolyfills || getDefaultPolyfills(corejs),
{
ignoreBrowserslistConfig,
configPath,
corejs
}
)
)
plugins.push([polyfillsPlugin, { polyfills }])
}
// Pass options along to babel-preset-env
presets.push([
require('@babel/preset-env'), {
bugfixes,
spec,
loose,
debug,
modules,
targets,
useBuiltIns,
corejs,
ignoreBrowserslistConfig,
configPath,
include,
exclude: polyfills.concat(exclude || []),
shippedProposals,
forceAllTransforms
}
], [
require('@babel/preset-typescript')
])
// JSX
if (options.jsx !== false) {
// presets.push([require('@vue/babel-preset-jsx'), Object.assign({}, options.jsx)])
}
plugins.push(
[require('@babel/plugin-proposal-decorators'), {
decoratorsBeforeExport,
legacy: decoratorsLegacy !== false
}],
[require('@babel/plugin-proposal-class-properties'), { loose: true }]
)
// Transform runtime, but only for helpers
plugins.push([require('@babel/plugin-transform-runtime'), {
regenerator: useBuiltIns !== 'usage',
corejs: false,
helpers: useBuiltIns === 'usage',
useESModules: envName !== 'server',
absoluteRuntime
}])
return {
sourceType: 'unambiguous',
presets,
plugins
}
}
// Add polyfill imports to the first file encountered.
function polyfillsPlugin ({ _types }) {
let entryFile
return {
name: 'inject-polyfills',
visitor: {
Program (path, state) {
if (!entryFile) {
entryFile = state.filename
} else if (state.filename !== entryFile) {
return
}
const { polyfills } = state.opts
const { createImport } = require('@babel/preset-env/lib/utils')
// Imports are injected in reverse order
polyfills.slice().reverse().forEach((p) => {
createImport(path, p)
})
}
}
}
}

View File

@ -8,21 +8,19 @@ export interface WebpackConfigContext extends ReturnType<typeof createWebpackCon
type WebpackConfigPreset = (ctx: WebpackConfigContext, options?: object) => void
type WebpackConfigPresetItem = WebpackConfigPreset | [WebpackConfigPreset, any]
export function createWebpackConfigContext ({ nuxt }) {
export function createWebpackConfigContext (nuxt: Nuxt) {
return {
nuxt: nuxt as Nuxt,
options: nuxt.options as Nuxt['options'],
nuxt,
options: nuxt.options,
config: {} as Configuration,
name: 'base',
isDev: nuxt.options.dev,
isServer: false,
isClient: false,
isModern: undefined, // TODO
isLegacy: false,
alias: {} as Configuration['resolve']['alias'],
transpile: [] as any[]
transpile: [] as RegExp[]
}
}
@ -42,7 +40,7 @@ export function applyPresets (ctx: WebpackConfigContext, presets: WebpackConfigP
export function fileName (ctx: WebpackConfigContext, key: string) {
const { options } = ctx
let fileName = options.build.filenames[key]
let fileName = options.webpack.filenames[key]
if (typeof fileName === 'function') {
fileName = fileName(ctx)

View File

@ -9,7 +9,7 @@ export function createMFS () {
const fs = createFsFromVolume(new Volume())
// Clone to extend
const _fs : Partial<IFs> & { join?(...paths: string[]): string } = { ...fs }
const _fs: Partial<IFs> & { join?(...paths: string[]): string } = { ...fs }
// fs.join method is (still) expected by webpack-dev-middleware
// There might be differences with https://github.com/webpack/memory-fs/blob/master/lib/join.js
@ -19,5 +19,5 @@ export function createMFS () {
_fs.exists = p => Promise.resolve(_fs.existsSync(p))
_fs.readFile = pify(_fs.readFile)
return _fs
return _fs as IFs & { join?(...paths: string[]): string }
}

View File

@ -1,136 +1,41 @@
import fs from 'fs'
import { resolve } from 'pathe'
import { logger, requireModule } from '@nuxt/kit'
import { createCommonJS } from 'mlly'
import { defaults, merge, cloneDeep } from 'lodash-es'
import createResolver from 'postcss-import-resolver'
import { requireModule } from '@nuxt/kit'
import type { Nuxt } from '@nuxt/schema'
const isPureObject = obj => obj !== null && !Array.isArray(obj) && typeof obj === 'object'
const isPureObject = (obj: unknown): obj is Object => obj !== null && !Array.isArray(obj) && typeof obj === 'object'
export const orderPresets = {
cssnanoLast (names) {
cssnanoLast (names: string[]) {
const nanoIndex = names.indexOf('cssnano')
if (nanoIndex !== names.length - 1) {
names.push(names.splice(nanoIndex, 1)[0])
}
return names
},
autoprefixerLast (names) {
autoprefixerLast (names: string[]) {
const nanoIndex = names.indexOf('autoprefixer')
if (nanoIndex !== names.length - 1) {
names.push(names.splice(nanoIndex, 1)[0])
}
return names
},
autoprefixerAndCssnanoLast (names) {
autoprefixerAndCssnanoLast (names: string[]) {
return orderPresets.cssnanoLast(orderPresets.autoprefixerLast(names))
}
}
let _postcssConfigFileWarningShown
function postcssConfigFileWarning () {
if (_postcssConfigFileWarningShown) {
return
}
logger.warn('Please use `build.postcss` in your nuxt.config.js instead of an external config file. Support for such files will be removed in Nuxt 3 as they remove all defaults set by Nuxt and can cause severe problems with features like alias resolving inside your CSS.')
_postcssConfigFileWarningShown = true
}
export class PostcssConfig {
nuxt: Nuxt
options: Nuxt['options']
constructor (nuxt) {
this.nuxt = nuxt
this.options = nuxt.options
}
get postcssOptions () {
return this.options.build.postcss.postcssOptions
}
get postcssImportAlias () {
const alias = { ...this.options.alias }
for (const key in alias) {
if (key.startsWith('~')) {
continue
}
const newKey = '~' + key
if (!alias[newKey]) {
alias[newKey] = alias[key]
}
}
return alias
}
get defaultConfig () {
const { dev, srcDir, rootDir, modulesDir } = this.options
export const getPostcssConfig = (nuxt: Nuxt) => {
function defaultConfig () {
return {
sourceMap: this.options.build.cssSourceMap,
plugins: {
// https://github.com/postcss/postcss-import
'postcss-import': {
resolve: createResolver({
alias: this.postcssImportAlias,
modules: [srcDir, rootDir, ...modulesDir]
})
},
// https://github.com/postcss/postcss-url
'postcss-url': {},
autoprefixer: {},
cssnano: dev
? false
: {
preset: ['default', {
// Keep quotes in font values to prevent from HEX conversion
// https://github.com/nuxt/nuxt.js/issues/6306
minifyFontValues: { removeQuotes: false }
}]
}
},
sourceMap: nuxt.options.webpack.cssSourceMap,
plugins: nuxt.options.postcss.plugins,
// Array, String or Function
order: 'autoprefixerAndCssnanoLast'
}
}
searchConfigFile () {
// Search for postCSS config file and use it if exists
// https://github.com/michael-ciniawsky/postcss-load-config
// TODO: Remove in Nuxt 3
const { srcDir, rootDir } = this.options
for (const dir of [srcDir, rootDir]) {
for (const file of [
'postcss.config.js',
'.postcssrc.js',
'.postcssrc',
'.postcssrc.json',
'.postcssrc.yaml'
]) {
const configFile = resolve(dir, file)
if (fs.existsSync(configFile)) {
postcssConfigFileWarning()
return configFile
}
}
}
}
getConfigFile () {
const loaderConfig = this.postcssOptions && this.postcssOptions.config
const postcssConfigFile = loaderConfig || this.searchConfigFile()
if (typeof postcssConfigFile === 'string') {
return postcssConfigFile
}
}
sortPlugins ({ plugins, order }) {
function sortPlugins ({ plugins, order }) {
const names = Object.keys(plugins)
if (typeof order === 'string') {
order = orderPresets[order]
@ -138,11 +43,12 @@ export class PostcssConfig {
return typeof order === 'function' ? order(names, orderPresets) : (order || names)
}
loadPlugins (config) {
function loadPlugins (config) {
if (!isPureObject(config.plugins)) { return }
// Map postcss plugins into instances on object mode once
const cjs = createCommonJS(import.meta.url)
config.plugins = this.sortPlugins(config).map((pluginName) => {
config.plugins = sortPlugins(config).map((pluginName) => {
const pluginFn = requireModule(pluginName, { paths: [cjs.__dirname] })
const pluginOptions = config.plugins[pluginName]
if (!pluginOptions || typeof pluginFn !== 'function') { return null }
@ -150,41 +56,37 @@ export class PostcssConfig {
}).filter(Boolean)
}
config () {
/* istanbul ignore if */
if (!this.options.build.postcss) {
return false
if (!nuxt.options.webpack.postcss || !nuxt.options.postcss) {
return false
}
const configFile = nuxt.options.postcss?.config
if (configFile) {
return {
postcssOptions: {
config: configFile
},
sourceMap: nuxt.options.webpack.cssSourceMap
}
}
let postcssOptions = cloneDeep(nuxt.options.postcss)
// Apply default plugins
if (isPureObject(postcssOptions)) {
if (Array.isArray(postcssOptions.plugins)) {
defaults(postcssOptions, defaultConfig())
} else {
// Keep the order of default plugins
postcssOptions = merge({}, defaultConfig(), postcssOptions)
loadPlugins(postcssOptions)
}
const configFile = this.getConfigFile()
if (configFile) {
return {
postcssOptions: {
config: configFile
},
sourceMap: this.options.build.cssSourceMap
}
}
delete nuxt.options.webpack.postcss.order
let postcssOptions = cloneDeep(this.postcssOptions)
// Apply default plugins
if (isPureObject(postcssOptions)) {
if (Array.isArray(postcssOptions.plugins)) {
defaults(postcssOptions, this.defaultConfig)
} else {
// Keep the order of default plugins
postcssOptions = merge({}, this.defaultConfig, postcssOptions)
this.loadPlugins(postcssOptions)
}
delete this.options.build.postcss.order
return {
sourceMap: this.options.build.cssSourceMap,
...this.options.build.postcss,
postcssOptions
}
return {
sourceMap: nuxt.options.webpack.cssSourceMap,
...nuxt.options.webpack.postcss,
postcssOptions
}
}
}

View File

@ -1,23 +0,0 @@
export const reservedVueTags = [
// HTML tags
'html', 'body', 'base', 'head', 'link', 'meta', 'style', 'title', 'address',
'article', 'aside', 'footer', 'header', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
'hgroup', 'nav', 'section', 'div', 'dd', 'dl', 'dt', 'figcaption', 'figure',
'picture', 'hr', 'img', 'li', 'main', 'ol', 'p', 'pre', 'ul', 'a', 'b', 'abbr',
'bdi', 'bdo', 'br', 'cite', 'code', 'data', 'dfn', 'em', 'i', 'kbd', 'mark',
'q', 'rp', 'rt', 'rtc', 'ruby', 's', 'samp', 'small', 'span', 'strong', 'sub',
'sup', 'time', 'u', 'var', 'wbr', 'area', 'audio', 'map', 'track', 'video',
'embed', 'object', 'param', 'source', 'canvas', 'script', 'noscript', 'del',
'ins', 'caption', 'col', 'colgroup', 'table', 'thead', 'tbody', 'td', 'th', 'tr',
'button', 'datalist', 'fieldset', 'form', 'input', 'label', 'legend', 'meter',
'optgroup', 'option', 'output', 'progress', 'select', 'textarea', 'details',
'dialog', 'menu', 'menuitem', 'summary', 'content', 'element', 'shadow', 'template',
'blockquote', 'iframe', 'tfoot',
// SVG tags
'svg', 'animate', 'circle', 'clippath', 'cursor', 'defs', 'desc', 'ellipse', 'filter',
'font-face', 'foreignObject', 'g', 'glyph', 'image', 'line', 'marker', 'mask',
'missing-glyph', 'path', 'pattern', 'polygon', 'polyline', 'rect', 'switch', 'symbol',
'text', 'textpath', 'tspan', 'use', 'view',
// Vue built-in tags
'slot', 'component'
]

View File

@ -0,0 +1,26 @@
import { useNuxt } from '@nuxt/kit'
import VirtualModulesPlugin from 'webpack-virtual-modules'
export function registerVirtualModules () {
const nuxt = useNuxt()
// Initialize virtual modules instance
const virtualModules = new VirtualModulesPlugin(nuxt.vfs)
const writeFiles = () => {
for (const filePath in nuxt.vfs) {
virtualModules.writeModule(filePath, nuxt.vfs[filePath])
}
}
// Workaround to initialize virtual modules
nuxt.hook('build:compile', ({ compiler }) => {
if (compiler.name === 'server') { writeFiles() }
})
// Update virtual modules when templates are updated
nuxt.hook('app:templatesGenerated', writeFiles)
nuxt.hook('webpack:config', configs => configs.forEach((config) => {
// Support virtual modules (input)
config.plugins.push(virtualModules)
}))
}

View File

@ -1,302 +1,162 @@
import type { IncomingMessage, ServerResponse } from 'http'
import { resolve } from 'pathe'
import pify from 'pify'
import webpack from 'webpack'
import Glob from 'glob'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackDevMiddleware, { API } from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import VirtualModulesPlugin from 'webpack-virtual-modules'
import { logger } from '@nuxt/kit'
import type { Compiler, Watching } from 'webpack'
import type { Context as WebpackDevMiddlewareContext, Options as WebpackDevMiddlewareOptions } from 'webpack-dev-middleware'
import type { MiddlewareOptions as WebpackHotMiddlewareOptions } from 'webpack-hot-middleware'
import type { Nuxt } from '@nuxt/schema'
import { joinURL } from 'ufo'
import { logger, useNuxt } from '@nuxt/kit'
import { DynamicBasePlugin } from '../../vite/src/plugins/dynamic-base'
import { createMFS } from './utils/mfs'
import { registerVirtualModules } from './virtual-modules'
import { client, server } from './configs'
import { createWebpackConfigContext, applyPresets, getWebpackConfig } from './utils/config'
const glob = pify(Glob)
class WebpackBundler {
nuxt: Nuxt
plugins: Array<string>
compilers: Array<Compiler>
compilersWatching: Array<Watching & { closeAsync?: () => void }>
// TODO: change this when pify has better types https://github.com/sindresorhus/pify/pull/76
devMiddleware: Record<string, Function & { close?: () => Promise<void>, context?: WebpackDevMiddlewareContext<IncomingMessage, ServerResponse> }>
hotMiddleware: Record<string, Function>
virtualModules: VirtualModulesPlugin
mfs?: Compiler['outputFileSystem']
__closed?: boolean
// TODO: Support plugins
// const plugins: string[] = []
constructor (nuxt: Nuxt) {
this.nuxt = nuxt
// TODO: plugins
this.plugins = []
// Class fields
this.compilers = []
this.compilersWatching = []
this.devMiddleware = {}
this.hotMiddleware = {}
// Bind middleware to self
this.middleware = this.middleware.bind(this)
// Initialize shared MFS for dev
if (this.nuxt.options.dev) {
this.mfs = createMFS() as Compiler['outputFileSystem']
}
// Initialize virtual modules instance
this.virtualModules = new VirtualModulesPlugin(nuxt.vfs)
const writeFiles = () => {
for (const filePath in nuxt.vfs) {
this.virtualModules.writeModule(filePath, nuxt.vfs[filePath])
}
}
// Workaround to initialize virtual modules
nuxt.hook('build:compile', ({ compiler }) => {
if (compiler.name === 'server') { writeFiles() }
})
// Update virtual modules when templates are updated
nuxt.hook('app:templatesGenerated', writeFiles)
}
getWebpackConfig (name) {
const ctx = createWebpackConfigContext({ nuxt: this.nuxt })
if (name === 'client') {
applyPresets(ctx, client)
} else if (name === 'server') {
applyPresets(ctx, server)
} else {
throw new Error(`Unsupported webpack config ${name}`)
}
export async function bundle (nuxt: Nuxt) {
await registerVirtualModules()
const webpackConfigs = [client, ...nuxt.options.ssr ? [server] : []].map((preset) => {
const ctx = createWebpackConfigContext(nuxt)
applyPresets(ctx, preset)
return getWebpackConfig(ctx)
}
})
async build () {
const { options } = this.nuxt
await nuxt.callHook('webpack:config', webpackConfigs)
const webpackConfigs = [
this.getWebpackConfig('client')
]
// Initialize shared MFS for dev
const mfs = nuxt.options.dev ? createMFS() : null
if (options.ssr) {
webpackConfigs.push(this.getWebpackConfig('server'))
// Configure compilers
const compilers = webpackConfigs.map((config) => {
config.plugins.push(DynamicBasePlugin.webpack({
env: nuxt.options.dev ? 'dev' : config.name as 'client',
devAppConfig: nuxt.options.app,
globalPublicPath: '__webpack_public_path__'
}))
// Create compiler
const compiler = webpack(config)
// In dev, write files in memory FS
if (nuxt.options.dev) {
compiler.outputFileSystem = mfs
}
await this.nuxt.callHook('webpack:config', webpackConfigs)
return compiler
})
// Check styleResource existence
const { styleResources } = this.nuxt.options.build
if (styleResources && Object.keys(styleResources).length) {
logger.warn(
'Using styleResources without the @nuxtjs/style-resources is not suggested and can lead to severe performance issues.',
'Please use https://github.com/nuxt-community/style-resources-module'
)
for (const ext of Object.keys(styleResources)) {
await Promise.all(Array.from(styleResources[ext]).map(async (p) => {
const styleResourceFiles = await glob(resolve(this.nuxt.options.rootDir, p as string))
if (!styleResourceFiles || styleResourceFiles.length === 0) {
throw new Error(`Style Resource not found: ${p}`)
}
}))
}
}
// Configure compilers
this.compilers = webpackConfigs.map((config) => {
// Support virtual modules (input)
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
const compiler = webpack(config)
// In dev, write files in memory FS
if (options.dev) {
compiler.outputFileSystem = this.mfs!
}
return compiler
})
// Start Builds
if (options.dev) {
return Promise.all(this.compilers.map(c => this.webpackCompile(c)))
} else {
for (const c of this.compilers) {
await this.webpackCompile(c)
}
}
}
async webpackCompile (compiler) {
const { name } = compiler.options
const { options } = this.nuxt
await this.nuxt.callHook('build:compile', { name, compiler })
// Load renderer resources after build
compiler.hooks.done.tap('load-resources', async (stats) => {
await this.nuxt.callHook('build:compiled', {
name,
compiler,
stats
})
// Reload renderer
await this.nuxt.callHook('build:resources', this.mfs)
})
// --- Dev Build ---
if (options.dev) {
// Client build
if (['client', 'modern'].includes(name)) {
return new Promise((resolve, reject) => {
compiler.hooks.done.tap('nuxt-dev', () => { resolve(null) })
compiler.hooks.failed.tap('nuxt-errorlog', (err) => { reject(err) })
// Start watch
this.webpackDev(compiler)
})
}
// Server, build and watch for changes
return new Promise((resolve, reject) => {
const watching = compiler.watch(options.watchers.webpack, (err) => {
if (err) {
return reject(err)
}
resolve(null)
})
watching.closeAsync = pify(watching.close)
this.compilersWatching.push(watching)
})
}
// --- Production Build ---
compiler.run = pify(compiler.run)
const stats = await compiler.run()
if (stats.hasErrors()) {
// non-quiet mode: errors will be printed by webpack itself
const error = new Error('Nuxt build error')
if (options.build.quiet === true) {
error.stack = stats.toString('errors-only')
}
throw error
}
// Await for renderer to load resources (programmatic, tests and generate)
await this.nuxt.callHook('build:resources')
}
async webpackDev (compiler: Compiler) {
logger.debug('Creating webpack middleware...')
const { name } = compiler.options
const buildOptions = this.nuxt.options.build
const { client, ...hotMiddlewareOptions } = buildOptions.hotMiddleware || {}
// Create webpack dev middleware
this.devMiddleware[name] = pify(
// @ts-ignore
webpackDevMiddleware(
// @ts-ignore
compiler,
{
publicPath: joinURL(this.nuxt.options.app.baseURL, this.nuxt.options.app.buildAssetsDir),
outputFileSystem: this.mfs,
stats: 'none',
...buildOptions.devMiddleware
} as WebpackDevMiddlewareOptions<IncomingMessage, ServerResponse>
)
)
this.devMiddleware[name].close = pify(this.devMiddleware[name].close)
// @ts-ignore
this.compilersWatching.push(this.devMiddleware[name].context.watching)
this.hotMiddleware[name] = pify(
webpackHotMiddleware(
compiler as any,
{
log: false,
heartbeat: 10000,
path: joinURL(this.nuxt.options.app.baseURL, '__webpack_hmr', name),
...hotMiddlewareOptions
} as WebpackHotMiddlewareOptions
)
)
// Register devMiddleware on server
await this.nuxt.callHook('server:devMiddleware', this.middleware)
}
async middleware (req: IncomingMessage, res: ServerResponse, next: () => any) {
if (this.devMiddleware && this.devMiddleware.client) {
await this.devMiddleware.client(req, res)
}
if (this.hotMiddleware && this.hotMiddleware.client) {
await this.hotMiddleware.client(req, res)
}
next()
}
async unwatch () {
await Promise.all(this.compilersWatching.map(watching => watching.closeAsync()))
}
async close () {
if (this.__closed) {
return
}
this.__closed = true
// Unwatch
await this.unwatch()
// Stop webpack middleware
for (const devMiddleware of Object.values(this.devMiddleware)) {
await devMiddleware.close()
}
for (const compiler of this.compilers) {
nuxt.hook('close', async () => {
for (const compiler of compilers) {
await new Promise(resolve => compiler.close(resolve))
}
})
// Cleanup MFS
if (this.mfs) {
delete this.mfs
// Start Builds
if (nuxt.options.dev) {
return Promise.all(compilers.map(c => compile(c)))
}
for (const c of compilers) {
await compile(c)
}
}
async function createDevMiddleware (compiler: Compiler) {
const nuxt = useNuxt()
logger.debug('Creating webpack middleware...')
// Create webpack dev middleware
const devMiddleware = pify(webpackDevMiddleware(compiler, {
publicPath: joinURL(nuxt.options.app.baseURL, nuxt.options.app.buildAssetsDir),
outputFileSystem: compiler.outputFileSystem as any,
stats: 'none',
...nuxt.options.webpack.devMiddleware
})) as API<IncomingMessage, ServerResponse>
nuxt.hook('close', () => pify(devMiddleware.close.bind(devMiddleware))())
const { client: _client, ...hotMiddlewareOptions } = nuxt.options.webpack.hotMiddleware || {}
const hotMiddleware = pify(webpackHotMiddleware(compiler, {
log: false,
heartbeat: 10000,
path: joinURL(nuxt.options.app.baseURL, '__webpack_hmr', compiler.options.name),
...hotMiddlewareOptions
}))
// Register devMiddleware on server
await nuxt.callHook('server:devMiddleware', async (req, res, next) => {
for (const mw of [devMiddleware, hotMiddleware]) {
await mw?.(req, res)
}
next()
})
return devMiddleware
}
async function compile (compiler: Compiler) {
const nuxt = useNuxt()
const { name } = compiler.options
await nuxt.callHook('build:compile', { name, compiler })
// Load renderer resources after build
compiler.hooks.done.tap('load-resources', async (stats) => {
await nuxt.callHook('build:compiled', { name, compiler, stats })
// Reload renderer
await nuxt.callHook('build:resources', compiler.outputFileSystem)
})
// --- Dev Build ---
if (nuxt.options.dev) {
const compilersWatching: Watching[] = []
nuxt.hook('close', async () => {
await Promise.all(compilersWatching.map(watching => pify(watching.close.bind(watching))()))
})
// Client build
if (name === 'client') {
return new Promise((resolve, reject) => {
compiler.hooks.done.tap('nuxt-dev', () => { resolve(null) })
compiler.hooks.failed.tap('nuxt-errorlog', (err) => { reject(err) })
// Start watch
createDevMiddleware(compiler).then((devMiddleware) => {
compilersWatching.push(devMiddleware.context.watching)
})
})
}
// Cleanup more resources
delete this.compilers
delete this.compilersWatching
delete this.devMiddleware
delete this.hotMiddleware
// Server, build and watch for changes
return new Promise((resolve, reject) => {
const watching = compiler.watch(nuxt.options.watchers.webpack, (err) => {
if (err) { return reject(err) }
resolve(null)
})
compilersWatching.push(watching)
})
}
forGenerate () {
this.nuxt.options.target = 'static'
}
}
// --- Production Build ---
const stats = await new Promise<webpack.Stats>((resolve, reject) => compiler.run((err, stats) => err ? reject(err) : resolve(stats)))
export function bundle (nuxt: Nuxt) {
const bundler = new WebpackBundler(nuxt)
return bundler.build()
if (stats.hasErrors()) {
// non-quiet mode: errors will be printed by webpack itself
const error = new Error('Nuxt build error')
if (nuxt.options.build.quiet === true) {
error.stack = stats.toString('errors-only')
}
throw error
}
// Await for renderer to load resources (programmatic, tests and generate)
await nuxt.callHook('build:resources')
}

View File

@ -3,7 +3,7 @@ import { addComponent } from '@nuxt/kit'
export default defineNuxtConfig({
buildDir: process.env.NITRO_BUILD_DIR,
vite: !process.env.TEST_WITH_WEBPACK,
builder: process.env.TEST_WITH_WEBPACK ? 'webpack' : 'vite',
nitro: {
output: { dir: process.env.NITRO_OUTPUT_DIR }
},

View File

@ -3163,6 +3163,7 @@ __metadata:
defu: ^5.0.1
jiti: ^1.13.0
pathe: ^0.2.0
postcss-import-resolver: ^2.0.0
scule: ^0.2.1
std-env: ^3.0.1
ufo: ^0.7.9
@ -3393,7 +3394,6 @@ __metadata:
p-debounce: ^4.0.0
pathe: ^0.2.0
postcss-import: ^14.0.2
postcss-import-resolver: ^2.0.0
postcss-url: ^10.1.3
rollup-plugin-visualizer: ^5.6.0
ufo: ^0.7.9
@ -3480,7 +3480,7 @@ __metadata:
languageName: node
linkType: hard
"@nuxt/webpack-builder@3.0.0, @nuxt/webpack-builder@workspace:packages/webpack":
"@nuxt/webpack-builder@workspace:packages/webpack":
version: 0.0.0-use.local
resolution: "@nuxt/webpack-builder@workspace:packages/webpack"
dependencies:
@ -3489,14 +3489,11 @@ __metadata:
"@nuxt/kit": 3.0.0
"@nuxt/schema": 3.0.0
"@types/pify": ^5.0.1
"@types/terser-webpack-plugin": ^5.0.4
"@types/webpack-bundle-analyzer": ^4.4.1
"@types/webpack-dev-middleware": ^5.0.2
"@types/webpack-hot-middleware": ^2.25.6
"@types/webpack-virtual-modules": ^0
"@vue/babel-preset-jsx": ^1.2.4
autoprefixer: ^10.4.2
babel-loader: ^8.2.3
css-loader: ^6.6.0
css-minimizer-webpack-plugin: ^3.4.1
cssnano: ^5.0.17
@ -3504,7 +3501,6 @@ __metadata:
escape-string-regexp: ^5.0.0
file-loader: ^6.2.0
fs-extra: ^10.0.1
glob: ^7.2.0
hash-sum: ^2.0.0
lodash-es: ^4.17.21
memfs: ^3.4.1
@ -3514,7 +3510,6 @@ __metadata:
pify: ^5.0.0
postcss: ^8.4.7
postcss-import: ^14.0.2
postcss-import-resolver: ^2.0.0
postcss-loader: ^6.2.1
postcss-url: ^10.1.3
style-resources-loader: ^1.5.0
@ -4630,16 +4625,6 @@ __metadata:
languageName: node
linkType: hard
"@types/terser-webpack-plugin@npm:^5.0.4":
version: 5.0.4
resolution: "@types/terser-webpack-plugin@npm:5.0.4"
dependencies:
terser: ^5.3.8
webpack: ^5.1.0
checksum: 7b3845526d4ed7b636f7b2f8f35b5d7e45211f7a55afc85e32a66655eaf65cd193e2fec195bcdb473c0d9a5b2828798b9c23196fdc86e9cd2e9420227012f438
languageName: node
linkType: hard
"@types/throttle-debounce@npm:^2.1.0":
version: 2.1.0
resolution: "@types/throttle-debounce@npm:2.1.0"
@ -15675,7 +15660,6 @@ __metadata:
"@nuxt/nitro": 3.0.0
"@nuxt/schema": 3.0.0
"@nuxt/vite-builder": 3.0.0
"@nuxt/webpack-builder": 3.0.0
"@types/fs-extra": ^9.0.13
"@types/hash-sum": ^1.0.0
"@vue/reactivity": ^3.2.31
@ -20771,7 +20755,7 @@ __metadata:
languageName: node
linkType: hard
"terser@npm:^5.0.0, terser@npm:^5.3.4, terser@npm:^5.3.8, terser@npm:^5.7.2":
"terser@npm:^5.0.0, terser@npm:^5.3.4, terser@npm:^5.7.2":
version: 5.10.0
resolution: "terser@npm:5.10.0"
dependencies:
@ -22553,44 +22537,7 @@ __metadata:
languageName: node
linkType: hard
"webpack@npm:^5, webpack@npm:^5.1.0, webpack@npm:^5.38.1":
version: 5.69.0
resolution: "webpack@npm:5.69.0"
dependencies:
"@types/eslint-scope": ^3.7.3
"@types/estree": ^0.0.51
"@webassemblyjs/ast": 1.11.1
"@webassemblyjs/wasm-edit": 1.11.1
"@webassemblyjs/wasm-parser": 1.11.1
acorn: ^8.4.1
acorn-import-assertions: ^1.7.6
browserslist: ^4.14.5
chrome-trace-event: ^1.0.2
enhanced-resolve: ^5.9.0
es-module-lexer: ^0.9.0
eslint-scope: 5.1.1
events: ^3.2.0
glob-to-regexp: ^0.4.1
graceful-fs: ^4.2.9
json-parse-better-errors: ^1.0.2
loader-runner: ^4.2.0
mime-types: ^2.1.27
neo-async: ^2.6.2
schema-utils: ^3.1.0
tapable: ^2.1.1
terser-webpack-plugin: ^5.1.3
watchpack: ^2.3.1
webpack-sources: ^3.2.3
peerDependenciesMeta:
webpack-cli:
optional: true
bin:
webpack: bin/webpack.js
checksum: 0b0fc2ffcb926fc7506ec56901ae9a69f1ae969a6afc63395a3ed56f938d385c1d16d1dea39fd56dbb9362189c05da49174219904e5a337040aed5a46080e926
languageName: node
linkType: hard
"webpack@npm:^5.69.1":
"webpack@npm:^5, webpack@npm:^5.38.1, webpack@npm:^5.69.1":
version: 5.69.1
resolution: "webpack@npm:5.69.1"
dependencies: