Webpack原理与实践:关于如何选择合适的打包工具Rollup和Webpack?

Rollup是一款ES Modules打包器,它也可以将项目中散落的细小模块打包成整块代码,从而使得
首页 新闻资讯 行业资讯 Webpack原理与实践:关于如何选择合适的打包工具Rollup和Webpack?

[[441993]]

写在前面

Rollup是一款ES  Modules打包器,它也可以将项目中散落的细小模块打包成整块代码,从而使得这些划分的模块可以更好地运行在浏览器或node.js环境。Rollup与webpack的作用非常类似,但是小巧的多,诞生的初衷就是希望能够提供一个高效地ES  Modules打包器,充分利用ES Modules的各项特性。

Rollup的使用

Rollup 对代码模块使用新的标准化格式,这些标准都包含在 JavaScript 的 ES6 版本中,而不是以前的特殊解决方案,如  CommonJS 和 AMD。ES6 模块可以使你自由、无缝地使用你最喜爱的 library 中那些最有用独立函数,而你的项目不必携带其他未使用的代码。ES6  模块最终还是要由浏览器原生实现,但当前 Rollup 可以使你提前体验。

首先当然是需要执行安装命令进行安装rollup,接着就和webpack一样需要配置相关的config文件。我们可以配置不同的配置文件直接用cli进行打包,但是如果添加更多地选项,这种命令行的方式就变得很麻烦。为此我们需要创建配置文件来囊括所需的选项,配置文件以rollup.config.js形式命名,比cli更加灵活。

复制

$ npm i rollup -D
  • 1.

我们看到其实rollup配置和webpack大同小异,想要更详细的配置项信息可以异步rollup官网。

复制

//src/helloWorld.js export default function sayHello(){   console.log("nihao"); }  //src/index.js import sayHello from "./helloWorld" sayHello()  //rollup.config.js export default {   input:"src/index.js",//打包入口   output:{//文件输出配置     file:"dist/bundle.cjs.js",//打包后生成的文件位置和文件名     format:"cjs",//文件的输出格式,遵循cjs规范,这也是官方模块化规范     name:"bundleName"//包的全局变量名   } }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

我们在package.json文件中配置的打包命令是"build":"rollup -c",我们在执行打包命令npm run  build后,看到生成的文件dist/bundle.cjs.js中的代码是非常简洁清爽的,可读性非常强。

复制

//dist/bundle.cjs.js 'use strict';  function sayHello(){   console.log("nihao"); }  sayHello();
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

接下来,我们就详细谈谈rollup的相关配置问题,我们知道rollup默认采用的是ESM规范,但是如果你想使用CommonJS规范,你可以使用.cjs后缀进行区分:

复制

//rollup.config.cjs module.export = {   input:"src/index.js",   output:{     file:"dist/bundle.cjs.js",     format:"cjs"   } }
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

前面我们已经创建了一个简单的打包配置文件,但是当你需要创建更加复杂的bundles时,你将需要更大的弹性,比如:通过npm安装导入模块、通过babel编译代码,使用json配置文件等等。对此,我们可以使用plugins插件,通过在捆绑过程的关键点来改变rollup的行为。比如,我们可以使用@rollup/plugin-json插件来允许导入JSON文件,使用命令行npm  install --save-dev @rollup/plugin-json安装。

复制

// src/main.js import {version} from "../package.json";  export default function(){   console.log('version ' + version); }  // rollup.config.js import json from '@rollup/plugin-json';  export default {   input: 'src/main.js',   output: {     file: 'bundle.js',     format: 'cjs'   },   plugins: [json()] };
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

这样,执行npm run build命令进行打包,生成的文件是:

复制

'use strict';  var version = '1.0.0';  function main() {   console.log('version ' + version); }  module.exports = main;
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

当然,一些特殊的插件依赖于一些输出,有关特定于输出的插件可以做什么的技术细节,请参阅插件钩子。如果一个不兼容的插件被用作特定于输出的插件,那么  Rollup 会发出警告。

为了实践那些依赖于输出的插件,我们基于前面简单的项目打包进行相关的配置,先执行命令行npm install --save-dev  rollup-plugin-terser,

复制

// rollup.config.js import json from '@rollup/plugin-json'; import { terser } from 'rollup-plugin-terser';  export default {   input: 'src/main.js',   output: [     {       file: 'bundle.js',       format: 'cjs'     },     {       file: 'bundle.min.js',       format: 'iife',       name: 'version',       plugins: [terser()]     }   ],   plugins: [json()] };
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

  • 16.

  • 17.

  • 18.

  • 19.

  • 20.

此时打包得到:

复制

var version = (function () {   'use strict';   var n = '1.0.0';   return function () {     console.log('version ' + n);   }; })();
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

前面我们看到可以将多个文件的代码打包成一个文件,那么当项目比较大的时候就需要对代码进行分割。对于代码分割,有时候 Rollup  会自动将代码分割成块,比如动态加载或多个入口点,还有一种方法可以通过 output.manualChunks 选项显式告诉 Rollup  哪些模块要分割成单独的块。

复制

// src/main.js export default function () {   import('./foo.js').then(({ default: foo }) => console.log(foo)); }
  • 1.

  • 2.

  • 3.

  • 4.

Rollup将会使用动态导入去创建一个分割的chunk文件,只在需要的时候进行加载。为了rollup能够知道哪里是第二个chunk块,可以通过设置--file设定规范,通过--dir创建导出目录。

复制

$ rollup src/main.js -f cjs -d dist
  • 1.

接下来将会创建一个包含两个文件main.js和chunk-[hash].js的目录dist,此处的[hash]是一个hash字符串。你可以设置你自己想要的文件命令模式,通过  output.chunkFileNames和output.entryFileNames 进行配置。

复制

//→ main.js: 'use strict';  function main() {   Promise.resolve(require('./chunk-b8774ea3.js')).then(({ default: foo }) => console.log(foo)); }  module.exports = main;  //→ chunk-b8774ea3.js: ('use strict');  var foo = 'hello world!';  exports.default = foo;
  • 1.

  • 2.

  • 3.

  • 4.

  • 5.

  • 6.

  • 7.

  • 8.

  • 9.

  • 10.

  • 11.

  • 12.

  • 13.

  • 14.

  • 15.

Rollup的优势是:

  • 输出结果更加扁平,执行效率更高

  • 自动移除未引用代码

  • 打包结果依然完全可读

Rollup的缺点是:

  • 加载非ESM的第三方模块比较复杂

  • 因为模块最终会都被打包到全局中,所以无法实现HMR

  • 浏览器环境中,代码拆分功能必须使用Require.js这样的AMD库

写在最后

对于Webpack大而全,Rollup小而美,我的选择基本原则是应用开发优先webpack,类库或框架开发使用Rollup。这是因为在开发js库时,webpack的繁琐和打包后的文件体积太大,而rollup就是针对js库和框架开发的,它只是生成代码将我们的代码转为目标js。如果你想了解更多关于rollup的相关知识,可以阅读(官方文档)。

 

49    2021-12-25 22:29:04    Webpack Rollup 前端