esbuild
esbuild copied to clipboard
Extend the behavior of the file loader
The file loader works fine as it returns the path of the file I want (with the correct target path).
I'd like to extend that behavior by adding some additional properties, for example I my case, form images I would want to retrieve also the dimensions of images :
export function createImageLoaderWithAttributePlugin(): Plugin {
return {
name: 'image-loader-import-attributes',
setup(build: PluginBuild) {
build.onLoad({ filter: /\.(png|jpg|jpeg|gif|webp)$/ }, async (args) => {
const loader = args.with.loader as Loader | undefined;
if (!loader) {
return undefined;
}
const image = await readFile(args.path);
const dimensions = imageSize(image);
const contents = `export default "${args.path}";
export const width = ${dimensions.width};
export const height = ${dimensions.height};
`;
return {
contents,
loader: 'file'
};
})
},
};
}
When usin this plugin, I do get the correct path, but the additional properties are striped.
The file loader is not aimed to return the full path to that file, but to add the file to assets and copy the file to dist folder. Anyway, to generate 2 modules from 1 file (a.png → file-a.png + module-width+height), you can re-export the file in the custom loader:
await build({
entryPoints: ['src/index.js'],
bundle: true,
outdir: 'dist',
loader: { '.png': 'file' },
plugins: [{
name: 'cutsom-file-loader',
setup({ onLoad }) {
onLoad({ filter: /\.png$/ }, args => {
// If the user writes 'import a, {mtime} from "./a.png" with { loader: "custom" }',
if (args.with.loader == 'custom') {
// Return a module that re-exports itself and add additional properties.
// Note this triggers the default loader .png=file configured above.
let contents = `export {default} from ${JSON.stringify(args.path)}
export const mtime = ${+statSync(args.path).mtime}`
return {contents, loader: 'js'}
}
})
}
}]
})
This trick is common to see in many cases:
- The CSS modules plugin to generate the css module and also include a real CSS file;
- The svelte/vue plugin to generate js/css modules from one .svelte/.vue file;
- etc.