@ultimat3/render 22.2.0 → 22.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/render",
3
- "version": "22.2.0",
3
+ "version": "22.2.1",
4
4
  "description": "The route primitive and the five render modes: static, isr, ssr, stream, spa.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -36,11 +36,11 @@
36
36
  "test": "bun test"
37
37
  },
38
38
  "dependencies": {
39
- "@ultimat3/cache": "22.2.0",
40
- "@ultimat3/core": "22.2.0",
41
- "@ultimat3/http": "22.2.0",
42
- "@ultimat3/i18n": "22.2.0",
43
- "@ultimat3/seo": "22.2.0",
39
+ "@ultimat3/cache": "22.2.1",
40
+ "@ultimat3/core": "22.2.1",
41
+ "@ultimat3/http": "22.2.1",
42
+ "@ultimat3/i18n": "22.2.1",
43
+ "@ultimat3/seo": "22.2.1",
44
44
  "sass": "1.104.0"
45
45
  }
46
46
  }
@@ -8,7 +8,7 @@ import { renderThrowable } from '@ultimat3/core';
8
8
  import { compileStylesheet, isGlobalStylesheet, stripCharset } from './css-modules';
9
9
  import { PrerenderFailedError } from './errors';
10
10
  import type { Surface } from './surfaces';
11
- import { surfaceOf } from './surfaces';
11
+ import { surfaceUnder } from './surfaces';
12
12
 
13
13
  /**
14
14
  * Why a transform at all: `tsconfig.json` says `jsx: 'preserve'`, which makes Bun fall back to the
@@ -101,6 +101,32 @@ export function registeredStylesheets(): readonly Stylesheet[] {
101
101
  return [...stylesheets.values()];
102
102
  }
103
103
 
104
+ /**
105
+ * The directory a sheet's surface is read below. Absent, the process's working directory — which
106
+ * is the app root in the container (`WORKDIR /app`) and under every `x` command run from one.
107
+ */
108
+ let stylesheetRoot: string | undefined;
109
+
110
+ const surfaceOfSheet = (path: string): Surface | null =>
111
+ surfaceUnder(stylesheetRoot ?? process.cwd(), path);
112
+
113
+ /**
114
+ * Names the app root the registry classifies against; `loadApp` calls it before importing a module.
115
+ * Every sheet already registered is classified again, because a sheet can load before the root is
116
+ * named — and a classification frozen then would keep the answer the wrong root gave. The revision
117
+ * moves only when an answer does, so naming the same root twice mints no new stylesheet URL.
118
+ * `undefined` returns to the working directory.
119
+ */
120
+ export function setStylesheetRoot(root: string | undefined): void {
121
+ stylesheetRoot = root;
122
+ for (const [path, sheet] of stylesheets) {
123
+ const surface = surfaceOfSheet(path);
124
+ if (surface === sheet.surface) continue;
125
+ stylesheets.set(path, { ...sheet, surface });
126
+ revision += 1;
127
+ }
128
+ }
129
+
104
130
  /** Test seam: the registry is process-global because the module cache it mirrors is too. */
105
131
  export function clearStylesheets(): void {
106
132
  if (stylesheets.size > 0) revision += 1;
@@ -159,7 +185,7 @@ export function loadStylesheet(path: string, source: string): string {
159
185
  if (stylesheets.get(path)?.css !== compiled.css) revision += 1;
160
186
  stylesheets.set(path, {
161
187
  file: path,
162
- surface: surfaceOf(path),
188
+ surface: surfaceOfSheet(path),
163
189
  global: isGlobalStylesheet(path),
164
190
  css: compiled.css,
165
191
  });
package/src/server.ts CHANGED
@@ -30,6 +30,7 @@ export {
30
30
  installRenderLoader,
31
31
  loadStylesheet,
32
32
  registeredStylesheets,
33
+ setStylesheetRoot,
33
34
  stylesFor,
34
35
  stylesheetsRevision,
35
36
  transformTsx,
package/src/surfaces.ts CHANGED
@@ -91,6 +91,25 @@ export function surfaceOf(file: string): Surface | null {
91
91
  return locateSurface(file)?.surface ?? null;
92
92
  }
93
93
 
94
+ /**
95
+ * The surface of an ABSOLUTE path, read from the part below the app `root`. `surfaceOf` takes the
96
+ * first surface-named segment, which is right for the root-relative paths the route table and the
97
+ * boundary check hold — and wrong for an absolute one whose root is itself called `app/`: the
98
+ * scaffold's container runs from `WORKDIR /app`, and every stylesheet there read as `app`, so the
99
+ * site bundle was empty and every site document shipped with no stylesheet at all.
100
+ *
101
+ * A file outside `root` is read as `surfaceOf` reads it. A file inside an installed package
102
+ * (`node_modules/…`) has no surface whatever its directories are called: it is a package sheet,
103
+ * which both graphs carry.
104
+ */
105
+ export function surfaceUnder(root: string, file: string): Surface | null {
106
+ const base = normalize(root).replace(/\/+$/, '');
107
+ const path = normalize(file);
108
+ const relative = path.startsWith(`${base}/`) ? path.slice(base.length + 1) : path;
109
+ if (/(?:^|\/)node_modules\//.test(relative)) return null;
110
+ return surfaceOf(relative);
111
+ }
112
+
94
113
  function normalize(file: string): string {
95
114
  return file.replace(/\\/g, '/').replace(/^\.\//, '');
96
115
  }