Open rikbrown opened 2 months ago
Hey @rikbrown, thanks for filing this!
There's different levels to this issue, so I'll walk through them one by one 🗒️
Would it be possible to make it compatible, or possibly provide an alternative implementation which is? It looks like the coder is using useContext for configuration and useMemo to memoize config.rewritePath (not sure how important that is to memoize).
I agree, the long-term goal would be to provide a component that does not need the client directive, while supporting ad-hoc configuration (such a component could be an alternative named export). The nice thing about Context is that it is a built-in way of providing this configuration for a given React tree, but we can use a global initializer function, or some other pattern:
import {initializeGlobalConfig, type Config} from '@svg-use/react';
initializeGlobalConfig({
rewritePath,
runtimeChecksEnabled
})
// Other initialization logic
Before we get there, however, we should understand the use-cases for configuration, in an RSC world. The largest config use-case is rewriting paths to support CDN proxies, which I do not imagine varying per tree, but at the same time I do not know the idiomatic patterns for global config in RSC.
What you can do, both to unblock your use-case and to help us figure out the shape of a future component, is to provide your own component factory to svg-use
, via the componentFactory
option:
config.module.rules.push({
test: /\.svg$/i,
exclude: /node_modules\/(?!@packages\/icons)/,
use: [
{
loader: '@svg-use/webpack',
+ options: {
+ componentFactory: {
+ functionName: 'createRscCompatibleThemedSvg',
+ importFrom: 'path-to-your-component-file'
+ }
+ }
},
],
})
(You can use webpack's resolve aliases, if you need an absolute path to your component factory)
This changes the generated JS module to the equivalent of:
import { createRscCompatibleThemedSvg } from 'path-to-your-component-file';
export const id = 'use-href-target';
export const href = new URL('/assets/some-icon-1234.svg', import.meta.url).href;
export const viewBox = '0 0 32 32';
export const Component = createRscCompatibleThemedSvg({ href, id, viewBox });
The default component is more of a convenience, and it is a design goal to allow people to override it. So I definitely recommend creating your own that fits your use-case.
Does the above solve your use-case? How do you approach config in that scenario?
If the above works, I suggest that we turn this into a feature request, and gather feedback from other RSC + svg-use users. We can then work out an API that works best 😌
Thank you for your detailed explanation!! This makes a lot of sense. I'll try out your custom component approach when I get a chance this week and report back with feedback.
Unrelated Next.js question - have you had any success using your plugin with Turbopack in Next.js? It has only minimal support for Webpack plugins (svgr is supported). I couldn't get it to work when I tried really quickly but didn't go too deep into debugging. I can create a separate discussion for this if it isn't trivial/not on your radar. Turbopack is experimental so no worries right now.
Unrelated Next.js question - have you had any success using your plugin with Turbopack in Next.js? It has only minimal support for Webpack plugins (svgr is supported).
I haven't looked into Turbopack much, but glancing at their compatibility docs it seems that use-cases such as svg-use
are not supported at the moment:
Only loaders that return JavaScript code are supported. Loaders that transform files like stylesheets or images are not currently supported.
They don't spell out the webpack APIs (which is a bit meh, when talking about compatibility 😅), but I take this to mean that emitAsset
is not supported. svg-use
relies on that to emit the transformed SVG, while returning a JS module from the loader itself. We don't do any other fancy loader stuff, aside from this, so my gut feeling is that this will work eventually.
I can copy over some of this text to its own feature request, for documentation. I'll also edit this issue to mark RSC as a feature, to work on the component API 📔
Relevant package
@svg-use/react
@svg-use/webpack
Describe the bug
I'm trying to use this with Next.js 14 as a replacement for svgr. We're using the App Router and have a number of RSCs.
Unfortunately it looks like
ThemedExternalSvg
uses contexts/hooks which are not allowed in RSCs, thus to use the plugin we'd need to mark any component that uses a SVG with"use client"
. That's not particularly ideal and doesn't affect svgr.Would it be possible to make it compatible, or possibly provide an alternative implementation which is? It looks like the coder is using
useContext
for configuration anduseMemo
to memoize config.rewritePath (not sure how important that is to memoize).I'm calling this a "bug" as RSCs are a core feature of React now but I guess this could be seen as a feature request.
To Reproduce
Using this in my next.config.js webpack section:
Expected behavior
For it to work in RSCs.
Screenshots If applicable, add screenshots to help explain your problem.
Additional context Add any other context about the problem here.