1.1 场景

有时候,我们在开发项目时只会写有关 app 的代码,不会改 vender 第三方库源码,当我们改变 app 代码的时候,我们希望打包出来 bundle 不要被 app 所影响而去  改变它的版本号。比如页面已经缓存了 vue,但我们并没有改变 vue 的代码,只改变自己的业务代码,用户完全没有下载新的打包出来的 vue 的代码。

改变 app 代码,vender 变化

1.2 解决

  • 提取 vendor
  • hash -> chunkhash(代码块 hash)
  • webpack runtime 或者 manifest

接下来我们用代码演示

// src/main.js

import React from 'react';

console.log('hello world');
// webpack.conf.js

const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: {
    main: './src/main',
    vendor: ['react']
  },

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

  plugins: [
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vender',
      minChunks: Infinity
    })
  ]
};

打包结果


从打包结果来看,公共代码已经被抽离出来,但是哈希值还是一样,如果修改一个,另一个肯定也会跟着变化,我们使用 chunkhash

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

来看结果

从结果看,两个文件哈希值不一样了,试试修改 main 文件的代码,你会发现,两个文件还是同时会改变。

这里我们需要把 webpack runtime 提取出来

plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: 'vender',
    minChunks: Infinity
  }),
  new webpack.optimize.CommonsChunkPlugin({
    name: 'runtime'
  })
];

这时修改 main 的代码,发现 vender 不会再改变,这样就达到了我们第一个目的,改变业务代码,不改变 vender

2.1 场景

引入新模块,模块顺序变化,vendor hash 变化

// src/main.js

import React from 'react';
import module from './module';

console.log('hello world');
// src/module.js

export default 'module';

打包发现,vendor 的哈希值还是会变化,即便没有被修改。

原因是在打包的同时,webpack 会给每个模块,每个 chunk 一个 id,id 发生变化的时候也会导致哈希发生变化

2.2 解决

  • NamedChunksPlugin
  • NamedModulesPlugin

来解决模块顺序的变化而导致的 vendor hash 的变化

plugins: [
  new webpack.NamedChunksPlugin(),

  new webpack.optimize.CommonsChunkPlugin({
    name: 'vender',
    minChunks: Infinity
  }),

  new webpack.optimize.CommonsChunkPlugin({
    name: 'runtime'
  })
];

可以看到,chunks id 从 0,1,2 变为了名字,修改 main 代码,也会发现 vendor 的哈希值没变,main 和 manifest 变化了。

可以通过 NamedModulesPlugin 看到更清晰的模块,chunk 是有哪些模块组成
,模块的顺序也会影响哈希值的生成

plugins: [new webpack.NamedChunksPlugin(), new webpack.NamedModulesPlugin()];

3.1 场景

动态引入模块时,vendor hash 变化

// src/async.js

export default {
  name: 'async'
};
// src/main.js

import React from 'react';
import module from './module';

import('./async').then(function(a) {
  console.log(a);
});

console.log('hello world');

结果来看,vendor 不会变化,最新版本可能做了改进,但是还是会给这个  模块新加了  一个 id 0 ,而且没有 chunkName

3.2 解决

  • 定义动态模块的 chunkName
// src/main.js

import React from 'react';
import module from './module';

import(/* webpackChunkName: 'async' */ './async').then(function(a) {
  console.log(a);
});

console.log('hello world');

4 总结

  • 独立打包 vendor
  • 抽出 manifest(webpack runtime)
  • 使用 NamedChunksPlugin 和 NamedModulePlugin
  • 动态模块给定模块名称