@ubean/cli 0.4.2 → 0.4.4

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 (2) hide show
  1. package/dist/cli.js +52 -4
  2. package/package.json +13 -13
package/dist/cli.js CHANGED
@@ -19,7 +19,6 @@ import { createServer as createServer$1 } from "vite";
19
19
  import vue from "@vitejs/plugin-vue";
20
20
  import { ubeanPlugin } from "@ubean/build/vite";
21
21
  import { VUE_PLUGIN_INCLUDE, ubeanVite } from "@ubean/build/vue";
22
- import { createVueRenderer } from "@ubean/client/ssr";
23
22
  import { getVueLocaleParam, toVueRouterLocalePath } from "@ubean/i18n";
24
23
  import { ubeanIslandsPlugin } from "@ubean/islands/vite";
25
24
  import { findAvailablePort, findUserViteConfig, waitForPort } from "@ubean/shared/node";
@@ -501,6 +500,52 @@ function loadScaffoldOps() {
501
500
  recoverScaffold
502
501
  };
503
502
  }
503
+ /** Vite's browser-facing prefix for virtual module ids (see `wrapId`). */
504
+ const VALID_ID_PREFIX = "/@id/";
505
+ /** Vite's URL-safe encoding of the `\0` virtual-module marker. */
506
+ const NULL_BYTE_PLACEHOLDER = "__x00__";
507
+ /**
508
+ * Encode a module-graph URL into a browser-servable path.
509
+ *
510
+ * Virtual module ids carry a raw `\0` marker in the module graph (e.g.
511
+ * UnoCSS's `\0/__uno.css`). A literal NUL is invalid inside HTML — parse5
512
+ * rejects it with `unexpected-null-character`, which surfaces as a warning
513
+ * in `transformIndexHtml`. Mirror Vite's own import-analysis rewriting
514
+ * (`wrapId`: `/@id/` prefix + `\0` → `__x00__`) so the href stays valid
515
+ * and resolvable by the dev server.
516
+ */
517
+ function toDevCssHref(url) {
518
+ return url.includes("\0") ? `${VALID_ID_PREFIX}${url.replace(/\0/g, NULL_BYTE_PLACEHOLDER)}` : url;
519
+ }
520
+ /**
521
+ * Collect render-blocking CSS URLs from the Vite dev module graph.
522
+ *
523
+ * In dev, CSS imported from JS (virtual uno.css entry, global.css, font css)
524
+ * is only applied once the client entry module graph has fully loaded and
525
+ * executed — SSR HTML paints unstyled for that gap (FOUC). Injecting the same
526
+ * CSS modules as blocking `<link>` tags lets the browser fetch them in
527
+ * parallel with the JS graph, so the first paint is styled.
528
+ *
529
+ * `?direct` tells Vite's transform middleware to return raw CSS
530
+ * (`Content-Type: text/css`) instead of the JS style-injection wrapper.
531
+ * Modules whose URL already carries a query (SFC `<style>` blocks such as
532
+ * `*.vue?vue&type=style&...`) cannot be served this way and are skipped.
533
+ */
534
+ function collectDevCssLinks(moduleGraph) {
535
+ const links = /* @__PURE__ */ new Set();
536
+ for (const mod of moduleGraph.idToModuleMap.values()) {
537
+ const { url, id } = mod;
538
+ if (!url || url.includes("?")) continue;
539
+ if (id?.endsWith(".css") || url.endsWith(".css")) links.add(`${toDevCssHref(url)}?direct`);
540
+ }
541
+ return [...links];
542
+ }
543
+ /** Inject blocking stylesheet links right before `</head>`. */
544
+ function injectStylesheetLinks(html, hrefs) {
545
+ if (!hrefs.length || !html.includes("</head>")) return html;
546
+ const tags = hrefs.map((href) => `<link rel="stylesheet" href="${href}">`).join("");
547
+ return html.replace("</head>", `${tags}</head>`);
548
+ }
504
549
  async function createViteDevServer(options) {
505
550
  const { cwd, config, app: initialApp, layouts: initialLayouts = [] } = options;
506
551
  const host = options.host || "localhost";
@@ -573,8 +618,8 @@ async function createViteDevServer(options) {
573
618
  const contentType = webRes.headers.get("content-type") || "";
574
619
  const skipTransform = (req.url || "").startsWith("/_devtools");
575
620
  if (contentType.includes("text/html") && webRes.body && !skipTransform) {
576
- const html = await webRes.text();
577
- const transformedHtml = await viteServer.transformIndexHtml(req.url || "/", html);
621
+ const htmlWithCss = injectStylesheetLinks(await webRes.text(), collectDevCssLinks(viteServer.moduleGraph));
622
+ const transformedHtml = await viteServer.transformIndexHtml(req.url || "/", htmlWithCss);
578
623
  res.statusCode = webRes.status;
579
624
  res.statusMessage = webRes.statusText;
580
625
  webRes.headers.forEach((value, key) => {
@@ -629,6 +674,7 @@ async function createViteDevServer(options) {
629
674
  let viteDevtoolsPlugins = [];
630
675
  if (devtoolsEnabled) try {
631
676
  const { DevTools } = await import("@vitejs/devtools");
677
+ // @vitejs/devtools 也解析到含 @vitejs+devtools peer 上下文的 vite-plus-core
632
678
  viteDevtoolsPlugins = await DevTools({ builtinDevTools: false });
633
679
  } catch {}
634
680
  const userViteConfig = findUserViteConfig(cwd);
@@ -663,6 +709,7 @@ async function createViteDevServer(options) {
663
709
  viteServer = await createServer$1({
664
710
  root: cwd,
665
711
  configFile: userViteConfig ?? false,
712
+ resolve: { dedupe: ["vue", "vue-router"] },
666
713
  server: {
667
714
  middlewareMode: { server: httpServer },
668
715
  hmr: { port: actualPort + 1e3 }
@@ -686,10 +733,11 @@ async function createViteDevServer(options) {
686
733
  "#ubean-client-entry"
687
734
  ] },
688
735
  ssr: {
689
- noExternal: ["ubean"],
736
+ noExternal: ["ubean", /^@ubean\//],
690
737
  external: ["@ubean/i18n"]
691
738
  }
692
739
  });
740
+ const { createVueRenderer } = await viteServer.ssrLoadModule("@ubean/client/ssr");
693
741
  function enhanceAppWithVite(app, layouts = []) {
694
742
  app.options.layouts = layouts;
695
743
  const routeLoaders = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ubean/cli",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "CLI for ubean (ubean-next binary: dev, build, prepare, init, preview, page, env, config, devtools, api/layout/middleware/cron/plugin scaffolds) plus the Vite dev server runner",
5
5
  "bin": {
6
6
  "ubean-next": "./bin/ubean-next.mjs"
@@ -24,29 +24,29 @@
24
24
  }
25
25
  },
26
26
  "dependencies": {
27
- "@ubean/app": "0.4.2",
28
- "@ubean/build": "0.4.2",
29
- "@ubean/client": "0.4.2",
30
- "@ubean/config": "0.4.2",
31
- "@ubean/i18n": "0.4.2",
32
- "@ubean/islands": "0.4.2",
33
- "@ubean/preset": "0.4.2",
34
- "@ubean/scan": "0.4.2",
35
- "@ubean/shared": "0.4.2",
27
+ "@ubean/app": "0.4.4",
28
+ "@ubean/build": "0.4.4",
29
+ "@ubean/client": "0.4.4",
30
+ "@ubean/config": "0.4.4",
31
+ "@ubean/i18n": "0.4.4",
32
+ "@ubean/islands": "0.4.4",
33
+ "@ubean/preset": "0.4.4",
34
+ "@ubean/scan": "0.4.4",
35
+ "@ubean/shared": "0.4.4",
36
36
  "citty": "^0.2.2",
37
37
  "kolorist": "^1.8.0",
38
38
  "pathe": "^2.0.3"
39
39
  },
40
40
  "devDependencies": {
41
- "@types/node": "^26.4.1",
41
+ "@types/node": "^26.5.0",
42
42
  "@vitejs/plugin-vue": "^6.0.8",
43
43
  "typescript": "7.0.2",
44
44
  "vite": "npm:@voidzero-dev/vite-plus-core@0.3.0",
45
45
  "vite-plus": "0.3.0"
46
46
  },
47
47
  "peerDependencies": {
48
- "@ubean/content": "0.4.2",
49
- "@ubean/devtools": "0.4.2",
48
+ "@ubean/content": "0.4.4",
49
+ "@ubean/devtools": "0.4.4",
50
50
  "@vitejs/plugin-vue": "^6.0.8",
51
51
  "vite": "npm:@voidzero-dev/vite-plus-core@0.3.0"
52
52
  },