Loading...
rollup自定义插件插件
4/25/2024, 7:50:47 PM
开发
Rollup 插件是一个对象,具有 属性、构建钩子 和 输出生成钩子 中的一个或多个。 插件应作为一个导出一个函数的包进行发布,该函数可以使用插件特定的选项进行调用并返回此类对象。
插件允许你通过例如在打包之前进行转译代码或在node_modules文件夹中查找第三方模块来自定义 Rollup 的行为。
一些rollup插件开发中中核心概念和需要注意的点,以下简单列举。
虚拟模块,按照我的理解,更准确的说应该是 定义磁盘上不存在的模块的插件,让你可以动态在内存中添加ESM语法的js文件/模块。官方说法如下:
虚拟模块是一种很实用的模式,使你可以对使用 ESM 语法的源文件传入一些编译时信息。
思考一个根据模块名称动态生成的虚拟模块,如import date from '@year/1970/01/01'
,返回的是这一天的日期,当然不可能手动创建这么多模块,那么我们直接在内存中创建,因此叫虚拟模块:
插件文件: ./plugin/virtual-test.js
/** * @example const birthday = require('@year/1970/01/01'), 返回传入的日期,而不必真的存在这个模块 * @returns Plugin */ export default function MyVirtualDatesPlugin() { // 虚拟模块的前缀,在使用的时候,模块名必须以这个作为前缀的模块名才会被进一步解析 const modulePrefix = 'virtual-dates:' return { // 我们自定义的插件名 name: 'my-virtual-dates-plugin', resolveId(id) { // 判断是否符合插件的前缀条件 const [, date] = id.split(modulePrefix) // 如果不符合则停止 if (!date) return // 如果符合基本格式,但日期的值不合法,比如 13 月, 32 号 if (Number.isNaN(Date.parse(date))) { throw new Error('Trying to load an invalid date') } // 一切正常则返回 return id }, load(id) { // 在加载文件内容的钩子中返回这个虚拟模块的内容 const [, date] = id.split(modulePrefix) // 如果值不合法则跳过,加载下一个文件 if (!date) return // 返回一个预期的文件内容 return `export default new Date('${date}')` } } }
rollup.config.js配置文件
import virtualTest from './plugin/virtual-test.js'; export default { input: './src/main.js' //... plugins: [ //... virtualTest(), ], };
实际使用的地方: main.js
// import myDate from "virtual-dates:19970915" // 报错 (plugin my-virtual-dates-plugin) Error: Trying to load an invalid date, 因为日期格式不对 import myDate from "virtual-dates:1997/09/15" // ok export default function () { console.log(myDate); }
main文件这个Chunk打包后实际是:
var myDate = new Date('1997/09/15'); // src/main.js function main () { console.log(myDate); } export { main as default };
因此也就完成了官网说的 对使用 ESM 语法的源文件传入一些编译时信息
inlineDynamicImports
是Rollup的一个配置选项,用于将动态import()
转换成同步import。
默认情况下,inlineDynamicImports
的值为 false
,意味着动态导入不会被转换成同步导入。但是,当你将其设置为true
时,Rollup 会尝试将动态import()
转换为同步 import,这可能会影响到代码的打包结果和加载方式。
注意这个配置项目设置为true在多入口的情况下会报错:
RollupError: Invalid value for option "output.inlineDynamicImports" - multiple inputs are not supported when "output.inlineDynamicImports" is true.
构建钩子在构建阶段运行,该阶段由 rollup.rollup(inputOptions)
触发。它们主要涉及在 Rollup 处理输入文件之前定位、提供和转换输入文件(这就相当于webpack的loader了)。
除了函数之外,钩子也可以是对象。在这种情况下,实际的钩子函数必须指定为 handler
。这允许你提供更多的可选属性,以改变钩子的执行。
建阶段的第一个钩子是 options
,最后一个钩子始终是 buildEnd
。如果有构建错误,则在此之后将调用 closeBundle。此外,在监视模式下,watchChange 钩子可以在任何时候触发,以通知当前运行生成输出后将触发新的运行。另外,当监视器关闭时,closeWatcher 钩子将被触发。
为了与构建过程交互,你的插件对象包括“钩子”。钩子是在构建的各个阶段调用的函数。钩子可以影响构建的运行方式,提供关于构建的信息,或在构建完成后修改构建。有不同种类的钩子:
/** * js中 px转为rem插件: 使用构建钩子的插件 */ export default function(options){ // options 就是用户传入的配置 console.log(options); return { name: 'px-to-rem', transform: (code, id)=>{ if(!String(id).endsWith('.js')){ return; } const pxReg = /(\d+)px/g; const replace_code = String(code).replace(pxReg, function(matchStr,group1){ return (Number(group1)/2)+'rem'; }); return { code: replace_code, map: null, // 使用原本sourcemap,消除 插件sourcemap警告: } }, } }
输出/生成钩子可以提供有关生成的产物的信息并在构建完成后修改构建(类似于webpack的plugin插件)。它们的工作方式和类型与构建钩子相同,但是对于每个调用 bundle.generate(outputOptions)
或 bundle.write(outputOptions)
,它们都会单独调用。仅使用输出生成钩子的插件也可以通过输出选项传递,并且因此仅针对某些输出运行。
输出生成阶段的第一个钩子是 outputOptions,最后一个钩子是 generateBundle(如果通过 bundle.generate(...) 成功生成输出),writeBundle(如果通过 bundle.write(...) 成功生成输出),或 renderError(如果在输出生成期间的任何时候发生错误)。
const getHtmlTemplate = (str)=>` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My App</title> </head> <body> <h1>Welcome to My App</h1> ${str} </body> </html> `; export default function(){ return { name: 'generate-html-plugin', generateBundle(options,bundle){ // bundle 生成的文件的对象列表 const jsFiles = Object.values(bundle).filter(chunk => chunk.type === 'chunk' && chunk.isEntry).map(chunk => { const fileName = chunk.fileName; return `<script src="${fileName}"></script>`; }); const htmlStr = getHtmlTemplate( jsFiles.join('\n\t\t') ); this.emitFile({ type: 'asset', source: htmlStr, fileName: 'index.html' }); }, } }
可以通过 this 从大多数钩子中访问一些实用函数和信息位,例如常见的:
this.debug()
/this.error()
/this.warn()
打印日志this.emitFile()
产出一个包含在生成产物中的新文件,并返回一个 referenceId,可以在各种地方使用它来引用生成的文件。你可能会产出代码块、预构建的代码块或者资源文件。Vite插件和rollup插件基本一样,只是在rollup插件的基础上增加了部分功能,如
这些是主要的变化,还有我认为不重要的变化在Vite官网中有详细说明。
文章目录