[陈同学i前端] 一起学Rollup|打包器基本使用

507 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情

前言

大家好,我是陈同学,一枚野生前端开发者,感谢各位的点赞、收藏、评论

Rollup一个用于JavaScript的模块打包器,与webpack齐名并依靠自身差异化的体系设计赢得了许多业界工作者的青睐,同时也在Vite的架构体系中发挥着重要作用

本文阅读成本与收益如下:

阅读耗时:5mins

全文字数:5k+

预期效益

  • 入门学习Rollup基本概念
  • 掌握简单的Rollup打包操作

基本使用

  • 新建一个前端工程项目
pnpm init

20221009172838

若无pnpm,先执行命令npm install -g pnpm

  • 安装Rollup依赖
pnpm install rollup
  • 新增测试文件
mkdir src
touch src/index.js
touch src/tool.js
touch rollup.config.js

每一个文件内容如下

// src/index.js

import { add } from './tool';

console.log(add(1, 2));
// src/tool.js

export const add = (a, b) => a + b;

export const multi = (a, b) => a * b;
/**
 * @type { import('rollup').RollupOptions }
 */
const buildOptions = {
    input: ["src/index.js"],
    output: {
      // 产物输出目录
      dir: "dist/es",
      // 产物格式
      format: "esm",
    },
};
export default buildOptions;
  • 新增打包命令

package.jsonscript中新增语句rollup -c

20221009173629

  • 执行命令开始打包
pnpm run build

20221009173813

  • 得到打包产物

20221009173902

Tree Shaking 由于ES模块依赖关系是确定的,和运行时状态无关。因此Rollup可以在编译阶段分析出依赖关系,对AST语法树中没有使用到的节点进行删除

常用配置

  • input

定义打包入口文件,可以配置成字符串、数组或者对象,Rollup将根据此参数对应的路径开展打包工作流程

多入口配置:

{
  input: ["src/index.js", "src/tool.js"]
}
// 或者
{
  input: {
    index: "src/index.js",
    util: "src/tool.js",
  },
}
  • output

定义产物输出的目录、格式、是否压缩、静态文件产物命名规则等信息

output的描述对象:

{
    output: {
        // 产物输出目录
        dir: path.resolve(__dirname, 'dist'),
        // 以下三个配置项都可以使用这些占位符:
        // 1. [name]: 去除文件后缀后的文件名
        // 2. [hash]: 根据文件名和文件内容生成的 hash 值
        // 3. [format]: 产物模块格式,如 es、cjs
        // 4. [extname]: 产物后缀名(带`.`)
        // 入口模块的输出文件名
        entryFileNames: `[name].js`,
        // 非入口模块(如动态 import)的输出文件名
        chunkFileNames: 'chunk-[hash].js',
        // 静态资源文件输出文件名
        assetFileNames: 'assets/[name]-[hash][extname]',
        // 产物输出格式,包括`amd`、`cjs`、`es`、`IIFE`、`UMD`、`system`
        format: 'cjs',
        // 是否生成 sourcemap 文件
        sourcemap: true,
        // 如果是打包出 IIFE/UMD 格式,需要对外暴露出一个全局变量,通过 name 配置变量名
        name: 'DiyBundle',
        // 全局变量声明
        globals: {
            // 项目中可以直接用`$`代替`jquery`
            jquery: '$'
        }
    }
}

多产物配置:

{
    output: [
        {
            dir: "dist/es",
            format: "esm",
        },
        {
            dir: "dist/cjs",
            format: "cjs",
        },
    ],
}

output属性可为一个数组,数组中每个元素都是一个描述产物的对象,以控制不同产物的输出效果

  • external

希望Rollup不打包部分第三方依赖

{
  external: ['react', 'react-dom']
}
  • plugins

Rollup打包过程中用到的插件,以数组的形式提供

{
  plugins: [json()]
}

JavaScript API 方式使用

部分较为复杂的场景下需要基于Rollup定制一些打包过程,仅仅使用配置文件显得不够灵活,这时候需要用到对应JavaScript API来调用Rollup

主要分为rollup.rolluprollup.watch两个API

rollup.rollup

  • 项目根目录下新建文件build.js
// build.js
const rollup = require("rollup");

// 常用 inputOptions 配置
const inputOptions = {
  input: "./src/index.js",
  external: [],
  plugins:[]
};

const outputOptionsList = [
  // 常用 outputOptions 配置
  {
    dir: 'dist/es',
    entryFileNames: `[name].[hash].js`,
    chunkFileNames: 'chunk-[hash].js',
    assetFileNames: 'assets/[name]-[hash][extname]',
    format: 'es',
    sourcemap: true,
    globals: {
      jquery: '_'
    }
  },
  {
    dir: 'dist/cjs',
    entryFileNames: `[name].[hash].js`,
    chunkFileNames: 'chunk-[hash].js',
    assetFileNames: 'assets/[name]-[hash][extname]',
    format: 'cjs',
    sourcemap: true,
    globals: {
      jquery: '_'
    }
  },
  // 省略其它的输出配置
];

async function build() {
  let bundle;
  let buildFailed = false;
  try {
    bundle = await rollup.rollup(inputOptions); // 调用 rollup.rollup 生成 bundle 对象
    // 每一次循环体执行中的output均对应一种format的产物数组列表
    for (const outputOptions of outputOptionsList) {
      const { output } = await bundle.generate(outputOptions); // 拿到 bundle 对象,根据每一份输出配置,调用 generate 和 write 方法分别生成和写入产物
      console.log(output);
      await bundle.write(outputOptions); // 将产物写入文件系统
    }
  } catch (error) {
    buildFailed = true;
    console.error(error);
  }
  if (bundle) {
    // 最后调用 bundle.close 方法结束打包
    await bundle.close();
  }
  process.exit(buildFailed ? 1 : 0);
}

build();

文件保存后在终端执行命令node build.js

以上代码逻辑流程:

  • 通过rollup.rollup方法,传入inputOptions,生成bundle对象
  • 调用bundle对象的generatewrite方法,传入outputOptions,分别完成产物和生成和磁盘写入
  • 调用bundle对象的close方法来结束打包

最后可以在dist目录查看打包结果产物

rollup.watch

watch模式下的打包,即每次源文件变动后自动进行重新打包

// watch.js
const rollup = require("rollup");
const watcher = rollup.watch({
  input: "./src/index.js",
  output: [
    {
      dir: "dist/es",
      format: "esm",
    },
    {
      dir: "dist/cjs",
      format: "cjs",
    },
  ],
  watch: {
    exclude: ["node_modules/**"], // 排除第三方依赖变动监听
    include: ["src/**"], // 包括src目录下所有文件的变更监听
  },
});
// 监听 watch 各种事件
watcher.on("event", (e) => {
  if (e.code === "BUNDLE_END") {
    console.log("bundle message:", e);
  }
});
watcher.on("restart", () => {
  console.log("rebuild...");
});
watcher.on("change", (id) => {
  console.log("changed module ID ", id);
});

执行node watch.js开启Rollupwatch打包模式

讲到最后

本节文章我们学习了Rollup的基本配置项的含义以及JavaScript API的使用

实践中,我们能够通过简单的配置完成前端工程项目的简易打包流程

谢谢大家,我们下节再见!!!

感谢各位看到这里,如果你觉得本节内容还不错的话,欢迎各位的点赞、收藏、评论,大家的支持是我做内容的最大动力

本文为作者原创,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利