@ethisyscore/vite-plugin 1.121.0 → 1.123.0

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
@@ -456,7 +456,7 @@ function ethisysContractBPlugin(options = {}) {
456
456
  const externalSpecifiers = new Set(CONTRACT_B_IMPORT_MAP_ALLOWLIST);
457
457
  return {
458
458
  build: {
459
- rollupOptions: {
459
+ rolldownOptions: {
460
460
  input: { worker: slash(workerEntryAbs) },
461
461
  external: (id) => externalSpecifiers.has(id),
462
462
  // CRITICAL: single-file output for the worker bundle. The
@@ -464,7 +464,7 @@ function ethisysContractBPlugin(options = {}) {
464
464
  // chunk splitting or dynamic-import shards would defeat it.
465
465
  output: {
466
466
  format: "es",
467
- inlineDynamicImports: true,
467
+ codeSplitting: false,
468
468
  entryFileNames: `${outputPrefix}[name].js`,
469
469
  chunkFileNames: `${outputPrefix}[name]-[hash].js`,
470
470
  assetFileNames: `${outputPrefix}[name][extname]`
@@ -598,6 +598,48 @@ function ethisysContractBPlugin(options = {}) {
598
598
  };
599
599
  }
600
600
 
601
+ // src/utils/inline-css-sourcemap-log.ts
602
+ var PRE_CSS_POST_PLUGIN = /^(?:@tailwindcss\/vite:|vite:css$)/;
603
+ function isInlineCssSourcemapNoise(log) {
604
+ return log.code === "SOURCEMAP_BROKEN" && PRE_CSS_POST_PLUGIN.test(log.plugin ?? "") && /\.css\?(?:[^#]*&)?inline(?:[&=#]|$)/.test(log.id ?? "");
605
+ }
606
+ function dropInlineCssSourcemapNoise(next) {
607
+ const filtered = (level, log, handler) => {
608
+ if (isInlineCssSourcemapNoise(log)) {
609
+ return;
610
+ }
611
+ if (next) {
612
+ next(level, log, handler);
613
+ return;
614
+ }
615
+ handler(level, log);
616
+ };
617
+ return Object.assign(filtered, { [WRAPPED]: true });
618
+ }
619
+ var WRAPPED = /* @__PURE__ */ Symbol.for("ethisys.vite-plugin.inline-css-sourcemap-noise");
620
+ function wrapResolvedOnLog(config) {
621
+ const writable = config;
622
+ writable.build ??= {};
623
+ writable.build.rolldownOptions ??= {};
624
+ const current = writable.build.rolldownOptions.onLog;
625
+ if (current && current[WRAPPED]) {
626
+ return;
627
+ }
628
+ writable.build.rolldownOptions.onLog = dropInlineCssSourcemapNoise(current);
629
+ }
630
+ function inlineCssSourcemapNoisePlugin() {
631
+ return {
632
+ name: "ethisys-inline-css-sourcemap-noise",
633
+ apply: "build",
634
+ buildStart() {
635
+ const config = this?.environment?.config;
636
+ if (config) {
637
+ wrapResolvedOnLog(config);
638
+ }
639
+ }
640
+ };
641
+ }
642
+
601
643
  // src/utils/strings.ts
602
644
  function slash2(p) {
603
645
  return p.replace(/\\/g, "/");
@@ -938,6 +980,36 @@ var PLATFORM_REACT_EXTERNALS = [
938
980
  "react-dom",
939
981
  "@mui/material",
940
982
  "@mui/icons-material",
983
+ // MUI X. Every plugin previously shipped its own copy on top of the host's.
984
+ //
985
+ // EXACT STRINGS, and that is load-bearing rather than stylistic. Rolldown matches
986
+ // a string `external` by equality, verified by building an entry that imports both
987
+ // `date-fns` and `date-fns/addDays` against `external: ["date-fns"]`: the bare
988
+ // import stayed external, the subpath was bundled. So a prefix or regex matcher
989
+ // here would externalise `@mui/x-data-grid/style.css` and
990
+ // `@mui/x-date-pickers/AdapterDayjs` too, which the host does NOT register, and an
991
+ // external the host does not serve is an unresolvable bare import that kills the
992
+ // bundle before any plugin code runs. `startsWith("@mui/x-charts")` additionally
993
+ // swallows `@mui/x-charts-pro`. Add specifiers one at a time; never widen the match.
994
+ //
995
+ // THE CONSUMER-SIDE GATE: exact matching makes this safe but PARTIAL. A plugin that
996
+ // imports the package root AND a subpath of the same package gets TWO module
997
+ // instances, host-served and bundled, and React context does not cross that seam.
998
+ // The concrete break is `LocalizationProvider` from "@mui/x-date-pickers" (host)
999
+ // with `DatePicker` from "@mui/x-date-pickers/DatePicker" (bundled): the picker
1000
+ // cannot see the provider's context and MUI throws "Can not find the date and time
1001
+ // pickers localization context". Every root-exported symbol must therefore be
1002
+ // imported from the ROOT once its package is externalised.
1003
+ //
1004
+ // `@mui/x-date-pickers/AdapterDayjs` is the deliberate exception and stays a
1005
+ // sub-path import, because the root does not re-export it. That is safe here and it
1006
+ // was checked rather than assumed: `LocalizationProvider` validates the adapter with
1007
+ // `if (!dateAdapter.isMUIAdapter)`, a duck-typed flag, so a bundled adapter instance
1008
+ // handed to the host's provider passes. Contrast `instanceof`, which would not.
1009
+ "@mui/x-data-grid",
1010
+ "@mui/x-charts",
1011
+ "@mui/x-charts-pro",
1012
+ "@mui/x-date-pickers",
941
1013
  "@emotion/react",
942
1014
  "@emotion/styled",
943
1015
  "date-fns",
@@ -1029,6 +1101,34 @@ function rewriteAliasedExternalImports() {
1029
1101
  }
1030
1102
  };
1031
1103
  }
1104
+ function assertHostResolvableExternals(external) {
1105
+ return {
1106
+ name: "assert-host-resolvable-externals",
1107
+ renderChunk(code, chunk) {
1108
+ const offences = [];
1109
+ for (const spec of external) {
1110
+ const q = escapeRegExp(spec);
1111
+ const reExport = new RegExp(`\\bexport\\s[^;]{0,200}?from\\s*["']${q}["']`);
1112
+ const dynamic = new RegExp(`\\bimport\\s*\\(\\s*["']${q}["']\\s*\\)`);
1113
+ if (reExport.test(code)) {
1114
+ offences.push(`re-export of "${spec}" (export \u2026 from)`);
1115
+ }
1116
+ if (dynamic.test(code)) {
1117
+ offences.push(`dynamic import of "${spec}"`);
1118
+ }
1119
+ }
1120
+ if (offences.length > 0) {
1121
+ throw new Error(
1122
+ `[build-pages] ${chunk.fileName ?? "bundle"} emits host-provided specifiers in a form the host loader cannot rewrite, so the surface would fail to load at mount:
1123
+ ` + offences.map((o) => ` - ${o}`).join("\n") + `
1124
+
1125
+ Use a STATIC top-level import of the package root instead. A dynamic import of a host-provided package is never needed: the host already loads its namespaces on demand, per bundle. For a re-export, import the symbols and export them explicitly.`
1126
+ );
1127
+ }
1128
+ return null;
1129
+ }
1130
+ };
1131
+ }
1032
1132
  function virtualPageEntry(page, config) {
1033
1133
  const VIRTUAL_ID = `\0virtual:surface/${page.id}`;
1034
1134
  const views = page.views ?? {};
@@ -1117,7 +1217,10 @@ function makeDefaultBuild(viteBuild) {
1117
1217
  ctx.surfacePlugin,
1118
1218
  ...ctx.plugins,
1119
1219
  scopePluginCssPlugin(),
1120
- rewriteAliasedExternalImports()
1220
+ rewriteAliasedExternalImports(),
1221
+ // Last, so it sees exactly the bytes the host will fetch.
1222
+ assertHostResolvableExternals(ctx.external),
1223
+ inlineCssSourcemapNoisePlugin()
1121
1224
  ],
1122
1225
  resolve: {
1123
1226
  dedupe: [...ctx.dedupe],
@@ -1145,13 +1248,13 @@ function makeDefaultBuild(viteBuild) {
1145
1248
  cssMinify: ctx.cssMinify ?? true,
1146
1249
  reportCompressedSize: ctx.reportCompressedSize ?? false,
1147
1250
  sourcemap: ctx.sourcemap,
1148
- rollupOptions: {
1251
+ rolldownOptions: {
1149
1252
  input: { [ctx.pageId]: ctx.entryId },
1150
1253
  preserveEntrySignatures: "strict",
1151
1254
  external: [...ctx.external],
1152
1255
  output: {
1153
1256
  format: "es",
1154
- inlineDynamicImports: true,
1257
+ codeSplitting: false,
1155
1258
  sourcemapExcludeSources: ctx.sourcemapExcludeSources ?? true,
1156
1259
  entryFileNames: `${ctx.outputPrefix}/[name].js`,
1157
1260
  chunkFileNames: `${ctx.outputPrefix}/[name]-[hash].js`,
@@ -1348,7 +1451,11 @@ function assertHostOriginRelativePath2(value, label) {
1348
1451
  }
1349
1452
  }
1350
1453
  function ethisysPlatformReactPlugin(options = {}) {
1351
- return [ethisysPlatformReactPagesPlugin(options), scopePluginCssPlugin()];
1454
+ return [
1455
+ ethisysPlatformReactPagesPlugin(options),
1456
+ scopePluginCssPlugin(),
1457
+ assertHostResolvableExternals([...PLATFORM_REACT_EXTERNALS, "@ethisyscore/host-ui-externals"])
1458
+ ];
1352
1459
  }
1353
1460
  function ethisysPlatformReactPagesPlugin(options = {}) {
1354
1461
  const explicitRoot = options.root;
@@ -1498,7 +1605,7 @@ function ethisysPlatformReactPagesPlugin(options = {}) {
1498
1605
  // throws on the first hook). Vite minifies production builds by
1499
1606
  // default, so this MUST be forced off for every PlatformReact surface.
1500
1607
  minify: false,
1501
- rollupOptions: {
1608
+ rolldownOptions: {
1502
1609
  // CRITICAL: single-file ESM output per page. The host loads each
1503
1610
  // page via `import(url)` at mount time and reads the declared
1504
1611
  // `exportName` from the resulting module namespace. Chunk-split
@@ -1506,7 +1613,7 @@ function ethisysPlatformReactPagesPlugin(options = {}) {
1506
1613
  // import-map surface to resolve sibling chunks.
1507
1614
  output: {
1508
1615
  format: "es",
1509
- inlineDynamicImports: true,
1616
+ codeSplitting: false,
1510
1617
  entryFileNames: `${outputPrefix}[name].js`,
1511
1618
  chunkFileNames: `${outputPrefix}[name]-[hash].js`,
1512
1619
  assetFileNames: `${outputPrefix}[name][extname]`
@@ -1559,25 +1666,29 @@ function ethisysPlatformReactPagesPlugin(options = {}) {
1559
1666
  }
1560
1667
  const writable = config;
1561
1668
  writable.build ??= {};
1562
- writable.build.rollupOptions ??= {};
1563
- const rollupOptions = writable.build.rollupOptions;
1564
- const existing = rollupOptions.input;
1669
+ writable.build.rolldownOptions ??= {};
1670
+ const rolldownOptions = writable.build.rolldownOptions;
1671
+ const existing = rolldownOptions.input;
1565
1672
  if (existing && typeof existing === "object" && !Array.isArray(existing)) {
1566
- rollupOptions.input = { ...existing, ...input };
1673
+ rolldownOptions.input = { ...existing, ...input };
1567
1674
  } else if (typeof existing === "string") {
1568
- rollupOptions.input = { _entry: existing, ...input };
1675
+ rolldownOptions.input = { _entry: existing, ...input };
1569
1676
  } else if (Array.isArray(existing)) {
1570
1677
  const indexed = {};
1571
1678
  existing.forEach((entry, idx) => {
1572
1679
  indexed[`_entry${idx}`] = entry;
1573
1680
  });
1574
- rollupOptions.input = { ...indexed, ...input };
1681
+ rolldownOptions.input = { ...indexed, ...input };
1575
1682
  } else {
1576
- rollupOptions.input = input;
1683
+ rolldownOptions.input = input;
1577
1684
  }
1578
1685
  },
1579
1686
  buildStart() {
1580
1687
  validate();
1688
+ const config = this?.environment?.config;
1689
+ if (isBuild && config) {
1690
+ wrapResolvedOnLog(config);
1691
+ }
1581
1692
  },
1582
1693
  /**
1583
1694
  * Emit the companion `platform-react-pages.json` listing every declared
@@ -1956,7 +2067,7 @@ var defaultBuild = async (page) => {
1956
2067
  build: {
1957
2068
  outDir: page.outDir,
1958
2069
  emptyOutDir: true,
1959
- rollupOptions: {
2070
+ rolldownOptions: {
1960
2071
  input: path.resolve(page.root, page.entryPath)
1961
2072
  }
1962
2073
  }
@@ -2176,7 +2287,7 @@ function ethisysManifestPlugin(options = {}) {
2176
2287
  }
2177
2288
  return {
2178
2289
  build: {
2179
- rollupOptions: {
2290
+ rolldownOptions: {
2180
2291
  input
2181
2292
  }
2182
2293
  }
@@ -2294,6 +2405,7 @@ exports.EHX_PLUGIN_SCOPE_ROOTS = EHX_PLUGIN_SCOPE_ROOTS;
2294
2405
  exports.EHX_SCOPED_CSS_LAYERS = EHX_SCOPED_CSS_LAYERS;
2295
2406
  exports.PLATFORM_REACT_DEDUPE = PLATFORM_REACT_DEDUPE;
2296
2407
  exports.PLATFORM_REACT_EXTERNALS = PLATFORM_REACT_EXTERNALS;
2408
+ exports.assertHostResolvableExternals = assertHostResolvableExternals;
2297
2409
  exports.buildIframeSandboxPages = buildIframeSandboxPages;
2298
2410
  exports.buildPlatformReactPages = buildPlatformReactPages;
2299
2411
  exports.computePlatformReactPages = computePlatformReactPages;