@morlay/dsh-client-modules 0.2.11-alpha.2 → 0.2.11

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/dist/index.cjs CHANGED
@@ -8,6 +8,8 @@ let node_crypto = require("node:crypto");
8
8
  let _morlay_dsh_cordis_assets_styles = require("@morlay/dsh-cordis-assets/styles");
9
9
  let rolldown = require("rolldown");
10
10
  let vite = require("vite");
11
+ let node_child_process = require("node:child_process");
12
+ let node_util = require("node:util");
11
13
  // src/trace.ts
12
14
  /**
13
15
  * 诊断细节(逐包预编译、逐请求那一类)的具名 logger。
@@ -86,6 +88,122 @@ async function devExcluded(profileDir) {
86
88
  function isAggregated(name, patterns) {
87
89
  return patterns.some((pattern) => pattern.test(name));
88
90
  }
91
+ // src/client-meta.ts
92
+ /**
93
+ * 浏览器构建里烘焙的版本元数据。
94
+ *
95
+ * 上游的 client 构建(`scripts/client-build-environment.ts`)把一组 `DSH_CLIENT_*` 值当 `define` 注入产物:
96
+ * - `DSH_CLIENT_VERSION`:设置页「当前版本」那一行;
97
+ * - `DSH_CLIENT_COMMIT_HASH` + `DSH_CLIENT_GIT_DIRTY`:侧栏显示的 `<commit>` / `<commit>-dirty`;
98
+ * - `DSH_CLIENT_BUILD_PROFILE`:`official` / `local`(官方品牌只在 official 下出现)。
99
+ *
100
+ * 这条链以前把 `process.env` 整个替换成 `{ env: {} }`,于是这些值全是 `undefined`:版本行不显示、
101
+ * `ui-settings-account` 还会因为 `DSH_CLIENT_VERSION` 缺失直接抛错。取值顺序(越靠前越权威):
102
+ *
103
+ * 1. 宿主进程的 `DSH_CLIENT_*`(`dshdev` 与桌面壳在起宿主时注入);
104
+ * 2. 仓库根的 `.dsh-build/client-build-environment.json`(`just prepare` 里的 `dshdev client-meta` 写);
105
+ * 3. 现算:仓库根的 `package.json` 版本 + `git rev-parse` / `git status`(dev 常见,代价是几次 git 调用)。
106
+ */
107
+ /** `prepare` 写、构建读的那份记录(形状与上游 `client-build-environment.json` 一致)。 */
108
+ const CLIENT_BUILD_RECORD = (0, node_path.join)(".dsh-build", "client-build-environment.json");
109
+ const VERSION = "DSH_CLIENT_VERSION";
110
+ const COMMIT = "DSH_CLIENT_COMMIT_HASH";
111
+ const DIRTY = "DSH_CLIENT_GIT_DIRTY";
112
+ const PROFILE = "DSH_CLIENT_BUILD_PROFILE";
113
+ /** 环境里那组 `DSH_CLIENT_*` → 元数据。 */
114
+ function metaOfEnvironment(environment) {
115
+ const version = environment[VERSION];
116
+ const commit = environment[COMMIT];
117
+ const dirty = environment[DIRTY];
118
+ const profile = environment[PROFILE];
119
+ return {
120
+ ...version === void 0 || version === "" ? {} : { version },
121
+ ...commit === void 0 || commit === "" ? {} : { commit },
122
+ ...dirty === "true" ? { dirty: true } : {},
123
+ ...profile === void 0 || profile === "" ? {} : { profile }
124
+ };
125
+ }
126
+ const runFile = (0, node_util.promisify)(node_child_process.execFile);
127
+ /** `git` 的输出;不在 git 工作树里、或 git 不可用时 undefined。 */
128
+ async function gitOutput(root, args) {
129
+ try {
130
+ const { stdout } = await runFile("git", args, {
131
+ cwd: root,
132
+ encoding: "utf8"
133
+ });
134
+ return stdout.trim();
135
+ } catch {
136
+ return;
137
+ }
138
+ }
139
+ /**
140
+ * 现算:**装的是哪一版 harness**(`DEEPSEEK_HARNESS_VERSION`,与同步链同一个真源)+ 本仓库的 git 元数据。
141
+ *
142
+ * 正常路径拿不到这里:`dshdev` 会注入环境、`prepare` 会写记录。只有"绕过 dshdev 直接构建 client 产物"
143
+ * 时才走到,所以版本只能取环境或仓库根的 `package.json`(后者不是权威值,缺 env 时用它兜底)。
144
+ */
145
+ async function computeMeta(repoRoot) {
146
+ const explicit = process.env["DEEPSEEK_HARNESS_VERSION"];
147
+ let version = explicit === void 0 || explicit === "" ? void 0 : explicit;
148
+ if (version === void 0) {
149
+ const manifest = await (0, node_fs_promises.readFile)((0, node_path.join)(repoRoot, "package.json"), "utf8").catch(() => void 0);
150
+ if (manifest !== void 0) {
151
+ const parsed = JSON.parse(manifest);
152
+ if (typeof parsed.version === "string" && parsed.version !== "") version = parsed.version;
153
+ }
154
+ }
155
+ const commit = await gitOutput(repoRoot, [
156
+ "rev-parse",
157
+ "--short=7",
158
+ "HEAD"
159
+ ]);
160
+ const status = await gitOutput(repoRoot, [
161
+ "status",
162
+ "--porcelain",
163
+ "--untracked-files=normal"
164
+ ]);
165
+ return {
166
+ ...version === void 0 ? {} : { version },
167
+ ...commit === void 0 ? {} : { commit },
168
+ ...status === void 0 || status === "" ? {} : { dirty: true }
169
+ };
170
+ }
171
+ /** 读 `prepare` 写下的那份记录(缺失 / 坏掉都给 undefined,不挡构建)。 */
172
+ async function recordedMeta(repoRoot) {
173
+ const raw = await (0, node_fs_promises.readFile)((0, node_path.join)(repoRoot, CLIENT_BUILD_RECORD), "utf8").catch(() => void 0);
174
+ if (raw === void 0) return void 0;
175
+ try {
176
+ return metaOfEnvironment(JSON.parse(raw).environment ?? {});
177
+ } catch {
178
+ return;
179
+ }
180
+ }
181
+ /**
182
+ * 这个仓库在浏览器产物里该带的版本元数据。
183
+ * @param repoRoot - 仓库根(dev 是工作区,打包形态是 profile:那里通常读不到记录,靠宿主注入的环境)。
184
+ */
185
+ async function clientBuildMeta(repoRoot) {
186
+ const inherited = metaOfEnvironment(process.env);
187
+ if (inherited.version !== void 0 && inherited.commit !== void 0) return inherited;
188
+ return {
189
+ ...await recordedMeta(repoRoot) ?? await computeMeta(repoRoot),
190
+ ...inherited
191
+ };
192
+ }
193
+ /**
194
+ * `define` 用的一组键:`process.env.DSH_CLIENT_*` → 字面量。
195
+ *
196
+ * `browserProcessPlugin` 会跳过这些键(见那里的负向前瞻),所以 define 这一层能把它们换成真实值;
197
+ * 其余 `process.env` 仍是空壳对象。
198
+ */
199
+ function clientMetaDefines(meta) {
200
+ return {
201
+ [`process.env.${VERSION}`]: meta.version === void 0 ? "undefined" : JSON.stringify(meta.version),
202
+ [`process.env.${COMMIT}`]: meta.commit === void 0 ? "undefined" : JSON.stringify(meta.commit),
203
+ [`process.env.${DIRTY}`]: meta.dirty === true ? JSON.stringify("true") : "undefined",
204
+ [`process.env.${PROFILE}`]: meta.profile === void 0 ? "undefined" : JSON.stringify(meta.profile)
205
+ };
206
+ }
89
207
  // src/resolve.ts
