yanyue404 / blog

Just blog and not just blog.
https://yanyue404.github.io/blog/
Other
87 stars 13 forks source link

Rollup 打包入门 #232

Open yanyue404 opened 2 years ago

yanyue404 commented 2 years ago

前言

官方文档

rollup 对比 webpack

共同点:

  1. 通过插件生态的方式处理各种各样的资源依赖

不同点:

  1. webpack 致力于复杂 SPA 的模块化构建, rollup 致力于打造性能出众的类库;
  2. rollup 打包后生成的 bundle 内容十分干净,没有什么多余的代码。相比 webpack(webpack 打包后会生成 webpack_require 等 runtime 代码),rollup 拥有无可比拟的性能优势,这是由依赖处理方式决定的,编译时依赖处理(rollup)自然比运行时依赖处理(webpack)性能更好;
  3. 对于 ES 模块依赖库,rollup 会静态分析代码中的 import,并将排除任何未实际使用的代码(tree-shaking)
  4. rollup 支持导出 es 模块文件(webpack 不支持导出 es 模块)
  5. webpack 支持提取公共模块

快速入门

  1. 创建简单项目
mkdir -p my-rollup-project/src
cd my-rollup-project

首先,我们需要个 入口。将以下代码粘贴到新建的文件 src/main.js 中:

// src/main.js
import foo from "./foo.js";
export default function () {
  console.log(foo);
}

之后创建入口文件引用的 foo.js 模块:

// src/foo.js
export default "hello world!";
  1. 安装 rollup
npm init -y
yarn add rollup -D
  1. 创建 rollup.config.js
export default {
  input: "src/main.js", // 要打包的文件源路径
  output: {
    // 文件输出配置
    file: "dist/bundle.js", // 打包后生产的文件位置及文件名
    format: "iife", // 输出的文件类型 (amd, cjs, esm, iife, umd)
    name: "bundleName", // 包的全局变量名称
  },
};
  1. 编写 package.json 中的打包命令
{
  "scripts": {
    "build": "rollup --config rollup.config.js"
  }
}
  1. 执行npm run build 查看文件输出结果
var bundleName = (function () {
  "use strict";

  var foo = "hello world!";

  function main() {
    console.log(foo);
  }

  return main;
})();

核心配置

// rollup.config.js
import resolve from "rollup-plugin-node-resolve";
import commonjs from "rollup-plugin-commonjs";
import babel from "rollup-plugin-babel";
export default {
  input: "src/main.js", //填写打包的入口文件路径
  output: {
    file: "dist/bundle.js", // 打包后生产的文件位置及文件名
    format: "iife", // 输出的文件类型 (amd, cjs, esm, iife, umd)
    name: "bundleName", //当format为iife和umd时必须提供,将作为全局变量挂在window(浏览器环境)下:window.bundleName=...
    globals: {
      lodash: "_",
    },
  },
  external: ["lodash"], //告诉rollup不要将此lodash打包,而作为外部依赖
  plugins: [
    resolve(),
    commonjs(),
    babel({
      exclude: "node_modules/**",
    }),
  ],
};
  1. 打包格式说明

生成包的格式。 下列之一:

  1. external + output.globals

rollup 通过external + output.globals来标记外部依赖,以 react-redux 开源项目的 rollup 配置文件为例:

import nodeResolve from "rollup-plugin-node-resolve"; // 帮助寻找node_modules里的包
import babel from "rollup-plugin-babel"; // rollup 的 babel 插件,ES6转ES5
import replace from "rollup-plugin-replace"; // 替换待打包文件里的一些变量,如process在浏览器端是不存在的,需要被替换
import commonjs from "rollup-plugin-commonjs"; // 将非ES6语法的包转为ES6可用
import uglify from "rollup-plugin-uglify"; // 压缩包

const env = process.env.NODE_ENV;

