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 --hooks
augmentChunkHash() {
// 经过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 之前立即触发这个hook
console.log('generateBundle')
},
outputOptions(){
console.log('输出参数----outputOptions')
},
renderChunk(){
console.log('转译单个的chunk----renderChunk')
},
renderStart(){
// 这个hook,用来给chunk增加hash
console.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() {
// 获取chunk
ref1 = 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);
}
};
}