深入了解rollup(五)插件输出生成钩子

引言

Rollup是一个JavaScript模块打包器,它可以将多个模块打包成一个单独的文件,以便在浏览器中使用。与其他打包工具相比,Rollup的主要优势在于它可以生成更小、更快的代码。在本文中,我们将深入了解Rollup的插件输出生成钩子。


深入了解rollup(一)快速开始

深入了解rollup(二)常用配置

深入了解rollup(三)插件机制

# 深入了解rollup(四)插件开发示例


输出生成钩子

输出生成钩子可以提供有关生成的产物的信息并在构建完成后修改构建。它们的工作方式和类型与 构建钩子 相同,但是对于每个调用 bundle.generate(outputOptions)bundle.write(outputOptions),它们都会单独调用。仅使用输出生成钩子的插件也可以通过输出选项传递,并且因此仅针对某些输出运行。

输出生成阶段的第一个钩子是 outputOptions,最后一个钩子是 generateBundle(如果通过 bundle.generate(...) 成功生成输出),writeBundle(如果通过 bundle.write(...) 成功生成输出),或 renderError(如果在输出生成期间的任何时候发生错误)。

此外,closeBundle可以作为最后一个钩子调用,但是用户有责任手动调用 bundle.close()来触发此操作。CLI 将始终确保这一点。

输出钩子执行顺序

  1. 执行所有插件的 outputOptions 钩子函数,对 output 配置进行转换

  2. 执行 renderStart,该钩子读取所有outputOptions钩子的转换之后的输出选项

  3. 扫描 动态import 语句执行 renderDynamicImport 钩子,让开发者能自定义动态import的内容与行为

  4. 并发执行所有插件的 banner、footer、intro、outro 钩子,这四个钩子功能简单,就是往打包产物的固定位置(比如头部和尾部)插入一些自定义的内容,比如版本号、作者、内容、项目介绍等等

  5. 是否存在 import.meta 语句,没有就直接进入下一步,否则:对于import.meta.url调用 resolveFileUrl 来自定义 url 解析逻辑。对于import.meta调用 resolveImportMeta 来进行自定义元信息解析

  6. 生成chunk调用renderChunk钩子,便于在该钩子中进行自定义操作。如果生成的chunk文件有hash值,执行 augmentChunkHash 钩子,来决定是否更改 chunk 的哈希值。

  7. 调用 generateBundle 钩子,这个钩子的入参里面会包含所有的打包产物信息,包括 chunk (打包后的代码)、asset(最终的静态资源文件)。在这个钩子中你做自定义自己的操作,比如:可以在这里删除一些 chunk 或者 asset,最终被删除的内容将不会作为产物输出

  8. rollup.rollup方法会返回一个bundle对象,bundle对象的write方法,会触发writeBundle钩子,传入所有的打包产物信息,包括 chunkasset,与generateBundle钩子非常相似。唯一的区别是writeBundle钩子执行的时候,产物已经输出了。而 generateBundle 执行的时候产物还并没有输出。简单来说,顺序是:generateBundle--->输出并保存产物到磁盘--->writeBundle

  9. bundleclose方法被调用时,会触发closeBundle钩子,这个output阶段结束

代码压缩插件示例

安装uglify-js

bash 复制代码
npm install uglify-js -D

rollup-plugin-uglify

javascript 复制代码
import { minify } from 'uglify-js';

export default function uglifyPlugin() {
  return {
    name: 'uglify',

    renderChunk(code) {
      const result = minify(code);
      if (result.error) {
        throw new Error(`minify error: ${result.error}`);
      }
      return {
        code: result.code,
        map: { mappings: '' }
      };
    },
  };
}

这段代码是一个使用uglify-js库进行代码压缩的Rollup插件。

  1. minify(code): 这个函数来自于uglify-js库,用于对给定的JavaScript代码进行压缩。它接受一个字符串参数code,表示要压缩的JavaScript代码,然后返回一个对象,包含压缩后的代码和可能的错误信息。

  2. throw new Error(message): 这个语句用于抛出一个错误。在这段代码中,如果压缩过程中出现错误,就会抛出一个带有错误信息的Error对象。

  3. renderChunk(code): 这是Rollup插件中定义的一个钩子函数,用于处理每个chunk(模块)生成最终输出文件时的逻辑。在这段代码中,它接受一个参数code,表示当前chunk的源代码。然后使用minify()函数对源代码进行压缩,并检查是否有错误发生。如果有错误,则抛出一个带有错误信息的Error对象;否则返回一个包含压缩后代码和空映射(map)对象的结果。

  4. export default function uglifyPlugin() { ... }: 这是整个插件导出的默认函数。当其他地方导入这个插件时,实际上导入了这个默认函数。该函数返回一个包含namerenderChunk()方法的对象,作为Rollup插件的配置。

