setup()

in packages/ice/src/esbuild/transformPipe.ts [59:157]


    setup(build: PluginBuild) {
      const { plugins = [], namespace = '', filter = /.*/ } = options;
      const errors = [];
      const warnings = [];

      // TODO: support unplugin context such as parse / emitFile
      const pluginContext: UnpluginContext = {
        error(message) { errors.push({ text: String(message) }); },
        warn(message) { warnings.push({ text: String(message) }); },
      };
      const pluginResolveIds = [];
      plugins.forEach(plugin => {
        // Call esbuild specific Logic like onResolve.
        plugin?.esbuild?.setup(build);
        if (plugin?.resolveId) {
          pluginResolveIds.push(plugin?.resolveId);
        }
      });
      if (pluginResolveIds.length > 0) {
        build.onResolve({ filter }, async (args) => {
          const isEntry = args.kind === 'entry-point';
          const res = await pluginResolveIds.reduce(async (resolveData, resolveId) => {
            const { path, external } = await resolveData;
            if (!external) {
              const result = await resolveId(path, isEntry ? undefined : args.importer, { isEntry });
              if (typeof result === 'string') {
                return { path: result };
              } else if (typeof result === 'object' && result !== null) {
                return { path: result.id, external: result.external };
              }
            }
            return resolveData;
          }, Promise.resolve({ path: args.path }));
          if (path.isAbsolute(res.path) || res.external) {
            return res;
          }
        });
      }
      build.onLoad({ filter, namespace }, async (args) => {
        const id = args.path;
        // it is required to forward `resolveDir` for esbuild to find dependencies.
        const resolveDir = path.dirname(args.path);
        const loader = guessLoader(id);

        // If file extension is not recognized and load path is relative, return it to esbuild.
        if (!loader || !path.isAbsolute(id)) {
          return;
        }

        const transformedResult = await plugins.reduce(async (prevData, plugin) => {
          const { contents } = await prevData;
          const { transform, transformInclude, loadInclude } = plugin;
          let sourceCode = contents;
          let sourceMap = null;

          if (plugin.load && (!loadInclude || loadInclude?.(id))) {
            const result = await plugin.load.call(pluginContext, id);
            if (typeof result === 'string') {
              sourceCode = result;
            } else if (typeof result === 'object' && result !== null) {
              sourceCode = result.code;
              sourceMap = result.map;
            }
          }

          if (!transformInclude || transformInclude?.(id)) {
            if (!sourceCode) {
              // Caution: 'utf8' assumes the input file is not in binary.
              // If you want your plugin handle binary files, make sure to execute `plugin.load()` first.
              sourceCode = await fs.promises.readFile(args.path, 'utf8');
            }
            if (transform) {
              const result = await transform.call(pluginContext, sourceCode, id);
              if (typeof result === 'string') {
                sourceCode = result;
              } else if (typeof result === 'object' && result !== null) {
                sourceCode = result.code;
                sourceMap = typeof result.map === 'string' ? JSON.parse(result.map) : result.map;
              }
            }
            if (sourceMap && typeof sourceMap !== 'string') {
              if (!sourceMap.sourcesContent || sourceMap.sourcesContent.length === 0) {
                sourceMap.sourcesContent = [sourceCode];
              }
              // Use relative path to make sure the source map is correct.
              sourceMap.sources = [path.relative(resolveDir, id)];
              sourceMap = fixSourceMap(sourceMap);
              sourceCode += `\n//# sourceMappingURL=${sourceMap.toUrl()}`;
            }
            return { contents: sourceCode, resolveDir, loader };
          }
          return { contents, resolveDir, loader };
        }, Promise.resolve({ contents: null, resolveDir, loader }));
        // Make sure contents is not null when return.
        if (transformedResult.contents) {
          return transformedResult;
        }
      });
    },