openxiangda 1.0.35 → 1.0.36

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 (36) hide show
  1. package/README.md +2 -0
  2. package/lib/cli.js +1 -1
  3. package/openxiangda-skills/SKILL.md +1 -1
  4. package/openxiangda-skills/references/component-guide.md +10 -11
  5. package/openxiangda-skills/references/style-system.md +14 -18
  6. package/openxiangda-skills/references/troubleshooting.md +13 -13
  7. package/openxiangda-skills/skills/openxiangda-page/SKILL.md +2 -2
  8. package/package.json +1 -1
  9. package/packages/sdk/dist/runtime/index.cjs +67 -30
  10. package/packages/sdk/dist/runtime/index.cjs.map +1 -1
  11. package/packages/sdk/dist/runtime/index.mjs +67 -30
  12. package/packages/sdk/dist/runtime/index.mjs.map +1 -1
  13. package/packages/sdk/dist/styles/antd-theme.cjs +11 -3
  14. package/packages/sdk/dist/styles/antd-theme.cjs.map +1 -1
  15. package/packages/sdk/dist/styles/antd-theme.d.mts +2 -1
  16. package/packages/sdk/dist/styles/antd-theme.d.ts +2 -1
  17. package/packages/sdk/dist/styles/antd-theme.mjs +11 -3
  18. package/packages/sdk/dist/styles/antd-theme.mjs.map +1 -1
  19. package/packages/sdk/dist/styles/tailwind-preset.cjs +0 -1
  20. package/packages/sdk/dist/styles/tailwind-preset.cjs.map +1 -1
  21. package/packages/sdk/dist/styles/tailwind-preset.d.mts +0 -1
  22. package/packages/sdk/dist/styles/tailwind-preset.d.ts +0 -1
  23. package/packages/sdk/dist/styles/tailwind-preset.mjs +0 -1
  24. package/packages/sdk/dist/styles/tailwind-preset.mjs.map +1 -1
  25. package/packages/sdk/dist/styles/tokens.css +1 -0
  26. package/packages/sdk/src/build-source/scripts/build-forms.mjs +135 -50
  27. package/packages/sdk/src/build-source/scripts/build-pages.mjs +37 -10
  28. package/packages/sdk/src/build-source/scripts/register.mjs +2 -0
  29. package/packages/sdk/src/build-source/scripts/utils/load-config.mjs +3 -2
  30. package/packages/sdk/src/build-source/scripts/utils/register-payload.test.ts +2 -1
  31. package/packages/sdk/src/build-source/scripts/utils/tailwind-config.mjs +9 -7
  32. package/packages/sdk/src/build-source/scripts/utils/tailwind-config.test.ts +6 -4
  33. package/packages/sdk/src/build-source/src/cli.mjs +17 -0
  34. package/templates/sy-lowcode-app-workspace/app-workspace.config.ts +3 -3
  35. package/templates/sy-lowcode-app-workspace/postcss.config.cjs +0 -15
  36. package/templates/sy-lowcode-app-workspace/src/main.tsx +1 -12
@@ -1,4 +1,5 @@
1
1
  :root,
