likes
comments
collection
share

老记不住的Webpack知识点汇总(中)

作者站长头像
站长
· 阅读数 8

前言

因为最近一些实习的事情耽搁了博客文章的输出,但是还是在保持学习,今天刚好是周末,就继续接着上次的总结,总结一下webpack知识点。

Webpack中的Prefetch和Preload

  • prefetch(预获取):将来某些导航下可能需要的资源

  • preload(预加载):当前导航下可能需要资源

在使用import函数导入资源文件的时候,可以通过注释来说明是用prefetch还是preload。

老记不住的Webpack知识点汇总(中)

与 prefetch 指令相比,preload 指令有许多不同之处:

  • preload chunk 会在父 chunk 加载时,以并行方式开始加载。
  • prefetch chunk 会在父 chunk 加载结束后开始加载。
  • preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
  • preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。

Webpack中的CDN

CDN称之为内容分发网络(Content Delivery Network或Content Distribution Network,缩写:CDN)

  • 它是指通过相互连接的网络系统,利用最靠近每个用户的服务器;
  • 更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户;
  • 来提供高性能、可扩展性及低成本的网络内容传递给用户;

在开发完成后,我们的资源很有可能是放在CDN服务器上的,这个时候就需要在Webpack中配置一个公共前缀。

output: {
    clean: true,
    path: path.resolve(__dirname, './build'),
    // placeholder
    filename: '[name]-bundle.js',
    // 单独针对分包的文件进行命名
    chunkFilename: '[name]_chunk.js',
    //CDN地址前缀
    publicPath: 'http://aliyun.com/'
  },

但是有时候我们还面临一种情况,就是我们依赖的第三方库,我们不想自己打包,希望通过第三方CDN引入(国内外有很多免费的CDN开源库链接),

  • 国际上使用比较多的是unpkg、JSDelivr、cdnjs;
  • 国内也有一个比较好用的CDN是bootcdn;

首先,我们需要告诉Webpack不要打包这些依赖的第三方库,随后,我们再把依赖的第三方库的开源CDN链接配置到html文件中即可。

在webpack配置externals模块

externals: {
    react: "React",
    // key属性名: 排除的框架的名称
    // value值: 从CDN地址请求下来的js中提供对应的名称
    axios: "axios"
  },

在html文件中加入CDN链接

<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react/18.2.0/umd/react.production.min.js"</script>

Shimming

shimming是一个概念,是某一类功能的统称:

  • shimming翻译过来我们称之为 垫片,相当于给我们的代码填充一些垫片来处理一些问题;
  • 比如我们现在依赖一个第三方的库,这个第三方的库本身依赖lodash,但是默认没有对lodash进行导入(认为全局存在 lodash),那么我们就可以通过ProvidePlugin来实现shimming的效果;

注意:webpack并不推荐随意的使用shimming ,Webpack背后的整个理念是使前端开发更加模块化;也就是说,需要编写具有封闭性的、不存在隐含依赖(比如全局变量)的彼此隔离的模块;

我们可以通过使用ProvidePlugin来实现shimming的效果:

  • ProvidePlugin能够帮助我们在每个模块中,通过一个变量来获取一个package;
  • 如果webpack看到这个模块,它将在最终的bundle中引入这个模块;
  • 另外ProvidePlugin是webpack默认的一个插件,所以不需要专门导入;
plugins: [
    new HtmlWebpackPlugin({
      template: './index.html'
    }),
    //shimming
    new ProvidePlugin({
      axios: ['axios', 'default'],
      // get: ['axios', 'get'],
      dayjs: 'dayjs'
    })
  ]

这段代码的本质是告诉webpack:如果你遇到了至少一处用到 axios变量的模块实例,那请你将 axios package 引入进来,并将其提供给需要用到它的模块。

DLL库

DLL是什么呢?

  • DLL全程是动态链接库(Dynamic Link Library),是为软件在Windows中实现共享函数库的一种实现方式;
  • 那么webpack中也有内置DLL的功能,它指的是我们可以将能够共享,并且不经常改变的代码,抽取成一个共享的库;
  • 这个库在之后编译的过程中,会被引入到其他项目的代码中;

