feat: auto DLL

This commit is contained in:
Evan You
2018-01-24 20:24:43 -05:00
parent 7605bd62d2
commit 8dff383841
6 changed files with 165 additions and 90 deletions
+7 -7
View File
@@ -102,13 +102,6 @@ module.exports = (api, options) => {
child_process: 'empty'
})
const htmlPath = api.resolve('public/index.html')
webpackConfig
.plugin('html')
.use(require('html-webpack-plugin'), [
fs.existsSync(htmlPath) ? { template: htmlPath } : {}
])
// inject preload/prefetch to HTML
const PreloadPlugin = require('../webpack/PreloadPlugin')
webpackConfig
@@ -126,6 +119,13 @@ module.exports = (api, options) => {
include: 'asyncChunks'
}])
const htmlPath = api.resolve('public/index.html')
webpackConfig
.plugin('html')
.use(require('html-webpack-plugin'), [
fs.existsSync(htmlPath) ? { template: htmlPath } : {}
])
webpackConfig
.plugin('define')
.use(require('webpack/lib/DefinePlugin'), [
+112 -80
View File
@@ -42,95 +42,99 @@ module.exports = (api, options) => {
])
// minify JS
const UglifyPlugin = require('uglifyjs-webpack-plugin')
const uglifyPluginOptions = {
uglifyOptions: {
compress: {
// turn off flags with small gains to speed up minification
arrows: false,
collapse_vars: false, // 0.3kb
comparisons: false,
computed_props: false,
hoist_funs: false,
hoist_props: false,
hoist_vars: false,
inline: false,
loops: false,
negate_iife: false,
properties: false,
reduce_funcs: false,
reduce_vars: false,
switches: false,
toplevel: false,
typeofs: false,
// a few flags with noticable gains/speed ratio
// numbers based on out of the box vendor bundle
booleans: true, // 0.7kb
if_return: true, // 0.4kb
sequences: true, // 0.7kb
unused: true, // 2.3kb
// required features to drop conditional branches
conditionals: true,
dead_code: true,
evaluate: true
}
},
sourceMap: options.productionSourceMap,
cache: true,
parallel: true
}
// disable during tests to speed things up
if (!process.env.VUE_CLI_TEST) {
webpackConfig
.plugin('uglifyjs')
.use(require('uglifyjs-webpack-plugin'), [{
uglifyOptions: {
compress: {
// turn off flags with small gains to speed up minification
arrows: false,
collapse_vars: false, // 0.3kb
comparisons: false,
computed_props: false,
hoist_funs: false,
hoist_props: false,
hoist_vars: false,
inline: false,
loops: false,
negate_iife: false,
properties: false,
reduce_funcs: false,
reduce_vars: false,
switches: false,
toplevel: false,
typeofs: false,
// a few flags with noticable gains/speed ratio
// numbers based on out of the box vendor bundle
booleans: true, // 0.7kb
if_return: true, // 0.4kb
sequences: true, // 0.7kb
unused: true, // 2.3kb
// required features to drop conditional branches
conditionals: true,
dead_code: true,
evaluate: true
}
},
sourceMap: options.productionSourceMap,
cache: true,
parallel: true
}])
.plugin('uglify')
.use(UglifyPlugin, [uglifyPluginOptions])
}
// Chunk splits
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
// extract vendor libs into its own chunk for better caching, since they
// are more likely to stay the same.
webpackConfig
.plugin('split-vendor')
.use(CommonsChunkPlugin, [{
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(`node_modules`) > -1
)
}
}])
// Chunk splits
if (!options.dll) {
// extract vendor libs into its own chunk for better caching, since they
// are more likely to stay the same.
webpackConfig
.plugin('split-vendor')
.use(CommonsChunkPlugin, [{
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(`node_modules`) > -1
)
}
}])
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
webpackConfig
.plugin('split-manifest')
.use(CommonsChunkPlugin, [{
name: 'manifest',
minChunks: Infinity
}])
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
webpackConfig
.plugin('split-manifest')
.use(CommonsChunkPlugin, [{
name: 'manifest',
minChunks: Infinity
}])
// inline the manifest chunk into HTML
webpackConfig
.plugin('inline-manifest')
.use(require('../webpack/InlineSourcePlugin'), [{
include: /manifest\..*\.js$/
}])
// inline the manifest chunk into HTML
webpackConfig
.plugin('inline-manifest')
.use(require('../webpack/InlineSourcePlugin'), [{
include: /manifest\..*\.js$/
}])
// since manifest is inlined, don't preload it anymore
webpackConfig
.plugin('preload')
.tap(([options]) => {
options.fileBlacklist.push(/manifest\..*\.js$/)
return [options]
})
// since manifest is inlined, don't preload it anymore
webpackConfig
.plugin('preload')
.tap(([options]) => {
options.fileBlacklist.push(/manifest\..*\.js$/)
return [options]
})
}
// This instance extracts shared chunks from code splitted chunks and bundles them
// in a separate chunk, similar to the vendor chunk
// This CommonsChunkPlugin instance extracts shared chunks from async
// chunks and bundles them in a separate chunk, similar to the vendor chunk
// see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk
webpackConfig
.plugin('split-vendor-async')
@@ -141,6 +145,36 @@ module.exports = (api, options) => {
minChunks: 3
}])
// DLL
if (options.dll) {
const webpack = require('webpack')
const resolveClientEnv = require('../util/resolveClientEnv')
const dllEntries = Array.isArray(options.dll)
? options.dll
: Object.keys(api.service.pkg.dependencies)
webpackConfig
.plugin('dll')
.use(require('autodll-webpack-plugin'), [{
inject: true,
inherit: true,
path: 'js/',
context: api.resolve('.'),
filename: '[name].[hash:8].js',
entry: {
'vendor': [
...dllEntries,
'vue-loader/lib/component-normalizer'
]
},
plugins: [
new webpack.DefinePlugin(resolveClientEnv(options.baseUrl)),
new UglifyPlugin(uglifyPluginOptions)
]
}])
.after('preload')
}
// copy static assets in public/
webpackConfig
.plugin('copy')
@@ -162,8 +196,6 @@ module.exports = (api, options) => {
// .before('vue-loader')
// .loader('thread-loader')
// .options({ name: 'vue' })
// TODO DLL
}
})
}
+4
View File
@@ -6,6 +6,10 @@ const schema = createSchema(joi => joi.object({
compiler: joi.boolean(),
productionSourceMap: joi.boolean(),
vueLoader: joi.object(),
dll: joi.alternatives().try(
joi.boolean(),
joi.array().items(joi.string())
),
css: joi.object({
modules: joi.boolean(),
extract: joi.boolean(),
@@ -57,6 +57,18 @@ module.exports = class PreloadPlugin {
apply (compiler) {
const options = this.options
compiler.plugin('compilation', compilation => {
// Auto DLL plugin injects assets by mutating html plugin data, so the only
// way to get a hold of those is by saving the pre-mutated assets and
// comparing them later.
let originalAssets
compilation.plugin('html-webpack-plugin-before-html-generation', (htmlPluginData, cb) => {
originalAssets = [
...htmlPluginData.assets.js,
...htmlPluginData.assets.css
]
cb(null, htmlPluginData)
})
compilation.plugin('html-webpack-plugin-before-html-processing', (htmlPluginData, cb) => {
let filesToInclude = ''
let extractedChunks = []
@@ -95,11 +107,22 @@ module.exports = class PreloadPlugin {
const publicPath = compilation.outputOptions.publicPath || ''
// Only handle the chunk import by the htmlWebpackPlugin
// Only handle the chunk imported by the htmlWebpackPlugin
extractedChunks = extractedChunks.filter(chunk => doesChunkBelongToHTML(
chunk, getValues(htmlPluginData.assets.chunks), {}))
flatten(extractedChunks.map(chunk => chunk.files)).filter(entry => {
let files = flatten(extractedChunks.map(chunk => chunk.files))
// if handling initial or all chunks, also include assets injected by
// Auto DLL plugin.
if (options.include === 'initial' || options.include === 'all') {
files = [...htmlPluginData.assets.js, ...htmlPluginData.assets.css]
.filter(file => !originalAssets.includes(file))
.map(file => file.replace(publicPath, ''))
.concat(files)
}
Array.from(new Set(files)).filter(entry => {
return this.options.fileBlacklist.every(regex => regex.test(entry) === false)
}).forEach(entry => {
entry = `${publicPath}${entry}`
+1
View File
@@ -24,6 +24,7 @@
"@vue/cli-overlay": "^3.0.0-alpha.1",
"@vue/cli-shared-utils": "^3.0.0-alpha.1",
"address": "^1.0.3",
"autodll-webpack-plugin": "^0.3.8",
"autoprefixer": "^7.2.5",
"case-sensitive-paths-webpack-plugin": "^2.1.1",
"chalk": "^2.3.0",
+16 -1
View File
@@ -1003,6 +1003,21 @@ atob@^2.0.0:
version "2.0.3"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.0.3.tgz#19c7a760473774468f20b2d2d03372ad7d4cbf5d"
autodll-webpack-plugin@^0.3.8:
version "0.3.8"
resolved "https://registry.yarnpkg.com/autodll-webpack-plugin/-/autodll-webpack-plugin-0.3.8.tgz#d087dda8ca3f9e3231a15df3d42d1efde73c5777"
dependencies:
bluebird "^3.5.0"
del "^3.0.0"
find-cache-dir "^1.0.0"
lodash "^4.17.4"
make-dir "^1.0.0"
memory-fs "^0.4.1"
mkdirp "^0.5.1"
read-pkg "^2.0.0"
webpack-merge "^4.1.0"
webpack-sources "^1.0.1"
autoprefixer@^6.3.1:
version "6.7.7"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014"
@@ -9796,7 +9811,7 @@ webpack-dev-server@^2.11.0:
webpack-dev-middleware "1.12.2"
yargs "6.6.0"
webpack-merge@^4.1.1:
webpack-merge@^4.1.0, webpack-merge@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.1.tgz#f1197a0a973e69c6fbeeb6d658219aa8c0c13555"
dependencies: