developit / microbundle

📦 Zero-configuration bundler for tiny modules.
https://npm.im/microbundle
MIT License
7.99k stars 361 forks source link

How can I include SVGs into my build? #1072

Closed MarquesCoding closed 5 months ago

MarquesCoding commented 6 months ago

How do I include image formats inside of my build? I'm having issues with a component that I'm making...

e.g

<ComponentName imagePath="./textures/image.svg"/>

this works but when using the package within my React project, it tries to use "./textures/image.svg" location relative to where the component is and not using the package's assets. So I tried an alternative method...

import image from './textures/image.svg';

<ComponentName imagePath={image}/>

But I'm getting an error for this:

Error: Unexpected token (Note that you need plugins to import files that are not JavaScript)

I know this is meant to be easy to work with, but I don't fully understand how I'm meant to include assets into my package and use them on the components and they be relative to the component and not the project -- if that makes sense.

rschristian commented 6 months ago

Well firstly it's important to note that there's no way (at this time) to import SVGs into JS -- this is something bundlers have fudged but is completely against the spec and unsupported here.

Can you clarify this?

this works but when using the package within my React project, it tries to use "./textures/image.svg" location relative to where the component is and not using the package's assets.

What's the goal here specifically? Using an SVG distributed with the component, or is this SVG in your app (not component/library)? How are you then using this path?

MarquesCoding commented 6 months ago

What's the goal here specifically? Using an SVG distributed with the component, or is this SVG in your app (not component/library)? How are you then using this path?

Hi, thanks for the quick response.

I'm currently trying to make a shared UI library that I can use in my multiple React projects. I have a component that is a custom wrapper for three.js Texture Loader where it needs a string for the image path. But I want to bundle the images with the package rather than the React Projects providing them. I've got microbundle to copy the assets into the /dist folder but it cannot find it within React because the image path is ./textures/image.svg....

Sorry again if that doesn't make sense.

MarquesCoding commented 6 months ago

Example:

            <ThreeImageLoader
                imagePath="./assets/textures/location_pin.svg"
                ...
            />

And within ThreeImageLoader I have:

const texture = new TextureLoader().load(imagePath);

rschristian commented 6 months ago

Gotcha!

Unfortunately this is going to be very build tool dependent. You might have a better time if you simply provide the image path to the component from user code, rather than distributing your component with the correct path.

You might be able to do node_modules/<my-lib-name>/dist/textures/image.svg (or something along those lines) in your component but different tools will handle that differently, there is no spec here.

Referencing non-JS assets in a spec-compliant way is a headache that's being worked on and hopefully will be better in the next few years.

MarquesCoding commented 6 months ago

Thanks for the info :) I shall give it a dig and try

rschristian commented 6 months ago

If you get stuck, I can try to do some finagling too if you can provide a reproduction of your lib & a test app (with the sort of tools where you plan on using this lib).

MarquesCoding commented 6 months ago

Thanks for the help -- but sadly I can't share any of the code as it's my works code and under NDA, so a lot of the stuff I provide is vague 😢 I'm still stuck...

rschristian commented 6 months ago

Ah, sorry.

Unfortunately I can't do much to help without reproduction in some form (even a bare lib & app would be enough), but the reality is that it's going to be a guess and check anyhow. There is no spec for this and how different tools handle it is iffy at best. Your best bet is to provide the image URL to the component from your own app code

Edit: I will add that, in the off chance you're using Vite (and only Vite), this could work (but you'd need a post-build step, as Microbundle will not support it out-of-the-box):

import imgUrl from './textures/image.svg';
...
<img src={imgUrl} />

Again, very spec uncompliant, and Vite might change that behavior later (surprised me they actually apply those loaders to node_modules), but is the best I can suggest at the moment.

MarquesCoding commented 6 months ago

Yeah, we currently aren't using Vite. We are using a webpack react project for one of them and vite in the other 😢 Thanks

rschristian commented 6 months ago

Oof, if there's two consuming applications running on different tooling then there's little chance you'll be able to find something that works for both.

Good luck though.

MarquesCoding commented 6 months ago
Screenshot 2024-01-11 at 19 52 38

Just wanted to ask... but there is no way of reading ./assets?

From the components themselves within the library?

rschristian commented 6 months ago

Read how?

You can do something like new URL('./foo.jpg', import.meta.url), but whether a dev server/build process (for the consuming application) will actually respect that depends. Vite won't.

MarquesCoding commented 5 months ago

Okay, I've migrated over to vite and now the assets work... but the only issue is that the library is now x2 from 1.5MB to 3MB :(

rschristian commented 5 months ago

How would the library grow in size?

MarquesCoding commented 5 months ago

Going to close this, turns out in my rollup options I was including all the deps during the bundle 🤦

rschristian commented 5 months ago

If you're configuring Rollup then you're not using Microbundle. Bit confused as to what you're referring to.