@dom-expressions/jsx-compiler 0.50.0-next.17 → 0.50.0-next.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +46 -9
- package/index.js +59 -9
- package/package.json +23 -9
package/README.md
CHANGED
|
@@ -15,6 +15,29 @@ matching your platform automatically through `optionalDependencies`. On other
|
|
|
15
15
|
platforms, build from source with `pnpm run build` inside
|
|
16
16
|
`packages/jsx-compiler` (requires a Rust toolchain).
|
|
17
17
|
|
|
18
|
+
### WebAssembly and StackBlitz
|
|
19
|
+
|
|
20
|
+
The compiler also ships a WASI fallback for environments such as StackBlitz
|
|
21
|
+
WebContainers, where Node.js reports a native platform but cannot load `.node`
|
|
22
|
+
addons. Enable the `wasm32` optional dependency when installing:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install --cpu=wasm32 @dom-expressions/jsx-compiler
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
With pnpm, add the installation architecture to `pnpm-workspace.yaml`:
|
|
29
|
+
|
|
30
|
+
```yaml
|
|
31
|
+
supportedArchitectures:
|
|
32
|
+
cpu:
|
|
33
|
+
- current
|
|
34
|
+
- wasm32
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The normal package entry point prefers a native binding and falls back to
|
|
38
|
+
`@dom-expressions/jsx-compiler-wasm32-wasi` when native addons are unavailable.
|
|
39
|
+
Set `NAPI_RS_FORCE_WASI=error` to require the WASI binding for testing.
|
|
40
|
+
|
|
18
41
|
## Usage
|
|
19
42
|
|
|
20
43
|
This package exposes a compiler backend API. It is not a Vite, Rollup, or Babel
|
|
@@ -136,8 +159,9 @@ Supported options track the Babel plugin where currently implemented:
|
|
|
136
159
|
- `omitQuotes`
|
|
137
160
|
- `omitAttributeSpacing`
|
|
138
161
|
- `inlineStyles`
|
|
139
|
-
- `effectWrapper`:
|
|
140
|
-
-
|
|
162
|
+
- `effectWrapper`: custom import name string, or `false` to disable
|
|
163
|
+
- `memoWrapper`: custom import name string, or `false` to disable
|
|
164
|
+
- `wrapConditionals`
|
|
141
165
|
- `staticMarker`
|
|
142
166
|
- `validate`
|
|
143
167
|
- `omitNestedClosingTags`
|
|
@@ -146,6 +170,22 @@ Supported options track the Babel plugin where currently implemented:
|
|
|
146
170
|
- `requireImportSource`
|
|
147
171
|
- `renderers`
|
|
148
172
|
|
|
173
|
+
## Performance
|
|
174
|
+
|
|
175
|
+
Compared against `@dom-expressions/babel-plugin-jsx` compiling identical
|
|
176
|
+
sources under identical options (Apple Silicon, release build, in-process,
|
|
177
|
+
median of 7 iterations after warmup — run `pnpm bench` in this package to
|
|
178
|
+
reproduce on your machine):
|
|
179
|
+
|
|
180
|
+
| Workload | babel-plugin-jsx | jsx-compiler | Speedup |
|
|
181
|
+
| ----------------------------------------------- | ---------------: | -----------: | ------: |
|
|
182
|
+
| Fixture corpus (88 files, 174 KB, all 10 modes) | 151 ms | 8.4 ms | 18x |
|
|
183
|
+
| 129 KB single module | 230 ms | 4.6 ms | 50x |
|
|
184
|
+
| 1 MB single module | 10,164 ms | 39 ms | 258x |
|
|
185
|
+
|
|
186
|
+
Native throughput stays flat at ~20–27 MB/s as input grows, while Babel's
|
|
187
|
+
per-file cost grows super-linearly — so the gap widens with file size.
|
|
188
|
+
|
|
149
189
|
## Current Scope
|
|
150
190
|
|
|
151
191
|
This package is the AST-native compiler backend. It currently has checked fixture coverage for
|
|
@@ -159,10 +199,10 @@ the DOM, hydratable DOM, dev hydratable DOM, SSR, hydratable SSR, universal, dyn
|
|
|
159
199
|
attribute handling covered by the checked fixture suites for those targets
|
|
160
200
|
- Solid-compatible defaults such as `contextToCustomElements: true`
|
|
161
201
|
- option coverage for `hydratable`, `dev`, `delegateEvents`, `delegatedEvents`,
|
|
162
|
-
`omitQuotes`, `omitAttributeSpacing`, `inlineStyles`, `effectWrapper
|
|
163
|
-
|
|
164
|
-
`
|
|
165
|
-
|
|
202
|
+
`omitQuotes`, `omitAttributeSpacing`, `inlineStyles`, `effectWrapper`,
|
|
203
|
+
`memoWrapper`, `wrapConditionals`, `requireImportSource`, `staticMarker`,
|
|
204
|
+
`validate`, `omitNestedClosingTags`, `omitLastClosingTag`, `builtIns`, and
|
|
205
|
+
dynamic `renderers`
|
|
166
206
|
- source maps for the implemented path
|
|
167
207
|
|
|
168
208
|
## Not Implemented Yet
|
|
@@ -172,8 +212,6 @@ The compiler intentionally rejects unsupported features instead of pretending to
|
|
|
172
212
|
- DOM `namespaceElements` sections that the current Oxc parser rejects before transform
|
|
173
213
|
(for example, hyphenated JSX member segments)
|
|
174
214
|
- arbitrary custom renderer names beyond dynamic DOM renderer override plus universal fallback
|
|
175
|
-
- custom `effectWrapper` / `memoWrapper` helper names
|
|
176
|
-
- unpaired `wrapConditionals: false` or `memoWrapper: false`
|
|
177
215
|
- unknown/custom namespaced DOM attributes outside known runtime namespaces such as `xlink`
|
|
178
216
|
|
|
179
217
|
## Architecture
|
|
@@ -198,4 +236,3 @@ The module layout mirrors the Babel plugin shape where possible:
|
|
|
198
236
|
- `src/ssr/transform.rs`
|
|
199
237
|
- `src/universal/mod.rs`
|
|
200
238
|
- `src/universal/transform.rs`
|
|
201
|
-
|
package/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const path = require("path");
|
|
5
5
|
|
|
6
|
-
const native =
|
|
6
|
+
const native = requireBinding();
|
|
7
7
|
|
|
8
8
|
function transform(code, options) {
|
|
9
9
|
if (typeof code !== "string") {
|
|
@@ -152,10 +152,20 @@ function platformArchSuffix() {
|
|
|
152
152
|
return null;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
function
|
|
155
|
+
function requireBinding() {
|
|
156
156
|
const explicit = process.env.JSX_DOM_EXPRESSIONS_COMPILER_NATIVE;
|
|
157
157
|
if (explicit) return require(explicit);
|
|
158
158
|
|
|
159
|
+
const forceWasi = process.env.NAPI_RS_FORCE_WASI;
|
|
160
|
+
if (forceWasi === "true" || forceWasi === "error") {
|
|
161
|
+
const wasi = requireWasi();
|
|
162
|
+
if (wasi) return wasi;
|
|
163
|
+
if (forceWasi === "error") {
|
|
164
|
+
throw new Error("WASI binding not found and NAPI_RS_FORCE_WASI is set to error");
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
let nativeError;
|
|
159
169
|
const suffix = platformArchSuffix();
|
|
160
170
|
|
|
161
171
|
// Local builds (napi build output) take precedence for development.
|
|
@@ -164,23 +174,63 @@ function requireNative() {
|
|
|
164
174
|
localCandidates.push("jsx-compiler.node");
|
|
165
175
|
for (const file of localCandidates) {
|
|
166
176
|
const full = path.join(__dirname, file);
|
|
167
|
-
if (fs.existsSync(full))
|
|
177
|
+
if (fs.existsSync(full)) {
|
|
178
|
+
try {
|
|
179
|
+
return require(full);
|
|
180
|
+
} catch (error) {
|
|
181
|
+
nativeError = error;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
168
185
|
}
|
|
169
186
|
|
|
170
|
-
if (suffix) {
|
|
187
|
+
if (!nativeError && suffix) {
|
|
188
|
+
const packageName = `@dom-expressions/jsx-compiler-${suffix}`;
|
|
171
189
|
try {
|
|
172
|
-
return require(
|
|
190
|
+
return require(packageName);
|
|
173
191
|
} catch (error) {
|
|
174
|
-
if (error
|
|
192
|
+
if (!isMissingPackage(error, packageName)) nativeError = error;
|
|
175
193
|
}
|
|
176
194
|
}
|
|
177
195
|
|
|
196
|
+
const wasi = requireWasi();
|
|
197
|
+
if (wasi) return wasi;
|
|
198
|
+
|
|
199
|
+
if (nativeError) {
|
|
200
|
+
nativeError.message +=
|
|
201
|
+
"\nThe native binding could not be loaded and the optional " +
|
|
202
|
+
"@dom-expressions/jsx-compiler-wasm32-wasi fallback is not installed.";
|
|
203
|
+
throw nativeError;
|
|
204
|
+
}
|
|
205
|
+
|
|
178
206
|
throw new Error(
|
|
179
|
-
`Could not find
|
|
207
|
+
`Could not find an @dom-expressions/jsx-compiler binding for ${process.platform}-${process.arch}` +
|
|
180
208
|
(suffix
|
|
181
|
-
? ` (expected
|
|
209
|
+
? ` (expected @dom-expressions/jsx-compiler-${suffix}, @dom-expressions/jsx-compiler-wasm32-wasi, or a local build)`
|
|
182
210
|
: " (no prebuilt binary is published for this platform)") +
|
|
183
|
-
".
|
|
211
|
+
". Install with WASM support or run `pnpm run build` in packages/jsx-compiler."
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function requireWasi() {
|
|
216
|
+
const localWasi = path.join(__dirname, "jsx-compiler.wasi.cjs");
|
|
217
|
+
if (fs.existsSync(localWasi)) return require(localWasi);
|
|
218
|
+
|
|
219
|
+
const packageName = "@dom-expressions/jsx-compiler-wasm32-wasi";
|
|
220
|
+
try {
|
|
221
|
+
return require(packageName);
|
|
222
|
+
} catch (error) {
|
|
223
|
+
if (!isMissingPackage(error, packageName)) throw error;
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function isMissingPackage(error, packageName) {
|
|
229
|
+
return (
|
|
230
|
+
error &&
|
|
231
|
+
error.code === "MODULE_NOT_FOUND" &&
|
|
232
|
+
typeof error.message === "string" &&
|
|
233
|
+
error.message.includes(`'${packageName}'`)
|
|
184
234
|
);
|
|
185
235
|
}
|
|
186
236
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dom-expressions/jsx-compiler",
|
|
3
3
|
"description": "A JSX to DOM Expressions compiler implemented with Oxc",
|
|
4
|
-
"version": "0.50.0-next.
|
|
4
|
+
"version": "0.50.0-next.18",
|
|
5
5
|
"author": "Ryan Carniato",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -31,22 +31,36 @@
|
|
|
31
31
|
"aarch64-apple-darwin",
|
|
32
32
|
"x86_64-unknown-linux-gnu",
|
|
33
33
|
"aarch64-unknown-linux-gnu",
|
|
34
|
-
"x86_64-pc-windows-msvc"
|
|
35
|
-
|
|
34
|
+
"x86_64-pc-windows-msvc",
|
|
35
|
+
"wasm32-wasip1-threads"
|
|
36
|
+
],
|
|
37
|
+
"wasm": {
|
|
38
|
+
"browser": {
|
|
39
|
+
"fs": false,
|
|
40
|
+
"asyncInit": false,
|
|
41
|
+
"buffer": false,
|
|
42
|
+
"errorEvent": true
|
|
43
|
+
}
|
|
44
|
+
}
|
|
36
45
|
},
|
|
37
46
|
"devDependencies": {
|
|
38
|
-
"@
|
|
47
|
+
"@emnapi/core": "^1.11.2",
|
|
48
|
+
"@emnapi/runtime": "^1.11.2",
|
|
49
|
+
"@napi-rs/cli": "^3.7.2",
|
|
50
|
+
"@napi-rs/wasm-runtime": "^1.1.6"
|
|
39
51
|
},
|
|
40
52
|
"optionalDependencies": {
|
|
41
|
-
"@dom-expressions/jsx-compiler-darwin-x64": "0.50.0-next.
|
|
42
|
-
"@dom-expressions/jsx-compiler-darwin-arm64": "0.50.0-next.
|
|
43
|
-
"@dom-expressions/jsx-compiler-linux-x64-gnu": "0.50.0-next.
|
|
44
|
-
"@dom-expressions/jsx-compiler-linux-arm64-gnu": "0.50.0-next.
|
|
45
|
-
"@dom-expressions/jsx-compiler-win32-x64-msvc": "0.50.0-next.
|
|
53
|
+
"@dom-expressions/jsx-compiler-darwin-x64": "0.50.0-next.18",
|
|
54
|
+
"@dom-expressions/jsx-compiler-darwin-arm64": "0.50.0-next.18",
|
|
55
|
+
"@dom-expressions/jsx-compiler-linux-x64-gnu": "0.50.0-next.18",
|
|
56
|
+
"@dom-expressions/jsx-compiler-linux-arm64-gnu": "0.50.0-next.18",
|
|
57
|
+
"@dom-expressions/jsx-compiler-win32-x64-msvc": "0.50.0-next.18",
|
|
58
|
+
"@dom-expressions/jsx-compiler-wasm32-wasi": "0.50.0-next.18"
|
|
46
59
|
},
|
|
47
60
|
"scripts": {
|
|
48
61
|
"build": "napi build --release --strip --manifest-path ./Cargo.toml",
|
|
49
62
|
"build:debug": "napi build --manifest-path ./Cargo.toml",
|
|
63
|
+
"bench": "pnpm run build && node scripts/bench.mjs",
|
|
50
64
|
"lint": "cargo clippy --manifest-path ./Cargo.toml -- -D warnings",
|
|
51
65
|
"test": "pnpm run build:debug && jest --no-cache",
|
|
52
66
|
"artifacts": "napi artifacts",
|