rollup.config.mjs

js 复制代码
import { defineConfig } from "rollup";
import uglifyPlugin from './plugins/rollup-plugin-uglify.js'

export default defineConfig({
  input: "src/index.js",
  output: {
    dir: "dist",
    format: "esm",
    sourcemap: true,
  },
  plugins: [
    uglifyPlugin(),
  ],
});

打包大小和时间示例

该插件在构建开始时记录开始时间,在生成最终输出文件时统计文件大小,并在打包完成后计算并打印出打包时间。

rollup-plugin-bundle-stats

js 复制代码
export default function bundleStats() {
  let startTime;
  return {
    name: "bundle-stats",
    options() { 
      startTime = Date.now();
    },
    generateBundle(_, bundle) { 
      const fileSizes = {};

      for(const [fileName, output] of Object.entries(bundle)) { 
        if(output.type === "chunk") { 
          const content = output.code;
          const size = Buffer.byteLength(content, "utf-8");
          const sizeKB = (size / 1024).toFixed(2);

          fileSizes[fileName] = sizeKB + " KB";
        }
      }

      console.table(fileSizes);

    },
    closeBundle() { 
      const totalTime = Date.now() - startTime;
      console.log("打包时间:" + totalTime + "ms");
    }
  }
}
  1. options(): 这个函数是Rollup插件中的一个钩子函数,在构建开始时执行。在这段代码中,它被用来记录构建开始的时间,以便后续计算打包时间。

  2. generateBundle(_, bundle): 这个函数也是Rollup插件中的一个钩子函数,在生成最终输出文件时执行。它接受两个参数,第一个参数_表示当前构建选项,我们在这里不使用它;第二个参数bundle表示生成的bundle对象,包含了所有输出文件的信息。 在这段代码中,它被用来遍历bundle对象,并计算每个chunk文件的大小。对于每个chunk文件,它获取其代码内容并使用Buffer.byteLength()函数计算其字节长度。然后将字节长度转换为KB,并将结果存储在fileSizes对象中。 最后,使用console.table()函数将文件大小以表格形式打印出来。

  3. closeBundle(): 这个函数也是Rollup插件中的一个钩子函数,在打包完成后执行。在这段代码中,它被用来计算并打印出整个打包过程所花费的时间。

rollup.config.mjs

js 复制代码
import { defineConfig } from "rollup";
import bundleStats from './plugins/rollup-plugin-bundle-stats.js'

export default defineConfig({
  input: "src/index.js",
  output: {
    dir: "dist",
    format: "esm",
    sourcemap: true,
  },
  plugins: [
    bundleStats(),
  ],
});

输出结果

总结

输出钩子插件在Rollup构建过程中起到了关键作用。它们可以对生成的输出文件进行处理、优化或者添加额外的功能。以下是对输出钩子插件的作用进行总结:

  1. 代码压缩:输出钩子插件可以使用压缩工具(如uglify-js)对生成的代码进行压缩,以减小文件大小并提高加载速度。

  2. 文件大小统计:输出钩子插件可以统计生成的输出文件的大小,以便开发者了解每个文件的占用空间,并进行优化和调整。

  3. 文件格式转换:输出钩子插件可以将生成的代码转换为不同的格式,如将ES6模块转换为CommonJS模块,或将JavaScript代码转换为其他语言(如TypeScript)。

  4. 代码分割和合并:输出钩子插件可以根据需求对生成的代码进行分割和合并,以优化加载性能和减少网络请求。

  5. 添加额外功能:输出钩子插件可以在生成的输出文件中添加额外的功能或元数据,如添加版本号、注入环境变量等。

  6. 打包时间统计:输出钩子插件可以记录构建过程中打包所花费的时间,并将结果打印出来,以便开发者了解构建性能和优化构建流程。

总之,输出钩子插件可以在生成最终输出文件的过程中对代码进行处理和优化,以满足开发者的需求,并提供更好的性能和功能。

相关推荐
也无晴也无风雨1 小时前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang2 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational3 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、5 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
郝晨妤6 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui
喝旺仔la6 小时前
vue的样式知识点
前端·javascript·vue.js
别忘了微笑_cuicui6 小时前
elementUI中2个日期组件实现开始时间、结束时间(禁用日期面板、控制开始时间不能超过结束时间的时分秒)实现方案
前端·javascript·elementui