@uniflowed/vite 0.0.0-alpha.17 → 0.0.0-alpha.18

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.
Files changed (3) hide show
  1. package/driver.js +56 -0
  2. package/index.js +17 -7
  3. package/package.json +3 -3
package/driver.js CHANGED
@@ -980,6 +980,26 @@ const ADAPTERS = {
980
980
  server: nodeEntrySource("./handler.js"),
981
981
  }),
982
982
  },
983
+ // The same two files as `node`, with `@uniflowed/server/bun` in place of
984
+ // `@uniflowed/server/node`. That module is `./internal/static.js` for every
985
+ // decision and `Bun.file` for the bytes, which is where the measured win is
986
+ // — see ubugeeei-prod/uf#391 and the header of `packages/server/bun.js`.
987
+ //
988
+ // No `conditions` of its own, unlike `edge`. Bun honours a `bun` export
989
+ // condition and this deliberately does not ask for it: the measured win is
990
+ // `Bun.serve` and `Bun.file` and not resolution, so asking would trade a
991
+ // `handler.js` that is byte-for-byte `node`'s — which is what
992
+ // `every_adapter_answers_exactly_what_the_node_adapter_answers` checks, and
993
+ // what makes an adapter one file rather than one application — for whichever
994
+ // build a dependency happens to ship behind that condition, tested by
995
+ // nobody here. `edge` pays that price because it must: there is no
996
+ // `node:stream` in a Worker.
997
+ bun: {
998
+ entries: (document, cache) => ({
999
+ handler: handlerEntrySource(document, cache, BUN_CAPABILITIES),
1000
+ server: bunEntrySource("./handler.js"),
1001
+ }),
1002
+ },
983
1003
  // The same two files. What `--adapter container` adds is a `Dockerfile` and
984
1004
  // a `.dockerignore`, and both are plain text that `uf` writes beside this
985
1005
  // output rather than anything the bundler produces — see `uf_cli`'s
