Rollup:打造NPM包提高开发效率!

122 阅读7分钟

Rollup:打造NPM包提高开发效率!

起步

1. rollup与webpack区别

Rollup 更适合构建库和组件,追求更高的代码优化和性能;

Webpack 更适合构建复杂的应用,提供了更多的功能和灵活性。

2. 安装 Rollup

  • 初始化 package.json
    • yarn init -y
  • 安装 rollup
    • yarn add rollup -D
  • 新建src/foo.js
export default 'hello world!';
  • 新建src/index.js
import foo from './foo.js';
export default function () {
    console.log(foo);
}
  • 修改 package.json
"main": "dist/index.cjs.js",
"module": "dist/index.es.js",
"browser": "dist/index.umd.js",
"scripts": {
  "build": "rollup -c",
  "serve": "rollup -c -w"
},

-c:代表读取配置去打包,默认读取根目录下的rollup.config.mjs

-w:代表了watch监听,调试的时候可以用

  • 新建 rollup.config.mjs
import { defineConfig } from "rollup";
import pkg from "./package.json" assert { type: "json" }; //断言导出json模块

export default defineConfig([
  {
    input: "src/index.js", //入口文件
    output: [
      {
        file: pkg.main, //出口文件
        format: "cjs", //打包成CommonJS模块
      },
      {
        file: pkg.module, //出口文件
        format: "es", //打包成es module模块
      },
      {
        name: "myUtils", //打包成UMD模式,需提供name
        file: pkg.browser, //出口文件
        format: "umd", //打包成UMD模块
      },
    ],
  },
]);
  • 运行 yarn run build 进行打包,项目根目录会生成一个dist文件夹。
  • 根目录新建index.html引入打包后的文件,进行测试
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- 测试es module模块 -->
    <script type="module">
      import main from "./dist/index.es.js";
      main();
    </script>
    <!-- 测试umd模块 -->
    <script src="./dist/index.umd.js"></script>
    <script>
      window.myUtils();
    </script>
  </body>
</html>

提示:使用esm模块时,直接访问,浏览器会报跨域错误。

解决方式:安装vscode扩展 Live Server,然后使用open with Live Server打开。可以看到浏览器打印出两个hello world!,至此使用rollup已打包成功。

插件

插件列表:github.com/rollup/awes…

rollup有丰富的插件,可以让我们做更多的处理,这里列举常用的插件使用方式。

1. @rollup/plugin-json(处理JSON文件)

  1. 安装 yarn add @rollup/plugin-json -D
  2. 修改src/index.js 文件
import { version } from "../package.json";

export default function () {
  console.log("version " + version);
}
  1. 在 rollup.config.mjs 文件中加入 JSON plugin
import json from '@rollup/plugin-json';

export default defineConfig([
  {
    //...
    plugins: [
      json(),
    ],
  },
]);
  1. 用 yarn run build 运行 Rollup。dist/index.cjs.js文件内容应该如下所示
'use strict';

var version = "1.0.0";

function index () {
    console.log('version ' + version);
}

module.exports = index;

结果中JSON文件已成功被处理,并且只导入了我们实际需要的数据version,其他内容例如name、devDependencies都被忽略了。这就是 tree shaking 的作用

2. @rollup/plugin-terser(压缩文件)

  1. 安装 yarn add @rollup/plugin-terser -D

  2. 修改rollup.config.mjs

import terser from "@rollup/plugin-terser";

export default defineConfig([
  {
    //...
    plugins: [terser()],
  },
]);
  1. 使用 yarn run build 进行打包,生成的打包文件将全部被压缩

3. @rollup/plugin-node-resolve(处理外部依赖)

  1. 安装 yarn add @rollup/plugin-node-resolve -D
  2. 修改rollup.config.mjs
import resolve from "@rollup/plugin-node-resolve";

export default defineConfig([
  {
    //...
    plugins: [resolve()],
  },
]);
  1. 运行 yarn add lodash-es,安装lodash-es包进行测试
  2. 修改src/index.js
import { add } from "lodash-es"; //引入第三方包

export default function () {
  console.log("sum " + add(2 + 4));
}
  1. 使用 yarn run build 打包。这里如果不使用@rollup/plugin-node-resolve,会报错:Uncaught TypeError: Cannot read properties of undefined (reading 'add')

4. @rollup/plugin-commonjs(将第三方包CommonJS转ES)

  1. 安装 yarn add @rollup/plugin-commonjs -D
  2. 修改rollup.config.mjs
