将Anikyu的构建工具由Webpack迁移到Rollup


之前封Anikyu库的时候,主要是参考使用vue-cli脚手架构建应用程序的相关配置来进行的,因此之前的构建工具使用的是Webpack。但经过笔者的一些了解,很多库(例如,ECharts、Vue.js、Three.js)的构建工具并非Webpack,而是Rollup。当然也有部分库(例如,Axios)的构建工具使用的是Webpack。事实上,就在早前,Vue.js曾放出了Vue.js 3.0的相关消息,未来的项目将可能会使用一款名为Vite的工具来进行打包,而它基于的打包工具便是Rollup。

经过本人测试,相对使用Webpack打包的库而言,使用Rollup打包的库,冗余代码看起来更少一些。

下方分别是Axios和Vue两个库UMD包未压缩代码。

image
Axios

image
Vue

参考资料

10分钟快速入门rollup.js – 知乎
你还没有撸一个包扔到npm上? – 知乎

移除相关依赖,修改构建配置

有关Anikyu的相关内容,可参考封装Anikyu时写的文章:尝试通过封装一个库(Anikyu)来学习JavaScript(ES6)相关特性以及相关构建工具,本文操作步骤基于v1.0.1 版本

首先,打开package.json看一下旧版本中相关开发依赖:

    "@babel/cli": "^7.8.3",
    "@babel/core": "^7.8.3",
    "@babel/polyfill": "^7.8.3",
    "@babel/preset-env": "^7.8.3",
    "@purtuga/esm-webpack-plugin": "^1.2.1",
    "babel-loader": "^8.0.6",
    "clean-webpack-plugin": "^3.0.0",
    "eslint": "^6.8.0",
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10"

在此,Webpack相关依赖已经不再有用,可以直接删除,仅保留Babel与ESLint,然后再加入Rollup的相关依赖。

    "@babel/cli": "^7.8.3",
    "@babel/core": "^7.8.3",
    "@babel/polyfill": "^7.8.3",
    "@babel/preset-env": "^7.8.3",
    "eslint": "^6.8.0",
    "@rollup/plugin-babel": "^5.1.0",
    "@rollup/plugin-commonjs": "^14.0.0",
    "@rollup/plugin-node-resolve": "^8.4.0",
    "rollup": "^2.22.0",
    "rollup-plugin-terser": "^6.1.0"

此处可以了解一下与Rollup相关的依赖的作用:

  1. rollup
    Rollup打包工具的主要部分。
  2. @rollup/plugin-babel
    用于将Babel整合到Rollup的插件。
  3. @rollup/plugin-commonjs
    用于将CommonJS语法的模块转换为ES Module模块的插件。若不使用这一插件,在使用导出的UMD包时会报以下错误:
    image
    虽然我们的项目中统一使用的是ES Module,然而某些依赖却是使用CommonJS语法写的,例如@babel/polyfill所用到的core-js:
    image
    若不经过转换,在UMD包中会将require等语法原样保留,而浏览器原生不支持这种语法,因此需要对这种语法进行转换。
  4. @rollup/plugin-node-resolve
    用于定位某些模块的插件。若不使用该插件,打包时会报错:
    image
    对应的polyfill没有打入到最终生成的包中,低版本浏览器在执行时会报错:
    image
  5. rollup-plugin-terser
    用于对代码进行压缩的插件。

然后,需要更改package.json上方scripts中的build脚本。由于Webpack已经不再使用,因此把脚本从原先的webpack-cli替换为rollup -c
修改后如果我们迫不及待执行构建命令:
image
将会提示“找不到入口模块rollup.config.js”。
在这里,rollup.config.js的角色和webpack.config.js是一致的,都是打包工具的配置文件。

同时,我们来看一下旧版本中的Webpack配置文件webpack.config.js。在配置的输出中,包含四个版本的Anikyu。
| 版本 | UMD | ESM |
| – | – | – |
| 未压缩 | anikyu.js | anikyu.esm.js |
| 已压缩 | anikyu.min.js | anikyu.esm.min.js |

UMD版本用于老旧浏览器,通过script标签src属性引入;而ESM版本用于支持ES Module的浏览器,通过import语句引入。
我们迁移的最终目标,就是在保留Anikyu功能,不改动Anikyu库内部原有代码基础上,输出同样的这四种文件。

webpack.config.js可以先保留,之后可以参考这个文件进行输出配置(当然此时该文件也没用了,如果记下来相关输出配置,可以直接删除)。

接下来在项目根目录下新建rollup.config.js文件,内容如下:

import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';
import resolve from '@rollup/plugin-node-resolve';
import { terser } from "rollup-plugin-terser";

