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;
}
});
},