前端进阶之路之Webpack进阶

前言

近几年来,前端领域飞速发展,前端的工作早已不再是切几张图,写几个页面那么简单,项目比较大时,很可能会多人协同开发,模块化,组件化,CSS预编译等技术也被广泛的使用。所以前端自动化工程已经成为现在的主流。
这时候Webpack就派上用场了,Webpack是一个模块加载器兼打包工具,Webpack最大的特点是能将非js资源模块化,比如图片等

Webpack 核心概念

Entry(入口):这是Webpack的入口,执行构建的第一步将从 Entry 开始,可抽象成输入。
Module(模块):在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
Chunk(代码块):一个 Chunk 由多个模块组合而成,用于代码合并与分割。指若干个js module的集合
Bundle(集合):chunk的集合最后输出的文件,一个可运行的整体
Loader(模块转换器):用于把模块原内容按照需求转换成新内容。loader可以将所有类型的文件转换为webpack能够处理的有效模块
Plugin(扩展插件) :插件可用于执行广泛的任务,从打包优化压缩到定义环境变量,可以用来处理各式各样的任务

webpack 最出色的功能之一就是,除了 JavaScript,还可以通过 loader 引入任何其他类型的文件。

Webpack的执行流程

webpack从启动到结束会依次执行以下流程:
初始化:解析webpack配置参数,生产 Compiler 实例
注册插件:调用插件的apply方法,给插件传入compiler实例的引用,插件通过compiler调用Webpack提供的API,让插件可以监听后续的所有事件节点。执行对象的 run 方法开始执行编译
开始编译:根据配置中的 entry 找出所有的入口文件
解析文件:使用loader将文件解析成抽象语法树 AST
生成依赖图谱:找出每个文件的依赖项(遍历),得到每个模块被翻译后的最终内容以及它们之间的依赖关系
输出:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表
生成最后打包的文件
ps:由于 webpack 是根据依赖图动态加载所有的依赖项,所以,每个模块都可以明确表述自身的依赖,可以避免打包未使用的模块。

Webpack优化

插件的优化:

性能问题归根到底就是项目越来越大,文件越来越复杂,导致webpack打包的bundle.js的包越来越大,页面加载也就变的越来越慢。我们可以使用一些插件来对项目进行优化

webpack-bundle-analyzer

通过使用webpack-bundle-analyzer可以看到项目各模块的大小,以便我们知道哪些包可优化空间,可以按需优化

// NPM
npm install --save-dev webpack-bundle-analyzer
// Yarn
yarn add -D webpack-bundle-analyzer
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

CommonsChunkPlugin(<4.0)

CommonsChunkPlugin主要是用来提取第三方库和公共模块,避免首屏加载的bundle文件或者按需加载的bundle文件体积过大,从而导致加载时间过长.
如果把公共文件提取出一个文件,那么当用户访问了一个网页,加载了这个公共文件,再访问其他依赖公共文件的网页时,就直接使用文件在浏览器的缓存,这样公共文件就只用被传输一次。

CommonsChunkPlugin的可配置属性:

  • name:可以是已经存在的chunk(一般指入口文件)对应的name,那么就会把公共模块代码合并到这个chunk上;否则,会创建名字为name的commons chunk进行合并
  • filename:指定commons chunk的文件名
  • chunks:指定chunk来源,指定从哪些chunk当中去找公共模块。省略该选项的时候,默认就是entry chunks
  • minChunks:可以是数字或函数,也可以是Infinity,是指模块被多少个chunk公共引用才被抽取出来成为commons chunk
  • deepChildren: 设置为true那么所有chunk的后代模块都会被选择
entry: {
    vendor: ["jquery", "other-lib"], // 明确第三方库
    app: "./entry"
  },
  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: "vendor",
      // filename: "vendor.js"
      // (给 chunk 一个不同的名字)

      minChunks: Infinity,
      // (随着 entry chunk 越来越多,
      // 这个配置保证没其它的模块会打包进 vendor chunk)
    })
  ]

  // 打包后的文件
  <script src="vendor.js" charset="utf-8"></script>
  <script src="app.js" charset="utf-8"></script>

SplitChunksPlugin

CommonsChunkPlugin于4.0及以后被移除,使用SplitChunksPlugin替代。SplitChunksPlugin开箱即用 对于大多数的用户很好用.