export default {
  input: './src/anikyu.js',
  output: [{
    file: `./dist/anikyu.js`,
    name: `Anikyu`,
    format: 'umd'
  },
  {
    file: `./dist/anikyu.min.js`,
    name: `Anikyu`,
    format: 'umd',
    plugins:[
      terser()
    ]
  },
  {
    file: `./dist/anikyu.esm.js`,
    format: 'es'
  },
  {
    file: `./dist/anikyu.esm.min.js`,
    format: 'es',
    plugins:[
      terser()
    ]
  }],
  plugins: [
    commonjs({
      extensions: ['.js'],
      ignoreGlobal: false,
      sourceMap: false,
    }),
    resolve({
      browser:true
    }),
    babel({
      exclude: 'node_modules/**'
    })
  ]
};

这里的相关配置参考自Three.js的构建配置文件下方有关输出的章节。(其中的某些参数配置笔者暂未仔细了解🌚)

此时若我们再执行npm run build,即可生成使用Rollup进行打包后的最终文件。这里产生了四个文件,分别对应上文所述的四个版本。


最终产生的diff变化可见:Pull Request

至此,Anikyu项目由Webpack构建到Rollup的构建便成功完成。
从文件体积上看,Rollup打包出来的版本显然更小一些。
image

旧闻:过不去的一步

其实将Anikyu的构建工具迁移到Rollup是我一直都在尝试做的事情,今年四月就准备做,但由于当月太忙,就一直忘了,直到最近突然想起,便进行了一波尝试。
之前看了慕课网发布在知乎上的文章,遂一步步跟着做了下来,很完美。但后面发现文章里用到的Babel与Rollup版本其实是很早以前、已被deprecated的版本了;于是便研究如何从老版本升级到新版本,无奈中间总有一步过不去。(见:99fe673ad6a8d06848558a72d6717385a0edbc27)
这一版本的依赖包括:

  "devDependencies": {
    "@babel/cli": "^7.0.0",
    "@babel/core": "^7.0.0",
    "@babel/plugin-external-helpers": "^7.0.0",
    "@babel/plugin-transform-runtime": "^7.0.0",
    "@rollup/plugin-babel": "^5.1.0",
    "@rollup/plugin-commonjs": "^14.0.0",
    "@rollup/plugin-node-resolve": "^8.4.0",
    "babel-eslint": "^10.0.1",
    "babel-preset-env": "^1.7.0",
    "eslint": "^6.8.0",
    "rollup": "^2.22.0"
  }

这一版本Rollup及Babel的配置如下:

import resolve from '@rollup/plugin-node-resolve';
import babel from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';

export default {
  input: './src/anikyu.js',
  output: [{
    file: `./dist/anikyu.js`,
    name: `Anikyu`,
    format: 'umd'
  }, {
    file: `./dist/anikyu.esm.js`,
    format: 'es'
  }],
  plugins: [
    resolve(),
    commonjs({
      extensions: ['.js'],
      ignoreGlobal: false,
      sourceMap: false,
    }),
    babel({
      exclude: 'node_modules/**',
      babelHelpers: 'runtime',
      "presets": [
        [
          "env",
          {
            "modules": false,
            "targets": {
              // The % refers to the global coverage of users from browserslist
              "browsers": [">0.25%", "not ie 11", "not op_mini all"]
            }
          }
        ]
      ],
      "plugins": [
        "@babel/plugin-external-helpers",
        [
          "@babel/plugin-transform-runtime",
          {
            corejs: 3
          }
        ]
      ]
    })
  ]
};

这一版中打出来的包里不包含polyfill,并且打包时提示了一些错误,之前查各种资料,一无所获:

  • Trace: The node type RestProperty has been renamed to RestElement
    image
    问题产生原因:
    babel-preset-env": "^1.7.0依赖的版本过于古老。此处替换为较新的@babel/preset-env": "^7.0.0依赖,同时在Babel的配置中,presets下的"env"应当替换为"@babel/preset-env"。重新安装依赖后,问题即可解决。
  • (!) Unresolved dependencies
    image
    问题产生的原因:
    1. @babel/polyfill未安装 – 由于找不到这个依赖,导致@babel/polyfill没有打入包中,UMD包在浏览器中运行时将报错;若要把@babel/polyfill同时打包,需要安装这个依赖;
    2. 需要在Babel中增加一条配置:"useBuiltIns": "usage";若没有这条配置,@babel/polyfill也不会被打包。
    3. corejs配置的位置放错地方了,应当将其移动到上方,或者直接将其删去以使用默认值2
      image
    4. 在Rollup的配置文件中添加@rollup/plugin-node-resolve,并在插件中调用。
      image
      若打包后,在低版本浏览器下,某些代码依然报错,则尝试修改Babel将要编译到的目标浏览器。
  • (!) Missing global variable names
    image
    当上一个问题解决后,这个错就不会再报了。

今天居然成功解决!真的很意外,值得庆祝一下。


评论