Skip to content

Commit fe3c9f5

Browse files
feat: add transpileJsxSource api for raw jsx input. (#83)
1 parent 4ee5c89 commit fe3c9f5

11 files changed

Lines changed: 548 additions & 16 deletions

File tree

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

.github/workflows/playwright.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,6 @@ jobs:
2525
- name: Install dependencies
2626
run: npm ci
2727
- name: Install Playwright Browsers
28-
run: npx playwright install --with-deps chrome webkit
28+
run: npx playwright install --with-deps chromium webkit
2929
- name: Run Playwright tests
3030
run: npm run test:e2e

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,32 @@ const button = jsx`
6868
document.body.append(button)
6969
```
7070

71+
### Source transpilation (`transpileJsxSource`)
72+
73+
Need to transform raw JSX source text (e.g. code typed in an editor) without Babel? Use `transpileJsxSource`:
74+
75+
```ts
76+
import { transpileJsxSource } from '@knighted/jsx/transpile'
77+
78+
const input = `
79+
const App = () => {
80+
return <button>click me</button>
81+
}
82+
`
83+
84+
const { code } = transpileJsxSource(input)
85+
// -> const App = () => { return React.createElement("button", null, "click me") }
86+
```
87+
88+
By default this emits `React.createElement(...)` and `React.Fragment`. Override them when needed:
89+
90+
```ts
91+
transpileJsxSource(input, {
92+
createElement: '__jsx',
93+
fragment: '__fragment',
94+
})
95+
```
96+
7197
### React runtime (`reactJsx`)
7298

7399
Need to compose React elements instead of DOM nodes? Import the dedicated helper from the `@knighted/jsx/react` subpath (React 18+ and `react-dom` are still required to mount the tree):

docs/how-it-compares.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@ Use this quick matrix to see how `@knighted/jsx` stacks up against other tagged-
1111
| SSR / Node | `@knighted/jsx/node` bootstraps `linkedom`/`jsdom` automatically; fixtures cover Next.js, Lit + React hybrids, and plain Node usage. | Depends on the hyperscript target/framework to provide SSR. | Provides DOM-focused SSR utilities but no automatic shims or React interop. |
1212
| TypeScript support | First-class typings for DOM + React runtimes, loader options, and Node helpers. | Community types only for the tag factory. | Minimal typings; templates rely on generic DOM types. |
1313
| Component interoperability | Mix DOM helpers, React components, Lit roots, and loader-transformed calls in one file. | Primarily a JSX stand-in for Preact or hyperscript. | Focused on DOM updates, pairs with `uhtml/async` or low-level renderers. |
14-
| Approx. size | DOM: ~11.3 kB raw / ~2.8 kB min+gzip. Lite DOM: ~10.1 kB raw / ~4.2 kB min+gzip. | ~1 kB min+gzip. | ~7 kB min+gzip. |
14+
| Approx. size | DOM: ~11.5 kB raw / ~2.8 kB min+gzip. Lite DOM: ~10.4 kB raw / ~4.3 kB min+gzip. | ~1 kB min+gzip. | ~7 kB min+gzip. |
1515

1616
> `htm` and `uhtml` remain excellent when you only need lightweight hyperscript or DOM templating. `@knighted/jsx` trades a slightly larger runtime for full JSX semantics, React parity, loaders, and SSR tooling.
1717
1818
> [!NOTE]
19-
> `@knighted/jsx` sizes were measured by gzipping `dist/jsx.js` (default runtime) and `dist/lite/index.js` from the latest build. The lite bundle packs the DOM helper and bootstrap code together, so raw bytes dropped while gzip remains ~1.4 kB larger than the split default entry.
19+
> `@knighted/jsx` sizes were measured by gzipping `dist/jsx.js` (default runtime) and `dist/lite/index.js` from the latest build. The lite bundle packs the DOM helper and bootstrap code together, so raw bytes dropped while gzip remains ~1.5 kB larger than the split default entry.
2020
2121
## Detailed size breakdown
2222

2323
| Entry point | Raw size (bytes) | Min+gzip size (bytes) | Lite raw size (bytes) | Lite min+gzip size (bytes) | Notes |
2424
| --------------------------------------------- | ----------------------------------------------------------------------------- | --------------------- | --------------------------------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
25-
| DOM runtime (`@knighted/jsx`) | 11,549 (`dist/jsx.js`) | 2,870 | 10,337 (`dist/lite/index.js`) | 4,301 | Lite bundle keeps helper + bootstrap inline, shaving raw bytes (~10 kB) while staying ~1.4 kB heavier once gzipped. |
26-
| React runtime (`@knighted/jsx/react`) | 5,236 (`dist/react/react-jsx.js`) | 1,478 | 6,777 (`dist/lite/react/index.js`) | 2,974 | Lite React remains a single file with helpers + bootstrap, so gzip lands roughly 1.5 kB above the split default build. |
27-
| Node DOM entry (`@knighted/jsx/node`) | 14,044 combined (`dist/jsx.js` + `dist/node/bootstrap.js` via dynamic import) | ≈3,849 | 11,500 (`dist/lite/node/index.js`) | 4,808 | Lite node now reuses the trimmed DOM runtime, trimming ~1.3 kB raw compared to the previous monolithic build. |
28-
| Node React entry (`@knighted/jsx/node/react`) | 7,731 combined (`dist/react/react-jsx.js` + `dist/node/bootstrap.js`) | ≈2,457 | 6,777 (`dist/lite/node/react/index.js`) | 2,974 | Lite node/react shares the lite React runtime, so gzip matches that entry while the classic build loads two files. |
25+
| DOM runtime (`@knighted/jsx`) | 11,549 (`dist/jsx.js`) | 2,843 | 10,388 (`dist/lite/index.js`) | 4,295 | Lite bundle keeps helper + bootstrap inline, shaving raw bytes (~10 kB) while staying ~1.5 kB heavier once gzipped. |
26+
| React runtime (`@knighted/jsx/react`) | 5,236 (`dist/react/react-jsx.js`) | 1,461 | 6,828 (`dist/lite/react/index.js`) | 2,979 | Lite React remains a single file with helpers + bootstrap, so gzip lands roughly 1.5 kB above the split default build. |
27+
| Node DOM entry (`@knighted/jsx/node`) | 14,044 combined (`dist/jsx.js` + `dist/node/bootstrap.js` via dynamic import) | 3,803 | 11,551 (`dist/lite/node/index.js`) | 4,796 | Lite node now reuses the trimmed DOM runtime, trimming ~2.5 kB raw compared to the previous monolithic build. |
28+
| Node React entry (`@knighted/jsx/node/react`) | 7,731 combined (`dist/react/react-jsx.js` + `dist/node/bootstrap.js`) | 2,421 | 6,828 (`dist/lite/node/react/index.js`) | 2,979 | Lite node/react shares the lite React runtime, so gzip matches that entry while the classic build loads two files. |
2929

3030
> [!TIP]
3131
> Numbers were captured using `gzip -c <file> | wc -c`. “Combined” entries include every file the non-lite entry loads at runtime so you can compare end-to-end costs.

examples/esm-demo.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ <h1>@knighted/jsx + CDN</h1>
512512
{
513513
entry: '@knighted/jsx/lite',
514514
context: 'DOM runtime helpers',
515-
raw: '~10.3 kB raw',
515+
raw: '~10.4 kB raw',
516516
gzip: '~4.3 kB min+gzip',
517517
note: 'Great for browser demos or DOM-like shims without bundlers.',
518518
},
@@ -526,7 +526,7 @@ <h1>@knighted/jsx + CDN</h1>
526526
{
527527
entry: '@knighted/jsx/node/lite',
528528
context: 'Node DOM entry',
529-
raw: '~11.5 kB raw',
529+
raw: '~11.6 kB raw',
530530
gzip: '~4.8 kB min+gzip',
531531
note: 'Bundles the DOM shim bootstrap for headless SSR scripts.',
532532
},

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@knighted/jsx",
3-
"version": "1.7.9",
3+
"version": "1.8.0",
44
"description": "Runtime JSX tagged template that renders DOM or React trees anywhere with or without a build step.",
55
"keywords": [
66
"jsx runtime",
@@ -101,6 +101,11 @@
101101
"import": "./dist/lite/node/react/index.js",
102102
"default": "./dist/lite/node/react/index.js"
103103
},
104+
"./transpile": {
105+
"types": "./dist/transpile.d.ts",
106+
"import": "./dist/transpile.js",
107+
"default": "./dist/transpile.js"
108+
},
104109
"./loader": {
105110
"import": "./dist/loader/jsx.js",
106111
"default": "./dist/loader/jsx.js"

playwright.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ const LOADER_FIXTURE_PORT = Number(process.env.LOADER_FIXTURE_PORT ?? 4174)
77
const esmDemoUrl = process.env.ESM_DEMO_URL ?? `http://${HOST}:${ESM_DEMO_PORT}`
88
const projects: PlaywrightTestProject[] = [
99
{
10-
name: 'chrome',
11-
use: { channel: 'chrome' },
10+
name: 'chromium',
11+
use: { browserName: 'chromium' },
1212
},
1313
]
1414

0 commit comments

Comments
 (0)