webpack缓存

使用 webpack 打包模块化后的应用程序,webpack 会生成一个可部署的 /dist 目录,然后把打包后的内容放置在此目录中。只要 /dist 目录中的内容部署到 server 上,client(通常是浏览器)就能够访问此 server 的网站及其资源。而最后一步获取资源是比较耗费时间的,所以浏览器使用 缓存 的技术来降低网络流量,使网站加载速度更快。然而,如果我们在部署新版本时不更改资源的文件名,浏览器可能会认为它没有被更新,就会使用它的缓存版本。由于缓存的存在,当你需要获取新的代码时,就会显得很棘手。

在这里介绍通过必要的配置,以确保 webpack 编译生成的文件能够被客户端缓存,而在文件内容变化后,能够请求到新的文件。

输出文件的文件名(output filename)

我们可以通过替换 output.filename 中的 substitutions 设置,来定义输出文件的名称。webpack 提供了一种使用称为 substitution(可替换模板字符串) 的方式,通过带括号字符串来模板化文件名。其中,[contenthash] substitution 将根据资源内容创建出唯一 hash。当资源内容发生变化时,[contenthash] 也会发生变化。

 output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist')
  },

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  mode: 'development',
  devtool: 'inline-source-map',
  entry: {
    index: './src/index.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist')
  },
  plugins: [
    // new CleanWebpackPlugin(), // 构建前清理 /dist 文件夹
    new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
    new HtmlWebpackPlugin({ template: './src/index.html' })
    // new HtmlWebpackPlugin({ title: '管理输出' })
  ]
};

运行npm run build结果:
在这里插入图片描述
可以看到,bundle 的名称是它内容(通过 hash)的映射。如果文件不做修改,然后再次运行构建,我们以为文件名会保持不变。然而,真的运行,可能会发现情况并非如此,注意是可能,这个看webpack的版本。(本人当前demo下没有出现这个问题)

输出可能会因当前的 webpack 版本而稍有差异。与旧版本相比,新版本不一定有完全相同的问题,但我们仍然推荐的以下步骤,确保结果可靠。

提取引导模板(extracting boilerplate)

正如我们在 代码分离 中所学到的,SplitChunksPlugin 可以用于将模块分离到单独的 bundle 中。webpack 还提供了一个优化功能,可使用 optimization.runtimeChunk 选项将 runtime 代码拆分为一个单独的 chunk。将其设置为 single 来为所有 chunk 创建一个 runtime bundle。

 optimization: {
    runtimeChunk: 'single',
  },

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  mode: 'development',
  devtool: 'inline-source-map',
  entry: {
    index: './src/index.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist')
  },
  optimization: {
    runtimeChunk: 'single',
  },
  plugins: [
    // new CleanWebpackPlugin(), // 构建前清理 /dist 文件夹
    new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
    new HtmlWebpackPlugin({ template: './src/index.html' })
    // new HtmlWebpackPlugin({ title: '管理输出' })
  ]
};

将第三方库(library)(例如 lodash 或 react)提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。这样可以利用 client 的长效缓存机制,减少向 server 请求获取资源,同时还能保证 client 代码和 server 代码版本一致。 这可以通过 SplitChunksPlugin 插件的 cacheGroups 选项来实现。我们在 optimization.splitChunks 添加如下 cacheGroups 参数并构建:

splitChunks: {
       cacheGroups: {
         vendor: {
           test: /[\\/]node_modules[\\/]/,
           name: 'vendors',
           chunks: 'all',
         },
       },
     },

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  mode: 'development',
  devtool: 'inline-source-map',
  entry: {
    index: './src/index.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist')
  },
  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      // 将第三方库(library) (例如 lodash 或 react)提取到单独的 vendor chunk 文件中
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
  plugins: [
    // new CleanWebpackPlugin(), // 构建前清理 /dist 文件夹
    new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
    new HtmlWebpackPlugin({ template: './src/index.html' })
    // new HtmlWebpackPlugin({ title: '管理输出' })
  ]
};

运行npm run build结果:
在这里插入图片描述
我们可以看到 index 不再含有来自 node_modules 目录的 vendor 代码,并且体积减少到1.64kib!

