Home  >  Article  >  Web Front-end  >  About the usage of webpack caching and independent packaging

About the usage of webpack caching and independent packaging

巴扎黑
巴扎黑Original
2017-08-06 15:07:031152browse

This article mainly introduces the advanced use of webpack - caching and independent packaging. The editor thinks it is quite good, so I will share it with you now and give it as a reference. Let’s follow the editor and take a look.

This article introduces the advanced use of webpack - caching and independent packaging. I share it with you. I hope it will be helpful to everyone.

Let’s take a look at the basics first. Webpack configuration:


var path = require('path');
 
module.exports = {
 entry: './src/index.js',
 output: {
  filename: 'bundle.js',
  path: path.resolve(__dirname, 'dist')
 }
}

Introduced lodash library in index.js:

src/index.js:


import _ from 'lodash';
 
 function component() {
  var element = document.createElement('p');
  element.innerHTML = _.join(['Hello', 'webpack'], ' ');
 
  return element;
 }
 
 document.body.appendChild(component());

After packaging, only one bundle.js will be generated. In this case, every time you want to load a resource file, the browser will load the lodash library that will not change at all, which is very inefficient.

Since every time you visit the browser, the browser will re-download the resources. Since the network may be slow to obtain resources, the page may not be loaded for a long time, which is inefficient and unfriendly, so the browser will Cache resources to avoid having to fetch them over the network every time you access them.

However, due to browser caching, new problems will arise. If we do not change the file name of the resource when deploying the version, the browser may think that it has not been updated and will use its cached version. .

So we need to solve two problems: First, separate the packaging files. Second, solve the caching problem.


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  common: ['lodash'],
  app: './src/index.js'
 },
 output: {
  filename: '[name].[hash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  })
 ]
}

Main changes:

  • Add plug-in: CommonsChunkPlugin, extract the imported library, and rename it to achieve code separation .

  • A hash is added to the name in the output. After each package, the hash value is different, which solves the problem of browser caching.

Result: index.js is packaged as app.[hash].js, and lodash introduced by index.js is packaged as common.[hash].js. This solves the browser cache problem and achieves the separation of static resource code and source code, but new problems arise again.

After the first packaging (note the name under the Asset column):

Every time we modify the source code, we package it again, not only the index is generated The hash value of app.[hash].js has changed,

and the hash value of common.[hash].js is the same as the hash value of app and has also changed. (You can test it by yourself, package it once with webpack first, modify index.js and package it again).

This is not the result we want. Although the source code hash change solves the problem of the browser using the cached version, if the hash value of common.js also changes, the browser will also You also need to request the static code common that will not change every time, which still wastes network resources and is very inefficient.

Note: This case will be packaged multiple times, and too many junk files will be generated in the dist directory. In actual use, the CleanWebpackPlugin plug-in is used.

Copy code The code is as follows:


new CleanWebpackPlugin(['dist']) // Add to the plugin array for each Before packaging, all previously packaged files in the packaging folder should be cleared.

If the index is modified, only the hash value of the generated app changes, but the hash value of the common does not change, then our purpose can be achieved, which can both cache the library and identify the source. File changes.
We configure as follows: Change [name].[hash].js in output to [name].[chunkhash].js so that each file generates a unique hash value:


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  common: ['lodash'],
  app: './src/index.js'
 },
 output: {
  filename: '[name].[chunkhash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new CleanWebpackPlugin(['dist']),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  })
 ]
}

(Note: Do not use [chunkhash] in development environment as this will increase compilation time. Separate the configuration for development and production mode and use the file [name].js in development mode Name, use [name].[chunkhash].js file name in production mode, so if hot replacement is used at this time, the compilation will fail!)

We have configured it. After that, perform webpack packaging:

chunkhash is a hash generated based on the file content. It can be seen that the hash values ​​generated by app and common are different (compare using [name].[hash ].js package).

We make random modifications in index.js and package it again:

The strange thing is that although common and app generate separate hashes value, but after modifying index.js, the hash value of common still changes.