import commonjs from "@rollup/plugin-commonjs";

export default defineConfig([
  {
    //...
    plugins: [commonjs()],
  },
]);
  1. 运行 yarn add ms,安装ms包进行测试
  2. 修改src/index.js
import ms from "ms"; //引入CommonJS类型包

export default function () {
  console.log(ms("2 days"));
}
  1. 使用 yarn run build 进行打包

5. @rollup/plugin-alias(路径别名)

  1. 安装 yarn add @rollup/plugin-alias -D
  2. 修改rollup.config.mjs
import alias from "@rollup/plugin-alias";
import path from "path";
import { fileURLToPath } from "url";
import { dirname } from "path";

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

export default defineConfig([
  {
    //...
    plugins: [
      //之前的插件保留,在plugins数组末尾添加alias
      alias({
        entries: [{ find: "@", replacement: path.resolve(__dirname, "src") }],
      }),
    ],
  },
]);
  1. 新建src/utils/index.js
export function Add(a, b) {
  return a + b;
}
  1. 修改src/index.js
import { Add } from "@/utils";

export default () => {
  console.log(Add(1, 2));
};
  1. 使用 yarn run build 进行打包

代码分割

1. 自动拆分代码块

rollup对于使用import()方式引入的文件,会自动将代码拆分成块,并以chunk-[hash].js的格式命名文件,其中[hash]是基于内容的哈希字符串。

由于umd模块不支持代码分割,并且打包后从一个文件变为一个文件夹,因此需要做一些调整

  1. 修改package.json
"main": "dist/cjs", 
"module": "dist/es",
  1. 修改rollup.config.mjs
export default defineConfig([
  {
    //...
    output: [
      {
        dir: pkg.main, //出口文件夹
        format: "cjs", //打包成CommonJS模块
      },
      {
        dir: pkg.module, //出口文件夹
        format: "es", //打包成es module模块
      },
    ],
  },
]);
  1. 修改src/index.js
export default function () {
  import("./foo.js").then(({ default: foo }) => console.log(foo));
}
  1. 运行yarn run build
  2. 修改index.html,进行测试
<!-- 测试es module模块 -->
<script type="module">
  import main from "./dist/es/index.js";
  main();
</script>

2. 显式拆分代码块

通过配置 output.manualChunks 显式地将模块拆分成单独的块。常用于拆分第三方包。

  1. 修改rollup.config.mjs
export default defineConfig([
  {
    //...
    output: [
      {
        dir: pkg.main, //出口文件
        format: "cjs", //打包成CommonJS模块
        manualChunks: {
          lodash: ["lodash-es"],
        },
      },
      {
        dir: pkg.module, //出口文件
        format: "es", //打包成es module模块
        manualChunks: {
          lodash: ["lodash-es"],
        },
      },
    ],
  },
]);
  1. 修改src/index.js
import { add } from "lodash-es";

export default function () {
  console.log("sum " + add(2 + 4));
}
  1. 使用 yarn run build 运行 Rollup,可以看到lodash已被拆分出来,形成一个单独的文件

使用 babel

将es6代码转es5,以兼容旧版浏览器、特定的移动设备等

  1. 安装
  • @rollup/plugin-babel:在 Rollup 打包过程中使用 Babel 进行代码转换
  • @babel/core:babel核心库
  • @babel/preset-env:将ES6转换为向后兼容的JavaScript
  • @babel/plugin-transform-runtime:处理async,await、import()等语法关键字的帮助函数
yarn add @rollup/plugin-babel -D
yarn add @babel/core -D
yarn add @babel/preset-env -D
yarn add @babel/plugin-transform-runtime -D
  1. 修改rollup.config.mjs
import { babel } from "@rollup/plugin-babel";

export default defineConfig([
  {
    //...
    plugins: [
      babel({
        babelHelpers: "runtime",
        presets: ["@babel/preset-env"],
        plugins: [["@babel/plugin-transform-runtime", { useESModules: true }]],
      }),
    ],
  },
]);

注意:如果使用了@rollup/plugin-commonjs,@rollup/plugin-commonjs一定要在@rollup/plugin-babel之前调用

import { babel } from '@rollup/plugin-babel';
import commonjs from '@rollup/plugin-commonjs';

const config = {
  ...
  plugins: [
    commonjs(),
    babel(...)
  ],
};
  1. 修改src/index.js
import foo from "./foo";

export default () => {
  console.log(foo);
};
  1. 使用 yarn run build 运行 Rollup,在dist/es/index.js文件已将es6转es5

处理 Sass