webpack将根据以下条件自动拆分代码块:

  1. 会被共享的代码块或者 node_mudules 文件夹中的代码块
  2. 体积大于30KB的代码块(在gz压缩前)
  3. 按需加载代码块时的并行请求数量不超过5个
  4. 加载初始页面时的并行请求数量不超过3个
 optimization: {
    splitChunks: {
      chunks: 'all', // 只对异步加载的模块进行拆分,可选值还有all | initial
      minSize: 0, // 模块最少大于30KB才拆分
      maxSize: 0,  // 模块大小无上限,只要大于30KB都拆分
      minChunks: 1, // 模块最少引用一次才会被拆分
      maxAsyncRequests: 5, // 异步加载时同时发送的请求数量最大不能超过5,超过5的部分不拆分
      maxInitialRequests: 3, // 页面初始化时同时发送的请求数量最大不能超过3,超过3的部分不拆分
      automaticNameDelimiter: '-', // 默认的连接符
      name: true, // 拆分的chunk名,设为true表示根据模块名和CacheGroup的key来自动生成,使用上面连接符连接
      cacheGroups: { // 缓存组配置,上面配置读取完成后进行拆分,如果需要把多个模块拆分到一个文件,就需要缓存,所以命名为缓存组
        vendors: { // 自定义缓存组名
          name: 'venders',
          test: /[\\/]node_modules[\\/]/, // 检查node_modules目录,只要模块在该目录下就使用上面配置拆分到这个组
          priority: -10 // 权重-10,决定了哪个组优先匹配,例如node_modules下有个模块要拆分,同时满足vendors和default组,此时就会分到vendors组,因为-10 > -20
        },
        commons: { // 默认缓存组名
          name: 'commons',
          minChunks: 2, // 最少引用两次才会被拆分
          priority: -20, // 权重-5
          reuseExistingChunk: true, // 如果主入口中引入了两个模块,其中一个正好也引用了后一个,就会直接复用,无需引用两次
          test: /[\\/]src[\\/]/,
          minSize: 0,
          chunks: "all"
        }
      }
    }
  }

UglifyJSPlugin

uglifyJsPlugin 用来对js文件进行压缩,从而减小js文件的大小,加速load速度。该插件会分析JS代码语法树,理解代码的含义,从而做到去掉无效代码、去掉日志输入代码、缩短变量名等优化。
uglifyJsPlugin会拖慢webpack的编译速度,所以一般建议在开发环境下将其关闭,生产环境下用

plugins: [
      new UglifyJSPlugin({
          compress: {
              warnings: false,  //删除无用代码时不输出警告
              drop_console: true,  //删除所有console语句,可以兼容IE
              collapse_vars: true,  //内嵌已定义但只使用一次的变量
              reduce_vars: true,  //提取使用多次但没定义的静态值到变量
          },
          output: {
              beautify: false, //最紧凑的输出,不保留空格和制表符
              comments: false, //删除所有注释
          }
      })
  ]

图片的优化:

图像占了页面大小很大的空间。虽然他们不会阻塞呈现,但是它们占用了很大一部分带宽。
我们可以通过减小体积或者转化处理减少请求来对他进行优化,

url-loader

url-loader 功能类似于 file-loader,但是在文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL。
当图片小于limit(单位:byte)大小时转base64,大于limit时调用file-loader对图片进行处理。从而可以减少http请求

module.exports = {
  module: {
    rules: [
      {
        test: /\.(jpe?g|png|gif)$/,
        loader: 'url-loader',
        options: {
          // Inline files smaller than 10 kB (10240 bytes)
          limit: 10 * 1024,
        },
      },
    ],
  }
};

svg-url-loader

svg-url-loader 的工作原理与 url-loader 类似 — 只是它使用的是URL编码而不是Base64编码来编码文件。这对SVG图像很有用 — 因为SVG文件只是纯文本,这种编码更高效。

module.exports = {
  module: {
    rules: [
      {
        test: /\.svg$/,
        loader: 'svg-url-loader',
        options: {
          // Inline files smaller than 10 kB (10240 bytes)
          limit: 10 * 1024,
          // Remove the quotes from the url
          // (they’re unnecessary in most cases)
          noquotes: true,
        },
      },
    ],
  },
};

image-webpack-loader

image-webpack-loader 可支持JPG、PNG、GIF和SVG图像的压缩。需要配合url-loader这些一起使用

module: {
    rules: [
          {
            test: /\.(png|jpg|gif)$/i,
            use: [
              {
                loader: 'url-loader',
                options: {
                  limit: 100,
                },
              },
               {
                loader: 'image-webpack-loader',
                options: {
                  pngquant: {
                    quality: [0.25, 0.60],
                    speed: 4
                  },
                },
              },
            ],
          }
    ]
    ...
}

css的优化:

css常用 css-loader 和 style-loader

css-loader:用来处理css文件
style-loader:把js中import引入的样式代码打包到js中,将样式插入到style标签中
mini-css-extract-plugin:将CSS提取为独立的文件的插件,对每个包含css的js文件都会创建一个CSS文件,可以以link插入css文件,支持按需加载css和sourceMap

发布了2 篇原创文章 · 获赞 7 · 访问量 391

猜你喜欢

转载自blog.csdn.net/mclryan/article/details/104455993