webpack性能优化打包

492 阅读1分钟

1. 样式优化

1.1 MiniCssExtractPlugin 样式抽离

使用 MiniCssExtractPlugin 抽离出 css 文件,以 link 标签的形式引入样式文件

module: { rules: [ { test: /.css$/, use: [ MiniCssExtractPlugin.loader], }, ] } 
// 创建一个 link 标签 'css-loader', 
// css-loader 负责解析 CSS 代码, 处理 CSS 中的依赖

plugins: [ // 用 MiniCssExtractPlugin 抽离出 css 文件,以 link 标签的形式引入样式文件 
new MiniCssExtractPlugin({ filename: 'index.bundle.css' // 输出的 css 文件名为 index.css 
}), ]

1.2 cssnano 样式压缩

使用 optimize-css-assets-webpack-plugin

const OptmineCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
new OptmineCSSAssetsPlugin({
    cssProcessor:reuire('cssnano')
})

1.3 css摇树

npm i glob-all purify-css purifycss-webpack -D
 const  purifycss = reuire('purifycss-webpack')
 const  glob = reuire('glob-all')
 plugins: [
     new purifycss({
         paths: glob.sync([ //glob用于匹配路径
             path.resolve(__dirname, './src/*.html'), //html 上 也有css 需要摇树
             path.resolve(__dirname, './src/*.js'),
         ])
     })
 ]

注意 由于css 是使用 import './index.css' ,会有摇掉,所以需要在package.json 配置白名单

{
 "sideEffects": ["*.css","*.sass"]
}

2. 不同环境不同config 配置

通过 webpack-merge 合并webpack.common.config.js 到当前环境

  • webpack.common.config.js
  • webpack.dev.config.js
  • webpack.prod.config.js
//package.json
{
    "scripts": {
        "dev": "webpack --config ./webpack.dev.config.js",
        "prod": "webpack --config ./webpack.prod.config.js",
    }
}

//webpack.dev.config.js
const merge = require("webpack-merge")
const commonConfig = require("./webpack.common.config.js")
const devConfig = {
    ...
}
module.exports = merage(commonConfig,devConfig);

//webpack.prod.config.js
const merge = require("webpack-merge")
const commonConfig = require("./webpack.common.config.js")
const prodConfig = {
    ...
}
module.exports = merage(commonConfig,prodConfig);

3.代码分割

//多⼊⼝ entry是个对象 下面的output 通过[name]直接输出这里的命名index和login

