简要说说Rollup插件

171 阅读3分钟

Rollup插件

Rollup插件就是一个具有属性、输入钩子、输出钩子的对象; 如下所示

export default function myExample () {
  return {
    name: 'my-example', // 此名称将出现在警告和错误中
    resolveId ( source ) {
      if (source === 'virtual-module') {
        // 这表示 rollup 不应询问其他插件或
        // 从文件系统检查以找到此 ID
        return source;
      }
      return null; // 其他ID应按通常方式处理
    },
    load ( id ) {
      if (id === 'virtual-module') {
        // "virtual-module"的源代码
        return 'export default "This is virtual!"';
      }
      return null; // 其他ID应按通常方式处理
    }
  };
}

属性

插件的属性基本就是name, version,来描述插件的名称和版本

Rollup构建打包工作流

整个Rollup打包构建阶段,可以分为两个阶段build阶段和output阶段,所以所谓的构建钩子,指的就是Rollup构建阶段暴露出来的钩子;同理,输出钩子,就是Rollup输出阶段暴露出来的钩子;

构建钩子

先来看看Rollup构建阶段,重点说一下几个重要的钩子,其他可以在官网里面查询Rollup中文文档

buildStart构建开始钩子;
resolveld文件路径解析钩子;
load加载模块内容钩子
transform文件内容转换,比如babel转译等;

输出钩子

在构建阶段,将模块依赖分析完毕以后,就可以进入输出阶段,可以简要看看输出阶段的工作流,讲解下几个重点的工作流

outputOptions对output配置进行转换钩子;
renderStart开始正式打包钩子;
renderChunk开始生成chunk钩子
generateBundle开始整合chunk钩子,可以对chunk进行一些删减等操作;
writeBundle输出构建产出到磁盘钩子

常见rollup-plugin源码分析

rollup-plugin-alias

别名处理的插件,类似于webpack中的Reslove.alias,可以改写资源的引入方式,将路径引入更加简便, 比如@用来简要路径

import alias from '@rollup/plugin-alias';
export default {
    input: ["./src/index.js"],
    output: {
        file: "bundle.js",
        format: 'es'
    },
    plugins:  [
        alias({
            entries: [{
                find: '@', replacement: '.'
            }]
        }),
    ]
}

实现原理大致是在构建resolveId阶段,识别需要替换的路经,用replacement做替换;下面是rollup-plugin-alias源码

export default function alias(options: RollupAliasOptions = {}): Plugin {
  const entries = getEntries(options);

  if (entries.length === 0) {
    return {
      name: 'alias',
      resolveId: () => null
    };
  }

  return {
    name: 'alias',
    resolveId(importee, importer, resolveOptions) { 
      const matchedEntry = entries.find((entry) => matches(entry.find, importee));
      if (!matchedEntry) {
        return null;
      }
      // 针对传入的路径用replacement来替换
      const updatedId = importee.replace(matchedEntry.find, matchedEntry.replacement);

      if (matchedEntry.resolverFunction) {
        return matchedEntry.resolverFunction.call(this, updatedId, importer, resolveOptions);
      }

      // 这个rollup祖代的路径解析算法, 返回资源对象,资源对象是一个带id的对象;
      return this.resolve(
        updatedId,
        importer,
        Object.assign({ skipSelf: true }, resolveOptions)
      ).then((resolved) => {
        if (resolved) return resolved;
        // 如果不是绝对路径就报错
        if (!path.isAbsolute(updatedId)) {
          this.warn(
            `rewrote ${importee} to ${updatedId} but was not an abolute path and was not handled by other plugins. ` +
              `This will lead to duplicated modules for the same path. ` +
              `To avoid duplicating modules, you should resolve to an absolute path.`
          );
        }
        return { id: updatedId };
      });
    }
  };
}

@rollup/plugin-image

图片解析插件,在webpack打包构建过程,针对除js之外的资源,需要loader来解析;rollup中也是这样,对于图片资源需要进行资源转换,这里采用@rollup/plugin-image来进行图片资源的转换处理

import image from "@rollup/plugin-image";

import alias from '@rollup/plugin-alias';
export default {
    input: ["./src/index.js"],
    output: {
        file: "bundle.js",
        format: 'es'
    },
    plugins:  [
        image()
    ]
}

实现原理大致就是,在构建阶段,load加载资源的钩子过程中,读取图片的资源,用import的方式来进行重写;可以看下源码实现;

const constTemplate = ({ dataUri }) => `
  var img = "${dataUri}";
  export default img;
`;

export default function image(opts = {}) {
  const options = Object.assign({}, defaults, opts);
  const filter = createFilter(options.include, options.exclude);

  return {
    name: 'image',

    load(id) {
      if (!filter(id)) {
        return null;
      }

      const mime = mimeTypes[extname(id)];
      if (!mime) {
        // not an image
        return null;
      }

      this.addWatchFile(id);
      const isSvg = mime === mimeTypes['.svg'];
      const format = isSvg ? 'utf-8' : 'base64';
      // 如果格式不是svg,就用base64来加载读取图片资源;
      const source = readFileSync(id, format).replace(/[\r\n]+/gm, '');
      const dataUri = getDataUri({ format, isSvg, mime, source });
      // 如果没有定义需要dom方式,就利用ES module来加载解析图片资源;
      const code = options.dom ? domTemplate({ dataUri }) : constTemplate({ dataUri });

      return code.trim();
    }
  };
}

总结

以上从Rollup插件就是一个带有属性,构建钩子,输出钩子的对象,简要分析了Rollup整个打包构建的工作流,来分析了什么是构建钩子,什么是输出钩子