2
+ :root,
2
3
  .sy-app-workspace {
3
4
  --sy-color-primary: #1677ff;
4
5
  --sy-color-primary-hover: #4096ff;
@@ -9,7 +9,7 @@ import path from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
  import { gzipSync } from "node:zlib";
11
11
  import { build } from "vite";
12
- import { rootDir } from "./utils/load-config.mjs";
12
+ import { loadConfig, rootDir } from "./utils/load-config.mjs";
13
13
  import {
14
14
  cleanBuildCache,
15
15
  commitIncrementalBuild,
@@ -36,6 +36,7 @@ const tmpDir = path.join(rootDir, ".tmp");
36
36
  const runtimeVersionPlaceholder = "__SY_FORM_RUNTIME_VERSION__";
37
37
  const runtimeCacheFileName = "build-cache.json";
38
38
  const portalContainerResolverGlobal = "__OPENXIANGDA_GET_PORTAL_CONTAINER__";
39
+ let workspaceConfigPromise = null;
39
40
 
40
41
  const runtimePackages = [
41
42
  "react",
@@ -73,6 +74,20 @@ function readTextIfExists(filePath) {
73
74
  return fs.readFileSync(filePath, "utf-8");
74
75
  }
75
76
 
77
+ function normalizeCssIsolation(value) {
78
+ if (value === "namespace" || value === "shadow") return value;
79
+ return "none";
80
+ }
81
+
82
+ function usesNamespaceCss(cssIsolation) {
83
+ return cssIsolation === "namespace" || cssIsolation === "shadow";
84
+ }
85
+
86
+ function getWorkspaceConfig() {
87
+ if (!workspaceConfigPromise) workspaceConfigPromise = loadConfig();
88
+ return workspaceConfigPromise;
89
+ }
90
+
76
91
  function readPackageVersion(packageName) {
77
92
  try {
78
93
  let current = path.dirname(require.resolve(packageName));
@@ -92,10 +107,11 @@ function readPackageVersion(packageName) {
92
107
  }
93
108
  }
94
109
 
95
- function createRuntimeInputHash(runtimeEntryContent) {
110
+ function createRuntimeInputHash(runtimeEntryContent, cssIsolation) {
96
111
  const hash = crypto.createHash("sha256");
97
112
  const configFiles = [
98
113
  path.join(rootDir, "src/index.css"),
114
+ path.join(rootDir, "app-workspace.config.ts"),
99
115
  path.join(rootDir, "tailwind.config.cjs"),
100
116
  path.join(rootDir, "postcss.config.cjs"),
101
117
  fileURLToPath(import.meta.url),
@@ -107,6 +123,7 @@ function createRuntimeInputHash(runtimeEntryContent) {
107
123
 
108
124
  hash.update("sy-form-runtime-v2-input");
109
125
  hash.update(runtimeEntryContent);
126
+ hash.update(normalizeCssIsolation(cssIsolation));
110
127
  hash.update(JSON.stringify(packageVersions));
111
128
  configFiles.forEach((filePath) => {
112
129
  hash.update(filePath);
@@ -115,18 +132,21 @@ function createRuntimeInputHash(runtimeEntryContent) {
115
132
  return hash.digest("hex");
116
133
  }
117
134
 
118
- async function createCssOptions() {
135
+ async function createCssOptions(cssIsolation = "none") {
119
136
  const tailwindcssModule = await import("tailwindcss");
120
137
  const autoprefixerModule = await import("autoprefixer");
121
138
  const tailwindcss = tailwindcssModule.default ?? tailwindcssModule;
122
139
  const autoprefixer = autoprefixerModule.default ?? autoprefixerModule;
140
+ const plugins = [
141
+ tailwindcss({ config: path.join(rootDir, "tailwind.config.cjs") }),
142
+ ];
143
+ if (usesNamespaceCss(normalizeCssIsolation(cssIsolation))) {
144
+ plugins.push(createNamespaceCssPlugin());
145
+ }
146
+ plugins.push(autoprefixer());
123
147
  return {
124
148
  postcss: {
125
- plugins: [
126
- tailwindcss({ config: path.join(rootDir, "tailwind.config.cjs") }),
127
- createNamespaceCssPlugin(),
128
- autoprefixer(),
129
- ],
149
+ plugins,
130
150
  },
131
151
  };
132
152
  }
@@ -241,7 +261,7 @@ import { StyleProvider } from '@ant-design/cssinjs';
241
261
  import { App as AntdApp, ConfigProvider, message } from 'antd';
242
262
  import zhCN from 'antd/locale/zh_CN';
243
263
  import * as SyFormComponentsModule from 'openxiangda';
244
- import { antdTheme } from 'openxiangda/antd-theme';
264
+ import { antdTheme, legacyAntdTheme } from 'openxiangda/antd-theme';
245
265
  import 'antd-mobile/es/global';
246
266
  import '../src/index.css';
247
267
 
@@ -256,6 +276,33 @@ const PORTAL_CONTAINER_RESOLVER_GLOBAL = '${portalContainerResolverGlobal}';
256
276
  const MESSAGE_PROXY_GLOBAL = '__OPENXIANGDA_ANTD_MESSAGE_PROXY__';
257
277
  const MESSAGE_METHODS = ['open', 'success', 'info', 'warning', 'error', 'loading', 'destroy'];
258
278
  const portalContainers = new WeakMap();
279
+ const portalCssIsolations = new WeakMap();
280
+
281
+ function normalizeRuntimeCssIsolation(value) {
282
+ return value === 'namespace' || value === 'shadow' ? value : 'none';
283
+ }
284
+
285
+ function getRuntimeCssIsolation(context = {}) {
286
+ return normalizeRuntimeCssIsolation(
287
+ context.cssIsolation ||
288
+ context.runtime?.cssIsolation ||
289
+ context.page?.capabilities?.cssIsolation,
290
+ );
291
+ }
292
+
293
+ function usesLegacyCssIsolation(cssIsolation) {
294
+ return cssIsolation === 'namespace' || cssIsolation === 'shadow';
295
+ }
296
+
297
+ function getAntdRuntimeOptions(cssIsolation) {
298
+ const legacy = usesLegacyCssIsolation(cssIsolation);
299
+ return {
300
+ prefixCls: legacy ? 'sy-ant' : 'ant',
301
+ iconPrefixCls: legacy ? 'sy-anticon' : 'anticon',
302
+ messagePrefixCls: legacy ? 'sy-ant-message' : 'ant-message',
303
+ theme: legacy ? legacyAntdTheme : antdTheme,
304
+ };
305
+ }
259
306
 
260
307
  function getStyleContainer(el) {
261
308
  const rootNode = el.getRootNode?.();
@@ -291,14 +338,19 @@ function getTargetContainer(el) {
291
338
  return () => getRuntimeRoot(el);
292
339
  }
293
340
 
294
- function createAntdConfig(el, portalContainer) {
341
+ function createAntdConfig(el, portalContainer, cssIsolation) {
342
+ const antdOptions = getAntdRuntimeOptions(cssIsolation);
295
343
  return {
296
344
  locale: zhCN,
297
- prefixCls: 'sy-ant',
298
- iconPrefixCls: 'sy-anticon',
299
- theme: antdTheme,
300
- getPopupContainer: getPopupContainer(el, portalContainer),
301
- getTargetContainer: getTargetContainer(el),
345
+ prefixCls: antdOptions.prefixCls,
346
+ iconPrefixCls: antdOptions.iconPrefixCls,
347
+ theme: antdOptions.theme,
348
+ ...(usesLegacyCssIsolation(cssIsolation)
349
+ ? {
350
+ getPopupContainer: getPopupContainer(el, portalContainer),
351
+ getTargetContainer: getTargetContainer(el),
352
+ }
353
+ : {}),
302
354
  };
303
355
  }
304
356
 
@@ -352,12 +404,15 @@ function registerAntdMessageApi(api) {
352
404
  };
353
405
  }
354
406
 
355
- function installRuntimePortalContainer(el) {
356
- const portalContainer = createPortalContainer(el);
407
+ function installRuntimePortalContainer(el, cssIsolation) {
408
+ const portalContainer = usesLegacyCssIsolation(cssIsolation)
409
+ ? createPortalContainer(el)
410
+ : null;
357
411
  const stack = Array.isArray(globalThis[PORTAL_CONTAINER_STACK_GLOBAL])
358
412
  ? globalThis[PORTAL_CONTAINER_STACK_GLOBAL]
359
413
  : [];
360
- stack.push(portalContainer);
414
+ const stackTarget = portalContainer || el.ownerDocument.body;
415
+ stack.push(stackTarget);
361
416
  globalThis[PORTAL_CONTAINER_STACK_GLOBAL] = stack;
362
417
  globalThis[PORTAL_CONTAINER_RESOLVER_GLOBAL] = () => {
363
418
  for (let index = stack.length - 1; index >= 0; index -= 1) {
@@ -375,39 +430,44 @@ function installRuntimePortalContainer(el) {
375
430
  return {
376
431
  container: portalContainer,
377
432
  release: () => {
378
- const position = stack.lastIndexOf(portalContainer);
433
+ const position = stack.lastIndexOf(stackTarget);
379
434
  if (position >= 0) stack.splice(position, 1);
380
- portalContainer.remove();
435
+ portalContainer?.remove();
381
436
  },
382
437
  };
383
438
  }
384
439
 
385
- function installAntdStaticHolder(el, portalContainer) {
440
+ function installAntdStaticHolder(el, portalContainer, cssIsolation) {
386
441
  installAntdMessageProxy();
442
+ const antdOptions = getAntdRuntimeOptions(cssIsolation);
387
443
  const getMessageContainer = () =>
388
- portalContainer?.isConnected ? portalContainer : getRuntimeRoot(el);
444
+ portalContainer?.isConnected
445
+ ? portalContainer
446
+ : usesLegacyCssIsolation(cssIsolation)
447
+ ? getRuntimeRoot(el)
448
+ : document.body;
389
449
 
390
450
  ConfigProvider.config({
391
- prefixCls: 'sy-ant',
392
- iconPrefixCls: 'sy-anticon',
393
- theme: antdTheme,
451
+ prefixCls: antdOptions.prefixCls,
452
+ iconPrefixCls: antdOptions.iconPrefixCls,
453
+ theme: antdOptions.theme,
394
454
  holderRender: (children) => {
395
455
  if (!el.isConnected) {
396
456
  return (
397
- <ConfigProvider prefixCls="sy-ant" iconPrefixCls="sy-anticon" theme={antdTheme}>
457
+ <ConfigProvider prefixCls={antdOptions.prefixCls} iconPrefixCls={antdOptions.iconPrefixCls} theme={antdOptions.theme}>
398
458
  {children}
399
459
  </ConfigProvider>
400
460
  );
401
461
  }
402
462
  return (
403
463
  <StyleProvider hashPriority="high" container={getStyleContainer(el)}>
404
- <ConfigProvider {...createAntdConfig(el, portalContainer)}>{children}</ConfigProvider>
464
+ <ConfigProvider {...createAntdConfig(el, portalContainer, cssIsolation)}>{children}</ConfigProvider>
405
465
  </StyleProvider>
406
466
  );
407
467
  },
408
468
  });
409
469
  message.config({
410
- prefixCls: 'sy-ant-message',
470
+ prefixCls: antdOptions.messagePrefixCls,
411
471
  getContainer: getMessageContainer,
412
472
  });
413
473
  }
@@ -422,42 +482,62 @@ function RuntimeMessageBridge({ children }) {
422
482
 
423
483
  function renderStandardForm(el, schemaInput, context = {}) {
424
484
  let root = roots.get(el);
425
- el.classList.add(NAMESPACE_ROOT_CLASS);
485
+ const cssIsolation = getRuntimeCssIsolation(context);
486
+ if (usesLegacyCssIsolation(cssIsolation)) {
487
+ el.classList.add(NAMESPACE_ROOT_CLASS);
488
+ } else {
489
+ el.classList.remove(NAMESPACE_ROOT_CLASS);
490
+ }
426
491
  let portalContainer = portalContainers.get(el);
427
- if (!portalContainer?.isConnected) {
492
+ const previousCssIsolation = portalCssIsolations.get(el);
493
+ if (
494
+ previousCssIsolation !== cssIsolation ||
495
+ (usesLegacyCssIsolation(cssIsolation) && !portalContainer?.isConnected) ||
496
+ (!usesLegacyCssIsolation(cssIsolation) && portalContainer)
497
+ ) {
428
498
  const cleanup = portalContainerCleanups.get(el);
429
499
  if (cleanup) cleanup();
430
- const portalHandle = installRuntimePortalContainer(el);
500
+ const portalHandle = installRuntimePortalContainer(el, cssIsolation);
431
501
  portalContainer = portalHandle.container;
432
- portalContainers.set(el, portalContainer);
502
+ if (portalContainer) {
503
+ portalContainers.set(el, portalContainer);
504
+ } else {
505
+ portalContainers.delete(el);
506
+ }
507
+ portalCssIsolations.set(el, cssIsolation);
433
508
  portalContainerCleanups.set(el, portalHandle.release);
434
509
  }
435
- installAntdStaticHolder(el, portalContainer);
510
+ installAntdStaticHolder(el, portalContainer, cssIsolation);
436
511
  if (!root) {
437
512
  root = createRoot(el);
438
513
  roots.set(el, root);
439
514
  }
440
515
 
441
516
  const schema = defineFormSchema(schemaInput);
442
- const antdConfig = createAntdConfig(el, portalContainer);
517
+ const antdConfig = createAntdConfig(el, portalContainer, cssIsolation);
518
+ const content = (
519
+ <StandardFormPage
520
+ schema={schema}
521
+ mode={context.mode || 'submit'}
522
+ initialValues={context.initialValues}
523
+ permissions={context.permissions}
524
+ formUuid={context.formUuid}
525
+ appType={context.appType}
526
+ formInstanceId={context.formInstanceId}
527
+ onSubmit={context.onSubmit}
528
+ inDrawer={context.inDrawer}
529
+ />
530
+ );
443
531
  root.render(
444
532
  <StyleProvider hashPriority="high" container={getStyleContainer(el)}>
445
533
  <ConfigProvider {...antdConfig}>
446
534
  <AntdApp>
447
535
  <RuntimeMessageBridge>
448
- <div className="sy-app-workspace">
449
- <StandardFormPage
450
- schema={schema}
451
- mode={context.mode || 'submit'}
452
- initialValues={context.initialValues}
453
- permissions={context.permissions}
454
- formUuid={context.formUuid}
455
- appType={context.appType}
456
- formInstanceId={context.formInstanceId}
457
- onSubmit={context.onSubmit}
458
- inDrawer={context.inDrawer}
459
- />
460
- </div>
536
+ {usesLegacyCssIsolation(cssIsolation) ? (
537
+ <div className="sy-app-workspace">{content}</div>
538
+ ) : (
539
+ content
540
+ )}
461
541
  </RuntimeMessageBridge>
462
542
  </AntdApp>
463
543
  </ConfigProvider>
@@ -476,6 +556,7 @@ function unmountStandardForm(el) {
476
556
  releasePortalContainer();
477
557
  portalContainerCleanups.delete(el);
478
558
  portalContainers.delete(el);
559
+ portalCssIsolations.delete(el);
479
560
  }
480
561
  }
481
562
 
@@ -670,7 +751,9 @@ function logRuntimeAssetSummary(prefix = "共享 runtime") {
670
751
  async function buildSharedRuntime(options = {}) {
671
752
  const startedAt = Date.now();
672
753
  const entryContent = createRuntimeEntryContent();
673
- const inputHash = createRuntimeInputHash(entryContent);
754
+ const config = await getWorkspaceConfig();
755
+ const cssIsolation = normalizeCssIsolation(config.defaults?.cssIsolation);
756
+ const inputHash = createRuntimeInputHash(entryContent, cssIsolation);
674
757
  if (options.runtimeCache !== false && isRuntimeCacheValid(inputHash)) {
675
758
  console.log("[build] 表单共享 runtime 缓存命中,跳过构建");
676
759
  logRuntimeAssetSummary("缓存 runtime");
@@ -681,7 +764,7 @@ async function buildSharedRuntime(options = {}) {
681
764
 
682
765
  try {
683
766
  console.log("[build] 构建表单共享 runtime");
684
- const cssOptions = await createCssOptions();
767
+ const cssOptions = await createCssOptions(cssIsolation);
685
768
  const reactPlugin = await createReactPlugin();
686
769
  await build({
687
770
  configFile: false,
@@ -828,7 +911,9 @@ async function buildForm(form) {
828
911
 
829
912
  try {
830
913
  console.log(`[build] 构建表单: ${form.name} (shared runtime)`);
831
- const cssOptions = await createCssOptions();
914
+ const config = await getWorkspaceConfig();
915
+ const cssIsolation = normalizeCssIsolation(config.defaults?.cssIsolation);
916
+ const cssOptions = await createCssOptions(cssIsolation);
832
917
  const reactPlugin = await createReactPlugin();
833
918
  await build({
834
919
  configFile: false,
@@ -23,6 +23,7 @@ import {
23
23
  formatExtractedAssetSummary,
24
24
  } from "./utils/static-assets.mjs";
25
25
  import { warnShadcnTailwindTokens } from "./utils/tailwind-token-warnings.mjs";
26
+ import { loadConfig } from "./utils/load-config.mjs";
26
27
 
27
28
  process.env.NODE_ENV = "production";
28
29
  process.env.BABEL_ENV = "production";
@@ -40,6 +41,7 @@ const runtimeDistDir = path.join(distRoot, "page-runtime");
40
41
  const runtimeVersionPlaceholder = "__SY_PAGE_RUNTIME_VERSION__";
41
42
  const runtimeCacheFileName = "build-cache.json";
42
43
  const portalContainerResolverGlobal = "__OPENXIANGDA_GET_PORTAL_CONTAINER__";
44
+ let workspaceConfigPromise = null;
43
45
 
44
46
  const runtimePackages = [
45
47
  "react",
@@ -115,6 +117,20 @@ function readTextIfExists(filePath) {
115
117
  return fsSync.readFileSync(filePath, "utf-8");
116
118
  }
117
119
 
120
+ function normalizeCssIsolation(value) {
121
+ if (value === "namespace" || value === "shadow") return value;
122
+ return "none";
123
+ }
124
+
125
+ function usesNamespaceCss(cssIsolation) {
126
+ return cssIsolation === "namespace" || cssIsolation === "shadow";
127
+ }
128
+
129
+ function getWorkspaceConfig() {
130
+ if (!workspaceConfigPromise) workspaceConfigPromise = loadConfig();
131
+ return workspaceConfigPromise;
132
+ }
133
+
118
134
  function readPackageVersion(packageName) {
119
135
  try {
120
136
  let current = path.dirname(require.resolve(packageName));
@@ -208,7 +224,7 @@ build-pages - 构建复杂代码页
208
224
  `);
209
225
  }
210
226
 
211
- function createRuntimeInputHash(runtimeEntryContent) {
227
+ function createRuntimeInputHash(runtimeEntryContent, cssIsolation) {
212
228
  const hash = crypto.createHash("sha256");
213
229
  const packageVersions = runtimePackages.reduce((result, packageName) => {
214
230
  result[packageName] = readPackageVersion(packageName);
@@ -216,6 +232,7 @@ function createRuntimeInputHash(runtimeEntryContent) {
216
232
  }, {});
217
233
  const configFiles = [
218
234
  path.join(rootDir, "src/index.css"),
235
+ path.join(rootDir, "app-workspace.config.ts"),
219
236
  path.join(rootDir, "tailwind.config.cjs"),
220
237
  path.join(rootDir, "postcss.config.cjs"),
221
238
  fileURLToPath(import.meta.url),
@@ -223,6 +240,7 @@ function createRuntimeInputHash(runtimeEntryContent) {
223
240
 
224
241
  hash.update("sy-page-runtime-v1-input");
225
242
  hash.update(runtimeEntryContent);
243
+ hash.update(normalizeCssIsolation(cssIsolation));
226
244
  hash.update(JSON.stringify(packageVersions));
227
245
  configFiles.forEach((filePath) => {
228
246
  hash.update(filePath);
@@ -329,18 +347,21 @@ function isRuntimeCacheValid(inputHash) {
329
347
  return true;
330
348
  }
331
349
 
332
- async function createCssOptions() {
350
+ async function createCssOptions(cssIsolation = "none") {
333
351
  const tailwindcssModule = await import("tailwindcss");
334
352
  const autoprefixerModule = await import("autoprefixer");
335
353
  const tailwindcss = tailwindcssModule.default ?? tailwindcssModule;
336
354
  const autoprefixer = autoprefixerModule.default ?? autoprefixerModule;
355
+ const plugins = [
356
+ tailwindcss({ config: path.join(rootDir, "tailwind.config.cjs") }),
357
+ ];
358
+ if (usesNamespaceCss(normalizeCssIsolation(cssIsolation))) {
359
+ plugins.push(createNamespaceCssPlugin());
360
+ }
361
+ plugins.push(autoprefixer());
337
362
  return {
338
363
  postcss: {
339
- plugins: [
340
- tailwindcss({ config: path.join(rootDir, "tailwind.config.cjs") }),
341
- createNamespaceCssPlugin(),
342
- autoprefixer(),
343
- ],
364
+ plugins,
344
365
  },
345
366
  };
346
367
  }
@@ -375,7 +396,9 @@ function createResolveAlias() {
375
396
  async function buildSharedRuntime(options = {}) {
376
397
  const startedAt = Date.now();
377
398
  const entryContent = createRuntimeEntryContent();
378
- const inputHash = createRuntimeInputHash(entryContent);
399
+ const config = await getWorkspaceConfig();
400
+ const cssIsolation = normalizeCssIsolation(config.defaults?.cssIsolation);
401
+ const inputHash = createRuntimeInputHash(entryContent, cssIsolation);
379
402
  if (options.runtimeCache !== false && isRuntimeCacheValid(inputHash)) {
380
403
  const manifest = readRuntimeManifest();
381
404
  console.log(`[build] 代码页共享 runtime 缓存命中: ${manifest.version}`);
@@ -386,7 +409,7 @@ async function buildSharedRuntime(options = {}) {
386
409
  await fs.writeFile(entryPath, entryContent, "utf8");
387
410
 
388
411
  try {
389
- const cssOptions = await createCssOptions();
412
+ const cssOptions = await createCssOptions(cssIsolation);
390
413
  console.log("[build] 构建代码页共享 runtime");
391
414
  await build({
392
415
  configFile: false,
@@ -692,7 +715,11 @@ async function buildPage(page) {
692
715
  const outDir = path.join(distRoot, "pages", page.config.code);
693
716
  await fs.mkdir(outDir, { recursive: true });
694
717
 
695
- const cssOptions = await createCssOptions();
718
+ const config = await getWorkspaceConfig();
719
+ const cssIsolation = normalizeCssIsolation(
720
+ page.config.cssIsolation || config.defaults?.cssIsolation,
721
+ );
722
+ const cssOptions = await createCssOptions(cssIsolation);
696
723
  await build({
697
724
  configFile: false,
698
725
  mode: "production",
@@ -130,6 +130,7 @@ async function registerForms() {
130
130
  runtime,
131
131
  formCssPath: path.resolve(rootDir, `dist/forms/${formName}/style.css`),
132
132
  }),
133
+ cssIsolation: config.defaults.cssIsolation,
133
134
  version: config.version,
134
135
  };
135
136
  if (runtime) {
@@ -164,6 +165,7 @@ async function registerForms() {
164
165
  ? {
165
166
  bundleUrl: payload.bundleUrl,
166
167
  cssUrl: payload.cssUrl,
168
+ cssIsolation: payload.cssIsolation,
167
169
  version: payload.version,
168
170
  runtimeMode: payload.runtimeMode,
169
171
  runtime: payload.runtime,
@@ -111,13 +111,14 @@ function normalizeBaseUrl(value) {
111
111
 
112
112
  function normalizeCssIsolation(value) {
113
113
  if (value === "none") return "none";
114
+ if (value === "namespace") return "namespace";
114
115
  if (value === "shadow") {
115
116
  console.warn(
116
- "[lowcode-workspace] cssIsolation='shadow' is deprecated; use 'namespace' instead.",
117
+ "[lowcode-workspace] cssIsolation='shadow' is deprecated; use 'none' unless legacy isolation is required.",
117
118
  );
118
119
  return "shadow";
119
120
  }
120
- return "namespace";
121
+ return "none";
121
122
  }
122
123
 
123
124
  export function resolveOpenXiangdaEndpointConfig(baseUrl) {
@@ -19,7 +19,7 @@ const config = {
19
19
  defaults: {
20
20
  frameworkVersion: "19.0.0",
21
21
  protocolVersion: "1.0",
22
- cssIsolation: "namespace",
22
+ cssIsolation: "none",
23
23
  pageMenuParentId: "MENU_PARENT",
24
24
  pageMenuIcon: "dashboard",
25
25
  },
@@ -105,6 +105,7 @@ describe("register payload helpers", () => {
105
105
  hidePlatformNav: true,
106
106
  defaultRoute: "home",
107
107
  });
108
+ expect(payload.pages[0].runtime.cssIsolation).toBe("none");
108
109
  expect(JSON.stringify(payload)).not.toMatch(/manifest/i);
109
110
  });
110
111
 
@@ -29,12 +29,10 @@ const layeredTailwindCss = `@layer tailwind-base {
29
29
  `;
30
30
  const canonicalPostcssConfig = `const tailwindcss = require("tailwindcss");
31
31
  const autoprefixer = require("autoprefixer");
32
- const { createOpenXiangdaNamespaceCssPlugin } = require("openxiangda/build");
33
32
 
34
33
  module.exports = {
35
34
  plugins: [
36
35
  tailwindcss(),
37
- createOpenXiangdaNamespaceCssPlugin(),
38
36
  autoprefixer(),
39
37
  ],
40
38
  };
@@ -83,10 +81,10 @@ export function isWorkspaceTailwindCssCurrent(content) {
83
81
 
84
82
  export function isWorkspacePostcssConfigCurrent(content) {
85
83
  return Boolean(
86
- content.includes("createOpenXiangdaNamespaceCssPlugin") &&
87
- content.includes("openxiangda/build") &&
88
- content.includes("tailwindcss") &&
89
- content.includes("autoprefixer"),
84
+ !content.includes("createOpenXiangdaNamespaceCssPlugin") &&
85
+ /plugins\s*:\s*\[[\s\S]*tailwindcss\(\)[\s\S]*autoprefixer\(/s.test(
86
+ content,
87
+ ),
90
88
  );
91
89
  }
92
90
 
@@ -211,7 +209,11 @@ function isStandardPostcssConfig(content) {
211
209
 
212
210
  export function patchWorkspacePostcssConfig(content) {
213
211
  if (isWorkspacePostcssConfigCurrent(content)) return content;
214
- if (!content.trim() || isStandardPostcssConfig(content)) {
212
+ if (
213
+ !content.trim() ||
214
+ isStandardPostcssConfig(content) ||
215
+ content.includes("createOpenXiangdaNamespaceCssPlugin")
216
+ ) {
215
217
  return canonicalPostcssConfig;
216
218
  }
217
219
  return content;
@@ -58,8 +58,10 @@ describe("workspace Tailwind config helpers", () => {
58
58
  expect(cssContent).toContain("@tailwind base;");
59
59
  expect(cssContent).toContain("@tailwind components;");
60
60
  expect(cssContent).toContain("@tailwind utilities;");
61
- expect(postcssContent).toContain("createOpenXiangdaNamespaceCssPlugin");
62
- expect(postcssContent).toContain('require("openxiangda/build")');
61
+ expect(postcssContent).toContain("tailwindcss()");
62
+ expect(postcssContent).toContain("autoprefixer()");
63
+ expect(postcssContent).not.toContain("createOpenXiangdaNamespaceCssPlugin");
64
+ expect(postcssContent).not.toContain('require("openxiangda/build")');
63
65
  expect(cssContent).not.toContain('@import "openxiangda/styles/tokens.css";');
64
66
  expect(validateWorkspaceTailwindConfig(workspaceRoot)).toEqual([]);
65
67
  });
@@ -176,7 +178,7 @@ module.exports = {
176
178
  expect(nextContent).toContain("#root");
177
179
  });
178
180
 
179
- it("patches standard PostCSS config with openxiangda namespace css plugin", () => {
181
+ it("patches standard PostCSS config without the namespace css plugin", () => {
180
182
  const nextContent = patchWorkspacePostcssConfig(`module.exports = {
181
183
  plugins: {
182
184
  tailwindcss: {},
@@ -185,9 +187,9 @@ module.exports = {
185
187
  };
186
188
  `);
187
189
 
188
- expect(nextContent).toContain("createOpenXiangdaNamespaceCssPlugin");
189
190
  expect(nextContent).toContain("tailwindcss()");
190
191
  expect(nextContent).toContain("autoprefixer()");
192
+ expect(nextContent).not.toContain("createOpenXiangdaNamespaceCssPlugin");
191
193
  });
192
194
 
193
195
  it("preserves custom PostCSS config when it cannot be patched safely", () => {
@@ -460,6 +460,22 @@ function rewriteLocalSdkConfig(workspaceRoot) {
460
460
  }
461
461
  }
462
462
 
463
+ function rewriteCssIsolationDefault(workspaceRoot) {
464
+ const configPath = join(workspaceRoot, "app-workspace.config.ts");
465
+ if (!existsSync(configPath)) return;
466
+ replaceInFile(configPath, (content) =>
467
+ content.replace(
468
+ /cssIsolation:\s*\n\s*process\.env\.APP_PAGE_CSS_ISOLATION === ["']none["']\s*\n\s*\?\s*["']none["']\s*\n\s*:\s*process\.env\.APP_PAGE_CSS_ISOLATION === ["']shadow["']\s*\n\s*\?\s*["']shadow["']\s*\n\s*:\s*["']namespace["']/g,
469
+ `cssIsolation:
470
+ process.env.APP_PAGE_CSS_ISOLATION === "namespace"
471
+ ? "namespace"
472
+ : process.env.APP_PAGE_CSS_ISOLATION === "shadow"
473
+ ? "shadow"
474
+ : "none"`,
475
+ ),
476
+ );
477
+ }
478
+
463
479
  function walkFiles(root, onFile) {
464
480
  for (const entry of readdirSync(root)) {
465
481
  if (ignoredDirs.has(entry)) continue;
@@ -675,6 +691,7 @@ async function updateWorkspace(argv, { migrate = false } = {}) {
675
691
 
676
692
  updatePackageJson(workspaceRoot, channel);
677
693
  rewriteImports(workspaceRoot);
694
+ rewriteCssIsolationDefault(workspaceRoot);
678
695
  ensureWorkspaceTailwindConfig(workspaceRoot);
679
696
  ensureWrapperScripts(workspaceRoot);
680
697
  rewriteLocalSdkConfig(workspaceRoot);
@@ -21,11 +21,11 @@ export default defineAppWorkspaceConfig({
21
21
  protocolVersion: process.env.APP_PAGE_PROTOCOL_VERSION || "1.0",
22
22
  frameworkVersion: process.env.APP_FRAMEWORK_VERSION || "18.3.1",
23
23
  cssIsolation:
24
- process.env.APP_PAGE_CSS_ISOLATION === "none"
25
- ? "none"
24
+ process.env.APP_PAGE_CSS_ISOLATION === "namespace"
25
+ ? "namespace"
26
26
  : process.env.APP_PAGE_CSS_ISOLATION === "shadow"
27
27
  ? "shadow"
28
- : "namespace",
28
+ : "none",
29
29
  formMenuParentId: process.env.APP_FORM_MENU_PARENT_ID || "",
30
30
  formMenuIcon: process.env.APP_FORM_MENU_ICON || "",
31
31
  pageMenuParentId: process.env.APP_PAGE_MENU_PARENT_ID || "",
@@ -1,24 +1,9 @@
1
1
  const tailwindcss = require("tailwindcss");
2
2
  const autoprefixer = require("autoprefixer");
3
3
 
4
- function loadOpenXiangdaBuild() {
5
- try {
6
- return require("openxiangda/build");
7
- } catch (error) {
8
- try {
9
- return require("../../packages/sdk/dist/build/index.cjs");
10
- } catch {
11
- throw error;
12
- }
13
- }
14
- }
15
-
16
- const { createOpenXiangdaNamespaceCssPlugin } = loadOpenXiangdaBuild();
17
-
18
4
  module.exports = {
19
5
  plugins: [
20
6
  tailwindcss(),
21
- createOpenXiangdaNamespaceCssPlugin(),
22
7
  autoprefixer(),
23
8
  ],
24
9
  };