plugin要求

  • 可以是一个对象、一个class、一个方法、但是始终返回一个对象给到rollup
  • 插件应该有一个清晰的名称和 rollup-plugin- 前缀
  • 尽可能使用异步方法
  • 如果合适,请确保您的插件输出正确的源映射

    build/hooks

    1. function insertNotes(){
    2. return {
    3. name:"rollup-plugin-insertNotes", // 名称会在 warnings 和 errors 中显示
    4. resolveId(source, importer, options){
    5. console.log("当前解析的文件信息---resolveId")
    6. },
    7. load(id) {
    8. console.log("加载的模块")
    9. },
    10. transform(code){
    11. console.log('每一个文件转换---transform')
    12. },
    13. buildStart(InputOptions){
    14. console.log('开始构建---buildStart')
    15. },
    16. buildEnd(error){
    17. console.log('打包结束--buildEnd')
    18. },
    19. watchChange(){
    20. console.log('watch模式下文件变动----watchChange')
    21. },
    22. closeWatcher(){
    23. console.log('关闭了watch---closeWatcher')
    24. },
    25. moduleParsed(moduleInfo){
    26. console.log("Rollup 完全解析模块时都会调用此钩子---moduleParsed")
    27. },
    28. options(InputOptions){
    29. console.log('这是构建阶段的第一个钩子--下一个执行buildStart')
    30. },
    31. }
    32. }

    rollup自定义plugin - 图1

    output/hooks

    1. module.exports = function insertNotes() {
    2. return {
    3. name: "rollup-plugin-insertNotes",
    4. // output --hooks
    5. augmentChunkHash() {
    6. // 经过renderStart +banner/footer 等阶段后,将会生成chunk。 每个chunk再接下来的步骤,都会先经历这个hook。
    7. console.log("为每个汇总输出块调用---augmentChunkHash")
    8. },
    9. banner(){
    10. /*
    11. banner 、 footer 、 intro 、 outro 四个钩子当输出的配置中,配置了这四项时,会触发的钩子。
    12. banner 和 footer 是分别向代码的开头和结尾插入代码;
    13. intro 和 outro 是分别向包装器的内部和外部插入代码。
    14. */
    15. console.log('banner')
    16. },
    17. footer(){
    18. console.log('footer')
    19. },
    20. intro(){
    21. console.log('intro')
    22. },
    23. outro(){
    24. console.log('outro')
    25. },
    26. generateBundle(){
    27. // 在调用 bundle.generate 后,或者在调用 bundle.write 之前立即触发这个hook
    28. console.log('generateBundle')
    29. },
    30. outputOptions(){
    31. console.log('输出参数----outputOptions')
    32. },
    33. renderChunk(){
    34. console.log('转译单个的chunk----renderChunk')
    35. },
    36. renderStart(){
    37. // 这个hook,用来给chunk增加hash
    38. console.log('renderStart')
    39. },
    40. resolveFileUrl(){
    41. console.log('resolveFileUrl')
    42. },
    43. resolveImportMeta(){
    44. console.log('resolveImportMeta')
    45. },
    46. writeBundle(){
    47. // bundle.write后,所有的chunk都写入文件后,最后会调用一次 writeBundle 。
    48. console.log('writeBundle')
    49. }
    50. }
    51. }

    image.png

    插件的上下文

    我们在使用钩子的时候会往上下文绑定一些工具方法、这些工具方法可以让我们对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
image.png

  • 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)
示例:
image.png

  • 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

  1. module.exports = function removeConsole() {
  2. return {
  3. name: 'remove-console',
  4. transform(code, id) {
  5. const Reg = /console\.log\(.*\)/ig;
  6. return code.replace(Reg, "")
  7. }
  8. }
  9. }

生成一个index.html并引入打包后的js文件

  1. module.exports = function generateHtmlPlugin() {
  2. let ref1;
  3. return {
  4. name: "rollup-plugin-generateHtml",
  5. buildStart() {
  6. // 获取chunk
  7. ref1 = this.emitFile({
  8. type: 'chunk',
  9. id: 'packages/core/src/index.ts' // 需要你当前入口文件地址
  10. });
  11. },
  12. generateBundle(){
  13. this.emitFile({
  14. type: 'asset',
  15. fileName: 'index.html',
  16. source: `
  17. <!DOCTYPE html>
  18. <html>
  19. <head>
  20. <meta charset="UTF-8">
  21. <title>Title</title>
  22. </head>
  23. <body>
  24. <script src="${this.getFileName(ref1)}" type="module"></script>
  25. </body>
  26. </html>`
  27. });
  28. console.log('generateBundle')
  29. }
  30. }
  31. }

插件通信

通过this.resolve

  1. module.exports = function myPlugin1(){
  2. return{
  3. name: 'requesting',
  4. async buildStart() {
  5. const resolution = await this.resolve('foo', undefined, {
  6. custom: {
  7. resolving: { specialResolution: true },
  8. type:111
  9. }
  10. });
  11. console.log(resolution.id);
  12. }
  13. }
  14. }
  15. //
  16. module.exports = function myPlugin2() {
  17. return {
  18. name: 'resolving',
  19. resolveId(id, importer, { custom }) {
  20. if (custom.resolving?.specialResolution) {
  21. return 'special';
  22. }
  23. return null;
  24. }
  25. };
  26. }

通过自定义meta

  1. module.exports = function demo1(){
  2. return{
  3. name: 'annotating',
  4. transform(code, id) {
  5. if (this.getModuleIds(code, id)) {
  6. return {
  7. meta: {
  8. annotating: {
  9. special: true
  10. },
  11. type:1111
  12. }
  13. };
  14. }
  15. }
  16. }
  17. }
  18. //
  19. module.exports = function demo2() {
  20. return {
  21. name: 'reading',
  22. buildEnd() {
  23. const specialModules = Array.from(this.getModuleIds()).filter(
  24. id => this.getModuleInfo(id).meta.annotating?.special
  25. );
  26. console.log(specialModules)
  27. }
  28. };
  29. }

直接插件与插件通信

  1. module.exports = function demo1(){
  2. return{
  3. name: 'parent',
  4. api: {
  5. doSomething(...args) {
  6. console.log('执行了111')
  7. }
  8. }
  9. }
  10. }
  11. module.exports = function demo2() {
  12. let parentApi;
  13. return {
  14. name: 'dependent',
  15. buildStart({ plugins }) {
  16. const parentName = 'parent';
  17. const parentPlugin = plugins.find(plugin => plugin.name === parentName);
  18. parentApi = parentPlugin.api;
  19. },
  20. transform(code, id) {
  21. parentApi.doSomething(id);
  22. }
  23. };
  24. }