90
208
  /** 路由前缀(沿用上游的 `/plugins`,页面上不改 URL 形态)。 */
91
209
  const PLUGIN_ROUTE = "/plugins";
@@ -386,7 +504,7 @@ function clientModulesAlias(options) {
386
504
  * 实例)。内容变了**不换 URL**,靠 `cache-control: no-cache` + `ETag` 协商(vite dev 对它自己的模块
387
505
  * 也是这套)。
388
506
  */
389
- const BUNDLER_REV = (0, node_crypto.createHash)("sha1").update(`client-modules:rules:22`).digest("hex").slice(0, 8);
507
+ const BUNDLER_REV = (0, node_crypto.createHash)("sha1").update(`client-modules:rules:36`).digest("hex").slice(0, 8);
390
508
  /** 包 → 它在浏览器里的地址(联邦式)。 */
391
509
  function depsUrlOf(specifier, version, file = "index.js") {
392
510
  const name = packageNameOf(specifier) || specifier;
@@ -513,8 +631,13 @@ function urlOf(specifier, tables) {
513
631
  * **只替换 `process.env` 系列**:裸的 `process` 不能碰——它可能只是个普通标识符(`zod` 里就有一个叫
514
632
  * `process` 的函数,替换掉直接把源码变成语法错误)。
515
633
  */
516
- function browserProcessPlugin() {
517
- const replace = (code) => code.replaceAll(/\bprocess\.env\.NODE_ENV\b/gu, JSON.stringify("development")).replaceAll(/\bprocess\.env\b/gu, "({ env: {} })");
634
+ function browserProcessPlugin(meta = {}) {
635
+ const metaDefines = Object.entries(clientMetaDefines(meta));
636
+ const replace = (code) => {
637
+ let next = code.replaceAll(/\bprocess\.env\.NODE_ENV\b/gu, JSON.stringify("development"));
638
+ for (const [key, value] of metaDefines) next = next.replaceAll(key, value);
639
+ return next.replaceAll(/\bprocess\.env\b/gu, "({ env: {} })");
640
+ };
518
641
  return {
519
642
  name: "dsh-browser-process",
520
643
  enforce: "pre",
@@ -528,52 +651,205 @@ function browserProcessPlugin() {
528
651
  };
529
652
  }
530
653
  /**
531
- * CJS 入口的**具名导出包装**(`react` 这类)。
654
+ * `export const <名>` 用不了的键:JS 的保留字(`zod@4` 的 CJS 面有 `function` / `void` / `null`
655
+ * 这些键,原样拼出去就是 `SyntaxError`)。
656
+ */
657
+ const RESERVED_EXPORT_NAMES = /* @__PURE__ */ new Set([
658
+ "await",
659
+ "break",
660
+ "case",
661
+ "catch",
662
+ "class",
663
+ "const",
664
+ "continue",
665
+ "debugger",
666
+ "default",
667
+ "delete",
668
+ "do",
669
+ "else",
670
+ "enum",
671
+ "eval",
672
+ "export",
673
+ "extends",
674
+ "false",
675
+ "finally",
676
+ "for",
677
+ "function",
678
+ "if",
679
+ "implements",
680
+ "import",
681
+ "in",
682
+ "instanceof",
683
+ "interface",
684
+ "let",
685
+ "new",
686
+ "null",
687
+ "package",
688
+ "private",
689
+ "protected",
690
+ "public",
691
+ "return",
692
+ "static",
693
+ "super",
694
+ "switch",
695
+ "this",
696
+ "throw",
697
+ "true",
698
+ "try",
699
+ "typeof",
700
+ "undefined",
701
+ "var",
702
+ "void",
703
+ "while",
704
+ "with",
705
+ "yield"
706
+ ]);
707
+ /** ESM 的顶层语法节点:`import` / `export` 声明。 */
708
+ const ESM_STATEMENT_TYPES = /* @__PURE__ */ new Set([
709
+ "ImportDeclaration",
710
+ "ExportNamedDeclaration",
711
+ "ExportDefaultDeclaration",
712
+ "ExportAllDeclaration"
713
+ ]);
714
+ /**
715
+ * `.js` 且没有 `type` 时,按 **Node 的语法检测**判:有 ESM 语法(顶层 `import`/`export`)就是 ESM,
716
+ * 否则 CJS(Node 23+ 默认开启 `--experimental-detect-module`)。
717
+ *
718
+ * 用 rolldown 自带的解析器(`rolldown/parseAst`),不自己写词法扫描。
719
+ *
720
+ * @param entry - `.js` 入口的绝对路径。
721
+ * @returns 是否含 ESM 语法。
722
+ */
723
+ async function hasModuleSyntax(entry) {
724
+ try {
725
+ const [{ parseAst }, source] = await Promise.all([import("rolldown/parseAst"), (0, node_fs_promises.readFile)(entry, "utf8")]);
726
+ return parseAst(source, null, entry).body.some((node) => ESM_STATEMENT_TYPES.has(node.type));
727
+ } catch {
728
+ return false;
729
+ }
730
+ }
731
+ /**
732
+ * 一个入口的模块类型:**扩展名 + 最近的 `package.json`**,不猜源码。
733
+ *
734
+ * | 入口 | 类型 |
735
+ * | --- | --- |
736
+ * | `.mjs` / `.mts` | `esm` |
737
+ * | `.cjs` / `.cts` | `cjs` |
738
+ * | `.js` + `type: "module"` | `esm` |
739
+ * | `.js` + `module` 字段指向它 | `esm`(打包器约定) |
740
+ * | 其余 `.js` | `cjs` |
741
+ * | `.ts` / `.tsx` / `.jsx` | `source`(转译面,原样) |
742
+ * | `.css` | `style` |
743
+ * | 其他(图片 / 字体 / `.json` …) | `asset` |
744
+ *
745
+ * 这是 `exports` 条件(`import` / `require`)选出入口之后的**第二步**:条件决定"哪个文件",这里决定
746
+ * "那个文件是什么模块"。只有 `cjs` 需要导出面适配,`esm` / `source` 一律原样。
747
+ *
748
+ * @param entry - 入口的绝对路径。
749
+ * @returns 模块类型。
750
+ */
751
+ async function moduleKindOf(entry) {
752
+ const extension = (0, node_path.extname)(entry).toLowerCase();
753
+ if (extension === ".css") return "style";
754
+ if (extension === ".mjs" || extension === ".mts") return "esm";
755
+ if (extension === ".cjs" || extension === ".cts") return "cjs";
756
+ if (extension === ".ts" || extension === ".tsx" || extension === ".jsx") return "source";
757
+ if (extension !== ".js") return "asset";
758
+ const manifestPath = await packageJsonNear(entry);
759
+ const manifest = JSON.parse(await (0, node_fs_promises.readFile)(manifestPath, "utf8").catch(() => "{}"));
760
+ if (manifest.type === "module") return "esm";
761
+ if (manifest.type === "commonjs") return "cjs";
762
+ return await hasModuleSyntax(entry) ? "esm" : "cjs";
763
+ }
764
+ /**
765
+ * CJS 入口的**具名导出包装**(`react` / `@xterm/xterm` 这类)。
766
+ *
767
+ * rolldown 对 CJS 入口的产物的具名导出只能靠静态分析;`module.exports = require(…)` 与 UMD 包装它都分析
768
+ * 不出来,产物只剩 `export default …`——而浏览器侧要 `import { Fragment } from "react"`、`import { Terminal }
769
+ * from "@xterm/xterm"`,整个 import 阶段就失败。ESM 的导出必须**静态可枚举**,所以这里求值入口拿到它的键,
770
+ * 生成一份把它们写成 `export const` 的包装文件,拿包装文件当入口。
532
771
  *
533
- * `react` 的入口是 `module.exports = require('./cjs/react.development.js')`,rolldown 静态分析不出具名
534
- * 导出,产物只剩 `export default …`——而浏览器侧要 `import { Fragment } from "react"`,于是**整个 import
535
- * 阶段就失败**(入口一行都执行不了)。ESM 的导出必须**静态可枚举**(不能 `export * from` 一个运行期对象),
536
- * 所以这里求值入口拿到它的键,生成一份把它们写成 `export const` 的包装文件,拿包装文件当入口。
772
+ * 类型由 {@link moduleKindOf} 先按 **exports 落点 + 扩展名/type** 静态判定,只有 CJS 才进来;
773
+ * 这里求值一次只为**拿键**(`export const <键>` + `default = module.exports`)。ESM 原封不动。
537
774
  *
538
- * @returns 包装文件路径;入口不是 CJS、或求值拿不到键时 undefined(保持原样)。
775
+ * @returns 包装文件路径;入口不是 node 能求值的 CJS、或没有可静态导出的键时 undefined(保持原样)。
539
776
  */
540
777
  async function cjsShimOf(options) {
541
- const source = await (0, node_fs_promises.readFile)(options.entry, "utf8").catch(() => "");
542
- if (!(/\.(?:cjs|js)$/u.test(options.entry) && /(?:^|\n)\s*(?:module\.exports\s*=|exports\.[A-Za-z_$][A-Za-z0-9_$]*\s*=)/u.test(source))) return void 0;
543
- let keys;
778
+ let loaded;
544
779
  try {
545
- const loaded = (0, node_module.createRequire)(options.entry)(options.entry);
546
- keys = Object.keys(loaded ?? {});
780
+ loaded = (0, node_module.createRequire)(options.entry)(options.entry);
547
781
  } catch {
548
782
  return;
549
783
  }
550
- const named = keys.filter((key) => key !== "default" && /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(key));
784
+ const named = Object.keys(loaded ?? {}).filter((key) => key !== "default" && /^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(key) && !RESERVED_EXPORT_NAMES.has(key));
551
785
  if (named.length === 0) return void 0;
552
- const file = (0, node_path.join)(options.outDir, `${options.exportName.replaceAll("/", "+")}.cjs-shim.mjs`);
553
- await (0, node_fs_promises.mkdir)((0, node_path.dirname)(file), { recursive: true });
554
- await (0, node_fs_promises.writeFile)(file, [
555
- `import mod from ${JSON.stringify(options.entry)};`,
786
+ const id = `\0dsh-cjs-shim:${options.name}:${options.exportName}`;
787
+ const code = [
788
+ `import mod from ${JSON.stringify(options.from)};`,
556
789
  "const __cjs = mod ?? {};",
557
790
  "export default __cjs;",
558
791
  ...named.map((key) => `export const ${key} = __cjs[${JSON.stringify(key)}];`),
559
792
  ""
560
- ].join("\n"), "utf8");
793
+ ].join("\n");
561
794
  options.log?.(`[bundle-cjs] ${options.name}/${options.exportName}: 补 ${String(named.length)} 个具名导出\n`);
562
- return file;
795
+ return {
796
+ id,
797
+ code
798
+ };
563
799
  }
564
800
  /**
565
- * CSS 入口的包装:**样式文件不能直接当入口**——vite 的库模式固定 `cssCodeSplit: false`,遇到
566
- * `rolldownOptions.input` 里有 `.css` 直接报错。包一层 side-effect import,让样式插件按它一贯的方式
567
- * 把它编成"注入 `<style>`"的模块。
801
+ * CSS 出口的产物:**就是 CSS 文本**(不包装成 JS、不注入 `<style>`)。
568
802
  *
569
- * @returns 包装文件路径;入口不是 CSS 时 undefined。
803
+ * JS 里的 `import "x.css"` 是另一条路(`cssInlinePlugins` 在构建期内联成注入样式的模块),与本函数无关。
804
+ * 这里的 `url()` 指向包内资产:读到字节、按内容 hash 落到 `assets/`、改写成联邦地址——否则浏览器会按
805
+ * CSS 的相对路径去请求 `.pnpm` 里的文件,路由按清单服务就是 404。
806
+ *
807
+ * `lightningcss` 的 visitor 是同步回调,所以分两遍:第一遍只收集相对 `url()`,异步读资产/算 hash;
808
+ * 第二遍按映射改写(全程异步 IO)。
809
+ *
810
+ * @param options - 入口文件、出口名、缓存目录、包键、产物清单。
570
811
  */
571
- async function cssShimOf(options) {
572
- if (!options.entry.endsWith(".css")) return void 0;
573
- const file = (0, node_path.join)(options.outDir, `${options.exportName.replaceAll("/", "+")}.css-shim.mjs`);
812
+ async function bundleStyleOf(options) {
813
+ const { transform } = await import("lightningcss");
814
+ const source = await (0, node_fs_promises.readFile)(options.entry);
815
+ const relativeUrl = (ref) => ref !== "" && !ref.startsWith("#") && !ref.startsWith("/") && !/^[a-z][a-z0-9+.-]*:/iu.test(ref);
816
+ const refs = /* @__PURE__ */ new Set();
817
+ transform({
818
+ filename: options.entry,
819
+ code: source,
820
+ minify: false,
821
+ visitor: { Url(node) {
822
+ if (relativeUrl(node.url)) refs.add(node.url);
823
+ } }
824
+ });
825
+ const mapping = /* @__PURE__ */ new Map();
826
+ for (const ref of refs) {
827
+ const absolute = (0, node_path.join)((0, node_path.dirname)(options.entry), ref);
828
+ const bytes = await (0, node_fs_promises.readFile)(absolute).catch(() => void 0);
829
+ if (bytes === void 0) continue;
830
+ const extension = (0, node_path.extname)(absolute);
831
+ const name = `assets/${(0, node_path.basename)(absolute, extension)}-${(0, node_crypto.createHash)("sha256").update(bytes).digest("hex").slice(0, 8)}${extension}`;
832
+ mapping.set(ref, `${CLIENT_MODULES_PREFIX}/${options.key}/${name}`);
833
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)((0, node_path.join)(options.outDir, name)), { recursive: true });
834
+ await (0, node_fs_promises.writeFile)((0, node_path.join)(options.outDir, name), bytes);
835
+ options.files[name] = `${options.key}/${name}`;
836
+ }
837
+ const result = transform({
838
+ filename: options.entry,
839
+ code: source,
840
+ minify: false,
841
+ visitor: { Url(node) {
842
+ const rewritten = mapping.get(node.url);
843
+ return rewritten === void 0 ? void 0 : {
844
+ ...node,
845
+ url: rewritten
846
+ };
847
+ } }
848
+ });
849
+ const file = (0, node_path.join)(options.outDir, options.exportName);
574
850
  await (0, node_fs_promises.mkdir)((0, node_path.dirname)(file), { recursive: true });
575
- await (0, node_fs_promises.writeFile)(file, `import ${JSON.stringify(options.entry)};\n`, "utf8");
576
- return file;
851
+ await (0, node_fs_promises.writeFile)(file, result.code);
852
+ options.files[options.exportName] = `${options.key}/${options.exportName}`;
577
853
  }
578
854
  /**
579
855
  * 确保该包的产物在(指纹没变、且**这次要的出口**都在就直接用)。
@@ -658,7 +934,8 @@ async function bundlePackageOnce(options, key) {
658
934
  const outDir = (0, node_path.join)(options.cacheRoot, key);
659
935
  const manifestPath = (0, node_path.join)(outDir, ".files.json");
660
936
  options.log?.(`[bundle-rev] ${options.name}: hash-start watch=${options.watch.join(",")}\n`);
661
- const rev = `${BUNDLER_REV}:${await fingerprint(options.watch)}`;
937
+ const rootRev = (0, node_crypto.createHash)("sha1").update((0, node_path.dirname)(options.watch[0] ?? options.manifestOf ?? "")).digest("hex").slice(0, 8);
938
+ const rev = `${BUNDLER_REV}:${rootRev}:${await fingerprint(options.watch)}`;
662
939
  options.log?.(`[bundle-rev] ${options.name}: hash=${rev}\n`);
663
940
  const cached = JSON.parse(await (0, node_fs_promises.readFile)(manifestPath, "utf8").catch(() => "{}"));
664
941
  const fresh = cached.rev === rev;
@@ -675,32 +952,70 @@ async function bundlePackageOnce(options, key) {
675
952
  for (const { find, replacement } of options.alias) if (typeof find === "string" ? source.startsWith(find) : find.test(source)) return source.replace(find, replacement);
676
953
  }
677
954
  },
678
- browserProcessPlugin(),
955
+ browserProcessPlugin(await clientBuildMeta(options.repoRoot)),
956
+ {
957
+ name: "dsh-css-specifiers",
958
+ resolveId(source, importer) {
959
+ if (!source.endsWith(".css") || source.startsWith(".") || source.startsWith("/")) return;
960
+ try {
961
+ return (0, node_module.createRequire)(importer ?? (0, node_path.join)(options.repoRoot, "package.json")).resolve(source);
962
+ } catch {
963
+ return;
964
+ }
965
+ }
966
+ },
679
967
  (0, _morlay_dsh_cordis_assets_styles.cssInlinePlugins)({
680
968
  name: key,
681
969
  assets: "threshold",
682
970
  assetUrl: (file) => `${CLIENT_MODULES_PREFIX}/${key}/${file}`
683
971
  }),
684
972
  (0, _morlay_dsh_cordis_assets_assets.clientAssetPlugin)({ assets: "threshold" }),
685
- (0, vite.esmExternalRequirePlugin)({ external: [...resolvable.keys()].filter((name) => !_morlay_dsh_cordis_assets_assets.NODE_BUILTIN.test(name)).map((name) => barePackageRegExp(name)) })
973
+ (0, vite.esmExternalRequirePlugin)({ external: [...resolvable.keys()].filter((name) => !_morlay_dsh_cordis_assets_assets.NODE_BUILTIN.test(name) && name !== options.name).map((name) => barePackageRegExp(name)) })
686
974
  ];
687
975
  const startedAt = Date.now();
688
976
  options.log?.(`[bundle-build] ${options.name}: rolldown start\n`);
689
977
  const input = {};
690
- for (const [exportName, entry] of Object.entries(options.input)) input[exportName] = await cjsShimOf({
691
- name: options.name,
692
- exportName,
693
- entry,
694
- ...options.log === void 0 ? {} : { log: options.log },
695
- outDir
696
- }) ?? await cssShimOf({
697
- exportName,
698
- entry,
699
- outDir
700
- }) ?? entry;
978
+ const entryShims = /* @__PURE__ */ new Map();
979
+ const styleEntries = /* @__PURE__ */ new Map();
980
+ for (const [exportName, entry] of Object.entries(options.input)) {
981
+ const kind = await moduleKindOf(entry);
982
+ if (kind === "cjs") {
983
+ const shim = await cjsShimOf({
984
+ name: options.name,
985
+ exportName,
986
+ entry,
987
+ from: entry,
988
+ ...options.log === void 0 ? {} : { log: options.log }
989
+ });
990
+ if (shim !== void 0) entryShims.set(shim.id, shim.code);
991
+ input[exportName] = shim?.id ?? entry;
992
+ continue;
993
+ }
994
+ if (kind === "style") {
995
+ styleEntries.set(exportName, entry);
996
+ const styleId = `\0dsh-style:${options.name}:${exportName}:entry`;
997
+ entryShims.set(styleId, "export {};\n");
998
+ input[exportName] = styleId;
999
+ continue;
1000
+ }
1001
+ input[exportName] = entry;
1002
+ }
1003
+ if (entryShims.size !== 0) plugins.push({
1004
+ name: "dsh-entry-shims",
1005
+ resolveId(source) {
1006
+ return entryShims.has(source) ? source : void 0;
1007
+ },
1008
+ load(source) {
1009
+ return entryShims.get(source);
1010
+ }
1011
+ });
701
1012
  const bundle = await (0, rolldown.rolldown)({
702
1013
  input,
703
1014
  plugins,
1015
+ onLog: (level, log, handler) => {
1016
+ if (log.code === "CONFIGURATION_FIELD_CONFLICT" && log.message?.includes("experimentalDecorators") === true) return;
1017
+ handler(level, log);
1018
+ },
704
1019
  ...options.tsconfig === void 0 ? {} : { resolve: { tsconfigFilename: options.tsconfig } },
705
1020
  transform: {
706
1021
  target: [
@@ -710,10 +1025,7 @@ async function bundlePackageOnce(options, key) {
710
1025
  "safari16.4"
711
1026
  ],
712
1027
  decorator: { legacy: true },
713
- define: {
714
- "process.env": "{ env: {} }",
715
- process: "{ env: {} }"
716
- }
1028
+ define: { process: "{ env: {} }" }
717
1029
  }
718
1030
  });
719
1031
  const { output: items } = await bundle.generate({
@@ -733,8 +1045,10 @@ async function bundlePackageOnce(options, key) {
733
1045
  return;
734
1046
  }
735
1047
  await (0, node_fs_promises.mkdir)(outDir, { recursive: true });
1048
+ const styleExports = new Set(styleEntries.keys());
736
1049
  for (const item of items) {
737
1050
  if (item.type !== "chunk") continue;
1051
+ if (item.isEntry && styleExports.has(item.name)) continue;
738
1052
  await (0, node_fs_promises.mkdir)((0, node_path.dirname)((0, node_path.join)(outDir, item.fileName)), { recursive: true });
739
1053
  await (0, node_fs_promises.writeFile)((0, node_path.join)(outDir, item.fileName), item.code, "utf8");
740
1054
  files[item.isEntry ? item.name : item.fileName] = `${key}/${item.fileName}`;
@@ -745,6 +1059,13 @@ async function bundlePackageOnce(options, key) {
745
1059
  await (0, node_fs_promises.writeFile)((0, node_path.join)(outDir, asset.fileName), asset.source ?? "");
746
1060
  files[asset.fileName] = `${key}/${asset.fileName}`;
747
1061
  }
1062
+ for (const [exportName, entry] of styleEntries) await bundleStyleOf({
1063
+ entry,
1064
+ exportName,
1065
+ outDir,
1066
+ key,
1067
+ files
1068
+ });
748
1069
  await (0, node_fs_promises.writeFile)(manifestPath, `${JSON.stringify({
749
1070
  rev,
750
1071
  files
@@ -1010,11 +1331,7 @@ async function startViteDev(ctx, options) {
1010
1331
  const server = await (0, vite.createServer)({
1011
1332
  root: appRoot,
1012
1333
  base: "/",
1013
- define: {
1014
- "process.env.NODE_ENV": JSON.stringify(process.env["NODE_ENV"] ?? "development"),
1015
- "process.env": "{ env: {} }",
1016
- process: "{ env: {} }"
1017
- },
1334
+ define: { process: "{ env: {} }" },
1018
1335
  publicDir: false,
1019
1336
  appType: "mpa",
1020
1337
  configFile: false,
@@ -1036,11 +1353,10 @@ async function startViteDev(ctx, options) {
1036
1353
  }
1037
1354
  },
1038
1355
  optimizeDeps: {
1039
- disabled: true,
1040
1356
  noDiscovery: true,
1041
1357
  include: []
1042
1358
  },
1043
- plugins: [dshClientRowsPlugin({
1359
+ plugins: [browserProcessPlugin(await clientBuildMeta(repoRoot)), dshClientRowsPlugin({
1044
1360
  repoRoot,
1045
1361
  rows: () => rowsOf(options.rows),
1046
1362
  resolvePluginUrl: options.resolvePluginUrl,
@@ -1098,7 +1414,8 @@ const inject = ["loader", "webServer"];
1098
1414
  */
1099
1415
  async function clientRowsOf(loader) {
1100
1416
  const found = /* @__PURE__ */ new Map();
1101
- for (const entry of loader.entries()) {
1417
+ for (const raw of loader.entries()) {
1418
+ const entry = raw;
1102
1419
  if (entry.disabled === true || entry.fiber === void 0) continue;
1103
1420
  const name = entry.options?.name;
1104
1421
  if (typeof name !== "string" || name === "") continue;
@@ -1277,6 +1594,7 @@ function apply(ctx) {
1277
1594
  */
1278
1595
  const depsUrlOfSpecifier = async (specifier, importer) => {
1279
1596
  if (specifier.startsWith("@/")) return void 0;
1597
+ if (specifier.endsWith(".css")) return void 0;
1280
1598
  if (_morlay_dsh_cordis_assets_assets.NODE_BUILTIN.test(specifier)) return void 0;
1281
1599
  const bare = packageNameOf(specifier) || specifier;
1282
1600
  const root = await rootOf(bare);
@@ -1363,8 +1681,9 @@ function apply(ctx) {
1363
1681
  if (code === void 0) return false;
1364
1682
  const cacheControl = root !== void 0 && !root.includes("node_modules") ? "no-cache" : "public, max-age=31536000, immutable";
1365
1683
  const etag = `"${bundled.rev}"`;
1684
+ const extension = target.slice(target.lastIndexOf(".") + 1).toLowerCase();
1366
1685
  res.writeHead(200, {
1367
- "content-type": "text/javascript; charset=utf-8",
1686
+ "content-type": extension === "css" ? "text/css; charset=utf-8" : "text/javascript; charset=utf-8",
1368
1687
  "cache-control": cacheControl,
1369
1688
  etag
1370
1689
  });