const config = {
  input: "src/index.js",
  external: ["react", "redux"], // 告诉rollup,不打包react,redux;将其视为外部依赖
  output: {
    format: "umd", // 输出 UMD格式,各种模块规范通用
    name: "ReactRedux", // 打包后的全局变量,如浏览器端 window.ReactRedux
    globals: {
      react: "React", // 这跟external 是配套使用的,指明global.React即是外部依赖react
      redux: "Redux",
    },
  },
  plugins: [
    nodeResolve(),
    babel({
      exclude: "**/node_modules/**",
    }),
    replace({
      "process.env.NODE_ENV": JSON.stringify(env),
    }),
    commonjs(),
  ],
};

if (env === "production") {
  config.plugins.push(
    uglify({
      compress: {
        pure_getters: true,
        unsafe: true,
        unsafe_comps: true,
        warnings: false,
      },
    })
  );
}

export default config;
  1. 常用插件

附插件配置案例:

{
  "scripts": {
    "rollup:dev": "cross-env NODE_ENV=development rollup --config ./rollup/rollup.config.js -w",
    "rollup:build": "cross-env NODE_ENV=production rollup --config ./rollup/rollup.config.js"
  }
}
import babel from "rollup-plugin-babel";
import node from "@rollup/plugin-node-resolve";
import commonjs from "@rollup/plugin-commonjs";
import replace from "@rollup/plugin-replace";
import json from "rollup-plugin-json";
import { terser } from "rollup-plugin-terser";
import alias from "@rollup/plugin-alias";
import postcss from "rollup-plugin-postcss";
import serve from "rollup-plugin-serve";
import livereload from "rollup-plugin-livereload";
import { version } from "../package.json";

const path = require("path");
const resolve = (p) => path.resolve(__dirname, p);

const env = process.env.NODE_ENV;

const config = {
  input: "./rollup/src/main.js",
  output: {
    file: "./dist/bundle.js",
    format: "iife", //输出格式 amd es6 iife umd cjs
    // window.MyBundle.exportFunctionName
    name: "MyBundle", //当format为iife和umd时必须提供,将作为全局变量挂在window(浏览器环境)下:window.A=...
    banner: "/* my-library version " + version + " */",
    intro: 'var ENVIRONMENT = "production";',
    sourcemap: true, // 生成 bundle.map.js文件,方便调试
  },
  plugins: [
    node(),
    babel({
      exclude: "node_modules/**", // 只编译我们的源代码
    }),
    json(),
    postcss(),
    alias({
      entries: {
        "@": resolve("src"),
        "~": resolve("../"),
      },
      customResolver: node({
        extensions: [".vue", ".js", ".scss"],
      }),
    }),
    replace({
      "process.env.NODE_ENV": JSON.stringify(env),
    }),
    commonjs(),
    // 热更新与开启本地服务器
    livereload(),
    serve({
      open: true,
      port: 8001,
      contentBase: "dist",
    }),
  ],
  global: {
    lodash: "_", //告诉rollup全局变量
  },
  external: ["lodash"], // 不参与打包,使用外部引用
};

if (env !== "production") {
  config.plugins.push(
    terser({
      compress: {
        pure_getters: true,
        unsafe: true,
        unsafe_comps: true,
        warnings: false,
      },
    })
  );
}

export default config;

完整配置项

https://rollupjs.org/guide/zh/#big-list-of-options

// rollup.config.js
export default {
  // 核心选项
  input,     // 必须
  external,
  plugins,

  // 额外选项
  onwarn,

  // danger zone
  acorn,
  context,
  moduleContext,
  legacy

  output: {  // 必须 (如果要输出多个,可以是一个数组)
    // 核心选项
    file,    // 必须
    format,  // 必须
    name,
    globals,

    // 额外选项
    paths,
    banner,
    footer,
    intro,
    outro,
    sourcemap,
    sourcemapFile,
    interop,

    // 高危选项
    exports,
    amd,
    indent
    strict
  },
};

参考链接