plugin要求
- 可以是一个对象、一个class、一个方法、但是始终返回一个对象给到rollup
- 插件应该有一个清晰的名称和 rollup-plugin- 前缀
- 尽可能使用异步方法
-
build/hooks
function insertNotes(){return {name:"rollup-plugin-insertNotes", // 名称会在 warnings 和 errors 中显示resolveId(source, importer, options){console.log("当前解析的文件信息---resolveId")},load(id) {console.log("加载的模块")},transform(code){console.log('每一个文件转换---transform')},buildStart(InputOptions){console.log('开始构建---buildStart')},buildEnd(error){console.log('打包结束--buildEnd')},watchChange(){console.log('watch模式下文件变动----watchChange')},closeWatcher(){console.log('关闭了watch---closeWatcher')},moduleParsed(moduleInfo){console.log("Rollup 完全解析模块时都会调用此钩子---moduleParsed")},options(InputOptions){console.log('这是构建阶段的第一个钩子--下一个执行buildStart')},}}
output/hooks
module.exports = function insertNotes() {return {name: "rollup-plugin-insertNotes",// output --hooksaugmentChunkHash() {// 经过renderStart +banner/footer 等阶段后,将会生成chunk。 每个chunk再接下来的步骤,都会先经历这个hook。console.log("为每个汇总输出块调用---augmentChunkHash")},banner(){/*banner 、 footer 、 intro 、 outro 四个钩子当输出的配置中,配置了这四项时,会触发的钩子。banner 和 footer 是分别向代码的开头和结尾插入代码;intro 和 outro 是分别向包装器的内部和外部插入代码。*/console.log('banner')},footer(){console.log('footer')},intro(){console.log('intro')},outro(){console.log('outro')},generateBundle(){// 在调用 bundle.generate 后,或者在调用 bundle.write 之前立即触发这个hookconsole.log('generateBundle')},outputOptions(){console.log('输出参数----outputOptions')},renderChunk(){console.log('转译单个的chunk----renderChunk')},renderStart(){// 这个hook,用来给chunk增加hashconsole.log('renderStart')},resolveFileUrl(){console.log('resolveFileUrl')},resolveImportMeta(){console.log('resolveImportMeta')},writeBundle(){// bundle.write后,所有的chunk都写入文件后,最后会调用一次 writeBundle 。console.log('writeBundle')}}}
插件的上下文
我们在使用钩子的时候会往上下文绑定一些工具方法、这些工具方法可以让我们对rollup的构建添加或者删除某些操作
this.addWatchFile()
hooks:【buildStart、load、resolveId、transform 】
描述:添加一个监听文件,当监听文件发送变化时,会重新构建
入参:(id:string)=> void
示例: this.addWatchFile( require.resolve(“../../../../../video.txt”) )
- this.emitFile()
hooks: 基本上都有
描述:在构建输出中,发出一个新文件,然后返回这个文件的引用id,这个引用id可以在各个地方用来获取到发出的这个新文件
入参:(emittedFile:EmittedChunk | EmittedAsset)=> string
- this.getCombinedSourcemap()
hooks:【 transform 】
描述:获取所有以前插件的组合源映射
入参:() => SourceMap
示例:const sourcemap = this.getCombinedSourcemap()
- this.getModuleIds()
hooks: 【 buildStart、load、transfrom等等…… 】
描述:返回一个Iterator可以访问当前图中所有模块 ID 的值
入参:() => IterableIterator
示例:for (const moduleId of this.getModuleIds()) { / … / }
- this.getModuleInfo()
hooks:
描述:获取模块信息
入参:(moduleId: string) => (ModuleInfo | null)
示例:
- this.getWatchFiles()
hooks:
描述:获取监听的文件(包括this.addWatchFile添加的)
入参:() => string[]
示例:console.log( this.getWatchFiles() )
- this.load()
hooks:
描述:获取监听的文件(包括this.addWatchFile添加的)
入参: ({id: string, moduleSideEffects?: boolean | ‘no-treeshake’ | null, syntheticNamedExports?: boolean | string | null, meta?: {[plugin: string]: any} | null, resolveDependencies?: boolean}) => Promise
示例:console.log( this.getWatchFiles() )
- this.mate
hooks:
描述:包含可能有用的汇总元数据的对象
类型: { rollupVersion: string, watchMode: boolean }
示例:console.log( this.mate )
- this.parse()
hooks:
描述:使用 Rollup 的内部 acorn 实例将代码解析为 AST
入参: (code: string, acornOptions?: AcornOptions) => ESTree.Program
示例:console.log( this.parse(‘const a = 1’) )
- this.resolve()
hooks:
描述:插件解析对模块 ID(即文件名)的导入,并确定导入是否应该是外部的
入参: (source: string, importer?: string, options?: {skipSelf?: boolean, isEntry?: boolean, isEntry?: boolean, custom?: {[plugin: string]: any}}) => Promise<{id: string, external: boolean | “absolute”, moduleSideEffects: boolean | ‘no-treeshake’, syntheticNamedExports: boolean | string, meta: {[plugin: string]: any}} | null>
示例:
- this.setAssetsSource()
hooks:
描述:
入参: (referenceId: string, source: string | Uint8Array) => void
示例:
- this.warn()
hooks:
描述:设置警告
入参: (warning: string | RollupWarning, position?: number | { column: number; line: number }) => void
示例:this.warn({ message: ‘hmm…’ });
利用插件实现增删改查
移除代码中的console.log
module.exports = function removeConsole() {return {name: 'remove-console',transform(code, id) {const Reg = /console\.log\(.*\)/ig;return code.replace(Reg, "")}}}
生成一个index.html并引入打包后的js文件
module.exports = function generateHtmlPlugin() {let ref1;return {name: "rollup-plugin-generateHtml",buildStart() {// 获取chunkref1 = this.emitFile({type: 'chunk',id: 'packages/core/src/index.ts' // 需要你当前入口文件地址});},generateBundle(){this.emitFile({type: 'asset',fileName: 'index.html',source: `<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Title</title></head><body><script src="${this.getFileName(ref1)}" type="module"></script></body></html>`});console.log('generateBundle')}}}
插件通信
通过this.resolve
module.exports = function myPlugin1(){return{name: 'requesting',async buildStart() {const resolution = await this.resolve('foo', undefined, {custom: {resolving: { specialResolution: true },type:111}});console.log(resolution.id);}}}//module.exports = function myPlugin2() {return {name: 'resolving',resolveId(id, importer, { custom }) {if (custom.resolving?.specialResolution) {return 'special';}return null;}};}
通过自定义meta
module.exports = function demo1(){return{name: 'annotating',transform(code, id) {if (this.getModuleIds(code, id)) {return {meta: {annotating: {special: true},type:1111}};}}}}//module.exports = function demo2() {return {name: 'reading',buildEnd() {const specialModules = Array.from(this.getModuleIds()).filter(id => this.getModuleInfo(id).meta.annotating?.special);console.log(specialModules)}};}
直接插件与插件通信
module.exports = function demo1(){return{name: 'parent',api: {doSomething(...args) {console.log('执行了111')}}}}module.exports = function demo2() {let parentApi;return {name: 'dependent',buildStart({ plugins }) {const parentName = 'parent';const parentPlugin = plugins.find(plugin => plugin.name === parentName);parentApi = parentPlugin.api;},transform(code, id) {parentApi.doSomething(id);}};}
