上一章咱們介紹了Webpack經常使用配置和大體優化思路,這一章節咱們來看一下具體怎麼優化(未完待續,大佬們能夠在評論中提點意見)css
git地址:github.com/jxs7754/dem…html
const SpeedMeasureWebpackPlugin = reqire('speed-measure-webpack-plugin');
const smp = new SeedMeasureWebpackPlugin();
const webpackCofig = smp.wrap({
plugins:[
// MyPlugin(),
]
})
複製代碼
能夠分析整個打包的總耗時,能夠查看每一個loader和plugins的耗時狀況;vue
{
module:{
rules: [
{
test: '/.js$/',
use: [
{
loader: 'thread-loader',
options:{
workers: 3,
}
},
'babel-loader'
]
}
]
}
}
複製代碼
const HappyPack = require('happypack');
exports.module = {
rules: [
{
test: /.js$/,
// 1) replace your original list of loaders with "happypack/loader":
// loaders: [ 'babel-loader?presets[]=es2015' ],
use: 'happypack/loader',
include: [ /* ... */ ],
exclude: [ /* ... */ ]
}
]
};
exports.plugins = [
// 2) create the plugin:
new HappyPack({
// 3) re-add the loaders you replaced above in #1:
loaders: [ 'babel-loader?presets[]=es2015' ]
})
];
複製代碼
// terser-webpack-plugin
module.exports = {
optimization: {
minimizer: {
new TerserPlugin({
parallel: 4,
})
}
}
}
// 下面這倆個插件能夠配置多線程
// parallel-uglify-plugin
// uglifyjs-webpack-plugin
複製代碼
設置Externals,使用 html-webpack-externals-plugin將基礎包(vue vue-router)經過CDN,不打入包中。node
new HtmlWebpackExternalsPlugin({
externals: [
{
module: 'react',
entry: 'https://xxx/react.min.js',
global: 'React',
},
{
module: 'react-dom',
entry: 'https://xxx/react-dom.min.js',
global: 'ReactDOM',
},
],
}),
複製代碼
沒有CDN的狀況 能夠預編譯 DllPlugin進行分包,DllReferencePlugin對manifest.json 引用react
// 分包
module.exports = {
mode: 'production',
entry: {
vue: ['vue/dist/vue.esm.js', 'vue-router', 'vuex'],
axios: ['axios', 'qs'],
// ui: ['element-ui'],
},
output: {
filename: '[name]_[chunkhash:8].dll.js',
path: path.join(__dirname, 'build'),
library: '[name]',
},
plugins: [
new CleanWebpackPlugin(),
new webpack.DllPlugin({
name: '[name]_[hash]',
path: path.join(__dirname, 'build/[name].json'),
}),
],
};
// 引用
module.exports = {
plugins: [
...['vue', 'axios'].map((item) => new webpack.DllReferencePlugin({
context: path.join(__dirname, './build'),
manifest: require(`./build/${item}.json`),
})),
]
}
複製代碼
緩存是爲了二次構建時候,加快構建webpack
{
loader: 'babel-loader',
options:{
cacheDirectory: true
}
}
複製代碼
{
optimization: {
minimizer: {
new TerserPlugin({
// 多線程
parallel: 4,
// 緩存
cache: true,
})
}
}
}
複製代碼
因爲 Loader 對文件的轉換操做很耗時,因此須要讓儘量少的文件被 Loader 處理。能夠經過 test/include/exclude 三個配置項來命中 Loader 要應用規則的文件。ios
在實戰項目中常常會依賴一些龐大的第三方模塊,以 Vue 庫爲例,發佈出去的 Vue 庫中包含多套代碼, vue.runtime.esm.js 中只包含運行時的代碼。若是不用template選項能夠直接用這個減小打包體積。git
module.exports = {
resolve: {
alias: {
'vue$': 'vue/dist/vue.runtime.esm.js',
}
}
}
複製代碼
resolve.modules 的默認值是['node_modules'],含義是先去當前目錄的node_modules目錄下去找咱們想找的模塊,若是沒找到就去上一級目錄 ../node_modules 中找,再沒有就去 ../../node_modules中找,以此類推。當安裝的第三方模塊都放在項目根目錄的 node_modules 目錄下時,就沒有必要按照默認的方式去一層層地尋找,能夠指明存放第三方模塊的絕對路徑,以減小尋找。github
module.exports = {
resolve: {
modules: [path.resolve( __dirname,'node modules')]
}
}
複製代碼
在安裝的第三方模塊中都會有一個package.json文件,用於描述這個模塊的屬性,其中能夠存在多個字段描述入口文件,緣由是某些模塊能夠同時用於多個環境中,針對不一樣的運行環境須要使用不一樣的代碼。 segmentfault.com/a/119000001…web
在導入語句沒帶文件後綴時,Webpack會自動帶上後綴去嘗試詢問文件是否存在。若是這個列表越長,或者正確的後綴越日後,就會形成嘗試的次數越多,因此resolve.extensions的配置也會影響到構建的性能在配置resolve.extensions時須要遵照如下幾點,以作到儘量地優化構建性能。
{
extensions: ['.js'],
},
複製代碼
能夠分析依賴的第三方模塊的大小、業務裏面組件的代碼大小
const BoundAnalysisPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BoundAnalysisPlugin(),
]
}
複製代碼
// 組件按需加載
import {Button} from 'element-ui';
// 模塊按需加載
import {cloneDeep} from 'lodash-es';
// Vue 路由懶加載
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
複製代碼
optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000,
minRemainingSize: 0,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 6,
maxInitialRequests: 4,
automaticNameDelimiter: '~',
automaticNameMaxLength: 30,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
複製代碼
1個模塊可能有多個方法,只要其中的某個方法使用到了,則整個文件都會被打到 bundle 裏面去,tree shaking 就是隻把用到的方法打入 bundle ,沒用到的方法會在 uglify 階段被擦除掉。 注意事項:
使用 purgecss-webpack-plugin 配合 mini-css-extract-plugin 使用
const config = {
module:{
rules: [
{
test: '/.scss$/',
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => [
// 自動擴展css
require('autoprefixer')(),
],
},
},
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: getAssetPath(
`css/[name]_[contenthash:8]'}.css`, ), }), new PurgecssPlugin({ paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }), }), ] } 複製代碼
方案 | 優勢 | 缺點 |
---|---|---|
babel-polyfill | 大而全 | 體積太大 |
@babel/plugin-transform-runtime | 只polyfill用到的方法和類,體積較小 | 不能polyfill原型上的方法 |
polyfill-service | 只返回客戶須要的polyfill | 國內奇葩瀏覽器 |
ModuleConcatenationPlugin 如今webpack4在mode 不等於none都支持
使用 image-webpack-loader進行圖片壓縮
使用 @vue/preload-webpack-plugin 實現代碼預加載
const config = {
plugins: [
new PreloadPlugin({
rel: 'preload',
include: 'initial',
fileBlacklist: [/\.map$/, /hot-update\.js$/],
}),
new PreloadPlugin({
rel: 'prefetch',
include: 'asyncChunks',
}),
]
}
複製代碼
// js
{
output: {
filename: '[name]_[chunkhash:8].js'
}
}
// css
// MiniCssExtractPlugin
{
plugins:[
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css'
})
]
}
// 圖片
// file-loader 使用hash(這裏的hash是根據內容生成的,默認是md5)
{
module:{
rules:[
{
test: /\.(png|svg|jpg|gif)$/,
use: [{
loader: 'file-loader’, options: { name: 'img/[name][hash:8].[ext] ' } }] } ] } } 複製代碼
。。。未完待續