evolit 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -346,6 +346,36 @@ virtual modules, generation, finalization or global CSS links, and it does not n
346
346
  PostCSS. `@litsx/unocss` remains the owner of candidate extraction and CSS generation; Evolit only
347
347
  executes its neutral LitSX lifecycle.
348
348
 
349
+ Tailwind CSS uses the same neutral integration contract, without an Evolit adapter or application
350
+ owned Vite/PostCSS pipeline:
351
+
352
+ ```js
353
+ import { litsxTailwind } from "@litsx/tailwind";
354
+ import { defineEvolitConfig } from "evolit/litsx";
355
+
356
+ export default defineEvolitConfig({
357
+ litsx: {
358
+ compiler: { sourceMaps: true },
359
+ integrations: [
360
+ litsxTailwind({ integration: { entry: "./tailwind.css" } }),
361
+ ],
362
+ },
363
+ });
364
+ ```
365
+
366
+ ```css
367
+ /* tailwind.css */
368
+ @import "tailwindcss" source(none);
369
+
370
+ @theme {
371
+ --color-brand: oklch(62% 0.18 255);
372
+ }
373
+ ```
374
+
375
+ `source(none)` is recommended because LitSX owns candidate discovery and routes each finite class
376
+ to its component. `@litsx/tailwind` owns Tailwind compilation, virtual modules, dependency
377
+ invalidation, stale-candidate removal and the single document stylesheet.
378
+
349
379
  `compiler` accepts the public `TransformLitsxOptions` surface except the values Evolit must own for
350
380
  correct server and browser graphs. Evolit always supplies the current `filename`, selects `ssr` per
351
381
  target and forces native lowering with `reactCompat: false`; `compiler.sourceMaps` can override the
@@ -383,6 +413,11 @@ Root, preserves authored `Component.styles` before generated utilities, and emit
383
413
  theme/custom-property layers once. Those document variables inherit through Shadow Roots and the
384
414
  browser hydrates the server result without switching to `react-compat`.
385
415
 
416
+ `@litsx/tailwind` follows the same ordering and ownership rules: Shadow Root preflight, authored
417
+ `Component.styles`, then component-owned utilities. Its `global.css` output contains theme/custom
418
+ properties, document preflight, Tailwind property registrations and light-DOM utilities exactly
419
+ once. Component utilities are not copied into that document asset.
420
+
386
421
  ## Server Setup
387
422
 
388
423
  Server integrations that need one-time application setup can be registered with
@@ -409,6 +444,12 @@ configuration therefore stays isolated per render, extracted SSR data is read
409
444
  before the scope closes, and integration response headers are included before
410
445
  the response is cached.
411
446
 
447
+ The supported SSR combination is `evolit@0.4.4` or newer,
448
+ `@litsx/core@1.0.0-next.8` or newer, and `@litsx/urql@0.4.2` or newer. Evolit
449
+ resolves the server-conditioned URQL adapter from the application project and
450
+ uses that same module instance for setup, request resources, route rendering,
451
+ SSR extraction, and cleanup.
452
+
412
453
  ## Extensions
413
454
 
414
455
  Optional integrations are configured explicitly in `evolit.config.js`. Core only coordinates their
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "evolit",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "A convention-driven application framework for LitSX and web components.",
5
5
  "type": "module",
6
6
  "packageManager": "yarn@4.10.3",
@@ -75,7 +75,7 @@
75
75
  "ws": "^8.18.3"
76
76
  },
77
77
  "peerDependencies": {
78
- "@litsx/urql": "^0.4.0"
78
+ "@litsx/urql": "^0.4.2"
79
79
  },
80
80
  "peerDependenciesMeta": {
81
81
  "@litsx/urql": {
@@ -83,7 +83,9 @@
83
83
  }
84
84
  },
85
85
  "devDependencies": {
86
+ "@litsx/tailwind": "1.0.0-next.8",
86
87
  "@litsx/unocss": "1.0.0-next.8",
88
+ "@litsx/urql": "^0.4.2",
87
89
  "@playwright/test": "^1.62.0",
88
90
  "@webcomponents/scoped-custom-element-registry": "^0.0.10",
89
91
  "unocss": "66.8.1",
package/src/build.js CHANGED
@@ -606,7 +606,7 @@ export async function buildProject(projectRoot, options = {}) {
606
606
  urqlRequestContext,
607
607
  ),
608
608
  };
609
- });
609
+ }, { projectRoot });
610
610
  if (!response) {
611
611
  continue;
612
612
  }
@@ -581,7 +581,22 @@ function createSharedChunkGroup(id) {
581
581
  return "vendor-litsx";
582
582
  }
583
583
 
584
- return "vendor-misc";
584
+ return undefined;
585
+ }
586
+
587
+ function createBrowserEnvironmentPlugin(mode) {
588
+ const nodeEnvironment = mode === "production" ? "production" : "development";
589
+ const replacement = JSON.stringify(nodeEnvironment);
590
+ return {
591
+ name: "evolit-browser-environment",
592
+ transform(code) {
593
+ if (!code.includes("process.env.NODE_ENV")) return null;
594
+ return {
595
+ code: code.replaceAll("process.env.NODE_ENV", replacement),
596
+ map: null,
597
+ };
598
+ },
599
+ };
585
600
  }
586
601
 
587
602
  function isClientAssetStubModule(relativePath) {
@@ -746,6 +761,7 @@ export async function buildSharedVendorRuntime(
746
761
  .map((group) => buildSharedVendorRuntime(projectRoot, mode, {
747
762
  ...options,
748
763
  additionalEntrySpecifiers: group.specifiers,
764
+ externalSpecifiers: developmentGroups.baseSpecifiers,
749
765
  vendorGroup: group.vendorGroup,
750
766
  includeBase: false,
751
767
  })),
@@ -790,9 +806,16 @@ export async function buildSharedVendorRuntime(
790
806
  const specifierByEntryName = new Map(
791
807
  specifiers.map((specifier) => [createSharedEntryName(specifier), specifier]),
792
808
  );
809
+ const externalSpecifiers = new Set(
810
+ Array.isArray(options.externalSpecifiers) ? options.externalSpecifiers : [],
811
+ );
793
812
  const bundle = await rollup({
794
813
  input: inputEntries,
814
+ external(source) {
815
+ return externalSpecifiers.has(source);
816
+ },
795
817
  plugins: [
818
+ createBrowserEnvironmentPlugin(mode),
796
819
  {
797
820
  name: "evolit-browser-exports",
798
821
  resolveId(source) {
@@ -814,10 +837,6 @@ export async function buildSharedVendorRuntime(
814
837
  ],
815
838
  preserveEntrySignatures: "strict",
816
839
  onwarn(warning, warn) {
817
- if (warning.code === "CIRCULAR_DEPENDENCY") {
818
- return;
819
- }
820
-
821
840
  warn(warning);
822
841
  },
823
842
  });
@@ -836,6 +855,10 @@ export async function buildSharedVendorRuntime(
836
855
  manualChunks(id) {
837
856
  return createSharedChunkGroup(id);
838
857
  },
858
+ paths(id) {
859
+ if (!externalSpecifiers.has(id)) return id;
860
+ return `/_evolit/shared/base/${createSharedEntryName(id)}.mjs`;
861
+ },
839
862
  });
840
863
 
841
864
  const imports = {};
@@ -930,7 +930,7 @@ export async function createRequestRenderer({
930
930
  routeResult,
931
931
  response,
932
932
  };
933
- });
933
+ }, { projectRoot });
934
934
  },
935
935
  get assetManifest() {
936
936
  return currentAssetManifest;
package/src/urql-ssr.js CHANGED
@@ -1,13 +1,18 @@
1
- let adapterPromise = null;
1
+ import { createRequire } from "node:module";
2
+ import path from "node:path";
3
+ import { pathToFileURL } from "node:url";
4
+
5
+ const adapterPromisesByModuleUrl = new Map();
2
6
 
3
7
  function isMissingUrqlAdapter(error) {
4
- return error?.code === "ERR_MODULE_NOT_FOUND"
8
+ return (error?.code === "ERR_MODULE_NOT_FOUND" || error?.code === "MODULE_NOT_FOUND")
5
9
  && String(error.message).includes("@litsx/urql");
6
10
  }
7
11
 
8
- async function loadSsrUrqlAdapter() {
12
+ function resolveSsrUrqlAdapterUrl(projectRoot) {
9
13
  try {
10
- return await import("@litsx/urql");
14
+ const requireFromProject = createRequire(path.join(path.resolve(projectRoot), "package.json"));
15
+ return pathToFileURL(requireFromProject.resolve("@litsx/urql")).href;
11
16
  } catch (error) {
12
17
  if (isMissingUrqlAdapter(error)) {
13
18
  return null;
@@ -16,9 +21,22 @@ async function loadSsrUrqlAdapter() {
16
21
  }
17
22
  }
18
23
 
19
- export async function getSsrUrqlAdapter() {
20
- adapterPromise ??= loadSsrUrqlAdapter();
21
- return adapterPromise;
24
+ export async function getSsrUrqlAdapter(projectRoot = process.cwd()) {
25
+ const moduleUrl = resolveSsrUrqlAdapterUrl(projectRoot);
26
+ if (!moduleUrl) return null;
27
+ let adapterPromise = adapterPromisesByModuleUrl.get(moduleUrl);
28
+ if (!adapterPromise) {
29
+ adapterPromise = import(moduleUrl);
30
+ adapterPromisesByModuleUrl.set(moduleUrl, adapterPromise);
31
+ }
32
+ try {
33
+ return await adapterPromise;
34
+ } catch (error) {
35
+ if (adapterPromisesByModuleUrl.get(moduleUrl) === adapterPromise) {
36
+ adapterPromisesByModuleUrl.delete(moduleUrl);
37
+ }
38
+ throw error;
39
+ }
22
40
  }
23
41
 
24
42
  /**
@@ -40,7 +58,7 @@ export async function runWithOptionalSsrUrqlScope(
40
58
  }
41
59
  const adapter = Object.hasOwn(options, "adapter")
42
60
  ? options.adapter
43
- : await getSsrUrqlAdapter();
61
+ : await getSsrUrqlAdapter(options.projectRoot);
44
62
  if (!adapter) {
45
63
  return callback(null);
46
64
  }