Skip to content
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

Document how to use third party React libraries #1395

Open
marvinhagemeister opened this issue Jul 3, 2023 · 11 comments
Open

Document how to use third party React libraries #1395

marvinhagemeister opened this issue Jul 3, 2023 · 11 comments
Labels

Comments

@marvinhagemeister
Copy link
Collaborator

marvinhagemeister commented Jul 3, 2023

Preact has a React compatibility layer with which most React-based component libraries can be used with Preact. Document how this can be set up in fresh.

Aliases are not supported with npm: so far, but work with esm.sh when setting them in the import map:

  {
+   "react": "https://esm.sh/preact/compat",
+   "react-dom": "https://esm.sh/preact/compat",
+   "react/jsx-runtime": "https://esm.sh/preact/jsx-runtime",
+   "<react-library>": "https://esm.sh/<react-library>?external=react,react-dom,react%2Fjsx-runtime",
  }

Once set up, there is the caveat that those can only be used inside an island as they need client side JS to run

@marvinhagemeister marvinhagemeister changed the title Document how to use third party React Document how to use third party React libraries Jul 3, 2023
@deer
Copy link
Contributor

deer commented Jul 3, 2023

Thanks for creating this. I already wanted to do this, but sadly wasn't able to get it working. (Even with your hints here!) I tried using flowbite, after seeing this conversation: #1363.

Are you saying that it's not possible to do this as server rendered components? This stuff will only work as islands?

@marvinhagemeister
Copy link
Collaborator Author

FYI: Just fixed that for a discord user for radix-ui with the following changes: https://github.com/hapaxlife/test-fresh-radix-ui/pull/1/files

@ynwd
Copy link

ynwd commented Sep 11, 2023

I try to use https://floating-ui.com/docs/react. But ESBUILD always complaint:

✘ [ERROR] Module not found "https://esm.sh/@floating-ui/[email protected]?external=react,react-dom,react/jsx-runtime". [plugin deno-loader]

    uuid.tsx:3:28:
      3 │ import { useFloating } from "@floating-ui/react";
        ╵                             ~~~~~~~~~~~~~~~~~~~~

