webpack—— 优化输出质量

2021-06-08  本文已影响0人  黎明的叶子

webpack 优化从两个方面入手。
一、优化开发体检。包括优化构建速度和优化使用体验。参考链接优化开发体验
二、优化输出质量,包括减少用户能感知到的加载时间(首屏加载时间)和提升流畅度(提升代码性能)。
参考webpack官网深入浅出webpack

减少用户能感知到的加载时间

  1. 压缩代码
    压缩后,代码文件会变小,且混淆。文件变小会使在网络中传输更优化一点。使用UglifyJS进行压缩。

  2. 代码分离
    代码分离是 webpack 中最引人注目的特性之一。此特性能够把代码分离到不同的 bundle 中,然后可以 按需加载或并行加载 这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,如果使用合理,会极大影响加载时间。
    代码分离是为了防止文件过大,多页面的时候有重复代码导入等原因。
    常用的代码分离方法有三种:

    • 入口起点:使用 entry 配置手动地分离代码。(也就是多页面配置,entry中有多个入口的情况下,打包出来的就是按照入口分离的。但是这种没有去除重复的。)
     // 1.入口起点   缺点:重复模块都会引入。比如lodash
      entry: {
          index: './src/index.js',
          another: './src/another-module.js',
      }, 
    
    • 防止重复:使用 SplitChunksPlugin 去重和分离 chunk。(替代了webpack3.0版本中的CommonsChunkPlugin)
      分离的方式是:
      多入口的时候:将公共的代码分离到一个默认为vendors的chunk里面。然后每个入口是一个chunk.比如我有两个入口 a.js 和 b.js 。那么打包出来的就是a.bundle.js 、 b.bundle.js、 vendors~a~b.bundle.js。
      单入口的时候:会按照设置规则打包。比如默认的设置这种。会将入口文件打包成一个文件比如index.bundle.js,将里面引用的比较大的文件,打包成单独的文件为vendors~index.bundle.js。
    // 2.防止重复  如果是多页面应用可以去重并分离。如果是单页面应用可以做到分离。 
    optimization: {
     splitChunks: {
         chunks: 'all'
     },
    },
    
    • 动态导入:通过模块中的内联函数调用来分离代码。动态引入的文件也会单独打包出来。
      包括两种方式。 第一种,推荐的,使用符合 ECMAScript提案的 import() 语法 来实现动态导入。第二种,则是 webpack 的遗留功能,使用 webpack 特定的 require.ensure。他们的原理就是利用JSONP。参考Webpack的异步加载原理及分包策略。动态导入完整代码参考官网介绍。
      动态导入的案例

异步加载原理
webpack ensure 有人称它为异步加载,也有人称为代码切割,他其实就是将 js 模块给独立导出一个.js 文件,然后使用这个模块的时候,再创建一个 script 对象,加入到 document.head 对象中,浏览器会自动帮我们发起请求,去请求这个 js 文件,然后写个回调函数,让请求到的 js 文件做一些业务操作。
异步加载 就是动态导入。通过异步加载实现了按需加载。懒加载= 按需加载。依靠的方式是动态导入的方式

  1. 按需加载。就说用的时候才加载。框架里面的路由配置。多数都配置成路由按需加载。会自动生成对应的chunk。
  2. CDN 加速
    针对 HTML 文件:不开启缓存,把 HTML 放到自己的服务器上,而不是 CDN 服务上,同时关闭自己服务器上的缓存。自己的服务器只提供 HTML 文件和数据接口。
    针对静态的 JavaScript、CSS、图片等文件:开启 CDN 和缓存,上传到 CDN 服务上去,同时给每个文件名带上由文件内容算出的 Hash 值, 例如app_a6976b6d.css 文件。 带上 Hash 值的原因是文件名会随着文件内容而变化,只要文件发生变化其对应的 URL 就会变化,它就会被重新下载,无论缓存时间有多长。
    用 Webpack 实现 CDN 的接入。配置如下:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const {WebPlugin} = require('web-webpack-plugin');

module.exports = {
  // 省略 entry 配置...
  output: {
    // 给输出的 JavaScript 文件名称加上 Hash 值
    filename: '[name]_[chunkhash:8].js',
    path: path.resolve(__dirname, './dist'),
    // 指定存放 JavaScript 文件的 CDN 目录 URL
    publicPath: '//js.cdn.com/id/',
  },
  module: {
    rules: [
      {
        // 增加对 CSS 文件的支持
        test: /\.css$/,
        // 提取出 Chunk 中的 CSS 代码到单独的文件中
        use: ExtractTextPlugin.extract({
          // 压缩 CSS 代码
          use: ['css-loader?minimize'],
          // 指定存放 CSS 中导入的资源(例如图片)的 CDN 目录 URL
          publicPath: '//img.cdn.com/id/'
        }),
      },
      {
        // 增加对 PNG 文件的支持
        test: /\.png$/,
        // 给输出的 PNG 文件名称加上 Hash 值
        use: ['file-loader?name=[name]_[hash:8].[ext]'],
      },
      // 省略其它 Loader 配置...
    ]
  },
  plugins: [
    // 使用 WebPlugin 自动生成 HTML
    new WebPlugin({
      // HTML 模版文件所在的文件路径
      template: './template.html',
      // 输出的 HTML 的文件名称
      filename: 'index.html',
      // 指定存放 CSS 文件的 CDN 目录 URL
      stylePublicPath: '//css.cdn.com/id/',
    }),
    new ExtractTextPlugin({
      // 给输出的 CSS 文件名称加上 Hash 值
      filename: `[name]_[contenthash:8].css`,
    }),
    // 省略代码压缩插件配置...
  ],
};

以上代码中最核心的部分是通过 publicPath 参数设置存放静态资源的 CDN 目录 URL, 为了让不同类型的资源输出到不同的 CDN,需要分别在:

提升流畅度

1.使用 Prepack
实际上 Prepack 就是一个部分求值器,编译代码时提前将计算结果放到编译后的代码中,而不是在代码运行时才去求值。
Prepack 的工作原理和流程大致如下:
通过 Babel 把 JavaScript 源码解析成抽象语法树(AST),以方便更细粒度地分析源码;
Prepack 实现了一个 JavaScript 解释器,用于执行源码。借助这个解释器 Prepack 才能掌握源码具体是如何执行的,并把执行过程中的结果返回到输出中。
从表面上看去这似乎非常美好,但实际上 Prepack 还不够成熟与完善。Prepack 目前还处于初期的开发阶段,局限性也很大。可以看官网或者看书。不再多做介绍。

总结

优化输出质量。就是更快的让用户能看到页面。一方面页面足够小(加载会快点,利用压缩),一次不要加载太多(解决首屏慢)。一方面则是利用网络可以一次请求4-7个请求。利用此特点,则不能全部放到一个文件中,合理的使用代码分离。进而可以做到按需加载。按需加载又解决了首屏慢的问题。另外通过cdn可以让用户访问最近的代码。加快请求。还可以做一些预加载之类的。
在页面请求渲染的整个过程中,每一项都可以有优化的点。但是物极必反。合理的利用才是最好的选择。

上一篇下一篇

猜你喜欢

热点阅读