原因是:为了最小化生成的文件大小,webpack使用标识符而不是模块名称,在编译期间生成标识符,并映射到块文件名,然后放入一个名为chunk manifest的JS对象中。重点就在于!!当我们使用CommonsChunkPlugin分离代码时,被分离出来的代码(本文中的lodash库,被打包为common。),会默认被移动到entry中最后一个入口进行打包(第一个入口是index.js)。重要的是,chunk manifest将随着这些被分离出来的代码共同打包!!!

由于我们更改源代码后,不但会更新app的hash值,还会生成新的映射,然后新的映射又会和资源代码一同打包,又由于chunkhash是根据内容生成hash的,那么加入了新的映射对象chunk manifest的资源代码被打包后,hash自然也会发生改变。这反过来,产生的新hash将使长效缓存失效。

那么接下来我们需要做的就是讲 manifest分离出来。这里我们利用一个CommonsChunkPlugin一个较少有人知道的功能,能够在每次修改后的构建中将manifest提取出来,通过指定entry中未用到的名称,此插件会自动将我们需要的内容提取到单独的包中。

故再额外配置一个CommonsChunkPlugin:


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  common: ['lodash'],
  app: './src/index.js'
 },
 output: {
  filename: '[name].[chunkhash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new CleanWebpackPlugin(['dist']),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  }),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest' // 用于提取manifest
  })
 ]
}

webpack打包后:

从这里可以证明之前所说的manifest被打包进了common!!!仔细看之前的图:common的Size都是547kb,到这里common大小是541kb 而manifest大小正好为5.85kb,加起来正好为547kb。

然后我们修改index.js再次打包:

从这里可以发现!!我们修改了源代码,common的hash值已经不再发生改变了!到这里可以达到我们不缓存源代码缓存资源文件的目的了。

但是可别高兴得太早!!我们做了一个很小的修改,交换了entry中 app 和 common的顺序(对比上一个代码段):


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  app: './src/index.js',
  common: ['lodash']
 },
 output: {
  filename: '[name].[chunkhash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new CleanWebpackPlugin(['dist']),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  }),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest' // 用于提取manifest
  })
 ]
}

打包后:

这里发现对比上一张图片发现,common的hash值又发生改变了!!而且根本没有更改index.js的内容app的hash也变了,只是换了一下顺序而已!

大家注意看本张图与上一张图的模块解析顺序([1],[2],[3]...之后所对应的模块)。发现上一张图,lodash第一个解析,而现在lodash最后一个解析。

这就是hash更变的原因:这是因为每个module.id 会基于默认的解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变,所以hash值也会发生变化。

有人可能会决定,一般我们都不会更换webpack.config.js中entry的入口顺序,那么是否我就不会遇见这个问题了。答案是否定的,除否你能保证资源文件都写在entry的顶部。否则会出现这样的情况:

假如entry的顺序为: app -> common, 那么解析顺序为 index.js → lodash。 如果之后index.js引入了 print.js,那么解析顺序变为 index.js → print.js -> lodash。

以上,我们并没有在entry中更改入口顺序,解析的顺序还是会发生改变,common的hash还是会发生,不能缓存。

这里我们就引入一个新的组件:HashedModuleIdsPlugin:根据hash生成ID(NamedModulesPlugin也具有同样的效果,但是是根据路径名生成ID,可读性更高,也由此编译时间会相对长一些)。 这样module.id就不会使用数字标识符,而使用hash:


const path = require('path');
const webpack = require('webpack');
 
module.exports = {
 entry: {
  common: ['lodash'],
  app: './src/index.js'
 },
 output: {
  filename: '[name].[chunkhash].js',
  path: path.resolve(__dirname, 'dist')
 },
 plugins: [
  new CleanWebpackPlugin(['dist']),
  new webpack.HashedModuleIdsPlugin(), // 引入该插件
  new webpack.optimize.CommonsChunkPlugin({
   name: 'common' // 指代index.js引入的lodash库
  }),
  new webpack.optimize.CommonsChunkPlugin({
   name: 'manifest' // 用于提取manifest
  })
 ]
}

打包发现,之前[ ]里都是数字,现在都是一些字符,

接下来,我们再把app和common的顺序调换一下,并且随意修改index.js,再次打包:

现在大功告成,common的hash没有改变,而因为更变了内容app的hash改变了,这正是我们想要的结果。

The above is the detailed content of About the usage of webpack caching and independent packaging. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn