mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 08:02:01 +00:00
refactor: unify context in webpack module (#5054)
This commit is contained in:
parent
3ed9f3e6a6
commit
9860eb6a7c
@ -6,6 +6,10 @@ export default class BuildContext {
|
||||
this.isStatic = false
|
||||
}
|
||||
|
||||
get buildOptions() {
|
||||
return this.options.build
|
||||
}
|
||||
|
||||
get plugins() {
|
||||
return this._builder.plugins
|
||||
}
|
||||
|
@ -20,4 +20,14 @@ describe('builder: buildContext', () => {
|
||||
const context = new BuildContext(builder)
|
||||
expect(context.plugins).toEqual(builder.plugins)
|
||||
})
|
||||
|
||||
test('should return builder build options', () => {
|
||||
const buildOptions = { id: 'test-build-options' }
|
||||
const builder = {
|
||||
plugins: [],
|
||||
nuxt: { options: { build: buildOptions } }
|
||||
}
|
||||
const context = new BuildContext(builder)
|
||||
expect(context.buildOptions).toEqual(buildOptions)
|
||||
})
|
||||
})
|
||||
|
@ -19,8 +19,8 @@ import PerfLoader from './utils/perf-loader'
|
||||
const glob = pify(Glob)
|
||||
|
||||
export class WebpackBundler {
|
||||
constructor(context) {
|
||||
this.context = context
|
||||
constructor(buildContext) {
|
||||
this.buildContext = buildContext
|
||||
// Fields that set on build
|
||||
this.compilers = []
|
||||
this.compilersWatching = []
|
||||
@ -28,7 +28,7 @@ export class WebpackBundler {
|
||||
this.hotMiddleware = {}
|
||||
|
||||
// Initialize shared MFS for dev
|
||||
if (this.context.options.dev) {
|
||||
if (this.buildContext.options.dev) {
|
||||
this.mfs = new MFS()
|
||||
|
||||
// TODO: Enable when async FS required
|
||||
@ -38,7 +38,7 @@ export class WebpackBundler {
|
||||
}
|
||||
|
||||
async build() {
|
||||
const { options } = this.context
|
||||
const { options } = this.buildContext
|
||||
|
||||
const compilersOptions = []
|
||||
|
||||
@ -60,7 +60,7 @@ export class WebpackBundler {
|
||||
compilersOptions.push(serverConfig)
|
||||
}
|
||||
|
||||
for (const p of this.context.plugins) {
|
||||
for (const p of this.buildContext.plugins) {
|
||||
// Client config
|
||||
if (!clientConfig.resolve.alias[p.name]) {
|
||||
clientConfig.resolve.alias[p.name] = p.mode === 'server' ? './empty.js' : p.src
|
||||
@ -78,7 +78,7 @@ export class WebpackBundler {
|
||||
}
|
||||
|
||||
// Check styleResource existence
|
||||
const { styleResources } = this.context.options.build
|
||||
const { styleResources } = this.buildContext.options.build
|
||||
if (styleResources && Object.keys(styleResources).length) {
|
||||
consola.warn(
|
||||
'Using styleResources without the nuxt-style-resources-module is not suggested and can lead to severe performance issues.',
|
||||
@ -86,7 +86,7 @@ export class WebpackBundler {
|
||||
)
|
||||
for (const ext of Object.keys(styleResources)) {
|
||||
await Promise.all(wrapArray(styleResources[ext]).map(async (p) => {
|
||||
const styleResourceFiles = await glob(path.resolve(this.context.options.rootDir, p))
|
||||
const styleResourceFiles = await glob(path.resolve(this.buildContext.options.rootDir, p))
|
||||
|
||||
if (!styleResourceFiles || styleResourceFiles.length === 0) {
|
||||
throw new Error(`Style Resource not found: ${p}`)
|
||||
@ -122,7 +122,7 @@ export class WebpackBundler {
|
||||
|
||||
async webpackCompile(compiler) {
|
||||
const { name } = compiler.options
|
||||
const { nuxt, options } = this.context
|
||||
const { nuxt, options } = this.buildContext
|
||||
|
||||
await nuxt.callHook('build:compile', { name, compiler })
|
||||
|
||||
@ -179,7 +179,7 @@ export class WebpackBundler {
|
||||
consola.debug('Adding webpack middleware...')
|
||||
|
||||
const { name } = compiler.options
|
||||
const { nuxt: { server }, options } = this.context
|
||||
const { nuxt: { server }, options } = this.buildContext
|
||||
const { client, ...hotMiddlewareOptions } = options.build.hotMiddleware || {}
|
||||
|
||||
// Create webpack dev middleware
|
||||
@ -255,6 +255,6 @@ export class WebpackBundler {
|
||||
}
|
||||
|
||||
forGenerate() {
|
||||
this.context.isStatic = true
|
||||
this.buildContext.isStatic = true
|
||||
}
|
||||
}
|
||||
|
@ -20,16 +20,9 @@ import WarnFixPlugin from '../plugins/warnfix'
|
||||
import { reservedVueTags } from '../utils/reserved-tags'
|
||||
|
||||
export default class WebpackBaseConfig {
|
||||
constructor(builder, options) {
|
||||
this.name = options.name
|
||||
this.isServer = options.isServer
|
||||
this.isModern = options.isModern
|
||||
constructor(builder) {
|
||||
this.builder = builder
|
||||
this.nuxt = builder.context.nuxt
|
||||
this.isStatic = builder.context.isStatic
|
||||
this.options = builder.context.options
|
||||
this.loaders = this.options.build.loaders
|
||||
this.buildMode = this.options.dev ? 'development' : 'production'
|
||||
this.buildContext = builder.buildContext
|
||||
this.modulesToTranspile = this.normalizeTranspile()
|
||||
}
|
||||
|
||||
@ -43,17 +36,29 @@ export default class WebpackBaseConfig {
|
||||
|
||||
get nuxtEnv() {
|
||||
return {
|
||||
isDev: this.options.dev,
|
||||
isDev: this.dev,
|
||||
isServer: this.isServer,
|
||||
isClient: !this.isServer,
|
||||
isModern: !!this.isModern
|
||||
}
|
||||
}
|
||||
|
||||
get mode() {
|
||||
return this.dev ? 'development' : 'production'
|
||||
}
|
||||
|
||||
get dev() {
|
||||
return this.buildContext.options.dev
|
||||
}
|
||||
|
||||
get loaders() {
|
||||
return this.buildContext.buildOptions.loaders
|
||||
}
|
||||
|
||||
normalizeTranspile() {
|
||||
// include SFCs in node_modules
|
||||
const items = [/\.vue\.js/i]
|
||||
for (const pattern of this.options.build.transpile) {
|
||||
for (const pattern of this.buildContext.buildOptions.transpile) {
|
||||
if (pattern instanceof RegExp) {
|
||||
items.push(pattern)
|
||||
} else {
|
||||
@ -65,7 +70,7 @@ export default class WebpackBaseConfig {
|
||||
}
|
||||
|
||||
getBabelOptions() {
|
||||
const options = clone(this.options.build.babel)
|
||||
const options = clone(this.buildContext.buildOptions.babel)
|
||||
|
||||
if (typeof options.presets === 'function') {
|
||||
options.presets = options.presets({ isServer: this.isServer })
|
||||
@ -86,11 +91,11 @@ export default class WebpackBaseConfig {
|
||||
}
|
||||
|
||||
getFileName(key) {
|
||||
let fileName = this.options.build.filenames[key]
|
||||
let fileName = this.buildContext.buildOptions.filenames[key]
|
||||
if (typeof fileName === 'function') {
|
||||
fileName = fileName(this.nuxtEnv)
|
||||
}
|
||||
if (this.options.dev) {
|
||||
if (this.dev) {
|
||||
const hash = /\[(chunkhash|contenthash|hash)(?::(\d+))?]/.exec(fileName)
|
||||
if (hash) {
|
||||
consola.warn(`Notice: Please do not use ${hash[1]} in dev mode to prevent memory leak`)
|
||||
@ -105,11 +110,11 @@ export default class WebpackBaseConfig {
|
||||
|
||||
env() {
|
||||
const env = {
|
||||
'process.env.NODE_ENV': JSON.stringify(this.buildMode),
|
||||
'process.mode': JSON.stringify(this.options.mode),
|
||||
'process.static': this.isStatic
|
||||
'process.env.NODE_ENV': JSON.stringify(this.mode),
|
||||
'process.mode': JSON.stringify(this.mode),
|
||||
'process.static': this.buildContext.isStatic
|
||||
}
|
||||
Object.entries(this.options.env).forEach(([key, value]) => {
|
||||
Object.entries(this.buildContext.options.env).forEach(([key, value]) => {
|
||||
env['process.env.' + key] =
|
||||
['boolean', 'number'].includes(typeof value)
|
||||
? value
|
||||
@ -119,19 +124,21 @@ export default class WebpackBaseConfig {
|
||||
}
|
||||
|
||||
output() {
|
||||
const {
|
||||
options: { buildDir, router },
|
||||
buildOptions: { publicPath }
|
||||
} = this.buildContext
|
||||
return {
|
||||
path: path.resolve(this.options.buildDir, 'dist', this.isServer ? 'server' : 'client'),
|
||||
path: path.resolve(buildDir, 'dist', this.isServer ? 'server' : 'client'),
|
||||
filename: this.getFileName('app'),
|
||||
futureEmitAssets: true, // TODO: Remove when using webpack 5
|
||||
chunkFilename: this.getFileName('chunk'),
|
||||
publicPath: isUrl(this.options.build.publicPath)
|
||||
? this.options.build.publicPath
|
||||
: urlJoin(this.options.router.base, this.options.build.publicPath)
|
||||
publicPath: isUrl(publicPath) ? publicPath : urlJoin(router.base, publicPath)
|
||||
}
|
||||
}
|
||||
|
||||
optimization() {
|
||||
const optimization = cloneDeep(this.options.build.optimization)
|
||||
const optimization = cloneDeep(this.buildContext.buildOptions.optimization)
|
||||
|
||||
if (optimization.minimize && optimization.minimizer === undefined) {
|
||||
optimization.minimizer = this.minimizer()
|
||||
@ -142,13 +149,14 @@ export default class WebpackBaseConfig {
|
||||
|
||||
minimizer() {
|
||||
const minimizer = []
|
||||
const { terser, cache } = this.buildContext.buildOptions
|
||||
|
||||
// https://github.com/webpack-contrib/terser-webpack-plugin
|
||||
if (this.options.build.terser) {
|
||||
if (terser) {
|
||||
minimizer.push(
|
||||
new TerserWebpackPlugin(Object.assign({
|
||||
parallel: true,
|
||||
cache: this.options.build.cache,
|
||||
cache,
|
||||
sourceMap: this.devtool && /source-?map/.test(this.devtool),
|
||||
extractComments: {
|
||||
filename: 'LICENSES'
|
||||
@ -164,7 +172,7 @@ export default class WebpackBaseConfig {
|
||||
reserved: reservedVueTags
|
||||
}
|
||||
}
|
||||
}, this.options.build.terser))
|
||||
}, terser))
|
||||
)
|
||||
}
|
||||
|
||||
@ -172,7 +180,7 @@ export default class WebpackBaseConfig {
|
||||
}
|
||||
|
||||
alias() {
|
||||
const { srcDir, rootDir, dir: { assets: assetsDir, static: staticDir } } = this.options
|
||||
const { srcDir, rootDir, dir: { assets: assetsDir, static: staticDir } } = this.buildContext.options
|
||||
|
||||
return {
|
||||
'~': path.join(srcDir),
|
||||
@ -185,10 +193,9 @@ export default class WebpackBaseConfig {
|
||||
}
|
||||
|
||||
rules() {
|
||||
const perfLoader = new PerfLoader(this)
|
||||
const perfLoader = new PerfLoader(this.name, this.buildContext)
|
||||
const styleLoader = new StyleLoader(
|
||||
this.options,
|
||||
this.nuxt,
|
||||
this.buildContext,
|
||||
{ isServer: this.isServer, perfLoader }
|
||||
)
|
||||
const babelLoader = {
|
||||
@ -329,25 +336,26 @@ export default class WebpackBaseConfig {
|
||||
|
||||
plugins() {
|
||||
const plugins = []
|
||||
const { nuxt, buildOptions } = this.buildContext
|
||||
|
||||
// Add timefix-plugin before others plugins
|
||||
if (this.options.dev) {
|
||||
if (this.dev) {
|
||||
plugins.push(new TimeFixPlugin())
|
||||
}
|
||||
|
||||
// CSS extraction)
|
||||
if (this.options.build.extractCSS) {
|
||||
if (buildOptions.extractCSS) {
|
||||
plugins.push(new ExtractCssChunksPlugin(Object.assign({
|
||||
filename: this.getFileName('css'),
|
||||
chunkFilename: this.getFileName('css'),
|
||||
// TODO: https://github.com/faceyspacey/extract-css-chunks-webpack-plugin/issues/132
|
||||
reloadAll: true
|
||||
}, this.options.build.extractCSS)))
|
||||
}, buildOptions.extractCSS)))
|
||||
}
|
||||
|
||||
plugins.push(new VueLoader.VueLoaderPlugin())
|
||||
|
||||
plugins.push(...(this.options.build.plugins || []))
|
||||
plugins.push(...(buildOptions.plugins || []))
|
||||
|
||||
// Hide warnings about plugins without a default export (#1179)
|
||||
plugins.push(new WarnFixPlugin())
|
||||
@ -362,37 +370,38 @@ export default class WebpackBaseConfig {
|
||||
'profile',
|
||||
'stats'
|
||||
],
|
||||
basic: !this.options.build.quiet && env.minimalCLI,
|
||||
fancy: !this.options.build.quiet && !env.minimalCLI,
|
||||
profile: !this.options.build.quiet && this.options.build.profile,
|
||||
stats: !this.options.build.quiet && !this.options.dev && this.options.build.stats,
|
||||
basic: !buildOptions.quiet && env.minimalCLI,
|
||||
fancy: !buildOptions.quiet && !env.minimalCLI,
|
||||
profile: !buildOptions.quiet && buildOptions.profile,
|
||||
stats: !buildOptions.quiet && !this.dev && buildOptions.stats,
|
||||
reporter: {
|
||||
change: (_, { shortPath }) => {
|
||||
if (!this.isServer) {
|
||||
this.nuxt.callHook('bundler:change', shortPath)
|
||||
nuxt.callHook('bundler:change', shortPath)
|
||||
}
|
||||
},
|
||||
done: (context) => {
|
||||
if (context.hasErrors) {
|
||||
this.nuxt.callHook('bundler:error')
|
||||
done: (buildContext) => {
|
||||
if (buildContext.hasErrors) {
|
||||
nuxt.callHook('bundler:error')
|
||||
}
|
||||
},
|
||||
allDone: () => {
|
||||
this.nuxt.callHook('bundler:done')
|
||||
nuxt.callHook('bundler:done')
|
||||
}
|
||||
}
|
||||
}))
|
||||
|
||||
if (this.options.build.hardSource) {
|
||||
plugins.push(new HardSourcePlugin(Object.assign({}, this.options.build.hardSource)))
|
||||
if (buildOptions.hardSource) {
|
||||
plugins.push(new HardSourcePlugin(Object.assign({}, buildOptions.hardSource)))
|
||||
}
|
||||
|
||||
return plugins
|
||||
}
|
||||
|
||||
extendConfig(config) {
|
||||
if (typeof this.options.build.extend === 'function') {
|
||||
const extendedConfig = this.options.build.extend.call(
|
||||
const { extend } = this.buildContext.buildOptions
|
||||
if (typeof extend === 'function') {
|
||||
const extendedConfig = extend.call(
|
||||
this.builder, config, { loaders: this.loaders, ...this.nuxtEnv }
|
||||
)
|
||||
// Only overwrite config when something is returned for backwards compatibility
|
||||
@ -405,17 +414,17 @@ export default class WebpackBaseConfig {
|
||||
|
||||
config() {
|
||||
// Prioritize nested node_modules in webpack search path (#2558)
|
||||
const webpackModulesDir = ['node_modules'].concat(this.options.modulesDir)
|
||||
const webpackModulesDir = ['node_modules'].concat(this.buildContext.options.modulesDir)
|
||||
|
||||
const config = {
|
||||
name: this.name,
|
||||
mode: this.buildMode,
|
||||
mode: this.mode,
|
||||
devtool: this.devtool,
|
||||
optimization: this.optimization(),
|
||||
output: this.output(),
|
||||
performance: {
|
||||
maxEntrypointSize: 1000 * 1024,
|
||||
hints: this.options.dev ? false : 'warning'
|
||||
hints: this.dev ? false : 'warning'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.wasm', '.mjs', '.js', '.json', '.vue', '.jsx', '.ts', '.tsx'],
|
||||
|
@ -14,12 +14,15 @@ import VueSSRClientPlugin from '../plugins/vue/client'
|
||||
import WebpackBaseConfig from './base'
|
||||
|
||||
export default class WebpackClientConfig extends WebpackBaseConfig {
|
||||
constructor(builder, options) {
|
||||
super(builder, options || { name: 'client', isServer: false })
|
||||
constructor(builder) {
|
||||
super(builder)
|
||||
this.name = 'client'
|
||||
this.isServer = false
|
||||
this.isModern = false
|
||||
}
|
||||
|
||||
getFileName(...args) {
|
||||
if (this.options.build.analyze) {
|
||||
if (this.buildContext.buildOptions.analyze) {
|
||||
const [key] = args
|
||||
if (['app', 'chunk'].includes(key)) {
|
||||
return `${this.isModern ? 'modern-' : ''}[name].js`
|
||||
@ -44,7 +47,7 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
||||
// Small, known and common modules which are usually used project-wise
|
||||
// Sum of them may not be more than 244 KiB
|
||||
if (
|
||||
this.options.build.splitChunks.commons === true &&
|
||||
this.buildContext.buildOptions.splitChunks.commons === true &&
|
||||
optimization.splitChunks.cacheGroups.commons === undefined
|
||||
) {
|
||||
optimization.splitChunks.cacheGroups.commons = {
|
||||
@ -60,14 +63,13 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
||||
|
||||
minimizer() {
|
||||
const minimizer = super.minimizer()
|
||||
const { optimizeCSS } = this.buildContext.buildOptions
|
||||
|
||||
// https://github.com/NMFR/optimize-css-assets-webpack-plugin
|
||||
// https://github.com/webpack-contrib/mini-css-extract-plugin#minimizing-for-production
|
||||
// TODO: Remove OptimizeCSSAssetsPlugin when upgrading to webpack 5
|
||||
if (this.options.build.optimizeCSS) {
|
||||
minimizer.push(
|
||||
new OptimizeCSSAssetsPlugin(Object.assign({}, this.options.build.optimizeCSS))
|
||||
)
|
||||
if (optimizeCSS) {
|
||||
minimizer.push(new OptimizeCSSAssetsPlugin(Object.assign({}, optimizeCSS)))
|
||||
}
|
||||
|
||||
return minimizer
|
||||
@ -75,14 +77,15 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
||||
|
||||
plugins() {
|
||||
const plugins = super.plugins()
|
||||
const { buildOptions, options: { appTemplatePath, buildDir, rootDir, modern } } = this.buildContext
|
||||
|
||||
// Generate output HTML for SSR
|
||||
if (this.options.build.ssr) {
|
||||
if (buildOptions.ssr) {
|
||||
plugins.push(
|
||||
new HTMLPlugin({
|
||||
filename: '../server/index.ssr.html',
|
||||
template: this.options.appTemplatePath,
|
||||
minify: this.options.build.html.minify,
|
||||
template: appTemplatePath,
|
||||
minify: buildOptions.html.minify,
|
||||
inject: false // Resources will be injected using bundleRenderer
|
||||
})
|
||||
)
|
||||
@ -91,8 +94,8 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
||||
plugins.push(
|
||||
new HTMLPlugin({
|
||||
filename: '../server/index.spa.html',
|
||||
template: this.options.appTemplatePath,
|
||||
minify: this.options.build.html.minify,
|
||||
template: appTemplatePath,
|
||||
minify: buildOptions.html.minify,
|
||||
inject: true,
|
||||
chunksSortMode: 'dependency'
|
||||
}),
|
||||
@ -102,53 +105,53 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
||||
new webpack.DefinePlugin(this.env())
|
||||
)
|
||||
|
||||
if (this.options.dev) {
|
||||
if (this.dev) {
|
||||
// TODO: webpackHotUpdate is not defined: https://github.com/webpack/webpack/issues/6693
|
||||
plugins.push(new webpack.HotModuleReplacementPlugin())
|
||||
}
|
||||
|
||||
// Webpack Bundle Analyzer
|
||||
// https://github.com/webpack-contrib/webpack-bundle-analyzer
|
||||
if (!this.options.dev && this.options.build.analyze) {
|
||||
const statsDir = path.resolve(this.options.buildDir, 'stats')
|
||||
if (!this.dev && buildOptions.analyze) {
|
||||
const statsDir = path.resolve(buildDir, 'stats')
|
||||
|
||||
plugins.push(new BundleAnalyzer.BundleAnalyzerPlugin(Object.assign({
|
||||
analyzerMode: 'static',
|
||||
defaultSizes: 'gzip',
|
||||
generateStatsFile: true,
|
||||
openAnalyzer: !this.options.build.quiet,
|
||||
openAnalyzer: !buildOptions.quiet,
|
||||
reportFilename: path.resolve(statsDir, `${this.name}.html`),
|
||||
statsFilename: path.resolve(statsDir, `${this.name}.json`)
|
||||
}, this.options.build.analyze)))
|
||||
}, buildOptions.analyze)))
|
||||
}
|
||||
|
||||
if (this.options.modern) {
|
||||
if (modern) {
|
||||
plugins.push(new ModernModePlugin({
|
||||
targetDir: path.resolve(this.options.buildDir, 'dist', 'client'),
|
||||
targetDir: path.resolve(buildDir, 'dist', 'client'),
|
||||
isModernBuild: this.isModern
|
||||
}))
|
||||
}
|
||||
|
||||
if (this.options.build.crossorigin) {
|
||||
if (buildOptions.crossorigin) {
|
||||
plugins.push(new CorsPlugin({
|
||||
crossorigin: this.options.build.crossorigin
|
||||
crossorigin: buildOptions.crossorigin
|
||||
}))
|
||||
}
|
||||
|
||||
// TypeScript type checker
|
||||
// Only performs once per client compilation and only if `ts-loader` checker is not used (transpileOnly: true)
|
||||
if (!this.isModern && this.loaders.ts.transpileOnly && this.options.build.useForkTsChecker) {
|
||||
const forkTsCheckerResolvedPath = this.nuxt.resolver.resolveModule('fork-ts-checker-webpack-plugin')
|
||||
if (!this.isModern && this.loaders.ts.transpileOnly && buildOptions.useForkTsChecker) {
|
||||
const forkTsCheckerResolvedPath = this.buildContext.nuxt.resolver.resolveModule('fork-ts-checker-webpack-plugin')
|
||||
if (forkTsCheckerResolvedPath) {
|
||||
const ForkTsCheckerWebpackPlugin = require(forkTsCheckerResolvedPath)
|
||||
plugins.push(new ForkTsCheckerWebpackPlugin(Object.assign({
|
||||
vue: true,
|
||||
tsconfig: path.resolve(this.options.rootDir, 'tsconfig.json'),
|
||||
tsconfig: path.resolve(rootDir, 'tsconfig.json'),
|
||||
// https://github.com/Realytics/fork-ts-checker-webpack-plugin#options - tslint: boolean | string - So we set it false if file not found
|
||||
tslint: (tslintPath => fs.existsSync(tslintPath) && tslintPath)(path.resolve(this.options.rootDir, 'tslint.json')),
|
||||
tslint: (tslintPath => fs.existsSync(tslintPath) && tslintPath)(path.resolve(rootDir, 'tslint.json')),
|
||||
formatter: 'codeframe',
|
||||
logger: consola
|
||||
}, this.options.build.useForkTsChecker)))
|
||||
}, buildOptions.useForkTsChecker)))
|
||||
} else {
|
||||
consola.warn('You need to install `fork-ts-checker-webpack-plugin` as devDependency to enable TypeScript type checking !')
|
||||
}
|
||||
@ -159,8 +162,12 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
||||
|
||||
config() {
|
||||
const config = super.config()
|
||||
const {
|
||||
options: { router, buildDir },
|
||||
buildOptions: { hotMiddleware, quiet, friendlyErrors }
|
||||
} = this.buildContext
|
||||
|
||||
const { client = {} } = this.options.build.hotMiddleware || {}
|
||||
const { client = {} } = hotMiddleware || {}
|
||||
const { ansiColors, overlayStyles, ...options } = client
|
||||
const hotMiddlewareClientOptions = {
|
||||
reload: true,
|
||||
@ -170,17 +177,17 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
||||
...options,
|
||||
name: this.name
|
||||
}
|
||||
const clientPath = `${this.options.router.base}/__webpack_hmr/${this.name}`
|
||||
const clientPath = `${router.base}/__webpack_hmr/${this.name}`
|
||||
const hotMiddlewareClientOptionsStr =
|
||||
`${querystring.stringify(hotMiddlewareClientOptions)}&path=${clientPath}`.replace(/\/\//g, '/')
|
||||
|
||||
// Entry points
|
||||
config.entry = {
|
||||
app: [path.resolve(this.options.buildDir, 'client.js')]
|
||||
app: [path.resolve(buildDir, 'client.js')]
|
||||
}
|
||||
|
||||
// Add HMR support
|
||||
if (this.options.dev) {
|
||||
if (this.dev) {
|
||||
config.entry.app.unshift(
|
||||
// https://github.com/webpack-contrib/webpack-hot-middleware/issues/53#issuecomment-162823945
|
||||
'eventsource-polyfill',
|
||||
@ -190,7 +197,7 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
||||
}
|
||||
|
||||
// Add friendly error plugin
|
||||
if (this.options.dev && !this.options.build.quiet && this.options.build.friendlyErrors) {
|
||||
if (this.dev && !quiet && friendlyErrors) {
|
||||
config.plugins.push(
|
||||
new FriendlyErrorsWebpackPlugin({
|
||||
clearConsole: false,
|
||||
|
@ -2,8 +2,10 @@ import clone from 'lodash/clone'
|
||||
import WebpackClientConfig from './client'
|
||||
|
||||
export default class WebpackModernConfig extends WebpackClientConfig {
|
||||
constructor(builder) {
|
||||
super(builder, { name: 'modern', isServer: false, isModern: true })
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
this.name = 'modern'
|
||||
this.isModern = true
|
||||
}
|
||||
|
||||
env() {
|
||||
@ -13,7 +15,7 @@ export default class WebpackModernConfig extends WebpackClientConfig {
|
||||
}
|
||||
|
||||
getBabelOptions() {
|
||||
const options = clone(this.options.build.babel)
|
||||
const options = clone(this.buildContext.buildOptions.babel)
|
||||
|
||||
options.presets = [
|
||||
[
|
||||
|
@ -9,8 +9,10 @@ import VueSSRServerPlugin from '../plugins/vue/server'
|
||||
import WebpackBaseConfig from './base'
|
||||
|
||||
export default class WebpackServerConfig extends WebpackBaseConfig {
|
||||
constructor(builder) {
|
||||
super(builder, { name: 'server', isServer: true })
|
||||
constructor(...args) {
|
||||
super(...args)
|
||||
this.name = 'server'
|
||||
this.isServer = true
|
||||
this.whitelist = this.normalizeWhitelist()
|
||||
}
|
||||
|
||||
@ -18,7 +20,7 @@ export default class WebpackServerConfig extends WebpackBaseConfig {
|
||||
const whitelist = [
|
||||
/\.(?!js(x|on)?$)/i
|
||||
]
|
||||
for (const pattern of this.options.build.transpile) {
|
||||
for (const pattern of this.buildContext.buildOptions.transpile) {
|
||||
if (pattern instanceof RegExp) {
|
||||
whitelist.push(pattern)
|
||||
} else {
|
||||
@ -68,7 +70,7 @@ export default class WebpackServerConfig extends WebpackBaseConfig {
|
||||
target: 'node',
|
||||
node: false,
|
||||
entry: {
|
||||
app: [path.resolve(this.options.buildDir, 'server.js')]
|
||||
app: [path.resolve(this.buildContext.options.buildDir, 'server.js')]
|
||||
},
|
||||
output: Object.assign({}, config.output, {
|
||||
filename: 'server.js',
|
||||
@ -85,8 +87,8 @@ export default class WebpackServerConfig extends WebpackBaseConfig {
|
||||
// https://webpack.js.org/configuration/externals/#externals
|
||||
// https://github.com/liady/webpack-node-externals
|
||||
// https://vue-loader.vuejs.org/migrating.html#ssr-externals
|
||||
if (!this.options.build.standalone) {
|
||||
this.options.modulesDir.forEach((dir) => {
|
||||
if (!this.buildContext.buildOptions.standalone) {
|
||||
this.buildContext.options.modulesDir.forEach((dir) => {
|
||||
if (fs.existsSync(dir)) {
|
||||
config.externals.push(
|
||||
nodeExternals({
|
||||
|
@ -6,10 +6,10 @@ import { warmup } from 'thread-loader'
|
||||
// https://github.com/webpack-contrib/cache-loader
|
||||
|
||||
export default class PerfLoader {
|
||||
constructor(config) {
|
||||
this.name = config.name
|
||||
this.options = config.options
|
||||
this.workerPools = PerfLoader.defaultPools(this.options)
|
||||
constructor(name, buildContext) {
|
||||
this.name = name
|
||||
this.buildContext = buildContext
|
||||
this.workerPools = PerfLoader.defaultPools({ dev: buildContext.options.dev })
|
||||
return new Proxy(this, {
|
||||
get(target, name) {
|
||||
return target[name] ? target[name] : target.use.bind(target, name)
|
||||
@ -25,13 +25,13 @@ export default class PerfLoader {
|
||||
}
|
||||
}
|
||||
|
||||
static warmupAll(options) {
|
||||
options = PerfLoader.defaultPools(options)
|
||||
PerfLoader.warmup(options.js, [
|
||||
static warmupAll({ dev }) {
|
||||
const pools = PerfLoader.defaultPools({ dev })
|
||||
PerfLoader.warmup(pools.js, [
|
||||
require.resolve('babel-loader'),
|
||||
require.resolve('@babel/preset-env')
|
||||
])
|
||||
PerfLoader.warmup(options.css, ['css-loader'])
|
||||
PerfLoader.warmup(pools.css, ['css-loader'])
|
||||
}
|
||||
|
||||
static warmup(...args) {
|
||||
@ -41,7 +41,7 @@ export default class PerfLoader {
|
||||
use(poolName) {
|
||||
const loaders = []
|
||||
|
||||
if (this.options.build.cache) {
|
||||
if (this.buildContext.buildOptions.cache) {
|
||||
loaders.push({
|
||||
loader: 'cache-loader',
|
||||
options: {
|
||||
@ -50,7 +50,7 @@ export default class PerfLoader {
|
||||
})
|
||||
}
|
||||
|
||||
if (this.options.build.parallel) {
|
||||
if (this.buildContext.buildOptions.parallel) {
|
||||
const pool = this.workerPools[poolName]
|
||||
if (pool) {
|
||||
loaders.push({
|
||||
|
@ -19,34 +19,29 @@ export const orderPresets = {
|
||||
}
|
||||
|
||||
export default class PostcssConfig {
|
||||
constructor(options, nuxt) {
|
||||
this.nuxt = nuxt
|
||||
this.dev = options.dev
|
||||
this.postcss = options.build.postcss
|
||||
this.srcDir = options.srcDir
|
||||
this.rootDir = options.rootDir
|
||||
this.cssSourceMap = options.build.cssSourceMap
|
||||
this.modulesDir = options.modulesDir
|
||||
constructor(buildContext) {
|
||||
this.buildContext = buildContext
|
||||
}
|
||||
|
||||
get postcssOptions() {
|
||||
return this.buildContext.buildOptions.postcss
|
||||
}
|
||||
|
||||
get defaultConfig() {
|
||||
const { dev, srcDir, rootDir, modulesDir } = this.buildContext.options
|
||||
return {
|
||||
sourceMap: this.cssSourceMap,
|
||||
sourceMap: this.buildContext.buildOptions.cssSourceMap,
|
||||
plugins: {
|
||||
// https://github.com/postcss/postcss-import
|
||||
'postcss-import': {
|
||||
resolve: createResolver({
|
||||
alias: {
|
||||
'~': path.join(this.srcDir),
|
||||
'~~': path.join(this.rootDir),
|
||||
'@': path.join(this.srcDir),
|
||||
'@@': path.join(this.rootDir)
|
||||
'~': path.join(srcDir),
|
||||
'~~': path.join(rootDir),
|
||||
'@': path.join(srcDir),
|
||||
'@@': path.join(rootDir)
|
||||
},
|
||||
modules: [
|
||||
this.srcDir,
|
||||
this.rootDir,
|
||||
...this.modulesDir
|
||||
]
|
||||
modules: [ srcDir, rootDir, ...modulesDir ]
|
||||
})
|
||||
},
|
||||
|
||||
@ -55,7 +50,7 @@ export default class PostcssConfig {
|
||||
|
||||
// https://github.com/csstools/postcss-preset-env
|
||||
'postcss-preset-env': this.preset || {},
|
||||
'cssnano': this.dev ? false : { preset: 'default' }
|
||||
'cssnano': dev ? false : { preset: 'default' }
|
||||
},
|
||||
// Array, String or Function
|
||||
order: 'cssnanoLast'
|
||||
@ -65,7 +60,8 @@ export default class PostcssConfig {
|
||||
searchConfigFile() {
|
||||
// Search for postCSS config file and use it if exists
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
for (const dir of [this.srcDir, this.rootDir]) {
|
||||
const { srcDir, rootDir } = this.buildContext.options
|
||||
for (const dir of [ srcDir, rootDir ]) {
|
||||
for (const file of [
|
||||
'postcss.config.js',
|
||||
'.postcssrc.js',
|
||||
@ -82,12 +78,12 @@ export default class PostcssConfig {
|
||||
}
|
||||
|
||||
configFromFile() {
|
||||
const loaderConfig = (this.postcss && this.postcss.config) || {}
|
||||
const loaderConfig = (this.postcssOptions && this.postcssOptions.config) || {}
|
||||
loaderConfig.path = loaderConfig.path || this.searchConfigFile()
|
||||
|
||||
if (loaderConfig.path) {
|
||||
return {
|
||||
sourceMap: this.cssSourceMap,
|
||||
sourceMap: this.buildContext.buildOptions.cssSourceMap,
|
||||
config: loaderConfig
|
||||
}
|
||||
}
|
||||
@ -117,7 +113,7 @@ export default class PostcssConfig {
|
||||
// Map postcss plugins into instances on object mode once
|
||||
config.plugins = this.sortPlugins(config)
|
||||
.map((p) => {
|
||||
const plugin = this.nuxt.resolver.requireModule(p)
|
||||
const plugin = this.buildContext.nuxt.resolver.requireModule(p)
|
||||
const opts = plugins[p]
|
||||
if (opts === false) {
|
||||
return // Disabled
|
||||
@ -130,7 +126,7 @@ export default class PostcssConfig {
|
||||
|
||||
config() {
|
||||
/* istanbul ignore if */
|
||||
if (!this.postcss) {
|
||||
if (!this.postcssOptions) {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -139,7 +135,7 @@ export default class PostcssConfig {
|
||||
return config
|
||||
}
|
||||
|
||||
config = this.normalize(cloneDeep(this.postcss))
|
||||
config = this.normalize(cloneDeep(this.postcssOptions))
|
||||
|
||||
// Apply default plugins
|
||||
if (isPureObject(config)) {
|
||||
|
@ -6,24 +6,20 @@ import { wrapArray } from '@nuxt/utils'
|
||||
import PostcssConfig from './postcss'
|
||||
|
||||
export default class StyleLoader {
|
||||
constructor(options, nuxt, { isServer, perfLoader }) {
|
||||
constructor(buildContext, { isServer, perfLoader }) {
|
||||
this.buildContext = buildContext
|
||||
this.isServer = isServer
|
||||
this.perfLoader = perfLoader
|
||||
this.rootDir = options.rootDir
|
||||
this.loaders = {
|
||||
vueStyle: options.build.loaders.vueStyle,
|
||||
css: options.build.loaders.css,
|
||||
cssModules: options.build.loaders.cssModules
|
||||
}
|
||||
this.extractCSS = options.build.extractCSS
|
||||
this.resources = options.build.styleResources
|
||||
this.sourceMap = Boolean(options.build.cssSourceMap)
|
||||
|
||||
if (options.build.postcss) {
|
||||
this.postcssConfig = new PostcssConfig(options, nuxt)
|
||||
if (buildContext.options.build.postcss) {
|
||||
this.postcssConfig = new PostcssConfig(buildContext)
|
||||
}
|
||||
}
|
||||
|
||||
get extractCSS() {
|
||||
return this.buildContext.buildOptions.extractCSS
|
||||
}
|
||||
|
||||
get exportOnlyLocals() {
|
||||
return Boolean(this.isServer && this.extractCSS)
|
||||
}
|
||||
@ -34,19 +30,20 @@ export default class StyleLoader {
|
||||
}
|
||||
|
||||
styleResource(ext) {
|
||||
const extResource = this.resources[ext]
|
||||
const { buildOptions: { styleResources }, options: { rootDir } } = this.buildContext
|
||||
const extResource = styleResources[ext]
|
||||
// style-resources-loader
|
||||
// https://github.com/yenshih/style-resources-loader
|
||||
if (!extResource) {
|
||||
return
|
||||
}
|
||||
const patterns = wrapArray(extResource).map(p => path.resolve(this.rootDir, p))
|
||||
const patterns = wrapArray(extResource).map(p => path.resolve(rootDir, p))
|
||||
|
||||
return {
|
||||
loader: 'style-resources-loader',
|
||||
options: Object.assign(
|
||||
{ patterns },
|
||||
this.resources.options || {}
|
||||
styleResources.options || {}
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -66,7 +63,7 @@ export default class StyleLoader {
|
||||
|
||||
return {
|
||||
loader: 'postcss-loader',
|
||||
options: Object.assign({ sourceMap: this.sourceMap }, config)
|
||||
options: Object.assign({ sourceMap: this.buildContext.buildOptions.cssSourceMap }, config)
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,32 +91,34 @@ export default class StyleLoader {
|
||||
styleLoader() {
|
||||
return this.extract() || {
|
||||
loader: 'vue-style-loader',
|
||||
options: this.loaders.vueStyle
|
||||
options: this.buildContext.buildOptions.loaders.vueStyle
|
||||
}
|
||||
}
|
||||
|
||||
apply(ext, loaders = []) {
|
||||
const { css, cssModules } = this.buildContext.buildOptions.loaders
|
||||
|
||||
const customLoaders = [].concat(
|
||||
this.postcss(),
|
||||
this.normalize(loaders),
|
||||
this.styleResource(ext)
|
||||
).filter(Boolean)
|
||||
|
||||
this.loaders.css.importLoaders = this.loaders.cssModules.importLoaders = customLoaders.length
|
||||
css.importLoaders = cssModules.importLoaders = customLoaders.length
|
||||
|
||||
return [
|
||||
// This matches <style module>
|
||||
{
|
||||
resourceQuery: /module/,
|
||||
use: this.perfLoader.css().concat(
|
||||
this.cssModules(this.loaders.cssModules),
|
||||
this.cssModules(cssModules),
|
||||
customLoaders
|
||||
)
|
||||
},
|
||||
// This matches plain <style> or <style scoped>
|
||||
{
|
||||
use: this.perfLoader.css().concat(
|
||||
this.css(this.loaders.css),
|
||||
this.css(css),
|
||||
customLoaders
|
||||
)
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ describe('basic generate', () => {
|
||||
})
|
||||
|
||||
test('Check builder', () => {
|
||||
expect(builder.bundleBuilder.context.isStatic).toBe(true)
|
||||
expect(builder.bundleBuilder.buildContext.isStatic).toBe(true)
|
||||
expect(builder.build).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
|
@ -15,16 +15,18 @@ describe('webpack configuration', () => {
|
||||
])
|
||||
expect(PerfLoader.warmup).toHaveBeenCalledWith(css, ['css-loader'])
|
||||
|
||||
const perfLoader = new PerfLoader({
|
||||
name: 'test-perf',
|
||||
const perfLoader = new PerfLoader(
|
||||
'test-perf',
|
||||
{
|
||||
options: {
|
||||
dev: true,
|
||||
build: {
|
||||
dev: true
|
||||
},
|
||||
buildOptions: {
|
||||
parallel: true,
|
||||
cache: true
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
expect(perfLoader.workerPools).toMatchObject({ js, css })
|
||||
const loaders = perfLoader.use('js')
|
||||
const cacheDirectory = path.resolve('node_modules/.cache/cache-loader/test-perf')
|
||||
|
Loading…
Reference in New Issue
Block a user