@waniwani/kit 0.1.4 → 0.1.5
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 +48 -0
- package/cli/codegen.mjs +58 -1
- package/cli/index.mjs +6 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -529,6 +529,54 @@ flowchart LR
|
|
|
529
529
|
project carrying a `vercel.json`, which is what lets `vercel deploy` inside it
|
|
530
530
|
work with no special support.
|
|
531
531
|
|
|
532
|
+
### Deploying is a git push
|
|
533
|
+
|
|
534
|
+
`waniwani build` writes a Vercel Build Output tree inside `.waniwani/`: the
|
|
535
|
+
bundled function, the static assets, the routing config. A git-connected project
|
|
536
|
+
builds that tree itself on push, and the first build writes the config it needs
|
|
537
|
+
into the app repo:
|
|
538
|
+
|
|
539
|
+
```json
|
|
540
|
+
// vercel.json, generated once, yours to edit afterwards
|
|
541
|
+
{
|
|
542
|
+
"framework": null,
|
|
543
|
+
"buildCommand": "waniwani build && rm -rf .vercel/output && cp -R .waniwani/.vercel/output .vercel/output",
|
|
544
|
+
"routes": [{ "src": "/api(/.*)?", "dest": "/mcp" }]
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Each line answers something Vercel would otherwise get wrong.
|
|
549
|
+
|
|
550
|
+
`framework: null` stops the project's preset from hunting for a dependency the
|
|
551
|
+
repo does not have, which is what produces `No Next.js version detected` on a
|
|
552
|
+
repo holding no framework at all.
|
|
553
|
+
|
|
554
|
+
The `buildCommand` moves the tree from `.waniwani/`, which is gitignored and
|
|
555
|
+
absent from the clone, up to the one path where Vercel adopts the Build Output
|
|
556
|
+
API and serves the function as built.
|
|
557
|
+
|
|
558
|
+
The `routes` entry exists because Vercel reserves a root `api/` directory: it
|
|
559
|
+
compiles every file under one into a serverless function of its own, and an
|
|
560
|
+
endpoint module is not a Vercel handler. That entry is emitted ahead of Vercel's
|
|
561
|
+
filesystem layer, so `/api/*` reaches the server the kit built and the functions
|
|
562
|
+
Vercel made are never routed to. Deleting the directory during the build is not
|
|
563
|
+
an alternative, since the file list is read before the build command runs:
|
|
564
|
+
|
|
565
|
+
```
|
|
566
|
+
Error: File not found: /vercel/path0/api/cal/book.ts
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
Deploying without a build works too, once `build` has run:
|
|
570
|
+
|
|
571
|
+
```bash
|
|
572
|
+
cd .waniwani && vercel deploy --prebuilt
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
Environment variables live on the platform for both, since `.env` is read from
|
|
576
|
+
disk and a hosted build has no such file. A project that sets its variables for
|
|
577
|
+
production alone gets previews with none, which for an app whose flow reads
|
|
578
|
+
`WANIWANI_API_KEY` at import time means a function that fails to boot.
|
|
579
|
+
|
|
532
580
|
### Secrets live in the app's .env
|
|
533
581
|
|
|
534
582
|
`.env` and `.env.local` sit next to `waniwani.config.ts`, and every command reads
|
package/cli/codegen.mjs
CHANGED
|
@@ -875,6 +875,51 @@ function readProvenance(root) {
|
|
|
875
875
|
}
|
|
876
876
|
}
|
|
877
877
|
|
|
878
|
+
/**
|
|
879
|
+
* What a git-connected Vercel project needs at the app root, written there when
|
|
880
|
+
* the app has none.
|
|
881
|
+
*
|
|
882
|
+
* The build output lands in `.waniwani/`, which is gitignored and absent from
|
|
883
|
+
* the clone, so a hosted build has to run the kit itself and move the tree to
|
|
884
|
+
* the one path where Vercel adopts the Build Output API. Every line here is
|
|
885
|
+
* about this kit's own layout, which is why the file is generated rather than
|
|
886
|
+
* taken from the template: the template knows nothing about `waniwani build` or
|
|
887
|
+
* `.waniwani/`.
|
|
888
|
+
*
|
|
889
|
+
* The `routes` entry is the part that is not obvious. Vercel reserves a root
|
|
890
|
+
* `api/` directory and compiles every file under it into a serverless function
|
|
891
|
+
* of its own, which for an app folder means one broken function per endpoint
|
|
892
|
+
* (`defineEndpoint({ ... })` is an object, not a Vercel handler) sitting in the
|
|
893
|
+
* filesystem layer ahead of the server that actually serves them. A legacy
|
|
894
|
+
* `routes` entry is emitted before that layer, so `/api/*` reaches the kit's
|
|
895
|
+
* function and Vercel's own are never routed to. There is no way to stop it
|
|
896
|
+
* building them: it reads the file list before the build command runs, so a
|
|
897
|
+
* build that deletes the directory fails with `File not found`, and
|
|
898
|
+
* `outputDirectory` does not suppress it either.
|
|
899
|
+
*/
|
|
900
|
+
const VERCEL_JSON = {
|
|
901
|
+
$schema: "https://openapi.vercel.sh/vercel.json",
|
|
902
|
+
// Otherwise the project's framework preset decides, and a preset looking for a
|
|
903
|
+
// dependency an app folder does not have fails the build outright.
|
|
904
|
+
framework: null,
|
|
905
|
+
buildCommand:
|
|
906
|
+
"waniwani build && rm -rf .vercel/output && cp -R .waniwani/.vercel/output .vercel/output",
|
|
907
|
+
// Ahead of Vercel's filesystem layer, which is where its own api/ functions sit.
|
|
908
|
+
routes: [{ src: "/api(/.*)?", dest: "/mcp" }],
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* @returns true when the file was written, for the CLI to report
|
|
913
|
+
*/
|
|
914
|
+
function ensureVercelJson(appRoot) {
|
|
915
|
+
const file = join(appRoot, "vercel.json");
|
|
916
|
+
// An app that has edited its own deploy config keeps it. Overwriting would
|
|
917
|
+
// throw away a `maxDuration`, a region, or a cron someone needed.
|
|
918
|
+
if (existsSync(file)) return false;
|
|
919
|
+
writeFileSync(file, `${JSON.stringify(VERCEL_JSON, null, 2)}\n`);
|
|
920
|
+
return true;
|
|
921
|
+
}
|
|
922
|
+
|
|
878
923
|
/** Keep `.waniwani/` out of the app repo, the way `.next/` is kept out. */
|
|
879
924
|
function ignoreBuildOutput(appRoot) {
|
|
880
925
|
const file = join(appRoot, ".gitignore");
|
|
@@ -1055,11 +1100,23 @@ export function generate(app, { template, layout: layoutName = "build", outDir }
|
|
|
1055
1100
|
)}\n`,
|
|
1056
1101
|
);
|
|
1057
1102
|
|
|
1103
|
+
let vercelJson = false;
|
|
1058
1104
|
if (layoutName === "build") {
|
|
1059
1105
|
// A .gitignore inside the output would stop `vercel deploy` uploading
|
|
1060
1106
|
// anything, so the ignore goes in the app repo instead.
|
|
1061
1107
|
ignoreBuildOutput(app.root);
|
|
1108
|
+
// Same reasoning for the deploy config: what Vercel reads on a git build is
|
|
1109
|
+
// the app repo's root, not the output directory.
|
|
1110
|
+
vercelJson = ensureVercelJson(app.root);
|
|
1062
1111
|
}
|
|
1063
1112
|
|
|
1064
|
-
return {
|
|
1113
|
+
return {
|
|
1114
|
+
outDir: root,
|
|
1115
|
+
written,
|
|
1116
|
+
overrides,
|
|
1117
|
+
fromTemplate,
|
|
1118
|
+
moved,
|
|
1119
|
+
vercelJson,
|
|
1120
|
+
manifest: Boolean(manifest),
|
|
1121
|
+
};
|
|
1065
1122
|
}
|
package/cli/index.mjs
CHANGED
|
@@ -143,7 +143,12 @@ async function prepare(appRoot, flags, { quiet = false } = {}) {
|
|
|
143
143
|
console.log(`${yellow("!")} ${dim("GitHub unreachable — using the cached template")}`);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
const { outDir, overrides, fromTemplate, manifest } = generate(app, { template });
|
|
146
|
+
const { outDir, overrides, fromTemplate, manifest, vercelJson } = generate(app, { template });
|
|
147
|
+
// Written into the app's own repo rather than the output, so it is worth a
|
|
148
|
+
// line even outside debug: it is a tracked file that appeared.
|
|
149
|
+
if (!quiet && vercelJson) {
|
|
150
|
+
console.log(`${green("+")} ${bold("vercel.json")} ${dim("— deploy config for a git-connected project")}`);
|
|
151
|
+
}
|
|
147
152
|
if (!quiet && DEBUG) {
|
|
148
153
|
console.log(
|
|
149
154
|
`${dim(`${fromTemplate.length} files copied`)} ${dim(
|