entry: { index: "./src/index.js", login: "./src/login.js" }
output: { filename: "[name][chunkhash:8].js",//利⽤占位符,⽂件名称不要重复 path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径 },
 

4.dependOn 依赖引入

entry: {
    index: {
        import : './src/index.js',
        depenOn: 'axios'
    },
    list: {
        import : './src/list.js',
        depenOn: 'axios'
    }
    axios: 'axios' //这里使用的项目的npm安装库
}

5.懒加载

原理:动态生成 <script>标签 动态引入js 内容

//webpack.config.js
entry :  "index.js"
output: { filename: "main.js",
    path: path.resolve(__dirname, "dist")
}, 
//src/lib/a.js
export const fna = function() {
    console.log('aa')
}
//index.js
document.onclick = async function() {
    //fna();
    let {fna} = await import('./lib/a.js')
    fna();
}

构建后为:
//dist/main.js
//dist/349.js

//重命名 懒加载文件
//index.js
document.onclick = async function() {
    //fna();
    let {fna} = await import(
    /*webpackChunkName: 'a' */ //把生成文件改为 a.js
    './lib/a.js'
    )
    fna();
}

构建后为:
//dist/main.js
//dist/a.js

6.预加载 preload


原理:动态生成 <link rel="prefetch" as="script">标签 动态先加载js资源,但不执行任何代码
//index.js
document.onclick = async function() {
    //fna();
    let {fna} = await import(
    /*webpackChunkName: 'a',webpackPrefetch: true */ //设置webpackPrefetch为true打开预加载
    './lib/a.js'
    )
    fna();
}

7.CDN引入

 7.1使用html-webpack-externals-plugin

const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
module.exports = {
    // 其它省略...
    plugins: [
        new HtmlWebpackExternalsPlugin({
          externals: [{
            module: 'vue',
            entry: 'https://xxxx/vue.min.js',
            global: 'Vue'
          }]
        })
    ],
    // 其它省略...
}
//index.html引入
<script type="text/javascript" src="https://xxxx/vue.min.js"></script>
  

7.2直接配置externals

module.exports = {
    // 其它省略...
    externals: {
        vue: 'Vue'
    },
    // 其它省略...
} 

//index.html引入
<script type="text/javascript" src="https://xxxx/vue.min.js"></script>


## 7.3 output 指定publicPath

//webpack.config.js
output:{
    publicPath: '//xxxx.com' //cdn地址
}


8.treeShaking

7.1webpack自带默认设置

webpack 满足条件:
1. ESM //webapck4 只支持es 模块 (webpack5都支持)
2. webpack production //同时是生产模式
3. optmization 设置 usedExports:true

module.exports = {
    mode: 'production',
    optmization: {
        usedExports:true
    }
}

//测试代码
//src/lib/fn.js
export function a() {
    console.log('aaa')
}
export function b() {//这时候 方法b由于没有被使用过,会被摇掉
    console.log('bbb')
}

//src/index.js
import {a} from './lib/fn'
a();

7.2 terserPlugin

module.exports = {
    optimization: {
        minimizer: [
            new TerserPlugin({
                cache:true, //打开缓存
                parallel:true, //多线程
                terserOptions: {
                    comments : false,
                    compress: {
                        unused:true, //声明 未使用代码
                        drop_debugger:true,//移除debugger
                        drop_console:true,//移除console
                        dead_code:true //无用代码
                    }
                }
            })
            
        ]
    }
}

9.compression-webpack-plugin 开启gzip

1.webpack配置使用

 const CompressionWebpackPlugin = require('compression-webpack-plugin')
  const productionGzipExtensions = /\.(js|css)(\?.*)?$/i; 
  webpackConfig.plugins.push(
    new CompressionWebpackPlugin({
      filename: '[path].gz[query]',
      algorithm: 'gzip',
      test: productionGzipExtensions,
      threshold: 10240,
      minRatio: 0.8,
      deleteOriginalAssets: true
  })

2.服务端打开 gzip

nginx配置

http {
 gzip_static on;
}

10.优化构建速度 loader & plugin

1. 优化查找范围

test include exclude  (推荐使用include

exclude 优先与 include 和test ,所以三者冲突时候,优先exclude

2. 依赖库查找

resolve.modules默认会按当前目录下 查找 node_modules,没有继续往上找,一直到找到为止。 如果已经确定是在根目录, 可以直接指定


module.exports = {
    resolve = [path.resolve(__dirname,"./node_modules")]
}

3. 优化别名

resolve.alias通过别名 将原导入的路径映射成新的导入路径 如:react 导入会有 两套代码,cjs 和 umd 默认情况 webpack 会从 ./node_modules/bin/react/index 开始递归,效率低, 我们可以直接指定地址

alias:{
    react:path.resolve(__dirname,'./node_modules/react/umd/react.production.min.js'),
    react-dom:path.resolve(__dirname,'./node_modules/react/umd/react-dom.production.min.js')
} 

4. 减少无后缀检查

extensions:['.js','.json','.jsx','ts'] 
  • 上面描述的后缀尽量少一点
  • 代码尽量带上后缀

5. 启动多线程

thread-loader

module.exports = {
    module: {
        rules : [
            {
                test : /\.jx$/
                include:path.resolve('src')
                use: [
                    'thread-loader'
                    
                    //这是 把高开销的laoder放这里 ,执行会优先与其他loader
                ]
            
            }
        ]
    }
}

6. 打开缓存,空间换时间

6.1 babel-loader优化

提升babel-loader的打包时间,打开cacheDirectory:true,系统将会生产一个公用的缓存信息,方便babel多次引用。

一般路径在 node_modules/.cache/babel-loader

   rules : [
       {
           test : /\.js$/,
           loader: 'babel-loader',
           options : {
               cacheDirectory : true
           }
       }
   ]

6.2 terser-webpack-plugin

module.exports = {
    optimization: {
        minimizer: [
            new TerserPlugin({
                cache:true, //打开缓存
                parallel true //多线程
            })
            
        ]
    }
}