@dimina-kit/compiler 0.0.1-dev.20260706064107 → 0.0.1-dev.20260706125036

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.
@@ -14942,81 +14942,23 @@ var init_npm_resolver = __esm({
14942
14942
  });
14943
14943
 
14944
14944
  // ../../dimina/fe/packages/compiler/src/env.js
14945
- function normalizeExt(raw) {
14946
- if (typeof raw !== "string") {
14947
- return null;
14948
- }
14949
- const v = raw.trim().toLowerCase().replace(/^\.+/, "");
14950
- if (!/^[a-z0-9_-]+$/.test(v)) {
14951
- return null;
14952
- }
14953
- return `.${v}`;
14954
- }
14955
- function normalizeTag(raw) {
14956
- if (typeof raw !== "string") {
14957
- return null;
14958
- }
14959
- const v = raw.trim().toLowerCase().replace(/^\.+/, "");
14960
- if (!/^[a-z][a-z0-9_-]*$/.test(v)) {
14961
- return null;
14962
- }
14963
- return v;
14964
- }
14965
- function mergeUnique(builtins, custom, normalizer, reserved) {
14966
- const out = [...builtins];
14967
- const seen2 = new Set(builtins);
14968
- if (Array.isArray(custom)) {
14969
- for (const raw of custom) {
14970
- const n2 = normalizer(raw);
14971
- if (n2 && !seen2.has(n2) && !reserved?.has(n2)) {
14972
- seen2.add(n2);
14973
- out.push(n2);
14974
- }
14975
- }
14976
- }
14977
- return out;
14978
- }
14979
- function normalizeFileTypes(fileTypes = {}) {
14980
- const ft = fileTypes || {};
14981
- return {
14982
- templateExts: mergeUnique(DEFAULT_TEMPLATE_EXTS, ft.template, normalizeExt, RESERVED_EXTS),
14983
- styleExts: mergeUnique(DEFAULT_STYLE_EXTS, ft.style, normalizeExt, RESERVED_EXTS),
14984
- viewScriptExts: mergeUnique(DEFAULT_VIEW_SCRIPT_EXTS, ft.viewScript, normalizeExt, RESERVED_EXTS),
14985
- viewScriptTags: mergeUnique(DEFAULT_VIEW_SCRIPT_TAGS, ft.viewScript, normalizeTag)
14986
- };
14987
- }
14988
- function storeInfo(workPath, options = {}) {
14945
+ function storeInfo(workPath) {
14989
14946
  storePathInfo(workPath);
14990
14947
  storeProjectConfig();
14991
14948
  storeAppConfig();
14992
14949
  storePageConfig();
14993
- compilerOptions = normalizeFileTypes(options.fileTypes);
14994
14950
  return {
14995
14951
  pathInfo,
14996
- configInfo,
14997
- compilerOptions
14952
+ configInfo
14998
14953
  };
14999
14954
  }
15000
14955
  function resetStoreInfo(opts) {
15001
14956
  pathInfo = opts.pathInfo;
15002
14957
  configInfo = opts.configInfo;
15003
- compilerOptions = opts.compilerOptions || normalizeFileTypes();
15004
14958
  if (pathInfo.workPath) {
15005
14959
  npmResolver = new NpmResolver(pathInfo.workPath);
15006
14960
  }
15007
14961
  }
15008
- function getTemplateExts() {
15009
- return compilerOptions.templateExts;
15010
- }
15011
- function getStyleExts() {
15012
- return compilerOptions.styleExts;
15013
- }
15014
- function getViewScriptExts() {
15015
- return compilerOptions.viewScriptExts;
15016
- }
15017
- function getViewScriptTags() {
15018
- return compilerOptions.viewScriptTags;
15019
- }
15020
14962
  function storePathInfo(workPath) {
15021
14963
  pathInfo.workPath = workPath;
15022
14964
  if (process_default.env.TARGET_PATH) {
@@ -15254,7 +15196,7 @@ function getPages() {
15254
15196
  subPages
15255
15197
  };
15256
15198
  }
15257
- var import_node_path4, pathInfo, configInfo, npmResolver, DEFAULT_TEMPLATE_EXTS, DEFAULT_STYLE_EXTS, DEFAULT_VIEW_SCRIPT_EXTS, DEFAULT_VIEW_SCRIPT_TAGS, RESERVED_EXTS, compilerOptions;
15199
+ var import_node_path4, pathInfo, configInfo, npmResolver;
15258
15200
  var init_env = __esm({
15259
15201
  "../../dimina/fe/packages/compiler/src/env.js"() {
15260
15202
  init_fs();
@@ -15267,19 +15209,6 @@ var init_env = __esm({
15267
15209
  pathInfo = {};
15268
15210
  configInfo = {};
15269
15211
  npmResolver = null;
15270
- DEFAULT_TEMPLATE_EXTS = [".wxml", ".ddml"];
15271
- DEFAULT_STYLE_EXTS = [".wxss", ".ddss", ".less", ".scss", ".sass"];
15272
- DEFAULT_VIEW_SCRIPT_EXTS = [".wxs"];
15273
- DEFAULT_VIEW_SCRIPT_TAGS = ["wxs", "dds"];
15274
- RESERVED_EXTS = /* @__PURE__ */ new Set([
15275
- ...DEFAULT_TEMPLATE_EXTS,
15276
- ...DEFAULT_STYLE_EXTS,
15277
- ...DEFAULT_VIEW_SCRIPT_EXTS,
15278
- ".js",
15279
- ".ts",
15280
- ".json"
15281
- ]);
15282
- compilerOptions = normalizeFileTypes();
15283
15212
  }
15284
15213
  });
15285
15214
 
@@ -18693,7 +18622,7 @@ function warnUnsupportedWxApi(apiName, filePath, line) {
18693
18622
  }
18694
18623
  function warnUnsupportedComponent(tagName, filePath, line) {
18695
18624
  const { supportedBuiltinComponents: supportedBuiltinComponents2 } = loadReference();
18696
- if (!tagName || supportedBuiltinComponents2.has(tagName) || getViewScriptTags().includes(tagName)) {
18625
+ if (!tagName || supportedBuiltinComponents2.has(tagName)) {
18697
18626
  return;
18698
18627
  }
18699
18628
  const location = formatLocation(filePath, line);
@@ -18754,7 +18683,6 @@ var cachedReference, warnedItems;
18754
18683
  var init_compatibility = __esm({
18755
18684
  "../../dimina/fe/packages/compiler/src/common/compatibility.js"() {
18756
18685
  init_dist3();
18757
- init_env();
18758
18686
  init_compatibility_reference();
18759
18687
  cachedReference = null;
18760
18688
  warnedItems = /* @__PURE__ */ new Set();
@@ -45121,7 +45049,7 @@ function doCompileTemplate({
45121
45049
  ssrCssVars,
45122
45050
  isProd = false,
45123
45051
  compiler,
45124
- compilerOptions: compilerOptions2 = {},
45052
+ compilerOptions = {},
45125
45053
  transformAssetUrls
45126
45054
  }) {
45127
45055
  const errors2 = [];
@@ -45155,7 +45083,7 @@ function doCompileTemplate({
45155
45083
  if (inAST == null ? void 0 : inAST.transformed) {
45156
45084
  const newAST = (ssr ? CompilerDOM : compiler).parse(inAST.source, __spreadProps$5(__spreadValues$6({
45157
45085
  prefixIdentifiers: true
45158
- }, compilerOptions2), {
45086
+ }, compilerOptions), {
45159
45087
  parseMode: "sfc",
45160
45088
  onError: (e) => errors2.push(e)
45161
45089
  }));
@@ -45173,9 +45101,9 @@ function doCompileTemplate({
45173
45101
  scopeId: scoped ? longId : void 0,
45174
45102
  slotted,
45175
45103
  sourceMap: true
45176
- }, compilerOptions2), {
45104
+ }, compilerOptions), {
45177
45105
  hmr: !isProd,
45178
- nodeTransforms: nodeTransforms.concat(compilerOptions2.nodeTransforms || []),
45106
+ nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []),
45179
45107
  filename,
45180
45108
  onError: (e) => errors2.push(e),
45181
45109
  onWarn: (w) => warnings.push(w)
@@ -76947,8 +76875,6 @@ __export(view_compiler_exports, {
76947
76875
  compileML: () => compileML,
76948
76876
  generateSlotDirective: () => generateSlotDirective,
76949
76877
  generateVModelTemplate: () => generateVModelTemplate,
76950
- initWxsFilePathMap: () => initWxsFilePathMap,
76951
- loadWxsModule: () => loadWxsModule,
76952
76878
  parseBraceExp: () => parseBraceExp,
76953
76879
  parseClassRules: () => parseClassRules,
76954
76880
  parseKeyExpression: () => parseKeyExpression,
@@ -76957,13 +76883,6 @@ __export(view_compiler_exports, {
76957
76883
  processWxsContent: () => processWxsContent,
76958
76884
  splitWithBraces: () => splitWithBraces
76959
76885
  });
76960
- function buildExtStripRegex(exts) {
76961
- const alt = exts.map((e) => e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|");
76962
- return new RegExp(`(${alt})$`);
76963
- }
76964
- function stripViewScriptExt(p) {
76965
- return p.replace(buildExtStripRegex(getViewScriptExts()), "");
76966
- }
76967
76886
  function parseJs(code, filename = "view-compiler.js", sourceType = "module") {
76968
76887
  return parseSync(filename, code, {
76969
76888
  sourceType,
@@ -77129,8 +77048,8 @@ function scanWxsFiles(dir, workPath) {
77129
77048
  const stat2 = fs_default.statSync(fullPath);
77130
77049
  if (stat2.isDirectory()) {
77131
77050
  scanWxsFiles(fullPath, workPath);
77132
- } else if (stat2.isFile() && getViewScriptExts().some((ext) => item.endsWith(ext))) {
77133
- const relativePath = stripViewScriptExt(fullPath.replace(workPath, ""));
77051
+ } else if (stat2.isFile() && item.endsWith(".wxs")) {
77052
+ const relativePath = fullPath.replace(workPath, "").replace(/\.wxs$/, "");
77134
77053
  const moduleName = relativePath.replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
77135
77054
  wxsFilePathMap.set(moduleName, fullPath);
77136
77055
  }
@@ -77360,7 +77279,7 @@ function processWxsContent(wxsContent, wxsFilePath, scriptModule, workPath, file
77360
77279
  if (filePath && filePath.includes("/miniprogram_npm/")) {
77361
77280
  const currentWxsDir = import_node_path8.default.dirname(wxsFilePath);
77362
77281
  resolvedWxsPath = import_node_path8.default.resolve(currentWxsDir, requirePath);
77363
- const relativePath = stripViewScriptExt(resolvedWxsPath.replace(workPath, ""));
77282
+ const relativePath = resolvedWxsPath.replace(workPath, "").replace(/\.wxs$/, "");
77364
77283
  const moduleName = relativePath.replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
77365
77284
  processWxsDependency(resolvedWxsPath, moduleName, scriptModule, workPath, filePath);
77366
77285
  replacements.push({
@@ -77371,7 +77290,7 @@ function processWxsContent(wxsContent, wxsFilePath, scriptModule, workPath, file
77371
77290
  } else {
77372
77291
  const currentWxsDir = import_node_path8.default.dirname(wxsFilePath);
77373
77292
  resolvedWxsPath = import_node_path8.default.resolve(currentWxsDir, requirePath);
77374
- const relativePath = stripViewScriptExt(resolvedWxsPath.replace(workPath, ""));
77293
+ const relativePath = resolvedWxsPath.replace(workPath, "").replace(/\.wxs$/, "");
77375
77294
  const depModuleName = relativePath.replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
77376
77295
  processWxsDependency(resolvedWxsPath, depModuleName, scriptModule, workPath, filePath);
77377
77296
  replacements.push({
@@ -77587,7 +77506,7 @@ function toCompileTemplate(isComponent2, path10, components, componentPlaceholde
77587
77506
  const src = $2(elem).attr("src");
77588
77507
  if (src) {
77589
77508
  const includeFullPath = getAbsolutePath(workPath, path10, src);
77590
- let includePath = includeFullPath.replace(workPath, "").replace(buildExtStripRegex(getTemplateExts()), "");
77509
+ let includePath = includeFullPath.replace(workPath, "").replace(/\.(wxml|ddml)$/, "");
77591
77510
  const includeDiagnosticSource = includeFullPath.startsWith(workPath) ? includeFullPath.slice(workPath.length) : includePath;
77592
77511
  if (!includePath.startsWith("/")) {
77593
77512
  includePath = "/" + includePath;
@@ -77613,7 +77532,8 @@ function toCompileTemplate(isComponent2, path10, components, componentPlaceholde
77613
77532
  );
77614
77533
  processIncludedFileWxsDependencies(includeContent, includePath, scriptModule, components, processedPaths);
77615
77534
  $includeContent("template").remove();
77616
- $includeContent(getViewScriptTags().join(",")).remove();
77535
+ $includeContent("wxs").remove();
77536
+ $includeContent("dds").remove();
77617
77537
  const processedContent = processIncludeConditionalAttrs($2, elem, $includeContent.html());
77618
77538
  $2(elem).replaceWith(processedContent);
77619
77539
  } else {
@@ -77630,7 +77550,7 @@ function toCompileTemplate(isComponent2, path10, components, componentPlaceholde
77630
77550
  const src = $2(elem).attr("src");
77631
77551
  if (src) {
77632
77552
  const importFullPath = getAbsolutePath(workPath, path10, src);
77633
- let importPath = importFullPath.replace(workPath, "").replace(buildExtStripRegex(getTemplateExts()), "");
77553
+ let importPath = importFullPath.replace(workPath, "").replace(/\.(wxml|ddml)$/, "");
77634
77554
  const importDiagnosticSource = importFullPath.startsWith(workPath) ? importFullPath.slice(workPath.length) : importPath;
77635
77555
  if (!importPath.startsWith("/")) {
77636
77556
  importPath = "/" + importPath;
@@ -77677,7 +77597,8 @@ function transTagTemplate($2, templateModule, path10, components, componentPlace
77677
77597
  const templateContent = $2(elem);
77678
77598
  templateContent.find("import").remove();
77679
77599
  templateContent.find("include").remove();
77680
- templateContent.find(getViewScriptTags().join(",")).remove();
77600
+ templateContent.find("wxs").remove();
77601
+ templateContent.find("dds").remove();
77681
77602
  transAsses($2, templateContent.find("image"), path10);
77682
77603
  const res = [];
77683
77604
  transHtmlTag(templateContent.html(), res, components, componentPlaceholder);
@@ -77984,7 +77905,7 @@ function parseKeyExpression(exp, itemName = "item", indexName = "index") {
77984
77905
  }
77985
77906
  function getViewPath(workPath, src) {
77986
77907
  const aSrc = src.startsWith("/") ? src : `/${src}`;
77987
- for (const mlType of getTemplateExts()) {
77908
+ for (const mlType of fileType) {
77988
77909
  const mlFullPath = `${workPath}${aSrc}${mlType}`;
77989
77910
  if (fs_default.existsSync(mlFullPath)) {
77990
77911
  return mlFullPath;
@@ -78090,7 +78011,10 @@ function parseTemplateDataExp(exp) {
78090
78011
  return `{${parseBraceExp(exp)}}`;
78091
78012
  }
78092
78013
  function transTagWxs($2, scriptModule, filePath) {
78093
- const wxsNodes = $2(getViewScriptTags().join(","));
78014
+ let wxsNodes = $2("wxs");
78015
+ if (wxsNodes.length === 0) {
78016
+ wxsNodes = $2("dds");
78017
+ }
78094
78018
  wxsNodes.each((_, elem) => {
78095
78019
  const smName = $2(elem).attr("module");
78096
78020
  if (smName) {
@@ -78109,7 +78033,7 @@ function transTagWxs($2, scriptModule, filePath) {
78109
78033
  wxsFilePath = getAbsolutePath(workPath, filePath, src);
78110
78034
  }
78111
78035
  if (wxsFilePath) {
78112
- const relativePath = stripViewScriptExt(wxsFilePath.replace(workPath, ""));
78036
+ const relativePath = wxsFilePath.replace(workPath, "").replace(/\.wxs$/, "");
78113
78037
  uniqueModuleName = relativePath.replace(/[\/\\@\-]/g, "_").replace(/^_/, "");
78114
78038
  cacheKey = wxsFilePath;
78115
78039
  }
@@ -78182,8 +78106,12 @@ function collectAllWxsModules(scriptRes, collectedPaths = /* @__PURE__ */ new Se
78182
78106
  return allWxsModules;
78183
78107
  }
78184
78108
  function loadWxsModule(modulePath, workPath, scriptModule) {
78109
+ if (!modulePath.startsWith("miniprogram_npm__") || !modulePath.includes("_wxs_")) {
78110
+ return null;
78111
+ }
78185
78112
  const wxsFilePath = wxsFilePathMap.get(modulePath);
78186
78113
  if (!wxsFilePath) {
78114
+ console.warn(`[view] \u65E0\u6CD5\u627E\u5230 wxs \u6A21\u5757\u6587\u4EF6: ${modulePath}`);
78187
78115
  return null;
78188
78116
  }
78189
78117
  try {
@@ -78270,7 +78198,7 @@ function __resetViewState() {
78270
78198
  wxsModuleRegistry.clear();
78271
78199
  wxsFilePathMap.clear();
78272
78200
  }
78273
- var import_node_path8, compileResCache, wxsModuleRegistry, wxsFilePathMap, braceRegex, noBraceRegex, ternaryRegex;
78201
+ var import_node_path8, fileType, compileResCache, wxsModuleRegistry, wxsFilePathMap, braceRegex, noBraceRegex, ternaryRegex;
78274
78202
  var init_view_compiler = __esm({
78275
78203
  "../../dimina/fe/packages/compiler/src/core/view-compiler.js"() {
78276
78204
  init_fs();
@@ -78287,6 +78215,7 @@ var init_view_compiler = __esm({
78287
78215
  init_utils();
78288
78216
  init_env();
78289
78217
  init_expression_parser();
78218
+ fileType = [".wxml", ".ddml"];
78290
78219
  compileResCache = /* @__PURE__ */ new Map();
78291
78220
  wxsModuleRegistry = /* @__PURE__ */ new Set();
78292
78221
  wxsFilePathMap = /* @__PURE__ */ new Map();
@@ -291076,7 +291005,7 @@ function normalizeCssUrlValue(value, absolutePath) {
291076
291005
  function getAbsolutePath2(modulePath) {
291077
291006
  const workPath = getWorkPath();
291078
291007
  const src = modulePath.startsWith("/") ? modulePath : `/${modulePath}`;
291079
- for (const ssType of getStyleExts()) {
291008
+ for (const ssType of fileType2) {
291080
291009
  const ssFullPath = `${workPath}${src}${ssType}`;
291081
291010
  if (fs_default.existsSync(ssFullPath)) {
291082
291011
  return ssFullPath;
@@ -291129,7 +291058,7 @@ function processHostSelector(selector2, moduleId) {
291129
291058
  function __resetStyleState() {
291130
291059
  compileRes.clear();
291131
291060
  }
291132
- var import_node_path9, import_autoprefixer, import_cssnano, import_postcss_selector_parser, compileRes;
291061
+ var import_node_path9, import_autoprefixer, import_cssnano, import_postcss_selector_parser, fileType2, compileRes;
291133
291062
  var init_style_compiler = __esm({
291134
291063
  "../../dimina/fe/packages/compiler/src/core/style-compiler.js"() {
291135
291064
  init_fs();
@@ -291144,6 +291073,7 @@ var init_style_compiler = __esm({
291144
291073
  init_sass_default();
291145
291074
  init_utils();
291146
291075
  init_env();
291076
+ fileType2 = [".wxss", ".ddss", ".less", ".scss", ".sass"];
291147
291077
  compileRes = /* @__PURE__ */ new Map();
291148
291078
  if (!isMainThread) {
291149
291079
  parentPort.on("message", async ({ pages, storeInfo: storeInfo2 }) => {
@@ -291242,7 +291172,6 @@ var config_compiler_default = compileConfig;
291242
291172
  // ../../dimina/fe/packages/compiler/src/common/npm-builder.js
291243
291173
  init_fs();
291244
291174
  var import_node_path6 = __toESM(require_path_browserify(), 1);
291245
- init_env();
291246
291175
  var NpmBuilder = class {
291247
291176
  constructor(workPath, targetPath) {
291248
291177
  this.workPath = workPath;
@@ -291350,7 +291279,7 @@ var NpmBuilder = class {
291350
291279
  * @returns {boolean} 是否为小程序文件
291351
291280
  */
291352
291281
  isMiniprogramFile(filename) {
291353
- const miniprogramExts = [".js", ".json", ".ts", ...getTemplateExts(), ...getStyleExts(), ...getViewScriptExts()];
291282
+ const miniprogramExts = [".js", ".json", ".wxml", ".wxss", ".wxs", ".ts", ".less", ".scss", ".styl"];
291354
291283
  const ext = import_node_path6.default.extname(filename).toLowerCase();
291355
291284
  return miniprogramExts.includes(ext) || filename === "package.json" || filename === "README.md" || filename.startsWith(".");
291356
291285
  }
@@ -3,12 +3,12 @@ import {
3
3
  preloadStage,
4
4
  resetCompilerState,
5
5
  runStage
6
- } from "./pool.node-chunks/chunk-PDHO4Y56.js";
6
+ } from "./pool.node-chunks/chunk-MHOA4NGC.js";
7
7
  import {
8
8
  getAppId,
9
9
  getAppName,
10
10
  resetStoreInfo
11
- } from "./pool.node-chunks/chunk-7FGOYOXU.js";
11
+ } from "./pool.node-chunks/chunk-UYQ7D5I5.js";
12
12
 
13
13
  // src/stage-worker-node.js
14
14
  import { createRequire } from "node:module";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dimina-kit/compiler",
3
- "version": "0.0.1-dev.20260706064107",
3
+ "version": "0.0.1-dev.20260706125036",
4
4
  "description": "dmcc compiler bundles (browser + node) that drive @dimina/compiler against a caller-injected node:fs replacement (no bundled fs)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -8,7 +8,7 @@
8
8
  // and require our pool to match dmcc only where dmcc matches itself. Assets (uuid-named)
9
9
  // are matched by CONTENT hash multiset instead of name. Sourcemap is asserted against
10
10
  // dmcc's own map (parity), since that is the format devtools already consumes.
11
- import { readdirSync, readFileSync, statSync, rmSync, mkdirSync } from 'node:fs'
11
+ import { readdirSync, readFileSync, statSync, rmSync, mkdirSync, writeFileSync } from 'node:fs'
12
12
  import { fileURLToPath } from 'node:url'
13
13
  import { createHash } from 'node:crypto'
14
14
  import path from 'node:path'
@@ -42,7 +42,12 @@ function readTree(root) {
42
42
  }
43
43
 
44
44
  const dmccBuild = (await import('../../../dimina/fe/packages/compiler/src/index.js')).default
45
- const { createNodeCompilerPool } = await import('../dist/pool.node.js')
45
+ const poolNodeModule = await import('../dist/pool.node.js')
46
+ const { createNodeCompilerPool } = poolNodeModule
47
+ // Destructured lazily below (may be absent pre-fix): the default drop-in build(),
48
+ // the pure oxc-native-binding-hint mapper, and the lazy-singleton disposer.
49
+ const defaultBuild = poolNodeModule.default
50
+ const { oxcNativeBindingHint, disposeDefaultPool } = poolNodeModule
46
51
 
47
52
  // --- reference: dmcc twice ------------------------------------------------
48
53
  console.log(`[ref] dmcc build ×2 (sourcemap) from ${APP}`)
@@ -113,5 +118,90 @@ checkAgainstDmcc(readTree(path.join(dir('ours1'), appInfo1.appId)), 'cold')
113
118
  checkAgainstDmcc(readTree(path.join(dir('ours2'), appInfo2.appId)), 'warm')
114
119
 
115
120
  console.log(`[sourcemap] logic.js.map: ${refMap.sources.length} sources, sourcesContent present, matches dmcc ✅`)
116
- console.log(failed ? '\n❌ FAIL' : '\n✅ PASS: resident Node pool is dmcc-equivalent (incl. sourcemap) on cold+warm builds')
121
+
122
+ // --- failure contract: the default drop-in build() must REJECT a broken compile ------------------
123
+ // (never resolve undefined and let the caller mistake a failed compile for success), and the pool
124
+ // must expose a pure helper that turns a missing-oxc-native-binding message into an actionable
125
+ // packaging hint (checked as a string mapping only — a real environment can't be made to lack the
126
+ // binding on demand).
127
+ console.log("[fail] broken fixture: default build() must reject, not resolve undefined")
128
+ function writeBrokenFixture(root) {
129
+ const write = (rel, content) => {
130
+ const target = path.join(root, rel)
131
+ mkdirSync(path.dirname(target), { recursive: true })
132
+ writeFileSync(target, content)
133
+ }
134
+ write('project.config.json', JSON.stringify({ appid: 'fixture_app_broken', projectname: 'fixture-broken' }))
135
+ write('app.json', JSON.stringify({ pages: ['pages/index/index'] }))
136
+ write('app.js', 'App({})\n')
137
+ write('app.wxss', 'page { font-size: 14px; }\n')
138
+ write('pages/index/index.json', '{}\n')
139
+ // Unbalanced brace + bad tokens — same corruption shape used by devkit's
140
+ // open-project-compile-log fixture, chosen because it fails the logic stage
141
+ // rather than being silently absorbed by esbuild's error-tolerant fallback.
142
+ write('pages/index/index.js', 'Page({ data: { msg: "hi" } })\nconst broken = {{{ ;;; <<<\n')
143
+ write('pages/index/index.wxml', '<view>{{msg}}</view>\n')
144
+ write('pages/index/index.wxss', '.x { color: red; }\n')
145
+ }
146
+ const brokenRoot = dir('broken-fixture')
147
+ mkdirSync(brokenRoot, { recursive: true })
148
+ writeBrokenFixture(brokenRoot)
149
+
150
+ if (typeof defaultBuild !== 'function') {
151
+ fail('pool.node.js must have a default export `build(outputDir, workPath, useAppIdDir?, options?)` — default export is missing/not a function')
152
+ }
153
+ else {
154
+ let brokenResolvedValue
155
+ let brokenRejectedError
156
+ try {
157
+ brokenResolvedValue = await defaultBuild(dir('broken-out'), brokenRoot, true, {})
158
+ }
159
+ catch (e) {
160
+ brokenRejectedError = e
161
+ }
162
+ if (brokenRejectedError === undefined) {
163
+ fail(`default build() must REJECT on a broken compile — instead it resolved to ${JSON.stringify(brokenResolvedValue)} (a swallowed error looks like success to every caller)`)
164
+ }
165
+ else if (!(brokenRejectedError instanceof Error) || !brokenRejectedError.message) {
166
+ fail(`default build() rejected but without a usable Error message: ${brokenRejectedError}`)
167
+ }
168
+ else if (!/stage "logic" failed/.test(brokenRejectedError.message)) {
169
+ fail(`default build() rejection message must name the failing stage, got: ${brokenRejectedError.message.split('\n')[0]}`)
170
+ }
171
+ else if (!/Transform failed/.test(brokenRejectedError.message)) {
172
+ fail(`default build() rejection message must carry the underlying compile reason (esbuild transform failure), got: ${brokenRejectedError.message.split('\n')[0]}`)
173
+ }
174
+ else {
175
+ console.log(`[fail] ✅ default build() rejected with: ${brokenRejectedError.message.split('\n')[0]}`)
176
+ }
177
+ }
178
+
179
+ // --- oxcNativeBindingHint: pure message -> actionable-packaging-hint mapper -----------------------
180
+ if (typeof oxcNativeBindingHint !== 'function') {
181
+ fail('pool.node.js must export a named `oxcNativeBindingHint(message)` helper — export is missing')
182
+ }
183
+ else {
184
+ const hint = oxcNativeBindingHint('Cannot find native binding. It means oxc-parser was not installed correctly for this platform.')
185
+ if (typeof hint !== 'string' || !hint.includes('@oxc-parser/binding-') || !hint.includes('wasm32-wasi')) {
186
+ fail(`oxcNativeBindingHint must mention both the native platform binding package (@oxc-parser/binding-*) and the wasm32-wasi fallback, got: ${JSON.stringify(hint)}`)
187
+ }
188
+ else {
189
+ console.log('[fail] ✅ oxcNativeBindingHint surfaces a packaging fix for a missing native binding')
190
+ }
191
+ const noHint = oxcNativeBindingHint('some unrelated compile error')
192
+ if (noHint !== null) {
193
+ fail(`oxcNativeBindingHint must return null for a message that is not the native-binding failure, got: ${JSON.stringify(noHint)}`)
194
+ }
195
+ }
196
+
197
+ // The default export is a lazy module-level singleton pool (resident worker threads) — the
198
+ // broken-fixture build above spun it up, so the process cannot exit cleanly without disposing it.
199
+ if (typeof disposeDefaultPool !== 'function') {
200
+ fail('pool.node.js must export `disposeDefaultPool()` to tear down the lazy default-export singleton pool')
201
+ }
202
+ else {
203
+ await disposeDefaultPool()
204
+ }
205
+
206
+ console.log(failed ? '\n❌ FAIL' : '\n✅ PASS: resident Node pool is dmcc-equivalent (incl. sourcemap) on cold+warm builds, and rejects broken compiles')
117
207
  process.exit(failed ? 1 : 0)
package/src/pool-node.js CHANGED
@@ -167,7 +167,9 @@ export function createNodeCompilerPool({
167
167
  for (const r of results) {
168
168
  if (!r || r.type === 'error') {
169
169
  const info = r && r.error
170
- const err = new Error(`[compiler] stage "${r && r.stage}" failed: ${(info && info.message) || 'unknown error'}`)
170
+ const cause = (info && info.message) || 'unknown error'
171
+ const hint = oxcNativeBindingHint(cause)
172
+ const err = new Error(`[compiler] stage "${r && r.stage}" failed: ${cause}${hint ? ` — ${hint}` : ''}`)
171
173
  if (info && info.stack) err.stack = info.stack
172
174
  err.stage = r && r.stage
173
175
  err.code = 'compiler-stage-error' // worker-reported compile error — never retried
@@ -232,19 +234,40 @@ export function createNodeCompilerPool({
232
234
  // user-facing compile-log lines a host (e.g. devkit/devtools' log panel) already scrapes.
233
235
  const STAGE_TITLES = { logic: '编译页面逻辑', view: '编译页面文件', style: '编译样式文件' }
234
236
 
237
+ /**
238
+ * Map a failure message to an actionable packaging hint when it is oxc-parser's
239
+ * "missing runtime binding" error (thrown when NEITHER the platform-native
240
+ * `@oxc-parser/binding-<platform>` package NOR the `@oxc-parser/binding-wasm32-wasi`
241
+ * fallback resolves at runtime). Neither package is a direct dependency of a
242
+ * typical host, so app bundlers (e.g. electron-builder's dependency collection)
243
+ * silently drop them — and the raw oxc message says nothing about packaging.
244
+ * Returns null for every other message.
245
+ * @param {string} message
246
+ * @returns {string | null}
247
+ */
248
+ export function oxcNativeBindingHint(message) {
249
+ if (!/Cannot find native binding/i.test(String(message))) return null
250
+ return 'oxc-parser 的运行时绑定没有被打进宿主应用:@dimina-kit/compiler 的 Node 编译路径需要 '
251
+ + `@oxc-parser/binding-${process.platform}-${process.arch}(平台原生绑定)或 `
252
+ + '@oxc-parser/binding-wasm32-wasi(wasm 兜底)二者之一实际存在于包内。'
253
+ + '打包分发(如 electron-builder)时请把其中一个显式声明为宿主依赖,避免依赖收集时被丢弃'
254
+ }
255
+
235
256
  // Lazy singleton pool — a DROP-IN replacement for dmcc's `build(targetPath, workPath,
236
- // useAppIdDir, options)`, matching its behavior on BOTH the happy and error paths so a
237
- // host that consumed dmcc keeps working unchanged:
257
+ // useAppIdDir, options)` with ONE deliberate divergence on the error path:
238
258
  // • the first call spins up the resident workers; every later call (a watch rebuild)
239
259
  // reuses them warm;
240
260
  // • on success it emits `✔ 输出编译产物` on stdout (dmcc's listr2 completion line — the
241
261
  // pool has no listr2, so the equivalent user-facing line is surfaced here);
242
- // • on failure it reports the failing stage + summary on stderr and RESOLVES undefined
243
- // (never rethrows), exactly like dmcc's build() catch (index.js) the host normalizes
244
- // undefined to a null appInfo and the error detail (incl. dmcc's own
245
- // `[logic] esbuild 转换失败 …`) still reaches the log channel.
246
- // Callers that want structured throwing errors + explicit teardown should use
247
- // createNodeCompilerPool() directly instead.
262
+ // • on failure it reports the failing stage + summary on stderr (same lines a dmcc
263
+ // host already scrapes: `✖ <stage>` + `<workPath> 编译出错: …`) and then REJECTS
264
+ // with the error. dmcc's own build() swallows the error and resolves undefined,
265
+ // which makes a failed compile indistinguishable from benign "no app info" — a
266
+ // host would start a session that can only 404. Rejecting keeps the log surface
267
+ // identical while giving callers a real failure signal; a resolved null/undefined
268
+ // no longer means "compile failed", only "no app info to report".
269
+ // Callers that want structured errors (`.stage`/`.code`) + explicit teardown should
270
+ // use createNodeCompilerPool() directly instead.
248
271
  let singleton = null
249
272
  export default async function build(outputDir, workPath, useAppIdDir = true, options = {}) {
250
273
  if (!singleton) singleton = createNodeCompilerPool()
@@ -255,7 +278,7 @@ export default async function build(outputDir, workPath, useAppIdDir = true, opt
255
278
  } catch (e) {
256
279
  if (e && e.stage) console.error(`✖ ${STAGE_TITLES[e.stage] || e.stage}`)
257
280
  console.error(`${workPath} 编译出错: ${e && e.message}`)
258
- return undefined
281
+ throw e
259
282
  }
260
283
  }
261
284