@@ -1027,6 +1047,7 @@ const ADAPTERS = {
1027
1047
  * dropped.
1028
1048
  */
1029
1049
  const NODE_CAPABILITIES = { module: "@uniflowed/server/node", name: "nodeCapabilities" };
1050
+ const BUN_CAPABILITIES = { module: "@uniflowed/server/bun", name: "bunCapabilities" };
1030
1051
  const EDGE_CAPABILITIES = { module: "@uniflowed/server/edge", name: "edgeCapabilities" };
1031
1052
  const SERVERLESS_CAPABILITIES = { module: "@uniflowed/server/lambda", name: "lambdaCapabilities" };
1032
1053
 
@@ -1296,6 +1317,41 @@ serve({ handle: fetch, staticDir, beginRequest }).catch((error) => {
1296
1317
  `;
1297
1318
  }
1298
1319
 
1320
+ /**
1321
+ * The source of `server.js`: the Bun socket around that handler.
1322
+ *
1323
+ * `nodeEntrySource`'s twin, and identical but for the module it imports
1324
+ * `serve` from — `@uniflowed/server/bun` exports the same signature on
1325
+ * purpose, so that the two adapters are one contract and a project moving
1326
+ * between them changes a flag and nothing else.
1327
+ */
1328
+ function bunEntrySource(handlerSpecifier) {
1329
+ return `// Generated by \`uf build --adapter bun\`. Not checked in, not edited.
1330
+ import path from "node:path";
1331
+ import { fileURLToPath } from "node:url";
1332
+
1333
+ import { serve } from "@uniflowed/server/bun";
1334
+
1335
+ // \`beginRequest\` comes from the handler beside this file rather than from
1336
+ // \`@uniflowed/server/bun\` above, because the request has to be established in
1337
+ // the storage the *application* reads, which is the copy bundled into
1338
+ // \`handler.js\`. See ubugeeei-prod/uf#389.
1339
+ import { beginRequest, fetch } from ${JSON.stringify(handlerSpecifier)};
1340
+
1341
+ // Resolved from this file and not from the working directory: a process
1342
+ // manager, a container entrypoint and a person in a shell each start a server
1343
+ // from wherever they happen to be, and a directory that only served its own
1344
+ // assets when it was started from inside itself would be a deployment with a
1345
+ // trap in it.
1346
+ const staticDir = path.join(path.dirname(fileURLToPath(import.meta.url)), "static");
1347
+
1348
+ serve({ handle: fetch, staticDir, beginRequest }).catch((error) => {
1349
+ process.stderr.write(\`uf: \${error?.message ?? String(error)}\\n\`);
1350
+ process.exit(1);
1351
+ });
1352
+ `;
1353
+ }
1354
+
1299
1355
  /**
1300
1356
  * The source of `worker.js`: the Cloudflare Workers entry around that handler.
1301
1357
  *
package/index.js CHANGED
@@ -696,15 +696,25 @@ function flowPlugin({ routerRoot, appEntry, strictMode, command, accessibility }
696
696
  // result by then — so the terminal hears about it here or not
697
697
  // at all.
698
698
  onError: (error) => reportRenderError(devServer, url, error),
699
+ // Vite sees the head and only the head. That is what lets the
700
+ // development server stream like every other host — see below.
701
+ transformHead: (head) => devServer.transformIndexHtml(url, head),
699
702
  },
700
703
  );
701
704
  if (result.error != null) reportRenderError(devServer, url, result.error);
702
- // Collected rather than piped: `transformIndexHtml` is a
703
- // whole-document hook, so there is no first byte to send until it
704
- // has run. `uf start` and `uf preview` stream — see
705
- // `internal/serve.js` — and that is a property of the development
706
- // server rather than of the renderer. ubugeeei-prod/uf#374.
707
- const html = await devServer.transformIndexHtml(url, await result.text());
705
+ // Piped, like every other host. This used to collect the whole
706
+ // document and transform it at the end, because
707
+ // `transformIndexHtml` is a *whole document* hook — which made the
708
+ // one place a developer would notice streaming the one place it
709
+ // did not happen: a slow page showed nothing until it was finished
710
+ // and `_uf.loading.js` looked broken.
711
+ //
712
+ // `transformHead` above is the seam. `internal/stream.js` already
713
+ // held the opening chunk back until the head was complete and
714
+ // forwarded everything after it untouched, so the hook only ever
715
+ // sees the head — and Vite's dev hook handles a document that ends
716
+ // mid-`<body>` without complaint, which was the open question on
717
+ // ubugeeei-prod/uf#374.
708
718
  response.statusCode = result.status ?? 200;
709
719
  // The render's own headers, then the content type over the top:
710
720
  // exactly the order `@uniflowed/server`'s `fetch.js` writes them
@@ -714,7 +724,7 @@ function flowPlugin({ routerRoot, appEntry, strictMode, command, accessibility }
714
724
  response.setHeader(name, value);
715
725
  }
716
726
  response.setHeader("content-type", "text/html; charset=utf-8");
717
- response.end(html);
727
+ await result.pipe(response);
718
728
  return true;
719
729
  });
720
730
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uniflowed/vite",
3
- "version": "0.0.0-alpha.17",
3
+ "version": "0.0.0-alpha.18",
4
4
  "description": "Vite, driven by uf.config.js: every Flow module through `uf transform`, MDX, the file-system router and static rendering as Vite plugins.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -33,8 +33,8 @@
33
33
  "dependencies": {
34
34
  "@mdx-js/rollup": "^3.1.1",
35
35
  "@shikijs/rehype": "^3.23.0",
36
- "@uniflowed/host": "0.0.0-alpha.17",
37
- "@uniflowed/server": "0.0.0-alpha.17",
36
+ "@uniflowed/host": "0.0.0-alpha.18",
37
+ "@uniflowed/server": "0.0.0-alpha.18",
38
38
  "rehype-slug": "^6.0.0",
39
39
  "remark-frontmatter": "^5.0.0",
40
40
  "remark-gfm": "^4.0.1",