使用rollup编写一个现代化的模块

3,216 阅读4分钟

之所有选用 rollup 是因为它可以减少打包体积和提高构建速度,下面介绍不会详细讲解配置,你可以自行查阅官方文档

ES6 已经出现很久了,但是为了兼容以前的浏览器,我们还是需要使用各种构建工具,例如 webpack,在使用的时候很方便,可以通过 babel 转换 es6 的语法,比如下面导入一个模块

import moduleName from 'module';

不过编写一个现代化模块呢,预定目标应该有三点

  1. 支持 typescript,将 ES6 代码转化为 ES5 环境使用
  2. 支持构建工具和script type="module"的导入
  3. 支持 umd 格式引用

就以下面这段代码为演示,实现上述的目标

export default (arr = []) => {
  return Array.from(arr).length;
};

准备

npm init -y
npm i rollup -D
cd.>rollup.config.js
md src
cd.>src/index.js

这样就创建好我们想要的基本结构了,将上面例子复制到 index.js 文件下。

rollup可以通过命令行也可以通过脚本来调用,这里在package.jsonscripts字段,通过脚本调用

  "scripts": {
    "build": "rollup -c"
  }

-c是指配置文件,默认就是rollup.config.js所以不需要额外配置了

编写第一个例子

rollup.config.js

export default {
  input: "./src/index.js",
  output: [
    {
      file: "dist/index.esm.browser.js",
      format: "es",
      sourcemap: true
    }
  ]
};

上面配置信息input指的是入口文件,output 是出口文件,file是输出的文件路径,sourcemap是是否输出 map 文件,他可以方便调试错误,在开发模块中应该是必须的,format是指输出的格式

  • amd 异步模块定义,用于像 RequireJS 这样的模块加载器
  • cjs CommonJS,适用于 Node 和 Browserify/Webpack
  • es 将软件包保存为 ES 模块文件
  • iife 一个自动执行的功能,适合作为<\script>标签。(如果要为应用程序创建一个捆绑包,您可能想要使用它,因为它会使文件大小变小。)
  • umd 通用模块定义,以 amd,cjs 和 iife 为一体

执行npm run build

dist/index.esm.browser.js

var index = (arr = []) => {
  return Array.from(arr).length;
};

export default index;
//# sourceMappingURL=index.esm.browser.js.map

可以看到生成的信息十分简洁,上面说到要同时支持umd 格式和 import 导入,import可以通过es的形式来供构建工具和script type="module"使用,下面就来定义一下 umd 格式

export default {
  input: "./src/index.js",
  output: [
    {
      file: "dist/index.esm.browser.js",
      format: "es",
      sourcemap: true
    },
    {
      file: "dist/index.js",
      format: "umd",
      sourcemap: true,
      name: "index"
    }
  ]
};

注意使用umd或者iife必须指定 name 字段,他决定了暴露在全局作用下的变量名,再次执行可以看到index.js的信息了。

babel

上面完成了需求的第一步,不过对于 es6 的代码,并没有转化为 es5 的形式,只是将语法转换了,Array.from依旧存在,下面使用babel来完成需求

npm i @babel/core @babel/preset-env  core-js rollup-plugin-babel rollup-plugin-node-resolve rollup-plugin-commonjs -D

babel.config.js

module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        useBuiltIns: "usage",
        corejs: 3,
        modules: false
      }
    ]
  ]
};

上面代码的useBuiltInsusage是 babel7 的实验性特性,他支持按需加载

rollup.config.js

import babel from "rollup-plugin-babel";
import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
export default {
  input: "./src/index.js",
  output: [
    {
      file: "dist/index.esm.browser.js",
      format: "es",
      sourcemap: true
    },
    {
      file: "dist/index.js",
      format: "umd",
      sourcemap: true,
      name: "index"
    }
  ],
  plugins: [
    commonjs(),
    resolve(),
    babel({
      exclude: [/\/core-js\//],
      runtimeHelpers: true,
      sourceMap: true,
      extensions: [".js", ".jsx", ".es6", ".es", ".mjs", ".ts"]
    })
  ]
};

再次执行可以看到Arrar.from已经被babel转换为 ES5 的环境了

typescript

这个我们用babel提供给我们的@babel/preset-typescript即可完成,不过为了支持typescript一些其他扩展语法,我们还需要安装一些插件

npm i @babel/preset-typescript @babel/plugin-transform-typescript @babel/plugin-syntax-dynamic-import @babel/plugin-proposal-class-properties -D

babel.config.js

module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        useBuiltIns: "usage",
        corejs: 3,
        modules: false
      }
    ],
    ["@babel/preset-typescript"]
  ],
  plugins: [
    "@babel/plugin-transform-typescript",
    "@babel/plugin-syntax-dynamic-import",
    "@babel/plugin-proposal-class-properties"
  ]
};

修改一下 src/index.jsindex.tsrollup.config.jsinput字段

export default (arr: Array<any> = []): number => {
  return Array.from(arr).length;
};

再次执行npm run build,成功输出

优化

  1. 输出代码没有被压缩
  2. 每次输出的时候文件夹没有被删除

上面两个问题,可以通过插件来解决

npm i rollup-plugin-terser rollup-plugin-clear -D

rollup.config.js

import babel from "rollup-plugin-babel";
import clear from "rollup-plugin-clear";
import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import { terser } from "rollup-plugin-terser";
export default {
  input: "./src/index.ts",
  output: [
    {
      file: "dist/index.esm.browser.js",
      format: "es",
      sourcemap: true
    },
    {
      file: "dist/index.js",
      format: "umd",
      sourcemap: true,
      name: "index"
    }
  ],
  plugins: [
    clear({
      targets: ["dist"]
    }),
    resolve(),
    commonjs(),
    terser(),
    babel({
      exclude: [/\/core-js\//],
      runtimeHelpers: true,
      sourceMap: true,
      extensions: [".js", ".jsx", ".es6", ".es", ".mjs", ".ts"]
    })
  ]
};

这样基本的模块的基本功能就编写完成了