Webpack4使用SplitChunksPlugin进行代码拆分

2019-05-09250次阅读webpack

Webpack4引入了SplitChunksPlugin,这使得commonsChunksPlugin变得过时。如何拆分输出代码以提高应用程序的性能是本文的重点。

 

webpack中的代码拆分究竟是什么?

它允许您将代码拆分为多个文件。如果使用得当,它可以大大提高应用程序的性能。其中的原因是,浏览器正在缓存您的代码。每次进行更改时,包含它的文件都必须由访问您网站的所有人重新下载。但是,您可能不会更改依赖项。如果将它们拆分为单独的文件,则访问者不必再次下载它。

 

Entry入口

Entry可以定义一个入口点(单页应用程序会发生这种情况)或多个入口点(使用多页面应用程序)。如果只使用字符串定义一个入口点,那么它将被命名为main。如果您使用一个对象定义更多,它们将以Entry对象的参数命名。下面的例子是等效的:

entry: './src/index.js'
entry: {
  main: './src/index.js'
}

 

Output输出

Output输出对象是Webpack应该如何以及在何处输出我们的包等配置。由于我们想要拆分我们的代码,所以您可以使用[name]为输出文件的文件名:

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

这里要注意的一件重要事情是[chunkhash]:它是一个特定于块的哈希,它将根据文件的内容生成。只有当文件本身的内容更改时,它才会更改,否则浏览器会缓存它。如果文件名发生更改,浏览器将知道需要重新加载。chunkhash的一个例子如:  0c553ebfd158e16da428。我们的主块将绑定到名为main.[chunkash].bundle.js的文件中。

 

SplitChunksPlugin

SplitChunksPlugin可以将应用程序的某些部分移动到单独的文件中。如果一个模块在多个块中使用,那么可以很容易地在它们之间共享。这是Webpack的默认行为。

utilities/users.js

export default [
  { firstName: "Adam", age: 28 },
  { firstName: "Jane", age: 24 },
  { firstName: "Ben",  age: 31 },
  { firstName: "Lucy", age: 40 }
]

a.js

import _ from 'lodash';
import users from './users';
 
const adam = _.find(users, { firstName: 'Adam' });

b.js

import _ from 'lodash';
import users from './users';
 
const lucy = _.find(users, { firstName: 'Lucy' });

webpack.config.js

module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  }
};

运行它,您可以看到webpack创建了两个文件:a.[chunkash].bundle.js和b.[chunkash].bundle.js,每个文件都包含一个lodash库的副本:这不是很好!之前说过,为共享库创建单独的文件是webpack的默认行为,但这与异步块有关,这意味着我们异步导入的文件。在描述懒惰加载时,我们将更详细地讨论这个主题。要涉及所有类型的块,我们需要稍微更改webpack配置:

webpack.config.js

module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all"
    }
  },
};

现在我们可以看到vendors~a~b.[chunkhash].bundle.js文件已创建并包含Lodash库。即默认情况下我们有一些开箱即用的cacheGroups配置:

splitChunks: {
    chunks: "all",
    cacheGroups: {
      vendors: {
        test: /[\\/]node_modules[\\/]/,
        priority: -10
      },
      default: {
        minChunks: 2,
        priority: -20,
        reuseExistingChunk: true
      }
    }
  }

首先是包含node_modules文件的vendors。其次是所有其他共享模块的默认缓存组。这里有一个小问题:发生了冗余。a.[chunkash].bundle.js和b.[chunkash].bundle.js都包含users.js内容。这是因为默认情况下,SplitChunksPlugin仅对大于30KB的文件拆分块。我们可以很容易地改变:

webpack.config.js

module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all",
      minSize: 0
    }
  }
};

这导致创建了一个名为a~b.[chunkash].bundle.js的新文件。它是这里的默认缓存组。由于我们的users.js文件占用的空间比30Kb少得多,因此在不更改minSize属性的情况下,它不会捆绑到单独的文件中。实际情况下,这是一件好事,因为这不会给我们任何真正的性能提升,并会迫使浏览器对现在非常小的utilities.js文件做出额外的请求。

我们甚至可以更进一步,只是对utilities目录中的文件进行异常处理:

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
 
module.exports = {
  entry: {
    a: "./src/a.js",
    b: "./src/b.js"
  },
  output: {
    filename: "[name].[chunkhash].bundle.js",
    path: __dirname + "/dist"
  },
  optimization: {
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        utilities: {
          test: /[\\/]src[\\/]utilities[\\/]/,
          minSize: 0
        }
      }
    }
  }
};

现在我们的bundle包含4个文件:a.[chunkash].bundle.js,b.[chunkash].bundle.js,vendors~a~b.[chunkash].bundle.js和utilities~a~b.[chunkash].bundle.js。即使我们现在将minSize:0设置为全局设置(在splitchunks对象中),也不会创建默认缓存组。这是因为我们刚刚创建的实用程序组涵盖了可能包含的所有文件。它的默认优先级为0,高于默认缓存组。正如您可能已经注意到的,默认缓存组的优先级设置为-20。

您还可以设置其他默认参数,您可以在SplitChunksPlugin文档中查看。

提示:即使只有一个入口点(在大多数单页应用程序中都会发生这种情况),也最好将依赖项保存在单独的文件中。这实际上是非常简单的,因为使用splitchunksplugin是Webpack4的默认行为,并且它可能足够您在splitchunks配置中设置块:“all”。
 

上一篇: 再次认识requestAnimationFrame以及其polyfill库raf  下一篇: meta标签开启360极速模式  

Webpack4使用SplitChunksPlugin进行代码拆分相关文章