create-nifra 3.5.0 → 4.0.2
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 +3 -3
- package/dist/agent-files.d.ts +41 -26
- package/dist/agent-files.d.ts.map +1 -1
- package/dist/agent-files.js +80 -47
- package/dist/agent-files.js.map +1 -1
- package/dist/agents.d.ts +3 -3
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +65 -69
- package/dist/agents.js.map +1 -1
- package/dist/auth.d.ts +5 -4
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +27 -14
- package/dist/auth.js.map +1 -1
- package/dist/cli.d.ts +23 -25
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +141 -130
- package/dist/cli.js.map +1 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +49 -48
- package/dist/db.js.map +1 -1
- package/dist/scaffold/frameworks.d.ts +13 -38
- package/dist/scaffold/frameworks.d.ts.map +1 -1
- package/dist/scaffold/frameworks.js +9 -32
- package/dist/scaffold/frameworks.js.map +1 -1
- package/dist/scaffold/route-types.d.ts +9 -0
- package/dist/scaffold/route-types.d.ts.map +1 -0
- package/dist/scaffold/route-types.js +61 -0
- package/dist/scaffold/route-types.js.map +1 -0
- package/dist/scaffold/site-files.d.ts +14 -8
- package/dist/scaffold/site-files.d.ts.map +1 -1
- package/dist/scaffold/site-files.js +29 -60
- package/dist/scaffold/site-files.js.map +1 -1
- package/dist/scaffold/site.d.ts +8 -5
- package/dist/scaffold/site.d.ts.map +1 -1
- package/dist/scaffold/site.js +47 -34
- package/dist/scaffold/site.js.map +1 -1
- package/dist/scaffold/targets.d.ts +39 -0
- package/dist/scaffold/targets.d.ts.map +1 -0
- package/dist/scaffold/targets.js +116 -0
- package/dist/scaffold/targets.js.map +1 -0
- package/package.json +4 -1
- package/src/agent-files.ts +89 -47
- package/template/README.md +12 -6
- package/template/{src → backend}/app.test.ts +2 -2
- package/template/{src → backend}/app.ts +8 -3
- package/template/{src → backend}/index.ts +2 -2
- package/template/{src → backend}/routes.ts +1 -1
- package/template/nifra.assurance.ts +16 -14
- package/template/package.json +7 -7
- package/template/tsconfig.json +1 -1
- package/template-batteries/README.md +10 -6
- package/template-batteries/{src → backend}/app.test.ts +23 -23
- package/template-batteries/{src → backend}/app.ts +8 -3
- package/template-batteries/{src → backend}/index.ts +2 -2
- package/template-batteries/{src → backend}/notes.ts +1 -1
- package/template-batteries/nifra.assurance.ts +16 -14
- package/template-batteries/package.json +10 -9
- package/template-batteries/tsconfig.json +1 -1
- package/template-isr/README.md +3 -0
- package/template-isr/{backend.ts → backend/app.ts} +2 -0
- package/template-isr/{server.ts → backend/dev-server.ts} +4 -4
- package/template-isr/{worker.ts → backend/worker.ts} +4 -2
- package/template-isr/build.ts +3 -1
- package/template-isr/gitignore +7 -1
- package/template-isr/nifra.assurance.ts +15 -13
- package/template-isr/package.json +10 -9
- package/template-isr/routes/index.backend.ts +14 -0
- package/template-isr/routes/index.tsx +5 -17
- package/template-isr/tsconfig.json +5 -4
- package/template-isr/wrangler.toml +6 -1
- package/template-site/README.md +24 -23
- package/template-site/{backend.ts → backend/app.ts} +6 -4
- package/template-site/gitignore +5 -10
- package/template-site/nifra.assurance.ts +15 -13
- package/template-site/nifra.config.ts +4 -4
- package/template-site/routes/index.backend.ts +18 -0
- package/template-site/routes/index.tsx +2 -15
- package/template-site-preact/README.md +21 -20
- package/template-site-preact/nifra.config.ts +4 -4
- package/template-site-preact/routes/_layout.tsx +3 -1
- package/template-site-preact/routes/index.tsx +2 -15
- package/template-site-solid/README.md +21 -19
- package/template-site-solid/nifra.config.ts +5 -4
- package/template-site-solid/routes/index.tsx +2 -15
- package/template-site-svelte/README.md +21 -19
- package/template-site-svelte/nifra.config.ts +3 -2
- package/template-site-svelte/routes/index.svelte +3 -16
- package/template-site-vue/README.md +21 -20
- package/template-site-vue/nifra.config.ts +4 -3
- package/template-site-vue/routes/_layout.vue +21 -25
- package/template-site-vue/routes/index.vue +12 -18
- package/dist/scaffold/site-build.d.ts +0 -60
- package/dist/scaffold/site-build.d.ts.map +0 -1
- package/dist/scaffold/site-build.js +0 -198
- package/dist/scaffold/site-build.js.map +0 -1
- package/template-site/.dockerignore +0 -14
- package/template-site/Dockerfile +0 -25
- package/template-site/_worker.ts +0 -17
- package/template-site/deno.json +0 -7
- package/template-site/server-bun.ts +0 -35
- package/template-site/server-deno.ts +0 -38
- package/template-site/server-node.ts +0 -40
- package/template-site/server-vercel.ts +0 -17
- package/template-site/wrangler.toml +0 -4
- /package/template-isr/{page.ts → backend/page.ts} +0 -0
- /package/template-site/{counter.ts → backend/counter.ts} +0 -0
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { backend } from "../backend"
|
|
1
|
+
import type { Route } from "./+types/index"
|
|
3
2
|
|
|
4
3
|
export const meta = {
|
|
5
4
|
title: "nifra site",
|
|
6
5
|
meta: [{ name: "description", content: "A nifra + Preact SSR site, deployable to every runtime." }],
|
|
7
6
|
}
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
// client submit the loader revalidates with no full reload (progressive enhancement).
|
|
11
|
-
export async function loader({ api }: LoaderArgs<typeof backend>) {
|
|
12
|
-
const res = await api.count.get()
|
|
13
|
-
return { count: res.ok ? res.data.count : 0 }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function action({ api }: ActionArgs<typeof backend>) {
|
|
17
|
-
await api.count.post()
|
|
18
|
-
return { ok: true }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export default function Home(props: { data: LoaderData<typeof loader> }) {
|
|
8
|
+
export default function Home(props: Route.ComponentProps) {
|
|
22
9
|
return (
|
|
23
10
|
<>
|
|
24
11
|
<section className="hero">
|
|
@@ -7,7 +7,6 @@ is Web-standard, so only the server entry + build target differ per platform.
|
|
|
7
7
|
```sh
|
|
8
8
|
bun install
|
|
9
9
|
bun run dev # nifra dev → true-HMR dev server (Bun + nifra SSR) at http://localhost:3000
|
|
10
|
-
bun run preview # wrangler pages dev dist → preview the built Cloudflare bundle (run `bun run build` first)
|
|
11
10
|
```
|
|
12
11
|
|
|
13
12
|
The backend starter includes response security headers, explicit-origin CORS, a 30-second request
|
|
@@ -18,32 +17,35 @@ evidence in `nifra.assurance.ts`.
|
|
|
18
17
|
|
|
19
18
|
Routes are Solid function components (JSX, compiled by `solidBunPlugin`) under `routes/` - `index.tsx`
|
|
20
19
|
(landing + a live loader/action counter), `_layout.tsx` (chrome), `_404.tsx`. The frontend adapter is
|
|
21
|
-
one line in `framework.ts`; data lives behind `backend.ts`. Each `build*` script wires
|
|
20
|
+
one line in `backend/framework.ts`; data lives behind `backend/app.ts`. Each `build*` script wires
|
|
22
21
|
`solidBunPlugin("dom")` for the client and `("ssr")` + the `solid` export condition for the server.
|
|
23
22
|
|
|
24
|
-
## Deploy
|
|
23
|
+
## Deploy
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
The app deploys to the `target` in `nifra.config.ts` (chosen with `bun create nifra --target`, switched
|
|
26
|
+
with `nifra target <t>`). `bun run build` runs `nifra build`, which generates that target's server
|
|
27
|
+
entry from `backend/` and `routes/`, so the app carries no per-runtime entry or build script.
|
|
28
|
+
|
|
29
|
+
| target | `bun run build` emits | then |
|
|
27
30
|
| --- | --- | --- |
|
|
28
|
-
| **
|
|
29
|
-
| **
|
|
30
|
-
| **
|
|
31
|
-
| **
|
|
32
|
-
| **
|
|
31
|
+
| **bun** (default) | `dist/server.js` + assets | `bun dist/server.js` on any host (`--docker` adds a Dockerfile) |
|
|
32
|
+
| **node** | `dist/server.js` + assets | `node dist/server.js` (`--docker` adds a Dockerfile) |
|
|
33
|
+
| **deno** | `dist/server.js` + assets | `deployctl deploy --prod --entrypoint=dist/server.js` |
|
|
34
|
+
| **cloudflare** | `dist/` (`_worker.js`, `_routes.json`) | `wrangler pages deploy dist` |
|
|
35
|
+
| **vercel** | `.vercel/output/` (Build Output API) | `vercel deploy --prebuilt` |
|
|
33
36
|
|
|
34
|
-
nifra never enters your cloud credentials
|
|
35
|
-
`
|
|
37
|
+
nifra never enters your cloud credentials: it writes the target's config (`wrangler.toml`,
|
|
38
|
+
`deno.json`, a `Dockerfile`) and you run the vendor CLI.
|
|
36
39
|
|
|
37
40
|
## Structure
|
|
38
41
|
|
|
39
42
|
```
|
|
40
43
|
routes/ index.tsx (landing), _layout.tsx (chrome), _404.tsx
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
server-vercel.ts Vercel Edge function build-vercel.ts → .vercel/output/
|
|
44
|
+
index.backend.ts - the landing page's loader/action (server only)
|
|
45
|
+
backend/ app.ts - your contract (loaders/actions call it in-process)
|
|
46
|
+
framework.ts - the adapter (solidAdapter) - imported by the server entry `nifra build` generates (edge-bundlable)
|
|
47
|
+
frontend/ browser-only code (components, hooks) - created when you need it
|
|
48
|
+
shared/ code both sides import (types, formatting, validation) - may import only shared code
|
|
49
|
+
nifra.config.ts the nifra CLI's dev/build config (adapter + clientModule + Solid plugins) - read by `nifra dev` and `nifra build`,
|
|
50
|
+
including `target`, where `nifra build` deploys
|
|
49
51
|
```
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// The nifra CLI's config - read by `nifra dev|build|start`. It's imported ONLY by the CLI (which runs on
|
|
2
2
|
// Bun), so it can eagerly import the Vite plugin + the Solid compile plugin - keeping them OUT of the
|
|
3
|
-
// edge worker bundle that `framework.ts` (the render-adapter source the
|
|
4
|
-
// of. Solid needs the `"solid"` resolve condition (routes solid-js to its
|
|
5
|
-
|
|
3
|
+
// edge worker bundle that `backend/framework.ts` (the render-adapter source the generated server entry
|
|
4
|
+
// imports) must stay free of. Solid needs the `"solid"` resolve condition (routes solid-js to its
|
|
5
|
+
// source / JSX-dev build).
|
|
6
|
+
import { solidBunPlugin } from "@nifrajs/web-solid/plugin"
|
|
6
7
|
import solid from "vite-plugin-solid"
|
|
7
8
|
|
|
8
|
-
export { adapter } from "./framework"
|
|
9
|
+
export { adapter } from "./backend/framework"
|
|
9
10
|
export const clientModule = "@nifrajs/web-solid/client"
|
|
10
11
|
// `ssr: true` makes vite-plugin-solid emit hydratable client output, matching nifra's Bun SSR.
|
|
11
12
|
export const vitePlugins = [solid({ ssr: true })]
|
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { backend } from "../backend"
|
|
1
|
+
import type { Route } from "./+types/index"
|
|
3
2
|
|
|
4
3
|
export const meta = {
|
|
5
4
|
title: "nifra site",
|
|
6
5
|
meta: [{ name: "description", content: "A nifra + Solid SSR site, deployable to every runtime." }],
|
|
7
6
|
}
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
// client submit the loader revalidates with no full reload (progressive enhancement).
|
|
11
|
-
export async function loader({ api }: LoaderArgs<typeof backend>) {
|
|
12
|
-
const res = await api.count.get()
|
|
13
|
-
return { count: res.ok ? res.data.count : 0 }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function action({ api }: ActionArgs<typeof backend>) {
|
|
17
|
-
await api.count.post()
|
|
18
|
-
return { ok: true }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export default function Home(props: { data: LoaderData<typeof loader> }) {
|
|
8
|
+
export default function Home(props: Route.ComponentProps) {
|
|
22
9
|
return (
|
|
23
10
|
<div>
|
|
24
11
|
<section class="hero">
|
|
@@ -7,7 +7,6 @@ is Web-standard, so only the server entry + build target differ per platform.
|
|
|
7
7
|
```sh
|
|
8
8
|
bun install
|
|
9
9
|
bun run dev # nifra dev → true-HMR dev server (Bun + nifra SSR) at http://localhost:3000
|
|
10
|
-
bun run preview # wrangler pages dev dist → preview the built Cloudflare bundle (run `bun run build` first)
|
|
11
10
|
```
|
|
12
11
|
|
|
13
12
|
The backend starter includes response security headers, explicit-origin CORS, a 30-second request
|
|
@@ -20,32 +19,35 @@ Routes are `.svelte` components under `routes/` - `index.svelte` (landing + a li
|
|
|
20
19
|
counter), `_layout.svelte` (chrome via the `children` snippet), `_404.svelte`. A route's
|
|
21
20
|
`loader`/`action`/`meta` are named exports from its `<script module>` block; the page receives the
|
|
22
21
|
loader output as the `data` prop (`let { data } = $props()`). The frontend adapter is one line in
|
|
23
|
-
`framework.ts`; data lives behind `backend.ts`. Each `build*` script wires `svelteBunPlugin("dom")` for
|
|
22
|
+
`backend/framework.ts`; data lives behind `backend/app.ts`. Each `build*` script wires `svelteBunPlugin("dom")` for
|
|
24
23
|
the client and `("ssr")` for the server.
|
|
25
24
|
|
|
26
|
-
## Deploy
|
|
25
|
+
## Deploy
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
The app deploys to the `target` in `nifra.config.ts` (chosen with `bun create nifra --target`, switched
|
|
28
|
+
with `nifra target <t>`). `bun run build` runs `nifra build`, which generates that target's server
|
|
29
|
+
entry from `backend/` and `routes/`, so the app carries no per-runtime entry or build script.
|
|
30
|
+
|
|
31
|
+
| target | `bun run build` emits | then |
|
|
29
32
|
| --- | --- | --- |
|
|
30
|
-
| **
|
|
31
|
-
| **
|
|
32
|
-
| **
|
|
33
|
-
| **
|
|
34
|
-
| **
|
|
33
|
+
| **bun** (default) | `dist/server.js` + assets | `bun dist/server.js` on any host (`--docker` adds a Dockerfile) |
|
|
34
|
+
| **node** | `dist/server.js` + assets | `node dist/server.js` (`--docker` adds a Dockerfile) |
|
|
35
|
+
| **deno** | `dist/server.js` + assets | `deployctl deploy --prod --entrypoint=dist/server.js` |
|
|
36
|
+
| **cloudflare** | `dist/` (`_worker.js`, `_routes.json`) | `wrangler pages deploy dist` |
|
|
37
|
+
| **vercel** | `.vercel/output/` (Build Output API) | `vercel deploy --prebuilt` |
|
|
35
38
|
|
|
36
|
-
nifra never enters your cloud credentials
|
|
37
|
-
`
|
|
39
|
+
nifra never enters your cloud credentials: it writes the target's config (`wrangler.toml`,
|
|
40
|
+
`deno.json`, a `Dockerfile`) and you run the vendor CLI.
|
|
38
41
|
|
|
39
42
|
## Structure
|
|
40
43
|
|
|
41
44
|
```
|
|
42
45
|
routes/ index.svelte (landing), _layout.svelte (chrome), _404.svelte
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
server-vercel.ts Vercel Edge function build-vercel.ts → .vercel/output/
|
|
46
|
+
index.backend.ts - the landing page's loader/action (server only)
|
|
47
|
+
backend/ app.ts - your contract (loaders/actions call it in-process)
|
|
48
|
+
framework.ts - the adapter (svelteAdapter) - imported by the server entry `nifra build` generates (edge-bundlable)
|
|
49
|
+
frontend/ browser-only code (components, hooks) - created when you need it
|
|
50
|
+
shared/ code both sides import (types, formatting, validation) - may import only shared code
|
|
51
|
+
nifra.config.ts the nifra CLI's dev/build config (adapter + clientModule + Svelte plugins) - read by `nifra dev` and `nifra build`,
|
|
52
|
+
including `target`, where `nifra build` deploys
|
|
51
53
|
```
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// The nifra CLI's config - read by `nifra dev|build|start`. It's imported ONLY by the CLI (which runs on
|
|
2
2
|
// Bun), so it can eagerly import the Vite plugin + the Svelte compiler - keeping them OUT of the edge
|
|
3
|
-
// worker bundle that `framework.ts` (the render-adapter source the
|
|
3
|
+
// worker bundle that `backend/framework.ts` (the render-adapter source the generated server entry
|
|
4
|
+
// imports) must stay free of.
|
|
4
5
|
import { svelte } from "@sveltejs/vite-plugin-svelte"
|
|
5
6
|
import { svelteBunPlugin } from "@nifrajs/web-svelte/plugin"
|
|
6
7
|
|
|
7
|
-
export { adapter } from "./framework"
|
|
8
|
+
export { adapter } from "./backend/framework"
|
|
8
9
|
export const clientModule = "@nifrajs/web-svelte/client"
|
|
9
10
|
// `nifra dev` HMR: Vite + the official Svelte plugin compile/HMR the .svelte client modules.
|
|
10
11
|
export const vitePlugins = [svelte()]
|
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
<script module lang="ts">
|
|
2
|
-
import type { ActionArgs, LoaderArgs } from "@nifrajs/client"
|
|
3
|
-
import type { backend } from "../backend"
|
|
4
|
-
|
|
5
2
|
export const meta = {
|
|
6
3
|
title: "nifra site",
|
|
7
4
|
meta: [{ name: "description", content: "A nifra + Svelte SSR site, deployable to every runtime." }],
|
|
8
5
|
}
|
|
9
|
-
|
|
10
|
-
// Loader runs on the server (in-process during SSR). The action handles the form POST; after a
|
|
11
|
-
// client submit the loader revalidates with no full reload (progressive enhancement).
|
|
12
|
-
export async function loader({ api }: LoaderArgs<typeof backend>) {
|
|
13
|
-
const res = await api.count.get()
|
|
14
|
-
return { count: res.ok ? res.data.count : 0 }
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function action({ api }: ActionArgs<typeof backend>) {
|
|
18
|
-
await api.count.post()
|
|
19
|
-
return { ok: true }
|
|
20
|
-
}
|
|
21
6
|
</script>
|
|
22
7
|
|
|
23
8
|
<script lang="ts">
|
|
24
|
-
|
|
9
|
+
import type { Route } from "./+types/index"
|
|
10
|
+
|
|
11
|
+
let { data }: Route.ComponentProps = $props()
|
|
25
12
|
</script>
|
|
26
13
|
|
|
27
14
|
<section class="hero">
|
|
@@ -7,7 +7,6 @@ is Web-standard, so only the server entry + build target differ per platform.
|
|
|
7
7
|
```sh
|
|
8
8
|
bun install
|
|
9
9
|
bun run dev # nifra dev → true-HMR dev server (Bun + nifra SSR) at http://localhost:3000
|
|
10
|
-
bun run preview # wrangler pages dev dist → preview the built Cloudflare bundle (run `bun run build` first)
|
|
11
10
|
```
|
|
12
11
|
|
|
13
12
|
The backend starter includes response security headers, explicit-origin CORS, a 30-second request
|
|
@@ -20,32 +19,34 @@ Routes are **Vue SFCs** (`.vue`) under `routes/` - `index.vue` (landing + a live
|
|
|
20
19
|
counter), `_layout.vue` (chrome via the default slot), `_404.vue`. A route SFC's plain `<script>`
|
|
21
20
|
carries nifra's `loader`/`action`/`meta`; `<script setup>` + `<template>` are the component. The
|
|
22
21
|
build compiles them with `vueBunPlugin` (`@nifrajs/web-vue/plugin`). The frontend adapter is one line in
|
|
23
|
-
`framework.ts`; data lives behind `backend.ts`.
|
|
22
|
+
`backend/framework.ts`; data lives behind `backend/app.ts`.
|
|
24
23
|
|
|
25
|
-
## Deploy
|
|
24
|
+
## Deploy
|
|
26
25
|
|
|
27
|
-
|
|
26
|
+
The app deploys to the `target` in `nifra.config.ts` (chosen with `bun create nifra --target`, switched
|
|
27
|
+
with `nifra target <t>`). `bun run build` runs `nifra build`, which generates that target's server
|
|
28
|
+
entry from `backend/` and `routes/`, so the app carries no per-runtime entry or build script.
|
|
29
|
+
|
|
30
|
+
| target | `bun run build` emits | then |
|
|
28
31
|
| --- | --- | --- |
|
|
29
|
-
| **
|
|
30
|
-
| **
|
|
31
|
-
| **
|
|
32
|
-
| **
|
|
33
|
-
| **
|
|
32
|
+
| **bun** (default) | `dist/server.js` + assets | `bun dist/server.js` on any host (`--docker` adds a Dockerfile) |
|
|
33
|
+
| **node** | `dist/server.js` + assets | `node dist/server.js` (`--docker` adds a Dockerfile) |
|
|
34
|
+
| **deno** | `dist/server.js` + assets | `deployctl deploy --prod --entrypoint=dist/server.js` |
|
|
35
|
+
| **cloudflare** | `dist/` (`_worker.js`, `_routes.json`) | `wrangler pages deploy dist` |
|
|
36
|
+
| **vercel** | `.vercel/output/` (Build Output API) | `vercel deploy --prebuilt` |
|
|
34
37
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
configs (`Dockerfile`, `deno.json`, `wrangler.toml`, Vercel Build Output API); you run the vendor CLI.
|
|
38
|
+
nifra never enters your cloud credentials: it writes the target's config (`wrangler.toml`,
|
|
39
|
+
`deno.json`, a `Dockerfile`) and you run the vendor CLI.
|
|
38
40
|
|
|
39
41
|
## Structure
|
|
40
42
|
|
|
41
43
|
```
|
|
42
44
|
routes/ index.vue (landing), _layout.vue (chrome), _404.vue (Vue SFCs)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
server-vercel.ts Vercel Edge function build-vercel.ts → .vercel/output/
|
|
45
|
+
index.backend.ts - the landing page's loader/action (server only)
|
|
46
|
+
backend/ app.ts - your contract (loaders/actions call it in-process)
|
|
47
|
+
framework.ts - the adapter (vueAdapter) - imported by the server entry `nifra build` generates (edge-bundlable)
|
|
48
|
+
frontend/ browser-only code (components, hooks) - created when you need it
|
|
49
|
+
shared/ code both sides import (types, formatting, validation) - may import only shared code
|
|
50
|
+
nifra.config.ts the nifra CLI's dev/build config (adapter + clientModule + Vue plugins) - read by `nifra dev` and `nifra build`,
|
|
51
|
+
including `target`, where `nifra build` deploys
|
|
51
52
|
```
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
// The nifra CLI's config - read by `nifra dev|build|start`. It's imported ONLY by the CLI (which runs on
|
|
2
2
|
// Bun), so it can eagerly import the Vite plugin + the SFC compiler - keeping them OUT of the edge
|
|
3
|
-
// worker bundle that `framework.ts` (the render-adapter source the
|
|
3
|
+
// worker bundle that `backend/framework.ts` (the render-adapter source the generated server entry
|
|
4
|
+
// imports) must stay free of.
|
|
4
5
|
import { vueBunPlugin } from "@nifrajs/web-vue/plugin"
|
|
5
6
|
import vue from "@vitejs/plugin-vue"
|
|
6
7
|
|
|
7
|
-
export { adapter } from "./framework"
|
|
8
|
+
export { adapter } from "./backend/framework"
|
|
8
9
|
export const clientModule = "@nifrajs/web-vue/client"
|
|
9
10
|
// `nifra dev` HMR: Vite + the official Vue plugin compile/HMR the .vue client modules.
|
|
10
11
|
export const vitePlugins = [vue()]
|
|
11
12
|
// `nifra build` (client) + `nifra start`/`nifra dev` (Bun-side SSR) compile .vue via these.
|
|
12
13
|
export const clientPlugins = [vueBunPlugin("dom")]
|
|
13
14
|
export const serverPlugins = [vueBunPlugin("ssr")]
|
|
14
|
-
// Vue feature flags the plugin doesn't inject
|
|
15
|
+
// Vue feature flags the plugin doesn't inject; `nifra build` defines them in both bundles.
|
|
15
16
|
export const define = {
|
|
16
17
|
__VUE_OPTIONS_API__: "true",
|
|
17
18
|
__VUE_PROD_DEVTOOLS__: "false",
|
|
@@ -1,33 +1,10 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
Root layout (Vue SFC) - wraps every page; the compose fold passes the page through the default slot.
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
compiler's special-casing of a literal <style> tag. Keeps the whole template single-file.
|
|
3
|
+
The <style> block is global (not scoped): @nifrajs/web-vue/plugin compiles it into the app
|
|
4
|
+
stylesheet, which the document links before it renders.
|
|
6
5
|
-->
|
|
7
|
-
<script setup lang="ts">
|
|
8
|
-
const css = `
|
|
9
|
-
:root { --bg:#0a0a0f; --panel:#14141c; --border:#26263a; --fg:#e8e8f0; --muted:#9a9ab0; --accent:#7c5cff; --accent2:#00d4ff; }
|
|
10
|
-
* { box-sizing: border-box; } html { color-scheme: dark; }
|
|
11
|
-
body { margin:0; background:var(--bg); color:var(--fg); font:16px/1.6 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif; -webkit-font-smoothing:antialiased; }
|
|
12
|
-
a { color:var(--accent2); text-decoration:none; } a:hover { text-decoration:underline; }
|
|
13
|
-
.wrap { max-width:840px; margin:0 auto; padding:0 24px; }
|
|
14
|
-
header.site { border-bottom:1px solid var(--border); } header.site .wrap { display:flex; align-items:center; justify-content:space-between; height:62px; }
|
|
15
|
-
.logo, .logo b { font-weight:800; font-size:20px; } .logo b { background:linear-gradient(90deg,var(--accent),var(--accent2)); -webkit-background-clip:text; background-clip:text; color:transparent; }
|
|
16
|
-
.hero { text-align:center; padding:80px 0 56px; }
|
|
17
|
-
.hero h1 { font-size:clamp(36px,6vw,56px); line-height:1.05; margin:0 0 16px; letter-spacing:-0.03em; }
|
|
18
|
-
.hero h1 .grad { background:linear-gradient(90deg,var(--accent),var(--accent2)); -webkit-background-clip:text; background-clip:text; color:transparent; }
|
|
19
|
-
.hero p { font-size:19px; color:var(--muted); max-width:560px; margin:0 auto 28px; }
|
|
20
|
-
.card { background:var(--panel); border:1px solid var(--border); border-radius:14px; padding:24px 28px; display:flex; align-items:center; justify-content:space-between; gap:24px; flex-wrap:wrap; }
|
|
21
|
-
.card h3 { margin:0 0 4px; } .card p { margin:0; color:var(--muted); font-size:14px; }
|
|
22
|
-
.count { font-size:34px; font-weight:800; font-variant-numeric:tabular-nums; min-width:44px; text-align:center; background:linear-gradient(90deg,var(--accent),var(--accent2)); -webkit-background-clip:text; background-clip:text; color:transparent; }
|
|
23
|
-
.btn { background:linear-gradient(90deg,var(--accent),var(--accent2)); color:#0a0a0f; font:inherit; font-weight:700; border:none; cursor:pointer; padding:11px 20px; border-radius:10px; }
|
|
24
|
-
footer.site { border-top:1px solid var(--border); color:var(--muted); font-size:14px; } footer.site .wrap { padding:24px; }
|
|
25
|
-
`.trim()
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
6
|
<template>
|
|
29
7
|
<div id="app">
|
|
30
|
-
<component :is="'style'">{{ css }}</component>
|
|
31
8
|
<header class="site">
|
|
32
9
|
<div class="wrap">
|
|
33
10
|
<a href="/" class="logo"><b>nifra</b></a>
|
|
@@ -38,3 +15,22 @@ const css = `
|
|
|
38
15
|
<footer class="site"><div class="wrap">Built with nifra</div></footer>
|
|
39
16
|
</div>
|
|
40
17
|
</template>
|
|
18
|
+
|
|
19
|
+
<style>
|
|
20
|
+
:root { --bg:#0a0a0f; --panel:#14141c; --border:#26263a; --fg:#e8e8f0; --muted:#9a9ab0; --accent:#7c5cff; --accent2:#00d4ff; }
|
|
21
|
+
* { box-sizing: border-box; } html { color-scheme: dark; }
|
|
22
|
+
body { margin:0; background:var(--bg); color:var(--fg); font:16px/1.6 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif; -webkit-font-smoothing:antialiased; }
|
|
23
|
+
a { color:var(--accent2); text-decoration:none; } a:hover { text-decoration:underline; }
|
|
24
|
+
.wrap { max-width:840px; margin:0 auto; padding:0 24px; }
|
|
25
|
+
header.site { border-bottom:1px solid var(--border); } header.site .wrap { display:flex; align-items:center; justify-content:space-between; height:62px; }
|
|
26
|
+
.logo, .logo b { font-weight:800; font-size:20px; } .logo b { background:linear-gradient(90deg,var(--accent),var(--accent2)); -webkit-background-clip:text; background-clip:text; color:transparent; }
|
|
27
|
+
.hero { text-align:center; padding:80px 0 56px; }
|
|
28
|
+
.hero h1 { font-size:clamp(36px,6vw,56px); line-height:1.05; margin:0 0 16px; letter-spacing:-0.03em; }
|
|
29
|
+
.hero h1 .grad { background:linear-gradient(90deg,var(--accent),var(--accent2)); -webkit-background-clip:text; background-clip:text; color:transparent; }
|
|
30
|
+
.hero p { font-size:19px; color:var(--muted); max-width:560px; margin:0 auto 28px; }
|
|
31
|
+
.card { background:var(--panel); border:1px solid var(--border); border-radius:14px; padding:24px 28px; display:flex; align-items:center; justify-content:space-between; gap:24px; flex-wrap:wrap; }
|
|
32
|
+
.card h3 { margin:0 0 4px; } .card p { margin:0; color:var(--muted); font-size:14px; }
|
|
33
|
+
.count { font-size:34px; font-weight:800; font-variant-numeric:tabular-nums; min-width:44px; text-align:center; background:linear-gradient(90deg,var(--accent),var(--accent2)); -webkit-background-clip:text; background-clip:text; color:transparent; }
|
|
34
|
+
.btn { background:linear-gradient(90deg,var(--accent),var(--accent2)); color:#0a0a0f; font:inherit; font-weight:700; border:none; cursor:pointer; padding:11px 20px; border-radius:10px; }
|
|
35
|
+
footer.site { border-top:1px solid var(--border); color:var(--muted); font-size:14px; } footer.site .wrap { padding:24px; }
|
|
36
|
+
</style>
|
|
@@ -1,33 +1,27 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
Home route (Vue SFC). The plain <script> carries
|
|
3
|
-
|
|
4
|
-
component. The form POST is the SSR action path; after a client submit the loader revalidates with
|
|
2
|
+
Home route (Vue SFC). The plain <script> carries meta; loader and action live in index.backend.ts.
|
|
3
|
+
<script setup> + <template> are the component. The form POST is the SSR action path; after a client submit the loader revalidates with
|
|
5
4
|
no full reload (progressive enhancement). Compiled by @nifrajs/web-vue/plugin.
|
|
6
5
|
-->
|
|
7
6
|
<script lang="ts">
|
|
8
|
-
import type { ActionArgs, LoaderArgs } from "@nifrajs/client"
|
|
9
|
-
import type { backend } from "../backend"
|
|
10
|
-
|
|
11
7
|
export const meta = {
|
|
12
8
|
title: "nifra site",
|
|
13
9
|
meta: [{ name: "description", content: "A nifra + Vue SSR site, deployable to every runtime." }],
|
|
14
10
|
}
|
|
15
|
-
|
|
16
|
-
// Loader runs on the server (in-process during SSR). The action handles the form POST.
|
|
17
|
-
export async function loader({ api }: LoaderArgs<typeof backend>) {
|
|
18
|
-
const res = await api.count.get()
|
|
19
|
-
return { count: res.ok ? res.data.count : 0 }
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export async function action({ api }: ActionArgs<typeof backend>) {
|
|
23
|
-
await api.count.post()
|
|
24
|
-
return { ok: true }
|
|
25
|
-
}
|
|
26
11
|
</script>
|
|
27
12
|
|
|
28
13
|
<script setup lang="ts">
|
|
14
|
+
import type { Route } from "./+types/index"
|
|
15
|
+
|
|
29
16
|
// compose() spreads data/actionData/pending/submission as props - declare them so they aren't attrs.
|
|
30
|
-
defineProps(
|
|
17
|
+
// Listed rather than `defineProps<Route.ComponentProps>()`: the SFC compiler cannot follow an imported
|
|
18
|
+
// type through tsconfig `rootDirs`, but it can declare these keys and leave their types to TypeScript.
|
|
19
|
+
defineProps<{
|
|
20
|
+
data: Route.LoaderData
|
|
21
|
+
actionData?: Route.ActionData
|
|
22
|
+
pending?: Route.ComponentProps["pending"]
|
|
23
|
+
submission?: Route.ComponentProps["submission"]
|
|
24
|
+
}>()
|
|
31
25
|
</script>
|
|
32
26
|
|
|
33
27
|
<template>
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The five build entries a site scaffold ships, emitted from one shape.
|
|
3
|
-
*
|
|
4
|
-
* These were 25 files - five deploy targets copied across five framework directories - and the
|
|
5
|
-
* difference between any two of them is mechanical: which runtime it targets, and which compiler
|
|
6
|
-
* plugin, resolve conditions and defines the framework needs. Nothing else. So the target owns its
|
|
7
|
-
* own prose (what it emits, how to run it) and the framework contributes its injections, and the 25
|
|
8
|
-
* files come out of one function.
|
|
9
|
-
*
|
|
10
|
-
* The emitted text is asserted byte-for-byte against the templates that used to be checked in, so
|
|
11
|
-
* this is a refactor whose correctness is decided by a test rather than by reading.
|
|
12
|
-
*/
|
|
13
|
-
import type { FrameworkSpec } from "./frameworks.js";
|
|
14
|
-
/**
|
|
15
|
-
* Where the framework's own resolve conditions sit inside a target's server list.
|
|
16
|
-
*
|
|
17
|
-
* The edge targets end theirs with `browser` (the worker has no Node builtins, so packages must be
|
|
18
|
-
* asked for their browser build); Bun and Node do not. The framework's conditions go in the middle,
|
|
19
|
-
* which is the order every checked-in template used.
|
|
20
|
-
*/
|
|
21
|
-
export interface ServerConditionSlots {
|
|
22
|
-
readonly before: readonly string[];
|
|
23
|
-
readonly after: readonly string[];
|
|
24
|
-
}
|
|
25
|
-
export interface BuildTarget {
|
|
26
|
-
/** File name, e.g. `build-bun.ts`. */
|
|
27
|
-
readonly file: string;
|
|
28
|
-
/** Leading comment block, without the trailing newline. */
|
|
29
|
-
readonly header: string;
|
|
30
|
-
/**
|
|
31
|
-
* Frameworks whose header says something extra here - what their plugin does, or how to run the
|
|
32
|
-
* output once their compiler is in the picture.
|
|
33
|
-
*
|
|
34
|
-
* These are the one genuinely non-mechanical part of a build entry, and they are the reason this
|
|
35
|
-
* table exists rather than a pure `{framework, runtime}` function: the prose a framework needs to
|
|
36
|
-
* explain itself is written, not derived. Keeping them beside the target they belong to is the
|
|
37
|
-
* closest thing to having them in the file without having five copies of the file.
|
|
38
|
-
*/
|
|
39
|
-
readonly headerOverrides?: Readonly<Record<string, string>>;
|
|
40
|
-
/** Runtime conditions this target's SERVER build resolves with. */
|
|
41
|
-
readonly serverConditions: ServerConditionSlots;
|
|
42
|
-
/** Extra `node:fs` named imports beyond `cpSync, mkdirSync, rmSync`. */
|
|
43
|
-
readonly extraFsImports?: readonly string[];
|
|
44
|
-
/** Lines between the imports and the first build call, `dir` already declared. */
|
|
45
|
-
readonly setup: string;
|
|
46
|
-
/** Where `buildClient` writes assets, as a template expression. */
|
|
47
|
-
readonly clientOutDir: string;
|
|
48
|
-
/** The server entry this target boots from. */
|
|
49
|
-
readonly serverEntry: string;
|
|
50
|
-
/** Scratch directory for the server build. */
|
|
51
|
-
readonly serverOutDir: string;
|
|
52
|
-
/** `target:` line for `buildServer`, or empty for the default (workerd). */
|
|
53
|
-
readonly serverTarget: string;
|
|
54
|
-
/** Everything after the `buildServer` call. */
|
|
55
|
-
readonly tail: string;
|
|
56
|
-
}
|
|
57
|
-
export declare const BUILD_TARGETS: readonly BuildTarget[];
|
|
58
|
-
/** Emit one target's build entry for one framework. */
|
|
59
|
-
export declare function renderBuildFile(target: BuildTarget, framework: FrameworkSpec): string;
|
|
60
|
-
//# sourceMappingURL=site-build.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"site-build.d.ts","sourceRoot":"","sources":["../../src/scaffold/site-build.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAgEpD;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;IAClC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAA;CAClC;AAED,MAAM,WAAW,WAAW;IAC1B,sCAAsC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;;;;;;OAQG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IAC3D,mEAAmE;IACnE,QAAQ,CAAC,gBAAgB,EAAE,oBAAoB,CAAA;IAC/C,wEAAwE;IACxE,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3C,kFAAkF;IAClF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,mEAAmE;IACnE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,+CAA+C;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,8CAA8C;IAC9C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EA2H/C,CAAA;AAeD,uDAAuD;AACvD,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,GAAG,MAAM,CAsBrF"}
|