1. 打包支持sass文件

rollup-plugin-postcss 默认集成了对 scss、less、stylus 的支持

  1. 安装
yarn add sass -D
yarn add postcss rollup-plugin-postcss -D
  1. 修改rollup.config.mjs
import postcss from "rollup-plugin-postcss";

export default defineConfig([
  {
    //...
    plugins: [
      postcss(),
    ],
  },
]);
  1. 新建src/foo.scss
$color: red;

body {
  background-color: $color;
  display: flex;
}
  1. 使用 yarn run build 运行 Rollup,在dist/es/index.js中可以看到样式被打包了进去

2. css加前缀

  1. 安装 yarn add autoprefixer -D
  2. 更新 packages.json
"browserslist": [
    "defaults",
    "not ie < 8",
    "last 2 versions",
    "> 1%",
    "iOS 7",
    "last 3 iOS versions"
  ]

3. css压缩

  1. 安装 yarn add cssnano -D
  2. 修改rollup.config.mjs
import postcss from "rollup-plugin-postcss";
import autoprefixer from "autoprefixer";
import cssnano from "cssnano";

export default defineConfig([
  {
    //...
    plugins: [
      postcss({
        plugins: [autoprefixer(), cssnano()],
      }),
    ],
  },
]);

4. 抽离单独的css文件

修改rollup.config.mjs

export default defineConfig([
  {
    //...
    plugins: [
      postcss({
        plugins: [autoprefixer(), cssnano()],
        extract: "css/index.css",
      }),
    ],
  },
]);

使用 yarn run build 运行 Rollup,在dist/es中可以看到样式已被拆分出去,单独在css文件夹下

处理 Typescript

1. typescript 插件

  1. 安装 yarn add rollup-plugin-typescript2 typescript tslib -D
  2. 新建src/bar.ts
const str = "hello ts!";

export default str;
  1. 修改src/index.js
import bar from "./bar.ts";
import "./foo.scss";

export default function () {
  console.log(bar);
}
  1. 修改rollup.config.mjs
import typescript from "rollup-plugin-typescript2";

export default defineConfig([
  {
    //...
    plugins: [typescript()]
  },
]);

注意点:

  1. 如果使用了@rollup/plugin-node-resolve,@rollup/plugin-node-resolve要在rollup-plugin-typescript2之前调用
const config = {
    ...
    plugins: [
      resolve(),
      typescript(...)
    ],
  };
  1. 如果使用了@rollup/plugin-babel,需配置babel扩展
import { DEFAULT_EXTENSIONS } from '@babel/core';

export default defineConfig([
  {
    //...
    plugins: [
      babel({
        babelHelpers: 'runtime',
        presets: ["@babel/preset-env"],
        plugins: [["@babel/plugin-transform-runtime", { useESModules: true }]],
        extensions: [...DEFAULT_EXTENSIONS, ".ts", ".tsx"], //增加配置
      }),
    ],
  },
]);

2. 导出类型声明文件

新建tsconfig.json

{
  "compilerOptions": {
    "module": "ESNext",
    "target": "ESNext",
    "declaration": true, //生成声明文件
    "outDir": "dist",
    "rootDir": "src"
  },
  "exclude": ["node_modules", "dist"]
}

tsconfig.json配置会与typescript()配置合并,并覆盖其默认配置

使用 yarn run build 运行 Rollup,在dist/cjs与dist/es下会分别生成一份ts声明文件

优化

1. 打包前清空原打包目录

  1. 安装 rimraf 和 rollup-plugin-delete
yarn add rimraf -D //删除打包目录
yarn add rollup-plugin-delete -D //设置要删除的文件或目录
  1. 修改rollup.config.mjs
import { rimrafSync } from "rimraf";
import del from 'rollup-plugin-delete';

rimrafSync("dist");// 删除打包目录

export default defineConfig([
  {
    //...
    plugins: [
      del({ targets: "dist/*" }),
    ],
  },
]);

2. 打包产物清除调试代码

  1. 安装 yarn add @rollup/plugin-strip -D
  2. 修改rollup.config.mjs
import strip from "@rollup/plugin-strip";

export default defineConfig([
  {
    //...
    plugins: [
      strip()
    ],
  },
]);
  1. 修改src/index.js
import bar from "./bar.ts";
import "./foo.scss";

export default function () {
  console.log(bar);
  document.querySelector("body").innerHTML = bar;
}

使用 yarn run build 运行 Rollup,可以看到console.log部分的代码,在打包的时候已被删除

original text

original