mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 08:02:01 +00:00
feat: experimental dll support
`.cache/` should be git ignored in projects. disabled by default. Can be enabled using `options.build.dll: true`
This commit is contained in:
parent
d1a6b2bc80
commit
d7fbe47c31
@ -10,11 +10,12 @@ import Tapable from 'tappable'
|
||||
import MFS from 'memory-fs'
|
||||
import webpackDevMiddleware from 'webpack-dev-middleware'
|
||||
import webpackHotMiddleware from 'webpack-hot-middleware'
|
||||
import { r, wp, wChunk, createRoutes, parallel, relativeTo, isPureObject } from 'utils'
|
||||
import { r, wp, wChunk, createRoutes, sequence, relativeTo, isPureObject } from 'utils'
|
||||
import Debug from 'debug'
|
||||
import Glob from 'glob'
|
||||
import clientWebpackConfig from './webpack/client.config.js'
|
||||
import serverWebpackConfig from './webpack/server.config.js'
|
||||
import dllWebpackConfig from './webpack/dll.config.js'
|
||||
import vueLoaderConfig from './webpack/vue-loader.config'
|
||||
import styleLoader from './webpack/style-loader'
|
||||
|
||||
@ -66,6 +67,29 @@ export default class Builder extends Tapable {
|
||||
})
|
||||
}
|
||||
|
||||
vendor () {
|
||||
return [
|
||||
'vue',
|
||||
'vue-router',
|
||||
'vue-meta',
|
||||
'core-js',
|
||||
'regenerator-runtime',
|
||||
'es6-promise',
|
||||
'babel-runtime',
|
||||
'vuex'
|
||||
].concat(this.options.build.vendor).filter(v => v)
|
||||
}
|
||||
|
||||
vendorEntries () {
|
||||
// Used for dll
|
||||
const vendor = this.vendor()
|
||||
const vendorEntries = {}
|
||||
vendor.forEach(v => {
|
||||
vendorEntries[v] = [ v ]
|
||||
})
|
||||
return vendorEntries
|
||||
}
|
||||
|
||||
forGenerate () {
|
||||
this.isStatic = true
|
||||
}
|
||||
@ -361,6 +385,11 @@ export default class Builder extends Tapable {
|
||||
}
|
||||
})
|
||||
|
||||
// Make a dll plugin after compile to make next dev builds faster
|
||||
if (this.options.build.dll && this.options.dev) {
|
||||
compilersOptions.push(dllWebpackConfig.call(this, clientConfig))
|
||||
}
|
||||
|
||||
// Simulate webpack multi compiler interface
|
||||
// Separate compilers are simpler, safer and faster
|
||||
this.compiler = { compilers: [] }
|
||||
@ -377,7 +406,7 @@ export default class Builder extends Tapable {
|
||||
// Initialize compilers
|
||||
compilersOptions.forEach(compilersOption => {
|
||||
const compiler = webpack(compilersOption)
|
||||
if (sharedFS) {
|
||||
if (sharedFS && !compiler.name.includes('-dll')) {
|
||||
compiler.outputFileSystem = sharedFS
|
||||
}
|
||||
compiler.cache = sharedCache
|
||||
@ -398,6 +427,9 @@ export default class Builder extends Tapable {
|
||||
if (stats.hasErrors()) {
|
||||
return
|
||||
}
|
||||
|
||||
// console.log(stats.toString({ chunks: true }))
|
||||
|
||||
// Reload renderer if available
|
||||
if (this.nuxt.renderer) {
|
||||
this.nuxt.renderer.loadResources(sharedFS || fs)
|
||||
@ -414,12 +446,21 @@ export default class Builder extends Tapable {
|
||||
await this.applyPluginsAsync('compile', { builder: this, compiler: this.compiler })
|
||||
|
||||
// Start Builds
|
||||
await parallel(this.compiler.compilers, compiler => new Promise((resolve, reject) => {
|
||||
await sequence(this.compiler.compilers, compiler => new Promise((resolve, reject) => {
|
||||
if (this.options.dev) {
|
||||
// --- Dev Build ---
|
||||
if (compiler.options.name === 'client') {
|
||||
// Client watch is started by dev-middleware
|
||||
resolve()
|
||||
} else if (compiler.options.name.includes('-dll')) {
|
||||
// DLL builds should run once
|
||||
compiler.run((err, stats) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
debug('[DLL] updated')
|
||||
resolve()
|
||||
})
|
||||
} else {
|
||||
// Build and watch for changes
|
||||
compiler.watch(this.options.watchers.webpack, (err) => {
|
||||
@ -440,7 +481,7 @@ export default class Builder extends Tapable {
|
||||
if (err) return console.error(err) // eslint-disable-line no-console
|
||||
|
||||
// Show build stats for production
|
||||
console.log(stats.toString(this.webpackStats))// eslint-disable-line no-console
|
||||
console.log(stats.toString(this.webpackStats)) // eslint-disable-line no-console
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (stats.hasErrors()) {
|
||||
|
@ -12,10 +12,11 @@ import { isUrl, urlJoin } from 'utils'
|
||||
| webpack config files
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
export default function webpackBaseConfig ({ isClient, isServer }) {
|
||||
export default function webpackBaseConfig (name) {
|
||||
const nodeModulesDir = join(__dirname, '..', 'node_modules')
|
||||
|
||||
const config = {
|
||||
name,
|
||||
devtool: this.options.dev ? 'cheap-module-source-map' : 'nosources-source-map',
|
||||
entry: {
|
||||
app: null
|
||||
@ -63,7 +64,7 @@ export default function webpackBaseConfig ({ isClient, isServer }) {
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: this.vueLoader({ isClient, isServer })
|
||||
options: this.vueLoader()
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
|
@ -7,8 +7,13 @@ import ProgressBarPlugin from 'progress-bar-webpack-plugin'
|
||||
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
|
||||
import MinifyPlugin from 'babel-minify-webpack-plugin'
|
||||
import { resolve } from 'path'
|
||||
import { existsSync } from 'fs'
|
||||
import Debug from 'debug'
|
||||
import base from './base.config.js'
|
||||
|
||||
const debug = Debug('nuxt:build')
|
||||
debug.color = 2 // Force green color
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Webpack Client Config
|
||||
@ -20,29 +25,16 @@ import base from './base.config.js'
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
export default function webpackClientConfig () {
|
||||
let config = base.call(this, { isClient: true })
|
||||
|
||||
config.name = 'client'
|
||||
let config = base.call(this, 'client')
|
||||
|
||||
// App entry
|
||||
config.entry.app = resolve(this.options.buildDir, 'client.js')
|
||||
|
||||
// Add vendors
|
||||
// This vendors should explicitly extracted
|
||||
// Even if not used in 50% of the chunks!
|
||||
const vendor = [
|
||||
'vue',
|
||||
'vue-router',
|
||||
'vue-meta',
|
||||
'core-js',
|
||||
'regenerator-runtime',
|
||||
'es6-promise',
|
||||
'babel-runtime',
|
||||
'vuex'
|
||||
].concat(this.options.build.vendor).filter(v => v)
|
||||
|
||||
// Extract vendor chunks for better caching
|
||||
const _this = this
|
||||
const totalPages = _this.routes ? _this.routes.length : 0
|
||||
const vendor = this.vendor()
|
||||
|
||||
config.plugins.push(
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'common',
|
||||
@ -56,13 +48,11 @@ export default function webpackClientConfig () {
|
||||
}
|
||||
|
||||
// Extract all explicit vendor modules
|
||||
// Vendor should explicitly extracted even if not used in 50% of the chunks!
|
||||
if (module.context && vendor.some(v => module.context.includes(v))) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Total pages
|
||||
const totalPages = _this.routes ? _this.routes.length : 0
|
||||
|
||||
// A module is extracted into the vendor chunk when...
|
||||
return (
|
||||
// If it's inside node_modules
|
||||
@ -157,6 +147,27 @@ export default function webpackClientConfig () {
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin()
|
||||
)
|
||||
|
||||
// DllReferencePlugin
|
||||
// https://github.com/webpack/webpack/tree/master/examples/dll-user
|
||||
if (this.options.build.dll) {
|
||||
const _dlls = []
|
||||
const vendorEntries = this.vendorEntries()
|
||||
const dllDir = resolve(this.options.cacheDir, config.name + '-dll')
|
||||
Object.keys(vendorEntries).forEach(v => {
|
||||
const dllManifestFile = resolve(dllDir, v + '-manifest.json')
|
||||
if (existsSync(dllManifestFile)) {
|
||||
_dlls.push(v)
|
||||
config.plugins.push(
|
||||
new webpack.DllReferencePlugin({
|
||||
// context: this.options.rootDir,
|
||||
manifest: dllManifestFile // Using full path to allow finding .js dll file
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
debug('[DLL] ' + _dlls.join(','))
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------
|
||||
|
46
lib/builder/webpack/dll.config.js
Normal file
46
lib/builder/webpack/dll.config.js
Normal file
@ -0,0 +1,46 @@
|
||||
import webpack from 'webpack'
|
||||
import { resolve } from 'path'
|
||||
import ClientConfig from './client.config'
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Webpack Dll Config
|
||||
| https://github.com/webpack/webpack/tree/master/examples/dll
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
export default function webpackDllConfig (_refConfig) {
|
||||
const refConfig = _refConfig || new ClientConfig()
|
||||
|
||||
const name = refConfig.name + '-dll'
|
||||
const dllDir = resolve(this.options.cacheDir, name)
|
||||
|
||||
let config = {
|
||||
name,
|
||||
entry: this.vendorEntries(),
|
||||
// context: this.options.rootDir,
|
||||
resolve: refConfig.resolve,
|
||||
target: refConfig.target,
|
||||
resolveLoader: refConfig.resolveLoader,
|
||||
module: refConfig.module,
|
||||
plugins: []
|
||||
}
|
||||
|
||||
config.output = {
|
||||
path: dllDir,
|
||||
filename: '[name]_[hash].js',
|
||||
library: '[name]_[hash]'
|
||||
}
|
||||
|
||||
config.plugins.push(
|
||||
new webpack.DllPlugin({
|
||||
// The path to the manifest file which maps between
|
||||
// modules included in a bundle and the internal IDs
|
||||
// within that bundle
|
||||
path: resolve(dllDir, '[name]-manifest.json'),
|
||||
|
||||
name: '[name]_[hash]'
|
||||
})
|
||||
)
|
||||
|
||||
return config
|
||||
}
|
@ -12,9 +12,7 @@ import base from './base.config.js'
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
export default function webpackServerConfig () {
|
||||
let config = base.call(this, { isServer: true })
|
||||
|
||||
config.name = 'server'
|
||||
let config = base.call(this, 'server')
|
||||
|
||||
// env object defined in nuxt.config.js
|
||||
let env = {}
|
||||
|
@ -1,4 +1,4 @@
|
||||
export default function vueLoader ({ isClient }) {
|
||||
export default function vueLoader () {
|
||||
// https://vue-loader.vuejs.org/en
|
||||
const config = {
|
||||
postcss: this.options.build.postcss,
|
||||
|
@ -33,7 +33,8 @@ Options.from = function (_options) {
|
||||
options.rootDir = hasValue(options.rootDir) ? options.rootDir : process.cwd()
|
||||
options.srcDir = hasValue(options.srcDir) ? resolve(options.rootDir, options.srcDir) : options.rootDir
|
||||
options.modulesDir = resolve(options.rootDir, hasValue(options.modulesDir) ? options.modulesDir : 'node_modules')
|
||||
options.buildDir = join(options.rootDir, options.buildDir)
|
||||
options.buildDir = resolve(options.rootDir, options.buildDir)
|
||||
options.cacheDir = resolve(options.rootDir, options.cacheDir)
|
||||
|
||||
// If app.html is defined, set the template path to the user template
|
||||
options.appTemplatePath = resolve(options.buildDir, 'views/app.template.html')
|
||||
@ -162,9 +163,11 @@ Options.defaults = {
|
||||
dev: process.env.NODE_ENV !== 'production',
|
||||
debug: undefined, // Will be equal to dev if not provided
|
||||
buildDir: '.nuxt',
|
||||
cacheDir: '.cache',
|
||||
nuxtAppDir: resolve(__dirname, '../lib/app/'), // Relative to dist
|
||||
build: {
|
||||
analyze: false,
|
||||
dll: false,
|
||||
extractCSS: false,
|
||||
cssSourceMap: undefined,
|
||||
ssr: undefined,
|
||||
@ -266,7 +269,9 @@ Options.defaults = {
|
||||
}
|
||||
},
|
||||
watchers: {
|
||||
webpack: {},
|
||||
webpack: {
|
||||
ignored: /-dll/
|
||||
},
|
||||
chokidar: {}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user