Compatibility with preact
jakub-g opened this issue · 1 comments
Hello,
I was trying to use the loader with preact (bundling with webpack) and here's what I've found for other interested people.
I used following webpack conf:
rules: [
...
{
test: /\.svg$/,
loader: 'react-svg-loader',
}
]
Outside of the box, the module does not work with preact
because of a hard dependency on react
.
When trying to compile the app, there's an error like this:
ERROR in ./app/icons/XXX.svg (./node_modules/react-svg-loader/lib/loader.js!./app/icons/XXX.svg) Module not found: Error: Can't resolve 'react' in 'C:\git\<repo>\app\icons\'
I managed to fix it by installing preact-compat
and aliasing it as react
in webpack config:
{
...
resolve: {
...
alias: {
react: 'preact-compat',
}
}
This works but is not ideal, as preact-compat
is 13kB (5 kB gzipped) which seems wasteful because the only thing necessary for the module to work is React.createElement
which should be generally what preact.h
does.
I will try to find out if there's some way to have a build-time replacement of this instead of runtime dependency on preact-compat
. If anyone knows how to do it, please let me know.
Alright so for the future visitors, I managed to make this loader compatible with preact
v8 without using preact-compat
as follows:
- webpack config:
return {
rules: [
{
test: /\.svg$/,
use: [
// Note the loaders are applied in reverse order!
// 2. Transform JSX to JS.
// Basically copied the existing babel config for JSX files here.
{
loader: 'babel-loader',
options: {
presets: [['env', presetEnvLegacySettings]],
plugins: [
['transform-object-rest-spread', { useBuiltIns: true }],
['transform-react-jsx', { pragma: 'h' }],
]
},
},
// 1. Load SVG and transform it to JSX
{
loader: 'react-svg-loader',
options: {
jsx: true,
},
},
],
},
- Modify babel-plugin-react-svg:
react-svg-loader/packages/babel-plugin-react-svg/src/index.ts
Lines 152 to 155 in fa8b061
- path.node.body.unshift(t.importDeclaration([t.importDefaultSpecifier(t.identifier("React"))], t.stringLiteral("react")));
+ path.node.body.unshift(t.importDeclaration([t.importSpecifier(t.identifier("h"), t.identifier("h"))], t.stringLiteral("preact")));
- Alternatively in step 1, do not define
babel-loader
+options: { jsx: true,},
but instead modify react-svg-core as follows:
react-svg-loader/packages/react-svg-core/src/index.ts
Lines 23 to 25 in fa8b061
- presets: [jsx ? void 0 : "@babel/preset-react"].filter(Boolean),
+ presets: jsx ? [] : [["@babel/preset-react", {pragma: 'h'}]],
Another thing I tried but it didn't quite work: without passing { jsx: true }
to the plugin and add babel-loader, you could m
but this still requires preact-compat
to work (it is require
d but not used, but somehow webpack doesn't discard it).