@wular/pnext 0.0.1 → 0.0.3
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 +68 -103
- package/package.json +3 -2
- package/reference/data/bench.json +513 -0
- package/reference/performance.md +87 -29
- package/src/api/router/runtime.ts +10 -2
- package/src/cache/context.ts +4 -1
- package/src/cli/build.ts +39 -5
- package/src/cli/create.ts +146 -0
- package/src/cli/dev.ts +6 -0
- package/src/cli/index.ts +28 -4
- package/src/cli/migrate/index.ts +96 -0
- package/src/cli/migrate/package-json.ts +183 -0
- package/src/cli/migrate/report.ts +80 -0
- package/src/cli/migrate/scan.ts +135 -0
- package/src/cli/migrate/spinner.ts +20 -0
- package/src/cli/migrate/tsconfig.ts +77 -0
- package/src/cli/request-pipeline.ts +1340 -0
- package/src/cli/server-entry.ts +180 -0
- package/src/cli/start.ts +39 -1311
- package/src/client/build.ts +59 -20
- package/src/client/chunk-fold.ts +40 -0
- package/src/client/compat-surface.ts +175 -0
- package/src/client/entry.ts +67 -52
- package/src/compat/actions/action-client.ts +8 -1
- package/src/compat/actions/action-dispatch.ts +11 -1
- package/src/compat/actions/discovery.ts +23 -6
- package/src/compat/bundler/optimize-package-imports.ts +5 -1
- package/src/compat/bundler/worker.ts +2 -1
- package/src/compat/client/errors/bare-boundary.ts +32 -0
- package/src/compat/client/errors/error-boundary.ts +1 -15
- package/src/compat/client/errors/primitive-throw.ts +16 -0
- package/src/compat/client/link-status.ts +1 -1
- package/src/compat/css/lightningcss.ts +2 -1
- package/src/compat/css/modules.ts +4 -3
- package/src/compat/index.ts +1 -1
- package/src/compat/lifecycle/instrumentation-client.ts +1 -1
- package/src/compat/lifecycle/instrumentation.ts +5 -2
- package/src/compat/next/config-loader.ts +33 -5
- package/src/compat/next/dynamic.tsx +9 -5
- package/src/compat/next/link-validation-transform.ts +5 -1
- package/src/compat/next/link.tsx +51 -58
- package/src/compat/pages/client-plugin.ts +2 -1
- package/src/compat/react/action-state.ts +159 -0
- package/src/compat/react/client-lite.ts +74 -0
- package/src/compat/react/hooks-extra.ts +92 -0
- package/src/compat/react/parity.ts +128 -0
- package/src/compat/react/preact.ts +33 -420
- package/src/compat/react/server-inserted-html.ts +14 -7
- package/src/compat/react/use.ts +72 -0
- package/src/compat/register/actions.ts +27 -7
- package/src/compat/tsconfig-defaults.ts +6 -3
- package/src/config.ts +15 -1
- package/src/css/build.ts +13 -2
- package/src/dev/imports.ts +34 -5
- package/src/dev/module-cache.ts +35 -2
- package/src/dev/module-transform.ts +7 -1
- package/src/dev/server.ts +91 -22
- package/src/ppr.ts +5 -4
- package/src/proxy.ts +5 -1
- package/src/render/island-context.ts +21 -3
- package/src/render/renderer.ts +102 -26
- package/src/resolve/engine.ts +12 -2
- package/src/resolve/scan-facts.ts +5 -1
- package/src/routing/href.ts +4 -5
- package/src/routing/routes.ts +14 -2
- package/src/runtime/server.ts +8 -4
- package/src/runtime/vendor.ts +1 -1
- package/src/typegen.ts +3 -3
- package/src/utils/esbuild.ts +58 -0
- package/src/utils/fs.ts +14 -2
- package/src/utils/native-require.ts +28 -0
package/README.md
CHANGED
|
@@ -2,152 +2,117 @@
|
|
|
2
2
|
|
|
3
3
|
# pnext
|
|
4
4
|
|
|
5
|
-
**A fast little framework for server-first React apps, fully compatible with Next.js.**
|
|
5
|
+
**A fast little framework for server-first React apps, fully compatible with Next.js.**[<sup>1</sup>](./reference/compat.md)
|
|
6
6
|
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Getting started
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
| | pnext vs Next.js |
|
|
14
|
-
|---|--:|
|
|
15
|
-
| Dev server ready | **2.5–3× faster** |
|
|
16
|
-
| First page, cold | **6.5–13× faster** |
|
|
17
|
-
| Warm request | **4–7.5× faster** |
|
|
18
|
-
| HMR save → visible | **1–2.5× faster** |
|
|
19
|
-
| Production build | **4.5–10× faster** |
|
|
20
|
-
| First-page client JS (gzip) | **6–65× less** |
|
|
21
|
-
|
|
22
|
-
Nothing is prebundled — the dev server compiles what a request needs and caches it content-addressed, so it's ready in ~100 ms at any app size.
|
|
23
|
-
|
|
24
|
-
Core pnext (no Next compat) is its own story, and it's smaller still:
|
|
25
|
-
|
|
26
|
-
- **Server-only pages ship 0 KB of JavaScript.**
|
|
27
|
-
- A server-rendered page with links ships **~1 KB gzip** of framework, total; the router + prefetch runtime alone is **348 bytes**.
|
|
28
|
-
- A fully hydrated route pays **~7.5 KB gzip** of framework — **12.5 KB** with React compat, **15 KB** with the full `next/*` surface. Next.js ships 130+ KB before your first component.
|
|
29
|
-
|
|
30
|
-
Compatibility is proven, not promised: pnext runs Next.js's own test suite — 4,400+ tracked assertions passing — so `next/link`, `next/navigation`, `next/headers`, metadata, middleware, and friends behave the way you already know.
|
|
31
|
-
|
|
32
|
-
## How
|
|
33
|
-
|
|
34
|
-
One pipeline, three fast tools: [Bun](https://bun.sh) as runtime, esbuild as the only bundler (dev and prod are the same artifacts — no dev/prod drift), and oxc for parsing, resolving, and transforms. Preact renders and hydrates; React APIs work through compat. The dev server compiles exactly what a request needs, when it needs it.
|
|
35
|
-
|
|
36
|
-
## Install
|
|
11
|
+
A new app:
|
|
37
12
|
|
|
38
13
|
```sh
|
|
39
|
-
|
|
14
|
+
bunx @wular/pnext create my-app
|
|
40
15
|
```
|
|
41
16
|
|
|
42
|
-
|
|
43
|
-
{
|
|
44
|
-
"scripts": {
|
|
45
|
-
"dev": "pnext dev --port 3000",
|
|
46
|
-
"build": "pnext build",
|
|
47
|
-
"build:vercel": "pnext build --adapter vercel",
|
|
48
|
-
"start": "pnext start --port 3000",
|
|
49
|
-
"analyze": "pnext analyze"
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
```
|
|
17
|
+
Migrating a Next.js app? This rewrites scripts and config in place, scans your source, and reports anything that needs a look (it never edits your code):
|
|
53
18
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
pnext looks for `app/` or `src/app/`:
|
|
57
|
-
|
|
58
|
-
```txt
|
|
59
|
-
src/app/
|
|
60
|
-
globals.css
|
|
61
|
-
page.tsx
|
|
62
|
-
layout.tsx
|
|
63
|
-
users/
|
|
64
|
-
[id]/
|
|
65
|
-
page.tsx
|
|
66
|
-
api/
|
|
67
|
-
hello/
|
|
68
|
-
route.ts
|
|
69
|
-
public/
|
|
70
|
-
logo.svg
|
|
19
|
+
```sh
|
|
20
|
+
bunx @wular/pnext migrate
|
|
71
21
|
```
|
|
72
22
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
## Pages
|
|
23
|
+
Or by hand: `bun add -d @wular/pnext`, then `pnext dev`.
|
|
76
24
|
|
|
77
|
-
|
|
25
|
+
## Incremental by design
|
|
78
26
|
|
|
79
|
-
|
|
80
|
-
export const metadata = {
|
|
81
|
-
title: 'My app',
|
|
82
|
-
};
|
|
27
|
+
Server-rendered pages ship **0 KB** of JavaScript, or **~1 KB gzip** if you want client-side navigation and prefetching. Interactive pages hydrate on Preact for **~7.5 KB** of framework, **~12.5 KB** with React compatibility. And everything is instant: the first page in dev renders **11–13.5× faster** than Next's on **3.4–3.8× less memory**, and production builds run **7–10.5× faster**. See [Performance](./reference/performance.md).
|
|
83
28
|
|
|
84
|
-
|
|
85
|
-
const post = await getPost();
|
|
86
|
-
return <article>{post.title}</article>;
|
|
87
|
-
}
|
|
88
|
-
```
|
|
29
|
+
Core pnext is pure Preact. `compat.react` runs React components and libraries on it, and `compat.next` runs a whole Next.js App Router app unchanged. Start anywhere on that ladder and move when it suits you. The App Router compatibility is validated against Next's own test suite (4,400+ assertions passing). The `pages/` folder is not supported, and neither are private internal utilities of Next.js or React. See [Compatibility](./reference/compat.md).
|
|
89
30
|
|
|
90
|
-
|
|
31
|
+
## A quick tour
|
|
91
32
|
|
|
92
|
-
|
|
93
|
-
'use client';
|
|
33
|
+
### Your first page
|
|
94
34
|
|
|
95
|
-
|
|
35
|
+
Routes live in `app/`. A `page.tsx` is a Server Component by default. It runs only on the server, so it can be async and talk to your database, filesystem, or internal services directly. None of that code reaches the browser:
|
|
96
36
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
37
|
+
```tsx
|
|
38
|
+
// app/posts/[id]/page.tsx
|
|
39
|
+
import type { PageProps } from "#gen/app/posts/[id]/page";
|
|
40
|
+
|
|
41
|
+
export default async function Page({ params }: PageProps) {
|
|
42
|
+
const { id } = await params;
|
|
43
|
+
const post = await db.post.findUnique({ where: { id } });
|
|
44
|
+
return (
|
|
45
|
+
<article>
|
|
46
|
+
<h1>{post.title}</h1>
|
|
47
|
+
<p>{post.body}</p>
|
|
48
|
+
</article>
|
|
49
|
+
);
|
|
100
50
|
}
|
|
101
51
|
```
|
|
102
52
|
|
|
103
|
-
|
|
53
|
+
This page ships **0 KB** of JavaScript. Layouts work the same way: the root `layout.tsx` owns `<html>` and `<body>` and can export `metadata`.
|
|
54
|
+
|
|
55
|
+
### Adding interactivity
|
|
104
56
|
|
|
105
|
-
|
|
57
|
+
Mark a component with `"use client"` where you need state, effects, or event handlers. Server Components render it into the page, and only that island hydrates in the browser:
|
|
106
58
|
|
|
107
59
|
```tsx
|
|
108
|
-
|
|
60
|
+
// app/counter.tsx
|
|
61
|
+
"use client";
|
|
62
|
+
import { useState } from "preact/hooks";
|
|
109
63
|
|
|
110
|
-
export
|
|
111
|
-
|
|
112
|
-
}
|
|
64
|
+
export function Counter({ initial }: { initial: number }) {
|
|
65
|
+
const [count, setCount] = useState(initial);
|
|
66
|
+
return <button onClick={() => setCount(count + 1)}>Count {count}</button>;
|
|
67
|
+
}
|
|
113
68
|
```
|
|
114
69
|
|
|
115
|
-
|
|
70
|
+
Client Components hydrate on Preact for ~7.5 KB of framework, or ~12.5 KB with [`compat.react`](./reference/compat.md) if you want to run React components and libraries unchanged. Offscreen islands can stay out of the initial bundle entirely with `dynamic({ load: 'visible' })`.
|
|
116
71
|
|
|
117
|
-
|
|
72
|
+
### Streaming
|
|
118
73
|
|
|
119
|
-
|
|
120
|
-
import type { NextRequest } from '@wular/pnext/server';
|
|
74
|
+
Wrap slow server work in `<Suspense>`. The shell streams immediately and the content follows when it's ready:
|
|
121
75
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
76
|
+
```tsx
|
|
77
|
+
import { Suspense } from "@wular/pnext";
|
|
78
|
+
|
|
79
|
+
export default function Page() {
|
|
80
|
+
return (
|
|
81
|
+
<Suspense fallback={<p>Loading comments…</p>}>
|
|
82
|
+
<Comments />
|
|
83
|
+
</Suspense>
|
|
84
|
+
);
|
|
125
85
|
}
|
|
126
86
|
```
|
|
127
87
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
## Types
|
|
88
|
+
### APIs and everything else
|
|
131
89
|
|
|
132
|
-
|
|
90
|
+
A `route.ts` file is an HTTP handler:
|
|
133
91
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
92
|
+
```ts
|
|
93
|
+
// app/api/users/route.ts
|
|
94
|
+
export async function GET(request: NextRequest) {
|
|
95
|
+
return Response.json(await listUsers());
|
|
96
|
+
}
|
|
138
97
|
```
|
|
139
98
|
|
|
140
|
-
|
|
99
|
+
- `proxy.ts` runs before route matching.
|
|
100
|
+
- `loading.tsx`, `error.tsx`, and `not-found.tsx` define per-segment fallbacks.
|
|
101
|
+
- `pnext build` emits static HTML for routes that never read the request, and a server for the ones that do. `pnext start` serves it.
|
|
102
|
+
|
|
103
|
+
## Learn more
|
|
141
104
|
|
|
142
|
-
|
|
105
|
+
Apps are file-routed from `app/`: `page.tsx` and `layout.tsx` are Server Components, `route.ts` files are HTTP handlers, `public/` is served from `/`. The reference covers the rest:
|
|
143
106
|
|
|
144
107
|
- [Overview](./reference/overview.md)
|
|
108
|
+
- [Dev server](./reference/dev.md)
|
|
145
109
|
- [Routing](./reference/routing.md)
|
|
146
|
-
- [
|
|
110
|
+
- [Navigation](./reference/navigation.md)
|
|
147
111
|
- [Rendering](./reference/rendering.md)
|
|
112
|
+
- [Metadata](./reference/metadata.md)
|
|
148
113
|
- [CSS](./reference/css.md)
|
|
149
114
|
- [Environment Variables](./reference/env.md)
|
|
150
|
-
- [Compatibility](./reference/compat.md)
|
|
151
|
-
- [Typegen](./reference/typegen.md)
|
|
152
115
|
- [Config](./reference/config.md)
|
|
116
|
+
- [Typegen](./reference/typegen.md)
|
|
117
|
+
- [Compatibility](./reference/compat.md)
|
|
153
118
|
- [Performance](./reference/performance.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wular/pnext",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pnext": "bin/pnext"
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"./link": "./src/api/link.tsx",
|
|
24
24
|
"./navigation": "./src/api/navigation.ts",
|
|
25
25
|
"./navigation/client": "./src/api/client-navigation.ts",
|
|
26
|
-
"./server": "./src/api/server.ts"
|
|
26
|
+
"./server": "./src/api/server.ts",
|
|
27
|
+
"./config/*": "./config/*"
|
|
27
28
|
},
|
|
28
29
|
"scripts": {
|
|
29
30
|
"lint": "bun scripts/check-compat-boundary.ts && eslint . --max-warnings 0 && tsc --noEmit",
|