Skip to content

Compatibility with preact #290

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
jakub-g opened this issue Oct 29, 2019 · 1 comment
Open

Compatibility with preact #290

jakub-g opened this issue Oct 29, 2019 · 1 comment

Comments

@jakub-g
Copy link

jakub-g commented Oct 29, 2019

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.

@jakub-g
Copy link
Author

jakub-g commented Oct 29, 2019

Alright so for the future visitors, I managed to make this loader compatible with preact v8 without using preact-compat as follows:

  1. 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,
            },
          },
        ],
      },
  1. Modify babel-plugin-react-svg:

t.importDeclaration(
[t.importDefaultSpecifier(t.identifier("React"))],
t.stringLiteral("react")
)

-      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")));
  1. Alternatively in step 1, do not define babel-loader + options: { jsx: true,}, but instead modify react-svg-core as follows:

presets: [jsx ? void 0 : require.resolve("@babel/preset-react")].filter(
Boolean
),

-    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 required but not used, but somehow webpack doesn't discard it).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant