jsr-io / jsr

The open-source package registry for modern JavaScript and TypeScript
https://jsr.io
MIT License
2.49k stars 114 forks source link

Support publishing with JSX #24

Open lucacasonato opened 8 months ago

lucacasonato commented 8 months ago

To publish with JSX, we need to take the JSX relevant config options from tsconfig.json / deno.json and put them into the source files via pragmas.

For example, when publishing this index.jsx file with this deno.json file:

import { renderToString } from "npm:preact-render-to-string";
console.log(renderToString(<div>jsx</div>));
{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "npm:preact"
  }
}

emit this before publish:

/** @jsxRuntime automatic *//** @jsxImportSource npm:preact */
import { renderToString } from "npm:preact-render-to-string";
console.log(renderToString(<div>jsx</div>));
bartlomieju commented 8 months ago

@lucacasonato @dsherret I'm a bit confused by this issue. I thought that we only consider the first encountered directive like that - ie. different directives in different files will override each other. I assume that this situation can't be hit because we're gonna pull the directive value from the config file and it's essentially the first one loaded that will actually have effect. Is this correct?

lucacasonato commented 8 months ago

No - directives are per file.

lucacasonato commented 8 months ago

For now we can just add a warning if your publish contains a .jsx / .tsx file saying that .jsx / .tsx are not supported yet, linking to this issue.

bartlomieju commented 8 months ago

PR adding a warning: https://github.com/denoland/deno/pull/22631

nestarz commented 8 months ago

To support React JSX I think this issue should be resolved so JSR published React+JSX modules works also in Deno, right ?

https://github.com/denoland/deno/issues/18203

neves commented 5 months ago

@nestarz the above issue was resolved, what's the next step to support jsx?

neves commented 5 months ago

@lucacasonato any take on this one?

KyleJune commented 3 months ago

Any updates on this? Also is there a workaround involving manually adding the pragmas that would enable publishing jsx to jsr?

KyleJune commented 3 months ago

Here is one other issue present that may cause issues for packages with react dependencies.

kyle@DESKTOP-6071BGK:~/Projects/deno/react_app$ deno publish --dry-run
Check file:///home/kyle/Projects/deno/react_app/mod.tsx
Check file:///home/kyle/Projects/deno/react_app/build.ts
Check file:///home/kyle/Projects/deno/react_app/dev.ts
Check file:///home/kyle/Projects/deno/react_app/client.tsx
Check file:///home/kyle/Projects/deno/react_app/server.tsx
error: Uncaught Error: [ERR_PACKAGE_PATH_NOT_EXPORTED] Package subpath './client' is not defined for types by "exports" in '/home/kyle/.cache/deno/npm/registry.npmjs.org/react-dom/18.3.1/package.json' imported from 'file:///home/kyle/Projects/deno/react_app/client.tsx'
    at Object.resolveModuleNames (ext:deno_tsc/99_main_compiler.js:766:28)
    at actualResolveModuleNamesWorker (ext:deno_tsc/00_typescript.js:124316:142)
    at resolveModuleNamesWorker (ext:deno_tsc/00_typescript.js:124748:20)
    at resolveModuleNamesReusingOldState (ext:deno_tsc/00_typescript.js:124834:14)
    at processImportedModules (ext:deno_tsc/00_typescript.js:126351:118)
    at findSourceFileWorker (ext:deno_tsc/00_typescript.js:126129:7)
    at findSourceFile (ext:deno_tsc/00_typescript.js:125980:20)
    at processImportedModules (ext:deno_tsc/00_typescript.js:126377:11)
    at findSourceFileWorker (ext:deno_tsc/00_typescript.js:126129:7)
    at findSourceFile (ext:deno_tsc/00_typescript.js:125980:20)

Here are the compiler options that I use along with my react imports.

{
  "compilerOptions": {
    "lib": ["esnext", "dom", "dom.iterable", "dom.asynciterable", "deno.ns"],
    "jsx": "react-jsx",
    "jsxImportSource": "react",
    "jsxImportSourceTypes": "@types/react"
  },
  "imports": {
    "react": "npm:react@18",
    "@types/react": "npm:@types/react@18",
    "react-dom": "npm:react-dom@18",
  }
}

Hope this information is helpful. I think it's important to support JSX and react on JSR. It will help with adoption of Deno and JSR for building front end applications. My code works when I run it with deno, it's just not working with the deno publish command.

Edit: I checked my code and found only one line referencing react-dom/client. It's only actually used on the client side in my esbuild bundle.

import { hydrateRoot } from "react-dom/client";

I tried moving it inside the function that only ever gets called in the browser and making it a dynamic import but I get the same error.

const { hydrateRoot } = await import("react-dom/client");

I also checked the package.json that the error references and it is defined there.

  "files": [
    "LICENSE",
    "README.md",
    "index.js",
    "client.js",
    "profiling.js",
    "server.js",
    "server.browser.js",
    "server.node.js",
    "test-utils.js",
    "cjs/",
    "umd/"
  ],
  "exports": {
    ".": "./index.js",
    "./client": "./client.js",
    "./server": {
      "deno": "./server.browser.js",
      "worker": "./server.browser.js",
      "browser": "./server.browser.js",
      "default": "./server.node.js"
    },
    "./server.browser": "./server.browser.js",
    "./server.node": "./server.node.js",
    "./profiling": "./profiling.js",
    "./test-utils": "./test-utils.js",
    "./package.json": "./package.json"
  },

Edit 2: I found I can run the publish command by adding the --no-check flag.

KyleJune commented 3 months ago

I tried doing a manual fix, it looks like adding these pragmas to my files doesn't get rid of the warning regarding jsx/tsx files not being supported. I haven't checked if it allows you to publish if you get the warning. I'll try that out once I finish the package I'm working on.

/** @jsxRuntime automatic */
/** @jsxImportSource npm:react@18 */
/** @jsxImportSourceTypes npm:@types/react@18 */
warning[unsupported-jsx-tsx]: JSX and TSX files are currently not supported
 --> /home/kyle/Projects/deno/react_app/client.tsx

  info: follow https://github.com/jsr-io/jsr/issues/24 for updates
neves commented 3 months ago

I tried doing a manual fix, it looks like adding these pragmas to my files doesn't get rid of the warning regarding jsx/tsx files not being supported. I haven't checked if it allows you to publish if you get the warning. I'll try that out once I finish the package I'm working on.

/** @jsxRuntime automatic */
/** @jsxImportSource npm:react@18 */
/** @jsxImportSourceTypes npm:@types/react@18 */
warning[unsupported-jsx-tsx]: JSX and TSX files are currently not supported
 --> /home/kyle/Projects/deno/react_app/client.tsx

  info: follow https://github.com/jsr-io/jsr/issues/24 for updates

@KyleJune, today this warning is hard coded https://github.com/denoland/deno/pull/22631/files

KyleJune commented 3 months ago

I've verified that adding the pragmas and ignoring the warnings about JSX and TSX files not being supported allowed me to publish to JSR. I haven't tried publishing without the pragmas, I just know it works with them. I'm assuming it doesn't with out them by the existence of this issue.

I'm still working on it, but you can see the published package containing JSX here. https://jsr.io/@udibo/react-app

It's not quite ready for others to use but it works. Here is a repo you could fork to see that it's able to import JSX modules from JSR.

https://github.com/udibo/react-app-example

One thing worth noting is that it seems building is slower when I use the package from JSR. In that example repo, I consistently get build times around ~1200ms.

INFO Detected change: /home/kyle/Projects/deno/react_app_example/routes/index.tsx
INFO Building app
INFO Build completed in 1171 ms
INFO Restarting app
INFO Listening on: http://localhost:9000
INFO Server restarted

The same example is present in the repo for my published package. There it consistently takes around 650ms, almost half the time it does when I'm using it through jsr. https://github.com/udibo/react-app/tree/main/example

INFO Detected change: /home/kyle/Projects/deno/react_app/example/routes/index.tsx
INFO Building app
INFO Build completed in 643 ms
INFO Restarting app
INFO Listening on: http://localhost:9000
INFO Server restarted

The only real difference between the 2 is that one is importing the build script from JSR and the other is using it locally since it is present in the parent directory.

I'm not sure if it's that esbuild is slower or if it has something to do with the dynamic imports the script is doing. I filed a separate issue regarding a workaround I had to do to be able to dynamically import user files in my build script.

https://github.com/jsr-io/jsr/issues/670

Edit: I improved my logging, adding additional performance measurements. It appears the slowdown is specifically related to esbuild. Same build script running, only difference being that one is importing it from JSR and the other is importing it from a local file. Both depend on npm:esbuild@0.20.

tlgimenes commented 3 months ago

Why do I need to publish .js files only? Can't I publish a .jsx so that, if I'm using fresh, fresh will use it's own jsx config. If I'm using next.js, next.js will use it's own .jsx config. This way I can support both Fresh(preact) and Next.js(react)

ghandic commented 2 months ago

What are the dependencies for this to be resolved? There isnt much mentioned on this in the docs and its quite a sizable gap to move from npm

sgwilym commented 1 month ago

I've been sitting on top of a suite of macro libraries which I can't release because of the lack of this publishing with JSX, and for which we still rely on deno.land/x. Please bring publishing with JSX to JSR!

grenierdev commented 1 month ago

I was able to publish my .tsx to JSR without many issues (see for yourself @baseless/react).

My only issue is that when I use npx jsr add @baseless/react in a Nodejs project, the resulting package only contains the .tsx, no .js nor .js.map.

I've been using this script to locally build my modules for local development with npm link. I guess I went the extra mile and converted my .tsx to .js,.js.map,.d.ts.

I wouldn't mind looking at adding JSX support to the build process if someone could point me in the right direction. (I know my way around Rust too).