webpack 优化配置

1. webpack 开发和生产优化

资料参考1:https://www.cnblogs.com/wangjiachen666/p/11561186.html#_label1
资料参考2:https://blog.csdn.net/weixin_39699163/article/details/111649313
优化方向: 提升构建速度、减少构建后文件体积

2. 作用域提升(Scope Hoisting)

开发环境开启后,分析模块间的依赖关系,尽可能将被打散的模块合并到一个函数中,但不能造成代码冗余,所以只有被引用一次的模块才能被合并。

此功能开启会增加构建时间和时热模块替换功能失效,所以不可在开发环境开启

optimization: {
    concatenateModules: true, // webpack4.0 在生产环境下默认时true
  },

3. hash 缓存

1、hash:项目每次构建都会生成一个新hash,每个使用hash的文件内容改变,都会重构项目
2、chunkhash:根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,
生成对应的哈希值,每个出口的hash时不同的,也就不会相互影响。在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。并且webpack4中支持了异步import功能,顾chunkhash也作用于此。这样就会有个问题,只要对应css或则js改变,与其关联的文件hash值也会改变,但其内容并没有改变呢,所以没有达到缓存意义。顾contenthash的用途随之而来。
3、contenthash:是针对文件内容级别的,只有你自己模块的内容变了,那么hash值才改变,所以我们可以通过contenthash解决上诉问题。

所以:多出口的 output 设置 chunkhash,单入口也是chunkhash,
在通过import引入到main.js的文件,如css文件,设置contenthash

  // 打包出口设置 chunkhash
  output: {
    filename: "[name]-[chunkhash:20].js", 
  },
  // css 提取成独立文件设置 contenthash
 plugins: [
    new MiniCssExtractPlugin({
      filename: "css/[name]-[contenthash:10].css",
    }),
  },

4. webpack使用外部 cdn 资源

cdn官网: https://www.bootcdn.cn/

像jquery、vue、vue-router等依赖包、在构建项目的时候会很耗费时间、特别是如果写入构建后的主文件,体积超大,(使用cdn,可减少构建时间和减少打包后的项目体积)

  1. 安装依赖包
    cnpm i vue vue-router jquery -S
  2. 在main.js中使用
import Vue from 'vue'
import VueRouter from 'vue-router'
import $ from 'jquery'
  1. 在webpack.config.js中 配置 externals

在 externals 检测到,构建时就不构建node_modules中对应的包

externals: {
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'jquery': '$'
    },
  1. 在 index.html 中引入cdn
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <div id="app"></div>

    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
    <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  </body>
</html>

5. 配置静态资源路径(前缀拼接)

  1. 打包后在html中,为静态资源补上 url 前缀
  2. 不会上传到服务器,但是一定要上传到服务器指定位置,
output: {
    publicPath: "https://cdn.bootcss.com/assets/",
  },

6. css 压缩

将打包后的 css 文件进行压缩,减小体积从而减小带宽消耗,提升用户体验

  • 安装依赖
    cnpm i optimize-css-assets-webpack-plugin -D
  • 在 webpack 配置文件中配置
 const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
 plugins: [
    new OptimizeCSSAssetsPlugin({
      cssProcessor: require("cssnano"), //引入cssnano引擎,来自 postcss-loader
      cssProcessorOptions: {
        discardComments: { removeAll: true },
      },
    }),
]

6. html 压缩

将打包后的 html文件进行压缩,减小体积从而减小带宽消耗,提升用户体验

  • 安装依赖
    cnpm i html-webpack-plugin -D
  • 在 webpack 配置文件中配置
 plugins: [
    new HtmlWebpackPlugin({
      //选择html模板
      title: "首页",
      template: "./src/index.html",
      filename: "index.html",
      minify: {
        // 压缩HTML文件
        removeComments: true, // 移除HTML中的注释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true, // 压缩内联css
      },
    }),
  ],

7. css tree-shaking(摇树)

摇掉引入后但未使用,或者定义后没有使用的代码

1. css 摇树

  • 安装依赖:cnpm i glob-all purify-css purifycss-webpack -D
  • 在webpack配置文件中使用
const PurifyCSS = require("purifycss-webpack");
plugins: [
    // 对匹配到的文件下的css进行摇树处理
    new PurifyCSS({
      paths: glob.sync([
        path.resolve(__dirname, "./src/*.html"),  
        path.resolve(__dirname, "./src/*.js"),
      ]),
    }),
  ],