DDL库的使用分为两步:

  • 第一步:打包一个DLL库;
  • 第二步:项目中引入DLL库;

注意:在升级到webpack4之后,React和Vue脚手架都移除了DLL库(下面的vue作者的回复),所以知道有这么一个概念即可。

老记不住的Webpack知识点汇总(中)

Terser

什么是Terser呢?

  • Terser是一个JavaScript的解释(Parser)、Mangler(绞肉机)/Compressor(压缩机)的工具集;
  • 早期我们会使用 uglify-js来压缩、丑化我们的JavaScript代码,但是目前已经不再维护,并且不支持ES6+的语法;
  • Terser是从 uglify-es fork 过来的,并且保留它原来的大部分API以及适配 uglify-es和uglify-js@3等;

也就是说,Terser可以帮助我们压缩、丑化我们的代码,让我们的bundle变得更小。

真实开发中,我们不需要手动的通过terser来处理我们的代码,我们可以直接通过webpack来处理:

  • 在webpack中有一个minimizer属性,在production模式下,默认就是使用TerserPlugin来处理我们的代码的;
  • 如果我们对默认的配置不满意,也可以自己来创建TerserPlugin的实例,并且覆盖相关的配置;
 minimizer: [
      // JS代码简化
      new TerserPlugin({
        extractComments: false
      })
    ]

TreeShaking

什么是Tree Shaking呢?

  • Tree Shaking是一个术语,在计算机中表示消除死代码(dead_code);
  • 最早的想法起源于LISP,用于消除未调用的代码(纯函数无副作用,可以放心的消除,这也是为什么要求我们在进行函数式 编程时,尽量使用纯函数的原因之一);
  • 后来Tree Shaking也被应用于其他的语言,比如JavaScript、Dart;

事实上webpack实现Tree Shaking采用了两种不同的方案:

  • usedExports:通过标记某些函数是否被使用,之后通过Terser来进行优化的;
  • sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用;

将mode设置为development模式:

为了可以看到 usedExports带来的效果,我们需要设置为 development 模式

因为在 production 模式下,webpack默认的一些优化会带来很大的影响(production模式下默认开启usedExports)。

设置usedExports为true和false对比打包后的代码:

在usedExports设置为true时,会有一段注释:unused harmony export mul;

这段注释的意义是什么呢?告知Terser在优化时,可以删除掉这段代码;

所以,usedExports实现Tree Shaking是结合Terser来完成的。

optimization: {
    // 导入模块时, 分析模块中的哪些函数有被使用, 哪些函数没有被使用(tree shaking)
    usedExports: true,
    
    chunkIds: 'deterministic',
    // runtime的代码是否抽取到单独的包中(早Vue2脚手架中)
    runtimeChunk: {
      name: "runtime"
    },
    // 分包插件: SplitChunksPlugin
    splitChunks: {
      chunks: "all",
      minSize: 10,

      // 自己对需要进行拆包的内容进行分包
      cacheGroups: {
        utils: {
          test: /utils/,
          filename: "js/[id]_utils.js"
        },
        vendors: {
          // /node_modules/
          // window上面 /\
          // mac上面 /
          test: /[\\/]node_modules[\\/]/,
          filename: "js/[id]_vendors.js"
        }
      }
    },

sideEffects用于告知webpack compiler哪些模块时有副作用的:

副作用的意思是这里面的代码有执行一些特殊的任务,不能仅仅通过export来判断这段代码的意义;

在package.json中设置sideEffects的值:

如果我们将sideEffects设置为false,就是告知webpack可以安全的删除未用到的exports;

如果有一些我们希望保留,可以设置为数组;

比如我们有一个format.js、style.css文件:

该文件在导入时没有使用任何的变量来接受;

那么打包后的文件,不会保留format.js、style.css相关的任何代码;

//package.json

//保留所有css文件
"'sideEffects'":["*.css"],