
Security News
PolinRider: North Korea-Linked Supply Chain Campaign Expands Across Open Source Ecosystems
PolinRider expands across npm, Packagist, Go modules, and Chrome extensions, using hidden loaders to target developer environments.
@shadow-js/compiler
Advanced tools
The ShadowJS JSX compiler that transforms JSX code into Shadow-compatible reactive expressions. This compiler enables Shadow's fine-grained reactivity by automatically wrapping JSX expressions in reactive functions.
npm install @shadow-js/compiler
Usually used together with the Vite plugin:
npm install @shadow-js/compiler @shadow-js/vite
The compiler is typically used through the Vite plugin, but can also be used directly:
import { transformSource } from "@shadow-js/compiler";
const jsxCode = `
const App = () => (
<div>
<Show when={count() > 0} fallback={<div>No items</div>}>
<div>Count: {count()}</div>
</Show>
</div>
);
`;
const transformedCode = transformSource(jsxCode);
console.log(transformedCode);
The compiler transforms JSX in two main phases:
Transforms JSX in arrow function bodies:
// Input
const App = () => <div>{count()}</div>;
// Output
const App = () => <div>{() => count()}</div>;
Transforms JSX in return statements:
// Input
function App() {
return <div>{items.length}</div>;
}
// Output
function App() {
return <div>{() => items.length}</div>;
}
| Function | Description |
|---|---|
transformSource(code) | Transform JSX source code to Shadow-compatible expressions |
transformArrowImplicitBodies(code) | Transform JSX in arrow function implicit bodies |
transformAllReturnParens(code) | Transform JSX in return statement parentheses |
| Function | Description |
|---|---|
applyJsxTransforms(jsxContent) | Apply JSX-specific transformations |
findMatching(code, start, open, close) | Find matching brackets in code |
hasJsxTag(code) | Check if code contains JSX tags |
isFunction(code) | Check if code is a function expression |
// Input
<div>Hello {name}</div>
// Output
<div>Hello {() => name}</div>
// Input
<Show when={count > 0}>
<div>Count: {count}</div>
</Show>
// Output
<Show when={() => count > 0}>
<div>Count: {() => count}</div>
</Show>
// Input
<div ref={myRef} />
// Output
<div ref={(el) => myRef = el} />
// Input
<div style={{ color: "red" }} />
// Output
<div style={() => ({ color: "red" })} />
// Input
<For each={items}>
{(item) => <li>{item.name}</li>}
</For>
// Output
<For each={() => items}>
{(item) => <li>{() => item.name}</li>}
</For>
The compiler consists of several transformation modules:
transformSource.ts)Main entry point that orchestrates all transformations:
transformArrowImplicitBodies.ts)Handles JSX in arrow function bodies:
transformAllReturnParens.ts)Handles JSX in return statements:
return ( statementsapplyJsxTransforms.ts)Core JSX transformation logic:
Supporting utilities for code analysis:
You can extend the compiler by creating custom transformations:
import { applyJsxTransforms } from "@shadow-js/compiler";
function customTransform(jsxContent: string): string {
// Apply built-in transformations first
let result = applyJsxTransforms(jsxContent);
// Add custom transformations
result = result.replace(/@custom/g, "customTransform");
return result;
}
The recommended way to use the compiler:
// vite.config.ts
import { defineConfig } from "vite";
import shadow from "@shadow-js/vite";
export default defineConfig({
plugins: [shadow()],
});
For custom build setups:
import { transformSource } from "@shadow-js/compiler";
export function shadowPlugin() {
return {
name: "shadow-compiler",
transform(code, id) {
if (id.endsWith(".tsx") || id.endsWith(".jsx")) {
return transformSource(code);
}
},
};
}
The compiler provides detailed error messages:
try {
const transformed = transformSource(sourceCode);
// Use transformed code
} catch (error) {
console.error("ShadowJS compilation failed:", error.message);
// Handle compilation error
}
While the compiler currently has minimal configuration, future versions may include:
import { transformSource } from "@shadow-js/compiler";
describe("ShadowJS Compiler", () => {
test("transforms basic JSX expressions", () => {
const input = "<div>{name}</div>";
const output = transformSource(input);
expect(output).toContain("{() => name}");
});
test("handles control flow components", () => {
const input = "<Show when={count > 0}><div>Count</div></Show>";
const output = transformSource(input);
expect(output).toContain("when={() => count > 0}");
});
});
Expression not reactive: Check if expression is properly wrapped
// Wrong
<div>{count + 1}</div>
// Right
<div>{() => count + 1}</div>
Control flow not working: Ensure conditions are wrapped in functions
// Wrong
<Show when={count > 0}>
// Right
<Show when={() => count > 0}>
Ref not working: Check ref assignment function syntax
// Wrong
<div ref={myRef} />
// Right - compiler transforms this automatically
<div ref={myRef} />
// Becomes: <div ref={(el) => myRef = el} />
Enable debug mode for detailed transformation logs:
// Enable in development
process.env.SHADOW_DEBUG = "true";
const transformed = transformSource(sourceCode);
console.log("Transformation result:", transformed);
See the examples documentation for:
We welcome contributions! See the Contributing Guide for details.
Areas for contribution:
MIT License - see LICENSE for details.
Built by Jehaad AL-Johani for compile-time JSX transformations.
FAQs
JSX compiler and transforms for ShadowJS
We found that @shadow-js/compiler demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
PolinRider expands across npm, Packagist, Go modules, and Chrome extensions, using hidden loaders to target developer environments.

Security News
Open source attacks are accelerating as AI coding agents pull in dependencies faster, with less human review.

Research
/Security News
Malicious Chrome and Firefox extensions posed as free VPNs while stealing clipboard data through later extension updates.