欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Webpack 4教程 - 第四部分,使用SplitChunksPlugin分离代码

程序员文章站 2022-05-17 16:50:54
Webpack 4 给我们带来了一些变化。其中包括更快地打包,引入了SplitChunksPlugin,并淘汰掉之前的CommomsChunksPlugin。在本文,你将学习如何拆分输出代码以提高应用的性能。 ......

转载请注明出处:,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。
原文出处:https://wanago.io/2018/06/04/code-splitting-with-splitchunksplugin-in-webpack-4/

webpack 4 给我们带来了一些变化。其中包括更快地打包,引入了splitchunksplugin,并淘汰掉之前的commomschunksplugin。在本文,你将学习如何拆分输出代码以提高应用的性能。

代码分离的思想

先说重要的:在webpack中,到底什么是代码分离?代码分离允许你把代码拆分到多个文件中。如果使用得当,你的应用性能会提高很多。因为浏览器能缓存你的代码。

每当你做出一次修改,包含修改的文件需要被所有访问你网站的人重新下载。但你并不会经常修改应用的依赖库(译者注:你常修改的是你的业务逻辑)。如果你能把那些依赖库拆分到完全分离的文件中,即使业务逻辑发生了更改,访问者也不需要再次下载依赖库,直接使用之前的缓存就可以了。

使用webpack时,你会得到一个或多个,这些文件包含了我们源码的最终输出。而它们由组成。

入口(entry)

入口定义了我们代码中应用是从哪里开始执行的,这也是webpack开始打包的地方。你可以定义一个入口(常见于单页应用),或者多个入口(常见于多页应用)。

定义一个入口,就会得到一个chunk。如果你只使用字符串定义一个入口,那么这个chunk名为main。如果你使用对象定义了多个入口,那么它们会以entry对象的属性来命名。下面的例子会得到相同的chunk:

// 例1
entry: './src/index.js'
// 例2
entry: {
  main: './src/index.js'
}

输出(output)

在配置文件中,输出配置是一个对象,它指明了webpack应该在哪儿和如何对我们的打包结果和资源进行输出。虽然可能有多个入口,但是只能有一个输出配置对象。而chunk名称的用处,就在于根据入口对应不同的输出。你可以为我们的打包输出定义一个固定的文件名,但若想代码分离,就不应该这么做。你可以使用[name]为我们的输出文件创建文件名的模板:

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

一件值得注意的重要东西是[chunkhash]:它是一个基于文件内容的属于特定chunk的哈希值。它仅会随着文件内容的改变而改变。因此,浏览器就可以利用这一点来缓存它。如果打包输出的文件名变了,浏览器就知道自己需要重新下载它。一个chunkhash可能长这样:0c553ebfd158e16da428。

我们的主chunk会被打包进一个叫main.[chunkhash].bundle.js的文件。

splitchunksplugin

由于有了splitchunksplugin,你可以把应用中的特定部分移至不同文件。如果一个模块在不止一个chunk中被使用,那么利用代码分离,该模块就可以在它们之间很好地被共享。这是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.[chunkhash].bundle.js和b.[chunkhash].bundle.js,而且每一个文件都包含对lodash库的拷贝:这并不好!我之前说过,为共享的库创建分离的文件是webpack的一个默认行为,但这只涉及异步的chunk,即意味着只作用于我们异步引入的那些文件。我们会在介绍懒加载的时候讨论这个话题。为了使这个默认行为能支持所有类型的chunks,我们需要稍微改一下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
    }
  }
}

首先,是vendors,它包含的文件来自于你node_modules。再者,是所有其他共享模块的默认缓存组。这里有一个小点:有一些冗余。a.[chunkhash].bundle.js和b.[chunkhash].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.[chunkhash].bundle.js的文件。因为我们的users.js文件所占空间远远小于30kb,在没有修改minsize属性的情况下,它不会被打包到单独的分离文件。在真实环境下,这是一件好事,因为这样不会带来实质的性能提升,反而会强制浏览器为分离出的文件(它现在是很小的)再发一次额外的请求。

我们可以进一步,为仅在utilities目录下的做特殊处理:

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
        }
      }
    }
  }
};

这样我们的输出包含4个文件:a.[chunkhash].bundle.js,b.[chunkhash].bundle.js,vendors~a~b.[chunkhash].bundle.js和utilities~a~b.[chunkhash].bundle.js。(译者注:这需要在打包之前,把users.js文件移至./src/utilities目录下,并修改a.js和b.js中的相关引用路径)。虽然我们现在可以让minsize:0成为全局设置(即放在splitchunks对象中作为其属性),但即使这样,默认的缓存组也不会被创建。因为,所有可能被引入的文件都应该在我们刚创建的utilities组下。这个组具的优先级是0,高于默认缓存组的优先级。你可能已经注意到了,默认缓存组的优先级被设置为了-20。

还有其他的配置供你使用,可查看splitchunksplugin文档

总结

即使你只有一个入口(常发生于大多数单页应用中),把你的依赖放入一个独立的文件依然是个好主意。这其实很容易做到,因为使用splitchunksplugin是webpack 4的默认行为,可能你设置一下chunks: 'all'就足够了。如果你想让我讨论此相关话题,欢迎留言。很快我们将会学习如何使用懒加载,让你的应用性能更上一层楼。敬请期待!