Comments (2)
It's definitely possible to allow modules to resolve to multiple loaders. That's exactly what the WebAssembly example plugin does. Your problems are due to the way your code works.
import { ReactComponent as ImgSupplier } from 'assets/images/my-image.svg';
For this one, you are passing external: true
to esbuild. That tells esbuild to exclude that import path from the bundle (i.e. it will be loaded at run-time, not at compile-time). That is already documented here. That's why your onLoad
callback isn't running at compile-time. If you wanted that path to be internal to the bundle then you shouldn't be setting external: true
for that path.
.my-class { background-image: url('/assets/images/my-image.svg'); }
For this one, your code is deliberately falling back to esbuild's default behavior (the part of your code that says anything else falls back on the default (file) loader
). The default file loader takes the path and reads it from the file system. I'm guessing there is no file present at the absolute path /assets/images/my-image.svg
, which is why esbuild is saying Could not resolve "/assets/images/my-image.svg"
. That is not a problem with esbuild. Perhaps you meant to use a relative path instead? Relative paths start with ./
while absolute paths start with /
.
from esbuild.
Thanks, that pointed me in the right direction. For posterity the final code looked like below:
const { readFile: read } = require('node:fs/promises');
const path = require('node:path');
const JS_IMPORTS = ['import-statement', 'require-call', 'dynamic-import', 'require-resolve'];
/** Converts `my-image.svg` to `MyImage` */
const filename = fn => {
return `${fn.split('-').map(s => `${s[0].toUpperCase()}${s.substring(1)}`).join('')}`.replace(/\.svg$/, '').replace(/^(\d)/, '_$1');
};
/**
* esbuild plugin that converts SVG files to import-able ES modules.
* @param {{}} options
* @returns {import('esbuild').Plugin}
*/
module.exports = (options = {}) => {
return {
name: 'svg-resolver',
setup(build) {
build.onResolve({ filter: /\.svg$/ }, async args => {
if (args.namespace !== 'svg-component' && JS_IMPORTS.includes(args.kind))
return { path: path.join(process.cwd(), 'src', args.path), namespace: 'svg-component' };
else if (!args.path.startsWith(path.join(process.cwd(), 'src')))
return { path: path.join(process.cwd(), 'src', args.path), namespace: 'file' };
else
return { path: args.path, namespace: 'file' };
});
build.onLoad({ filter: /.*/, namespace: 'svg-component' }, async (args) => {
const fn = args.path.split('\\').at(-1);
const fname = `Svg${filename(fn)}`;
const contents =
`import React from 'react';
import contents from ${JSON.stringify(args.path)};
function ${fname}(props) {
return (
<img src={contents} {...props} />
);
}
export { ${fname} as ReactComponent };
export default contents;
`;
return {
contents,
loader: 'jsx',
resolveDir: process.cwd()
};
});
build.onLoad({ filter: /.*/, namespace: 'svg-file' }, async (args) => {
const fn = args.path;
const svg = await read(args.path, { encoding: 'utf8' });
const sanitized = svg.match(/<svg[^]+?<\/svg>/)?.[0];
if (!sanitized)
return { errors: [{ pluginName: 'svgr', location: args.path, text: `${fn} is not a valid svg.` }] };
return { contents: sanitized, loader: 'file' };
});
}
};
};
My intention was to make this as close as possible to the react-scripts
implementation, so it has an implicit root directory of 'src'
.
from esbuild.
Related Issues (20)
- idea: bundle embed or static file inside a single file. HOT 3
- Source maps containing `https://` urls get mangled
- Please give me tips how to solve router plain javascript app HOT 2
- How to get final version of build.initialOptions inside a plugin? HOT 2
- Basic question: where is the code that interacts with Nodejs workers? HOT 2
- How to add success log to watch ? HOT 2
- Bundling with HTML HOT 3
- How to build for adobe jsx? HOT 2
- CSS transforms can break nested selectors HOT 3
- Feature Request: Allow absolute paths for resolved chunks HOT 3
- Dynamic import issue when using react hook useEffect inside a remote component HOT 4
- Track which entryfile changed
- Glob pattern for `copy` file loader HOT 2
- Forcing node_modules resolution with the `resolve` function HOT 2
- punycode should be 'external' but bundled ? HOT 2
- Control module bundle dividers HOT 2
- [ERROR] Unexpected end of file in JSON ../jsconfig.json:18:0 - File does not exist in project and node_modules HOT 1
- `OnLoad` in custom plugin is called for disabled modules
- Specifying where compiled CSS files stored
- Assigning to the variable `name` doesnโt work when bundling to ESM output HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. ๐๐๐
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google โค๏ธ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from esbuild.