2. js 摇树

  • 说明:webpack 本身支持 js 摇树,所以配置 optimization.usedExports: true,
    开发环境不生效,只有生产环境才生效(mode:'production'),但是开发环境有注释标注哪个被使用啦
  • 注意: 只是支持 import 引入的文件摇树,不支持 commonjs 的 require 引入,针对依赖包和自定义的 js 文件
    安装依赖:cnpm i uglify-js -D (不需要配置,不安装会报错)
  • 在webpack的配置文件中
optimization: {
    usedExports: true,  
  },
回避摇树

被指定的文件将不被摇树处理

  • 在 package.json 中新增 slideEffects 属性,这个属性接收 false 或者数组,数组中放 global-all 修饰的类型文件,或者指定路径
"sideEffects": [
    "*.less"
  ],

8. 代码分割,code splitting

  • 使用 vue 这种 spa 单页应用有很多好处,但是由于后见后全部打包进入 main.js,就造成了体积过大不利于下载,无法充分利用浏览器资源,所以 我们将体积大的公共的模块分割出去,单独生产 js 文件
  • 参数:如果全部满足,则会被分割,其中注意 cacheGroups (可以将多个模块打包成一个文件,支持命名)
optimization: {
    splitChunks: {
      chunks: "all", // 支持异步和同步
      minChunks: 2, // 最少被引入次数
      automaticNameDelimiter: "-", // 分割后的连接符
      cacheGroups: {
        // odash 打包成一个独立的文件
        lodash: {
          test: /lodash/,
          name: "lodash",
        },
       // react和react-dom一起打包成一个独立的文件
        react: {
          test: /react|react-dom/,
          name: "react",
        },
      },
    },
  },

9. prefetch 预取 和 preload 预加载 (使用魔法注释的方式)

  • prefetch 预取 (页面初始不加载,等所有进程执行完空闲下来后加载,使用场景像下拉列表数据,即初始不需要展示的数据)
  • preload 预加载 (一个效果,并行执行,不等进程空闲)
// 场景 1:初始化预取,不需要马上执行的模块
import(/_webpackChunkName:'test',webpackPrefetch:true_/'./test')
/// 场景 2:等这个模块加载完执行,里面方法
async function(){
  const result = await import(/_webpackChunkName:'test',webpackPrefetch:true_/'./test')
}

10. 构建动态链接库

  1. DllPlugin 插件打包第三⽅类库,生成动态链接库, 优化构建性能
  2. .dll ⽂件称为动态链接库,用来做缓存的,在 windows 系统会经常看到,
  3. 就是先运行打包构建会生成第三方包的对应的.dll 文件,然后再次实际打包的时候会检测,将有.dll 文件的第三方包不列入打包构建范围,那么就减少了构建的时间,且不影响生产环境
  4. webpack 已经内置了对动态链接库的⽀持
    DllPlugin:⽤于打包出⼀个个单独的动态链接库⽂件
    DllReferencePlugin:⽤于在主要的配置⽂件中引⼊ DllPlugin 插件打包好的动态链接库⽂件
  • 单独创建一个 webpack 配置文件,webpack.config.dll.js 用于执行生产 dll 文件的指令,在 package 中执行 build:dll,生成 json 文件(做路径映射用的,js 文件是主文件)
//构建动态链接库的配置文件
const path = require("path");
const { DllPlugin } = require("webpack");
module.exports = {
  mode: "production",
  entry: {
    react: ["react", "react-dom"],
  },
  output: {
    path: path.resolve(__dirname, "./dist/dll/"),
    filename: "[name].dll.js",
    library: "reactLib",
  },
  plugins: [
    new DllPlugin({
      // 配置生成的dll json文件的路径
      path: path.join(__dirname, "./dist/dll/", "[name]-manifest.json"),
      // 对外暴露的函数名
      name: "react",
    }),
  ],
};
  • 在package.json中
"build:dll": "webpack --config ./webpack.config.dll.js"
  • 然后在webpack.config.js配置文件中,使用 DllReferencePlugin 用于构建时指定这个 dll 映射
const webpack = require("webpack");
plugins: [
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, "./dll/react-manifest.json"),
    }),
]
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351

推荐阅读更多精彩内容