Webpack配置-环境分离和代码分离

818 阅读8分钟
  • 环境分离

    • 第一种方案添加两个配置文件,然后添加两个 build指令分别指向两个配置文件如下图显示 image.png
    • 第二种方案是使用相同的入口配置文件但是需要在后面配置参数来区分生产环境还是开发环境
      这样做的好处就是可以将公共的配置摘取到一个文件中,不同的配置分别放到两个文件中如下图: image.png image.png image.png
    • 踩坑备注 image.png 上图我们可以发现入口文件我们配置的是"./src/test-ts/index.ts"但其实当前的配置文件并不是在根目录下的,所以有的人会以为 ./是当前目录也就是config所在的目录所以应该配置成 ../src/test-ts/index.ts其实不然,应为入口文件读取不是依赖于当前文件所在的目录的而是和context有关系的,当然如何过没有设置 context则默认是从根目录开始读起。我们现在可以尝试设置一下 context如下图: image.png
  • 代码分离

    • 为什么要进行代码分离

      如默认情况下,所有的JavaScript代码(业务代码、第三方依赖、暂时没有用到的模块)在首页全部都加载,就会影响首页的加载速度;代码分离可以分出出更小的bundle,以及控制资源加载优先级,提供代码的加载性能;

    • 代码分离方案-多入口起点

      具体配置如下图: image.png image.png 这里需要注意如果一个页面有多个入口时需设置 optimization.runtimeChunk: 'single',这里官网上都有对应的说明

    • 代码分离方案-SplitChunks

      SplitChunksPlugin 插件可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk 上文中公共模块的提起是需要自己再去配置设置依赖,这里我们就可以使用 SplitChunks帮我们做这些工作配置如下图: image.png
      一般的话我们在开发的过程中只需要设置 chunks一个参数就行其他的就是用 webpack默认配置就可以,如果项目需要特殊化配置也可以去官网查询对应的参数splitChunks对应配置参数 打包结果如下: image.png 发现将两个库分出来打包出一个文件

    • 代码分离方案-动态导入(dynamic import)

      动态导入是需要使用 es6import()来实现的,当然也可以使用 webpack遗留的 require.ensure语法来实现,但是此方法现在已经不推荐使用。

      实战中如何充分利用动态导入的特性呢? 比如有一块代码,需要满足一定的条件才去执行,此时我们就可以将这块代码独立封装出来,通过动态导入的方式,如果满足条件则加载否则不加载,这样就可以保证一些不需要执行的代码我们就可以不加载。

      具体用法如下图: image.png 打包之后发现 ./test-ts/index.js被打包在了一个单独的文件中 image.png 此时把项目跑起来发现 image.png 加载完成之后并没有加载动态导入的文件,此时点击按钮发现 image.png 动态导入的文件被加载,同时文件中的代码也被执行。

      打包成功后的文件名可以使用 chunkFilename属性来修改,具体配置如下: image.png 但是发现 idname是相同的,此时可以使用魔法注释修改 name的值具体修改方式如下图 image.png 但是修改完成其实我们还是会发现 idname是相同的,所以我们可以在命名规则上使用前六位的哈希值的方式来命名如下图: image.png

    • Prefetch和Preload

      上文中以动态导入的方式将懒加载的代码自动分割成一个文件,在需要加载的时候下载对应的代码。可以帮做一些首页加载的一些优化,然后问题在于如果被分割的文件很大,出发某个条件加载懒加载内容是,光下载这个文件就需要一点时间,那么呈现给用的的就是这个功能又有点延迟。针对这个问题这时我们就可以通过配置PrefetchPreload这两个参数这个问题

      • Prefetch
        通过魔法注释的方式添加设置成 true则懒加载的代码会在页面加载成功之后会找到空闲的时间加载懒加载内容具体配置如下: image.png image.png
      • Preload
        preload不同于 Prefetch chunk 会在父 chunk 加载时,以并行方式开始加载,具体配置同样是通过魔法注释的方式添加(平常项目建议还是使用Prefetch)如下图: image.png
    • optimization.runtimeChunk

      将运行时代码通过参数配置判断抽离成一个文件还是多个文件
      运行时代码:也就是异步加载的代码

    • 什么是CDN

      内容分发网络(英语:Content Delivery Network或Content Distribution Network,缩写:CDN)是指一种透过互联网互相连接的电脑网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、视频、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。

      通俗点讲CDN就是通过互联网链接的网络系统,其中含有 源站父节点边缘节点,如果使用 cdn首先我们会吧打包后的资源放到源站中,用户请求这些资源的时候会现从边缘节点请求,如果边缘节点没有则再去父节点查找还没有则去源站上请求最后将请求的内容分别缓存到父节点和边缘节点,这样第二个第二个用户就可以直接从边缘节点上请求到内容,如果源站在北京,那么一个新疆的用户(除了第一个发起请求的用户)请求响应速度就可以和北京的用户差不多。如下图: cdn.png 使用方式:

      • 将打包的所有资源都放到CDN服务器上
        一般项目比较大的时候会用到,通常我们只会将一些第三方的资源放到cdn服务器上具体配置如下: image.png 如果没有添加任何配置默认是冲本地服务器读取资源,我们可以通过添加 publicPath来添加CDN地址例如CDN地址是:https://tudou.com/cdn image.png image.png 此时资源都是冲CDN服务器上拉取的

      • 将一些第三方资源放到CDN服务器上 一般情况下还是将一些第三方的资源放到cdn服务器上通常一些第三方库会将自己的打包资源放到免费的cdn服务骑上具体的服务器地址第三方库的官网上应该都有 例如 dayjsimage.png 我们这边只需要在 html加入即可: image.png 但是通常对于我们开发来说应为开发阶段都是在本地创建一个服务将打包的资源放到本地服务上,这个时候访问本地服务上的资源肯定是要比访问cdn上的资源更快的,所以一般第三方库即使放到cdn也会有个判断就是开发环境下还是放到本地服务器上,生产环境放到cdn服务器上,所以可以再模板中添加环境判断是否需要通过cdn方式引入资源如下图: image.png 打包结果如下image.png 但是在生产环境就不需要再将第三方库打包,这里可以通过 webpack externals参数配置,防止将某些 import 的包(package)打包到 bundle 中,具体配置如下: image.png发现此时通过正式环境指令打包结果如下 dayjs不会被打包而是通过cdn的方式引入 image.png

        注意: 通过cdn方式引入的库导出的变量是全局变量,所以项目中需要避免创建同名变量

    • 关于defer知识点

      image.png

    • shimming

      如果我们使用的一些第三方库依赖了另外一个第三方库,但是使用时有没有对其进行导入,如果被依赖的第三方库是通过CDN方式引入的则没有问题,但是如果是通过npm方式引入的则会报错找不到对象,所以此时就可以通过 shimming来解决这个问题 image.png

    • MiniCssExtractPlugin

      MiniCssExtractPlugin可以帮助我们将css提取到一个独立的css文件中,该插件需要在webpack4+才可以使用。 配置如下: image.png 结果如下: image.png

    • Hash、ContentHash、ChunkHash
      • Hash
        hash值的生成和整个项目有关系所以一般所有文件的hash都是一样的所以但凡有一个文件有所改动重新打包后所有文件名都会变化
      • ChunkHash
        chunkhash可以有效的解决上面的问题,它会根据不同的入口进行解析来生成hash值:
      • ContentHash
        上文中如果一个入口文件分离出了多个 chunk那么如果改了一点点代码同样的对应的名称也都会会改变,但是 ContentHash示生成的文件hash名称,只和内容有关系,所以如果不是改动对应的 chunk的内容则文件名不会变换所以建议 placeholder可以使用 ContentHash