@farm.js/create-app 0.1.0-beta.34 → 0.1.0-beta.35
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/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +6 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/_renderers/preact/package.json +2 -2
- package/templates/_renderers/solid/package.json +2 -2
- package/templates/_renderers/svelte/package.json +2 -2
- package/templates/_renderers/vue/package.json +2 -2
- package/templates/auth/package.json +3 -3
- package/templates/basic/package.json +2 -2
- package/templates/better-auth/package.json +3 -3
- package/templates/react-compiler/README.md +60 -0
- package/templates/react-compiler/farm.config.ts +18 -0
- package/templates/react-compiler/gitignore +23 -0
- package/templates/react-compiler/package.json +31 -0
- package/templates/react-compiler/pnpm-workspace.yaml +8 -0
- package/templates/react-compiler/public/favicon.svg +5 -0
- package/templates/react-compiler/scripts/verify-experiment.mjs +107 -0
- package/templates/react-compiler/src/app/globals.css +465 -0
- package/templates/react-compiler/src/app/layout.tsx +22 -0
- package/templates/react-compiler/src/app/page.tsx +44 -0
- package/templates/react-compiler/src/components/compiler-comparison.tsx +93 -0
- package/templates/react-compiler/src/components/resource-links.tsx +78 -0
- package/templates/react-compiler/src/farm.d.ts +77 -0
- package/templates/react-compiler/src/lib/api.generated.ts +10 -0
- package/templates/react-compiler/tsconfig.json +24 -0
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type-check": "tsc --noEmit"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@farm.js/core": "0.1.0-beta.
|
|
14
|
+
"@farm.js/core": "0.1.0-beta.35",
|
|
15
15
|
"@farm.js/preact": "0.1.0-beta.30",
|
|
16
16
|
"@fontsource-variable/geist": "5.3.0",
|
|
17
17
|
"@fontsource-variable/geist-mono": "5.3.0",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"zod": "4.1.12"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@farm.js/cli": "0.1.0-beta.
|
|
22
|
+
"@farm.js/cli": "0.1.0-beta.35",
|
|
23
23
|
"tailwindcss": "^4.0.0",
|
|
24
24
|
"typescript": "^5.3.3"
|
|
25
25
|
},
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"type-check": "tsc --noEmit"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@farm.js/core": "0.1.0-beta.
|
|
13
|
+
"@farm.js/core": "0.1.0-beta.35",
|
|
14
14
|
"@farm.js/solid": "0.1.0-beta.26",
|
|
15
15
|
"@fontsource-variable/geist": "5.3.0",
|
|
16
16
|
"@fontsource-variable/geist-mono": "5.3.0",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"zod": "4.1.12"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@farm.js/cli": "0.1.0-beta.
|
|
21
|
+
"@farm.js/cli": "0.1.0-beta.35",
|
|
22
22
|
"tailwindcss": "^4.0.0",
|
|
23
23
|
"typescript": "^5.3.3"
|
|
24
24
|
},
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"type-check": "svelte-check --tsconfig ./tsconfig.json"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@farm.js/core": "0.1.0-beta.
|
|
14
|
+
"@farm.js/core": "0.1.0-beta.35",
|
|
15
15
|
"@farm.js/svelte": "0.1.0-beta.29",
|
|
16
16
|
"@fontsource-variable/geist": "5.3.0",
|
|
17
17
|
"@fontsource-variable/geist-mono": "5.3.0",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"zod": "4.1.12"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|
|
22
|
-
"@farm.js/cli": "0.1.0-beta.
|
|
22
|
+
"@farm.js/cli": "0.1.0-beta.35",
|
|
23
23
|
"svelte-check": "4.7.5",
|
|
24
24
|
"tailwindcss": "^4.0.0",
|
|
25
25
|
"typescript": "^5.3.3"
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"type-check": "vue-tsc --noEmit"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@farm.js/core": "0.1.0-beta.
|
|
13
|
+
"@farm.js/core": "0.1.0-beta.35",
|
|
14
14
|
"@farm.js/vue": "0.1.0-beta.26",
|
|
15
15
|
"@fontsource-variable/geist": "5.3.0",
|
|
16
16
|
"@fontsource-variable/geist-mono": "5.3.0",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"zod": "4.1.12"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@farm.js/cli": "0.1.0-beta.
|
|
21
|
+
"@farm.js/cli": "0.1.0-beta.35",
|
|
22
22
|
"tailwindcss": "^4.0.0",
|
|
23
23
|
"typescript": "^5.3.3",
|
|
24
24
|
"vue-tsc": "3.3.9"
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
"type-check": "tsc --noEmit"
|
|
13
13
|
},
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@farm.js/auth": "0.1.0-beta.
|
|
16
|
-
"@farm.js/core": "0.1.0-beta.
|
|
15
|
+
"@farm.js/auth": "0.1.0-beta.35",
|
|
16
|
+
"@farm.js/core": "0.1.0-beta.35",
|
|
17
17
|
"@fontsource-variable/geist": "5.3.0",
|
|
18
18
|
"@fontsource-variable/geist-mono": "5.3.0",
|
|
19
19
|
"better-call": "1.3.2",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"react-dom": "^19.0.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@farm.js/cli": "0.1.0-beta.
|
|
24
|
+
"@farm.js/cli": "0.1.0-beta.35",
|
|
25
25
|
"@types/node": "20.19.9",
|
|
26
26
|
"@types/react": "^19.0.0",
|
|
27
27
|
"@types/react-dom": "^19.0.0",
|
|
@@ -10,14 +10,14 @@
|
|
|
10
10
|
"type-check": "tsc --noEmit"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@farm.js/core": "0.1.0-beta.
|
|
13
|
+
"@farm.js/core": "0.1.0-beta.35",
|
|
14
14
|
"@fontsource-variable/geist": "5.3.0",
|
|
15
15
|
"@fontsource-variable/geist-mono": "5.3.0",
|
|
16
16
|
"react": "^19.0.0",
|
|
17
17
|
"react-dom": "^19.0.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@farm.js/cli": "0.1.0-beta.
|
|
20
|
+
"@farm.js/cli": "0.1.0-beta.35",
|
|
21
21
|
"@types/react": "^19.0.0",
|
|
22
22
|
"@types/react-dom": "^19.0.0",
|
|
23
23
|
"tailwindcss": "^4.0.0",
|
|
@@ -11,8 +11,8 @@
|
|
|
11
11
|
"type-check": "tsc --noEmit"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@farm.js/better-auth": "0.1.0-beta.
|
|
15
|
-
"@farm.js/core": "0.1.0-beta.
|
|
14
|
+
"@farm.js/better-auth": "0.1.0-beta.35",
|
|
15
|
+
"@farm.js/core": "0.1.0-beta.35",
|
|
16
16
|
"@fontsource-variable/geist": "5.3.0",
|
|
17
17
|
"@fontsource-variable/geist-mono": "5.3.0",
|
|
18
18
|
"better-auth": "1.6.25",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"react-dom": "^19.0.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@farm.js/cli": "0.1.0-beta.
|
|
25
|
+
"@farm.js/cli": "0.1.0-beta.35",
|
|
26
26
|
"@types/node": "20.19.9",
|
|
27
27
|
"@types/pg": "8.20.0",
|
|
28
28
|
"@types/react": "^19.0.0",
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# FARMJS React Compiler Starter
|
|
2
|
+
|
|
3
|
+
A focused experimental starter for FARMJS's React AOT compiler. It uses the same minimal dark shell
|
|
4
|
+
as the other Create FARMJS App starters and includes one live comparison: an eligible local state
|
|
5
|
+
update beside ordinary React reconciliation.
|
|
6
|
+
|
|
7
|
+
> The compiler is experimental. Unsupported component shapes stay on React, so the optimization is
|
|
8
|
+
> never required for correctness.
|
|
9
|
+
|
|
10
|
+
## Create this starter
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pnpm create @farm.js/app@beta my-compiler-app --template react-compiler --typescript
|
|
14
|
+
cd my-compiler-app
|
|
15
|
+
pnpm dev
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
You can also clone the standalone
|
|
19
|
+
[farmjs-react-compiler-starter](https://github.com/farming-labs/farmjs-react-compiler-starter).
|
|
20
|
+
|
|
21
|
+
## Compiler configuration
|
|
22
|
+
|
|
23
|
+
The starter enables the compiler through the React renderer:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
renderer: react({
|
|
27
|
+
experimental: {
|
|
28
|
+
compiler: true,
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The included environment switch defaults to enabled and makes comparison builds easy:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
FARM_REACT_COMPILER=true pnpm build
|
|
37
|
+
FARM_REACT_COMPILER=false pnpm build
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Components are considered automatically. Add `"use no compiler"` to a component when you need an
|
|
41
|
+
explicit React-only path.
|
|
42
|
+
|
|
43
|
+
## Verify the compiled path
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pnpm install
|
|
47
|
+
pnpm exec playwright install chromium
|
|
48
|
+
pnpm experiment
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The command builds the app, opens the production output in Chromium, checks both counters, verifies
|
|
52
|
+
that the compiled update does not execute the component again, and saves a screenshot to
|
|
53
|
+
`/tmp/farm-react-compiler-starter.png`.
|
|
54
|
+
|
|
55
|
+
For batching, multiple bindings, safe keyed-list fallback, and the full compiler-on/off benchmark,
|
|
56
|
+
see the maintained
|
|
57
|
+
[React Compiler example](https://github.com/farming-labs/farm.js/tree/main/examples/react-compiler).
|
|
58
|
+
|
|
59
|
+
Read the [React compiler guide](https://farm.js.dev/docs/renderers/react#experimental-aot-compiler)
|
|
60
|
+
for the supported component contract and rollout guidance.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { defineConfig } from "@farm.js/core";
|
|
2
|
+
import { react } from "@farm.js/react";
|
|
3
|
+
|
|
4
|
+
const compilerEnabled = process.env.FARM_REACT_COMPILER !== "false";
|
|
5
|
+
|
|
6
|
+
export default defineConfig({
|
|
7
|
+
renderer: react({
|
|
8
|
+
experimental: {
|
|
9
|
+
compiler: compilerEnabled,
|
|
10
|
+
},
|
|
11
|
+
}),
|
|
12
|
+
theme: {
|
|
13
|
+
default: "dark",
|
|
14
|
+
},
|
|
15
|
+
deploy: {
|
|
16
|
+
target: "node",
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Farm and deployment output
|
|
5
|
+
.farm/
|
|
6
|
+
.output/
|
|
7
|
+
.vercel/
|
|
8
|
+
dist/
|
|
9
|
+
|
|
10
|
+
# Local environment files
|
|
11
|
+
.env
|
|
12
|
+
.env.local
|
|
13
|
+
.env.*.local
|
|
14
|
+
|
|
15
|
+
# Local databases
|
|
16
|
+
*.sqlite
|
|
17
|
+
*.sqlite-*
|
|
18
|
+
*.db
|
|
19
|
+
*.db-*
|
|
20
|
+
|
|
21
|
+
# Logs and TypeScript cache
|
|
22
|
+
*.log
|
|
23
|
+
*.tsbuildinfo
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "farmjs-react-compiler-starter",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "farm dev",
|
|
8
|
+
"build": "farm build",
|
|
9
|
+
"start": "farm start",
|
|
10
|
+
"experiment": "pnpm run build && node scripts/verify-experiment.mjs",
|
|
11
|
+
"type-check": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@farm.js/core": "0.1.0-beta.35",
|
|
15
|
+
"@farm.js/react": "0.1.0-beta.0",
|
|
16
|
+
"@fontsource-variable/geist": "5.3.0",
|
|
17
|
+
"@fontsource-variable/geist-mono": "5.3.0",
|
|
18
|
+
"react": "19.2.8",
|
|
19
|
+
"react-dom": "19.2.8"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@farm.js/cli": "0.1.0-beta.35",
|
|
23
|
+
"@playwright/test": "^1.52.0",
|
|
24
|
+
"@types/react": "^19.0.0",
|
|
25
|
+
"@types/react-dom": "^19.0.0",
|
|
26
|
+
"tailwindcss": "^4.0.0",
|
|
27
|
+
"typescript": "^5.3.3",
|
|
28
|
+
"vite": "^5.0.10"
|
|
29
|
+
},
|
|
30
|
+
"packageManager": "pnpm@8.12.1"
|
|
31
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { access } from "node:fs/promises";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { chromium } from "@playwright/test";
|
|
6
|
+
|
|
7
|
+
const port = Number(process.env.FARM_EXPERIMENT_PORT || 4327);
|
|
8
|
+
const origin = `http://127.0.0.1:${port}`;
|
|
9
|
+
const serverEntry = path.resolve(".farm/.output/server/index.mjs");
|
|
10
|
+
const screenshotPath =
|
|
11
|
+
process.env.FARM_EXPERIMENT_SCREENSHOT || "/tmp/farm-react-compiler-starter.png";
|
|
12
|
+
|
|
13
|
+
await access(serverEntry);
|
|
14
|
+
|
|
15
|
+
let serverOutput = "";
|
|
16
|
+
const server = spawn(process.execPath, [serverEntry], {
|
|
17
|
+
env: {
|
|
18
|
+
...process.env,
|
|
19
|
+
HOST: "127.0.0.1",
|
|
20
|
+
NITRO_HOST: "127.0.0.1",
|
|
21
|
+
NITRO_PORT: String(port),
|
|
22
|
+
PORT: String(port),
|
|
23
|
+
},
|
|
24
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
server.stdout.on("data", (chunk) => {
|
|
28
|
+
serverOutput += chunk;
|
|
29
|
+
});
|
|
30
|
+
server.stderr.on("data", (chunk) => {
|
|
31
|
+
serverOutput += chunk;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
async function waitForServer() {
|
|
35
|
+
for (let attempt = 0; attempt < 120; attempt += 1) {
|
|
36
|
+
if (server.exitCode !== null) {
|
|
37
|
+
throw new Error(`Production server exited early.\n${serverOutput}`);
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const response = await fetch(origin);
|
|
41
|
+
if (response.ok) return;
|
|
42
|
+
} catch {
|
|
43
|
+
// The server is still starting.
|
|
44
|
+
}
|
|
45
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
46
|
+
}
|
|
47
|
+
throw new Error(`Production server did not start.\n${serverOutput}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async function readNumber(page, selector) {
|
|
51
|
+
return Number((await page.locator(selector).textContent())?.trim());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
let browser;
|
|
55
|
+
try {
|
|
56
|
+
await waitForServer();
|
|
57
|
+
browser = await chromium.launch({ headless: true });
|
|
58
|
+
const page = await browser.newPage({ viewport: { width: 1280, height: 900 } });
|
|
59
|
+
const browserErrors = [];
|
|
60
|
+
|
|
61
|
+
page.on("console", (message) => {
|
|
62
|
+
if (message.type() === "error") browserErrors.push(message.text());
|
|
63
|
+
});
|
|
64
|
+
page.on("pageerror", (error) => browserErrors.push(error.message));
|
|
65
|
+
|
|
66
|
+
await page.goto(origin, { waitUntil: "networkidle" });
|
|
67
|
+
await page.getByRole("heading", { name: /compiler handles the rest/i }).waitFor();
|
|
68
|
+
|
|
69
|
+
const executions = {};
|
|
70
|
+
for (const pathName of ["compiled", "react"]) {
|
|
71
|
+
const root = `[data-path="${pathName}"]`;
|
|
72
|
+
executions[pathName] = {
|
|
73
|
+
initial: await readNumber(page, `${root} [data-metric="executions"]`),
|
|
74
|
+
};
|
|
75
|
+
await page.locator(`${root} [data-action="update"]`).click();
|
|
76
|
+
await page.locator(`${root} [data-action="update"]`).click();
|
|
77
|
+
await page.waitForFunction(
|
|
78
|
+
(selector) => document.querySelector(selector)?.textContent?.trim() === "2",
|
|
79
|
+
`${root} [data-metric="state"]`,
|
|
80
|
+
);
|
|
81
|
+
executions[pathName].final = await readNumber(page, `${root} [data-metric="executions"]`);
|
|
82
|
+
executions[pathName].added = executions[pathName].final - executions[pathName].initial;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
assert.equal(executions.compiled.added, 0);
|
|
86
|
+
assert.equal(executions.react.added, 2);
|
|
87
|
+
assert.deepEqual(browserErrors, []);
|
|
88
|
+
|
|
89
|
+
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
90
|
+
|
|
91
|
+
console.log(
|
|
92
|
+
JSON.stringify(
|
|
93
|
+
{
|
|
94
|
+
result: "PASS",
|
|
95
|
+
productionUrl: origin,
|
|
96
|
+
screenshot: screenshotPath,
|
|
97
|
+
compiledUpdateExecutions: executions.compiled.added,
|
|
98
|
+
reactUpdateExecutions: executions.react.added,
|
|
99
|
+
},
|
|
100
|
+
null,
|
|
101
|
+
2,
|
|
102
|
+
),
|
|
103
|
+
);
|
|
104
|
+
} finally {
|
|
105
|
+
await browser?.close();
|
|
106
|
+
server.kill("SIGTERM");
|
|
107
|
+
}
|