error: Uncaught (in promise) Error: Build failed with 1 error:
uuid.tsx:3:28: ERROR: [plugin: deno-loader] Module not found "https://esm.sh/@floating-ui/[email protected]?external=react,react-dom,react/jsx-runtime".
  let error = new Error(text);
              ^
    at failureErrorWithLog (https://deno.land/x/[email protected]/mod.js:1625:15)
    at https://deno.land/x/[email protected]/mod.js:1034:25
    at runOnEndCallbacks (https://deno.land/x/[email protected]/mod.js:1460:45)
    at buildResponseToResult (https://deno.land/x/[email protected]/mod.js:1032:7)
    at https://deno.land/x/[email protected]/mod.js:1061:16
    at responseCallbacks.<computed> (https://deno.land/x/[email protected]/mod.js:679:9)
    at handleIncomingPacket (https://deno.land/x/[email protected]/mod.js:738:9)
    at readFromStdout (https://deno.land/x/[email protected]/mod.js:655:7)
    at https://deno.land/x/[email protected]/mod.js:1923:11
    at eventLoopTick (ext:core/01_core.js:183:11)

import_map

{
  "imports": {
    "react": "https://esm.sh/preact/compat",
    "react-dom": "https://esm.sh/preact/compat",
    "react/jsx-runtime": "https://esm.sh/preact/jsx-runtime",
    "@floating-ui/react": "https://esm.sh/@floating-ui/[email protected]?external=react,react-dom,react/jsx-runtime"
  }
}

Could you teach me how to use it in proper way?

@marvinhagemeister
Copy link
Collaborator Author

@ynwd ah, looks like the slash in react/jsx-runtime must be encoded for URLs.

  {
    "imports": {
      "react": "https://esm.sh/preact/compat",
      "react-dom": "https://esm.sh/preact/compat",
      "react/jsx-runtime": "https://esm.sh/preact/jsx-runtime",
-     "@floating-ui/react": "https://esm.sh/@floating-ui/[email protected]?external=react,react-dom,react/jsx-runtime"
+     "@floating-ui/react": "https://esm.sh/@floating-ui/[email protected]?external=react,react-dom,react%2Fjsx-runtime"
    }
  }

@ynwd
Copy link

ynwd commented Sep 11, 2023

Thanks @marvinhagemeister .

The error completely disappeared after I set import_map like this:

  "imports": {
    "react": "https://esm.sh/[email protected]/compat",
    "react-dom": "https://esm.sh/[email protected]/compat",
    "react/jsx-runtime": "https://esm.sh/[email protected]/jsx-runtime",
    "preact": "https://esm.sh/[email protected]",
    "preact/": "https://esm.sh/[email protected]/",
    "@floating-ui/react": "https://esm.sh/@floating-ui/[email protected]?alias=react:preact/compat,react-dom:preact/compat,@types/react:preact/compat&deps=react"
  }

and add configPath at esbuild deno-plugins:

plugins: [
  ...denoPlugins({
    configPath,
  }),
]

@marvinhagemeister
Copy link
Collaborator Author

marvinhagemeister commented Sep 11, 2023

@ynwd Why was the configPath argument needed?

The aliasing works too, although it's a bit more verbose than marking modules as external.

@ynwd
Copy link

ynwd commented Sep 11, 2023

@ynwd Why was the configPath argument needed?

The aliasing works too, although it's a bit more verbose than marking modules as external.

The plugin requires it to read from the deno.json path.

@adamgreg
Copy link
Contributor

adamgreg commented Sep 11, 2023

Is there a risk that the suggested approach will cause problems by introducing duplicate versions of Preact? I think you might have to be careful to include the same version specifier in the https://esm.sh URLs of 5 different import map entries - "preact", "preact/", "react", "react-dom" & "react/jsx-runtime".

I've been using an approach similar to @ynwd above - aliasing the react dependencies using the alias query parameter, and using the external query parameter to ensure the same preact version/source is used throughout the application.
I've also had to be careful to specify an "es" target, otherwise the components may include Deno-specific code and fail in islands.

"<react-library>": "https://esm.sh/<react-library>?alias=react:preact/compat,react-dom:preact/compat,@types/react:preact/compat&external=preact&target=es2022",

It's unpleasantly verbose, but it's working well for several different packages.

React dependencies are hard to avoid, and I found it very difficult to work out how to do this, so documentation would be extremely useful. It's a shame that there's no aliasing support (yet?) using npm: specifiers, as that might be easier.

@adamgreg
Copy link
Contributor

@marvinhagemeister are you sure about the "only to be used inside an island" caveat? I've been rendering some components imported this way on the server with no problems. Might it depend on the specific package/component?

@marvinhagemeister
Copy link
Collaborator Author

@adamgreg yeah depends on the package.

@shanipribadi
Copy link

shanipribadi commented Nov 5, 2024

With Fresh 2.0 being published in jsr, the approach of aliasing react using esm.sh ?external=react no longer works (old approach example: https://github.com/shanipribadi/spikepreact), due to fresh depending on npm:preact and jsr import can't be mixed with esm.sh import.

but unfortunately, since deno does not support doing npm package aliasing yet denoland/deno#18191, it's not possible to do so with only deno.

Instead I've figured out a way to make fresh 2.0 works with react using node-modules-dir manual and bun.

Following is the setup (using deno 2.0.4 and bun 1.1.33)

deno.json

  "imports": {
    "fresh": "jsr:@fresh/core@^2.0.0-alpha.24",
    "@fresh/plugin-tailwind": "jsr:@fresh/plugin-tailwind@^0.0.1-alpha.7",
    "preact/jsx-runtime": "npm:preact@^10.24.3/jsx-runtime"
  },

all jsr dependencies added to deno.json imports, with the occassional import-map mapping as required (e.g. preact/jsx-runtime imported by fresh)

package.json

  "nodeModulesDir": "manual",
  "dependencies": {
    "@coreui/react": "npm:@coreui/react@^5.4.1",
    "@preact/signals": "npm:@preact/signals@^1.3.0",
    "esbuild": "npm:[email protected]",
    "esbuild-wasm": "npm:[email protected]",
    "preact": "npm:preact@^10.24.3",
    "preact-render-to-string": "npm:preact-render-to-string@^6.5.11",
    "react": "npm:@preact/compat@^18.3.1",
    "react-dom": "npm:@preact/compat@^18.3.1"
  }

all npm dependencies added to package.json to be managed by bun, including transitive npm dependencies of the jsr dependencies.
react and react-dom is aliased by bun by configuring it in package.json.

bun install
deno task dev

Note: not all react npm components work this way, coreui does work because it seemed they published an esm module,
but react-insta-stories didn't work because of preactjs/preact#2690, I assumed because they're not publishing esm module, and the webpack require caused a duplicate preact import.

A working repository example is provided here: https://github.com/shanipribadi/spikefreshreact
The repo has a working CoreUI Button both in an islands and in a SSR context.

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

No branches or pull requests

5 participants