mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-19 23:21:09 +00:00
perf: improve build speed
In practice, both thread-loader and cache (uglify, babel, cache-loader) slow down process up to 10sec with their overhead so disabled by default.
This commit is contained in:
parent
ca80e0614d
commit
ac79cf3282
@ -18,6 +18,7 @@ import upath from 'upath'
|
|||||||
import { r, wp, wChunk, createRoutes, parallel, relativeTo, waitFor, createSpinner } from '../common/utils'
|
import { r, wp, wChunk, createRoutes, parallel, relativeTo, waitFor, createSpinner } from '../common/utils'
|
||||||
import Options from '../common/options'
|
import Options from '../common/options'
|
||||||
|
|
||||||
|
import PerfLoader from './webpack/utils/perf-loader'
|
||||||
import ClientWebpackConfig from './webpack/client'
|
import ClientWebpackConfig from './webpack/client'
|
||||||
import ServerWebpackConfig from './webpack/server'
|
import ServerWebpackConfig from './webpack/server'
|
||||||
|
|
||||||
@ -39,6 +40,9 @@ export default class Builder {
|
|||||||
this.webpackHotMiddleware = null
|
this.webpackHotMiddleware = null
|
||||||
this.filesWatcher = null
|
this.filesWatcher = null
|
||||||
this.customFilesWatcher = null
|
this.customFilesWatcher = null
|
||||||
|
this.perfLoader = null
|
||||||
|
|
||||||
|
// Shared spinner
|
||||||
this.spinner = createSpinner({ minimal: this.options.minimalCLI })
|
this.spinner = createSpinner({ minimal: this.options.minimalCLI })
|
||||||
this.spinner.enabled = !this.options.test
|
this.spinner.enabled = !this.options.test
|
||||||
|
|
||||||
@ -419,7 +423,8 @@ export default class Builder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async webpackBuild() {
|
async webpackBuild() {
|
||||||
debug('Building files...')
|
this.perfLoader = new PerfLoader(this)
|
||||||
|
|
||||||
const compilersOptions = []
|
const compilersOptions = []
|
||||||
|
|
||||||
// Client
|
// Client
|
||||||
@ -449,7 +454,7 @@ export default class Builder {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Initialize compilers
|
// Configure compilers
|
||||||
this.compilers = compilersOptions.map(compilersOption => {
|
this.compilers = compilersOptions.map(compilersOption => {
|
||||||
const compiler = webpack(compilersOption)
|
const compiler = webpack(compilersOption)
|
||||||
|
|
||||||
@ -461,6 +466,13 @@ export default class Builder {
|
|||||||
return compiler
|
return compiler
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Warmup perfLoader before build
|
||||||
|
if (this.options.build.parallel) {
|
||||||
|
this.spinner.start('Warming up worker pools')
|
||||||
|
this.perfLoader.warmup()
|
||||||
|
this.spinner.succeed('Worker pools ready')
|
||||||
|
}
|
||||||
|
|
||||||
// Start Builds
|
// Start Builds
|
||||||
await parallel(this.compilers, compiler => {
|
await parallel(this.compilers, compiler => {
|
||||||
return this.webpackCompile(compiler)
|
return this.webpackCompile(compiler)
|
||||||
|
@ -99,34 +99,6 @@ export default class WebpackBaseConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
perfLoaders(_baseLoaders) {
|
|
||||||
if (this.options.dev) {
|
|
||||||
return _baseLoaders
|
|
||||||
}
|
|
||||||
|
|
||||||
const loaders = []
|
|
||||||
|
|
||||||
if (this.options.build.cache) {
|
|
||||||
// https://github.com/webpack-contrib/cache-loader
|
|
||||||
loaders.push({
|
|
||||||
loader: 'cache-loader',
|
|
||||||
options: {
|
|
||||||
cacheDirectory: path.resolve('node_modules/.cache/cache-loader')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.options.build.parallel) {
|
|
||||||
// https://github.com/webpack-contrib/thread-loader
|
|
||||||
loaders.push({
|
|
||||||
loader: 'thread-loader',
|
|
||||||
options: {}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return loaders.concat(_baseLoaders)
|
|
||||||
}
|
|
||||||
|
|
||||||
rules() {
|
rules() {
|
||||||
const styleLoader = new StyleLoader(
|
const styleLoader = new StyleLoader(
|
||||||
this.options,
|
this.options,
|
||||||
@ -134,6 +106,8 @@ export default class WebpackBaseConfig {
|
|||||||
{ isServer: this.isServer }
|
{ isServer: this.isServer }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const perfLoader = this.builder.perfLoader
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
test: /\.vue$/,
|
test: /\.vue$/,
|
||||||
@ -143,56 +117,62 @@ export default class WebpackBaseConfig {
|
|||||||
{
|
{
|
||||||
test: /\.jsx?$/,
|
test: /\.jsx?$/,
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
use: this.perfLoaders({
|
use: perfLoader.pool('js', {
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: this.getBabelOptions()
|
options: this.getBabelOptions()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/,
|
test: /\.css$/,
|
||||||
use: styleLoader.apply('css')
|
use: perfLoader.pool('css', styleLoader.apply('css'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.less$/,
|
test: /\.less$/,
|
||||||
use: styleLoader.apply('less', 'less-loader')
|
use: perfLoader.pool('css', styleLoader.apply('less', 'less-loader'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.sass$/,
|
test: /\.sass$/,
|
||||||
use: styleLoader.apply('sass', {
|
use: perfLoader.pool('css', styleLoader.apply('sass', {
|
||||||
loader: 'sass-loader',
|
loader: 'sass-loader',
|
||||||
options: { indentedSyntax: true }
|
options: { indentedSyntax: true }
|
||||||
})
|
}))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.scss$/,
|
test: /\.scss$/,
|
||||||
use: styleLoader.apply('scss', 'sass-loader')
|
use: perfLoader.pool('css', styleLoader.apply('scss', 'sass-loader'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.styl(us)?$/,
|
test: /\.styl(us)?$/,
|
||||||
use: styleLoader.apply('stylus', 'stylus-loader')
|
use: perfLoader.pool('css', styleLoader.apply('stylus', 'stylus-loader'))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|jpe?g|gif|svg)$/,
|
test: /\.(png|jpe?g|gif|svg)$/,
|
||||||
loader: 'url-loader',
|
use: perfLoader.pool('assets', {
|
||||||
options: {
|
loader: 'url-loader',
|
||||||
limit: 1000, // 1KO
|
options: {
|
||||||
name: 'img/[name].[hash:7].[ext]'
|
limit: 1000, // 1KO
|
||||||
}
|
name: 'img/[name].[hash:7].[ext]'
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||||
loader: 'url-loader',
|
use: perfLoader.pool('assets', {
|
||||||
options: {
|
loader: 'url-loader',
|
||||||
limit: 1000, // 1 KO
|
options: {
|
||||||
name: 'fonts/[name].[hash:7].[ext]'
|
limit: 1000, // 1 KO
|
||||||
}
|
name: 'fonts/[name].[hash:7].[ext]'
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(webm|mp4)$/,
|
test: /\.(webm|mp4)$/,
|
||||||
loader: 'file-loader',
|
use: perfLoader.pool('assets', {
|
||||||
options: {
|
loader: 'file-loader',
|
||||||
name: 'videos/[name].[hash:7].[ext]'
|
options: {
|
||||||
}
|
name: 'videos/[name].[hash:7].[ext]'
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
|||||||
config.optimization.minimizer = [
|
config.optimization.minimizer = [
|
||||||
new UglifyJsWebpackPlugin({
|
new UglifyJsWebpackPlugin({
|
||||||
parallel: true,
|
parallel: true,
|
||||||
cache: true,
|
cache: this.options.build.cache,
|
||||||
sourceMap: false
|
sourceMap: false
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
@ -44,7 +44,8 @@ export default class ProgressPlugin extends webpack.ProgressPlugin {
|
|||||||
const progress = Math.floor(percent * 100)
|
const progress = Math.floor(percent * 100)
|
||||||
|
|
||||||
this.state.progress = progress
|
this.state.progress = progress
|
||||||
this.state.msg = (msg && msg.length) ? msg : 'wait'
|
this.state.msg = (msg && msg.length) ? msg : (progress === 100 ? 'done' : 'still building')
|
||||||
|
this.state.details = details
|
||||||
|
|
||||||
// Process all states
|
// Process all states
|
||||||
let inProgress = false
|
let inProgress = false
|
||||||
@ -72,7 +73,9 @@ export default class ProgressPlugin extends webpack.ProgressPlugin {
|
|||||||
if (!inProgress) {
|
if (!inProgress) {
|
||||||
logUpdate.clear()
|
logUpdate.clear()
|
||||||
} else {
|
} else {
|
||||||
logUpdate('\n' + lines.join('\n') + '\n')
|
const title = chalk.bgRedBright.black('BUILDING')
|
||||||
|
|
||||||
|
logUpdate('\n' + title + '\n\n' + lines.join('\n'))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
60
lib/builder/webpack/utils/perf-loader.mjs
Normal file
60
lib/builder/webpack/utils/perf-loader.mjs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
import threadLoader from 'thread-loader'
|
||||||
|
|
||||||
|
// https://github.com/webpack-contrib/thread-loader
|
||||||
|
// https://github.com/webpack-contrib/cache-loader
|
||||||
|
|
||||||
|
export default class PerfLoader {
|
||||||
|
constructor(builder) {
|
||||||
|
this.builder = builder
|
||||||
|
this.options = builder.options
|
||||||
|
|
||||||
|
this.workerPools = {
|
||||||
|
js: {
|
||||||
|
name: 'js',
|
||||||
|
poolTimeout: this.options.dev ? Infinity : 2000
|
||||||
|
|
||||||
|
},
|
||||||
|
css: {
|
||||||
|
name: 'css',
|
||||||
|
poolTimeout: this.options.dev ? Infinity : 2000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
warmup() {
|
||||||
|
if (!this.options.build.parallel) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
threadLoader.warmup(this.workerPools.js, ['babel-loader', 'babel-preset-env'])
|
||||||
|
threadLoader.warmup(this.workerPools.css, ['css-loader'])
|
||||||
|
}
|
||||||
|
|
||||||
|
pool(poolName, _loaders) {
|
||||||
|
const loaders = [].concat(_loaders)
|
||||||
|
|
||||||
|
if (this.options.build.parallel) {
|
||||||
|
const pool = this.workerPools[poolName]
|
||||||
|
|
||||||
|
if (pool) {
|
||||||
|
loaders.unshift({
|
||||||
|
loader: 'thread-loader',
|
||||||
|
options: pool
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.build.cache) {
|
||||||
|
loaders.unshift({
|
||||||
|
loader: 'cache-loader',
|
||||||
|
options: {
|
||||||
|
cacheDirectory: path.resolve('node_modules/.cache/cache-loader')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return loaders
|
||||||
|
}
|
||||||
|
}
|
@ -37,8 +37,8 @@ export default {
|
|||||||
extractCSS: false,
|
extractCSS: false,
|
||||||
cssSourceMap: undefined,
|
cssSourceMap: undefined,
|
||||||
ssr: undefined,
|
ssr: undefined,
|
||||||
parallel: os.cpus().length > 1,
|
parallel: false,
|
||||||
cache: true,
|
cache: false,
|
||||||
publicPath: '/_nuxt/',
|
publicPath: '/_nuxt/',
|
||||||
filenames: {
|
filenames: {
|
||||||
app: '[name].[chunkhash].js',
|
app: '[name].[chunkhash].js',
|
||||||
|
@ -143,7 +143,7 @@ Options.from = function (_options) {
|
|||||||
|
|
||||||
// babel cacheDirectory
|
// babel cacheDirectory
|
||||||
if (options.build.babel.cacheDirectory === undefined) {
|
if (options.build.babel.cacheDirectory === undefined) {
|
||||||
options.build.babel.cacheDirectory = options.dev
|
options.build.babel.cacheDirectory = options.dev && options.build.cache
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resource hints
|
// Resource hints
|
||||||
|
Loading…
Reference in New Issue
Block a user