以下是配置代码对比结果

optimization不做配置:

asset index.90d8de6a91772c9eed3d.js 1.38 MiB [emitted] [immutable] (name: index)
asset index.html 262 bytes [emitted]
runtime modules 1.25 KiB 6 modules
cacheable modules 530 KiB                                                                                             184ad84822250661af.js 1.61 KiB
  ./src/index.js 228 bytes [built] [code generated]
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.16.0 compiled successfully in 667 ms

增加optimization配置:

  optimization: {
    runtimeChunk: 'single',
  },
asset index.71620420237e492d60bb.js 1.37 MiB [emitted] [immutable] (name: index)
asset runtime.bcea988bda22c3d406e4.js 15.9 KiB [emitted] [immutable] (name: runtime)
asset index.html 317 bytes [emitted]
Entrypoint index 1.38 MiB = runtime.bcea988bda22c3d406e4.js 15.9 KiB index.71620420237e492d60bb.js 1.37 MiB
runtime modules 3.75 KiB 7 modules
cacheable modules 530 KiB
  ./src/index.js 228 bytes [built] [code generated]
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.16.0 compiled successfully in 660 ms

接着增加optimization配置:

  optimization: {
    runtimeChunk: 'single',
    splitChunks: {
      // 将第三方库(library) (例如 lodash 或 react)提取到单独的 vendor chunk 文件中
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
asset vendors.e7928d05f3918ae6d79c.js 1.37 MiB [emitted] [immutable] (name: vendors) (id hint: vendor)
asset runtime.bcea988bda22c3d406e4.js 15.9 KiB [emitted] [immutable] (name: runtime)
asset index.a7184ad84822250661af.js 1.61 KiB [emitted] [immutable] (name: index)
asset index.html 372 bytes [emitted]
Entrypoint index 1.39 MiB = runtime.bcea988bda22c3d406e4.js 15.9 KiB vendors.e7928d05f3918ae6d79c.js 1.37 MiB index.a7184ad84822250661af.js 1.61 KiB
runtime modules 3.75 KiB 7 modules
cacheable modules 530 KiB
  ./src/index.js 228 bytes [built] [code generated]
  ./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.16.0 compiled successfully in 590 ms
模块标识符(module identifier)

以下demo结果在本人当前webpack版本下不会出现,但是需要了解到有这种情况出现。
在这里插入图片描述
在项目中再添加一个模块 print.js,再次运行构建,然后我们期望的是,只有 main bundle 的 hash 发生变化,然而……

可以看到这三个文件的 hash 都变化了。这是因为每个 module.id 会默认地基于解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变。因此,简要概括:

  • main bundle 会随着自身的新增内容的修改,而发生变化。
  • vendor bundle 会随着自身的 module.id 的变化,而发生变化。
  • runtime bundle 会因为现在包含一个新模块的引用,而发生变化。

第一个和最后一个都是符合预期的行为,vendor hash 发生变化是我们要修复的。将 optimization.moduleIds 设置为 'deterministic'

 moduleIds: 'deterministic',

webpack.config.js文件:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
  mode: 'development',
  devtool: 'inline-source-map',
  entry: {
    index: './src/index.js',
  },
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist')
  },
  optimization: {
    moduleIds: 'deterministic',
    runtimeChunk: 'single',
    splitChunks: {
      // 将第三方库(library) (例如 lodash 或 react)提取到单独的 vendor chunk 文件中
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors',
          chunks: 'all',
        },
      },
    },
  },
  plugins: [
    // new CleanWebpackPlugin(), // 构建前清理 /dist 文件夹
    new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
    new HtmlWebpackPlugin({ template: './src/index.html' })
    // new HtmlWebpackPlugin({ title: '管理输出' })
  ]
};

现在,不论是否添加任何新的本地依赖,对于前后两次构建,vendor hash 都应该保持一致。

然后,修改 src/index.js,临时移除额外的依赖:
在这里插入图片描述
可以看到,这两次构建中,vendor bundle 文件名称没有发生变化。
在这里插入图片描述
相关代码链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值