@ultimat3/render 22.3.4 → 22.3.6

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.3.4",
3
+ "version": "22.3.6",
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.3.4",
40
- "@ultimat3/core": "22.3.4",
41
- "@ultimat3/http": "22.3.4",
42
- "@ultimat3/i18n": "22.3.4",
43
- "@ultimat3/seo": "22.3.4",
39
+ "@ultimat3/cache": "22.3.6",
40
+ "@ultimat3/core": "22.3.6",
41
+ "@ultimat3/http": "22.3.6",
42
+ "@ultimat3/i18n": "22.3.6",
43
+ "@ultimat3/seo": "22.3.6",
44
44
  "sass": "1.104.0"
45
45
  }
46
46
  }
@@ -79,11 +79,9 @@ export interface Stylesheet {
79
79
  /** A plain (non-module) stylesheet: the tokens and the reset, which the cascade needs first. */
80
80
  readonly global: boolean;
81
81
  /**
82
- * Registered only by an ISLAND build, never by the server's module graph. Such a sheet is ordered
83
- * by path, not by arrival: `Bun.build` loads an island graph in parallel, so its arrival order
84
- * differs between processes, and the surface stylesheet — its URL a hash of the joined bytes —
85
- * differed between two pods of one image (notificado.co, 22.3.2: one pod's `/styles/<hash>.css`
86
- * was the other's 404, and each `sw.js` precached a sheet the other did not serve).
82
+ * Registered only by an ISLAND build, never by the server's module graph — what `x build --target
83
+ * docker` records in the island store. Not an ordering key: every sheet is ordered by
84
+ * `stylesheetOrder`, whoever registered it.
87
85
  */
88
86
  readonly island: boolean;
89
87
  readonly css: string;
@@ -147,18 +145,25 @@ export function clearStylesheets(): void {
147
145
  }
148
146
 
149
147
  /**
150
- * The CSS a document on `surface` must carry: the global layer first, then the modules, each group
151
- * in load order. A `site/` page never receives `app/` CSS — that is axiom 6 applied to bytes the
152
- * browser parses, not just bytes it executes.
148
+ * The CSS a document on `surface` must carry. A `site/` page never receives `app/` CSS — that is
149
+ * axiom 6 applied to bytes the browser parses, not just bytes it executes.
153
150
  *
154
151
  * `shared/` is carried by both graphs by definition — it is the one directory both surfaces import
155
152
  * from, and it is where an app's own global stylesheet lives. Filtering it out (which this did)
156
153
  * meant an app could put its tokens in the one place the convention names and have every document
157
154
  * silently drop them.
158
155
  *
159
- * Globals sort ahead of modules rather than riding load order: the reset styles bare elements at
160
- * the lowest specificity there is, so a reset that happened to register after a module rule wins
161
- * ties it must lose. Insertion order alone made that depend on which page a request hit first.
156
+ * THE ORDER IS A FUNCTION OF THE SHEETS, NEVER OF THEIR ARRIVAL (22.3.5). A sheet registers in Bun's
157
+ * `onLoad`, which runs as the loader fetches a module's dependencies — in parallel — and an island
158
+ * build's too: the arrival order differed on every boot of one image, and so did the joined bytes
159
+ * and the `/styles/<hash>.css` minted from them (notificado.co, 22.3.2–22.3.4: two pods, two URLs,
160
+ * each the other's 404). `stylesheetOrder` is the whole rule:
161
+ *
162
+ * | key | first | why |
163
+ * |---|---|---|
164
+ * | global | the global layer | the reset styles bare elements at the lowest specificity there is, so a reset after a module rule wins ties it must lose |
165
+ * | owner | a package's sheet, then `shared/`, then the surface's own | library before app: an app's rule wins a tie against the component it restyles |
166
+ * | path | app-root-relative, by code unit | a total order; the same on every machine |
162
167
  */
163
168
  export function stylesFor(surface: Surface | null): string {
164
169
  const carried = [...stylesheets.values()].filter(
@@ -166,17 +171,28 @@ export function stylesFor(surface: Surface | null): string {
166
171
  );
167
172
  // `stripCharset` on every sheet, not only the first: a `@charset` or a BOM is legal at byte 0 of
168
173
  // a FILE and nowhere else, and this join is what turns seven files into one.
169
- //
170
- // Within each group, the server graph's sheets keep load order — deterministic, because `loadApp`
171
- // imports in sorted order, and meaningful, because a page's module loads after the component
172
- // module it overrides — and the island-only sheets follow, by path.
173
- const byPath = (a: Stylesheet, b: Stylesheet): number =>
174
- a.file < b.file ? -1 : a.file > b.file ? 1 : 0;
175
- const group = (global: boolean): Stylesheet[] => [
176
- ...carried.filter((sheet) => sheet.global === global && !sheet.island),
177
- ...carried.filter((sheet) => sheet.global === global && sheet.island).sort(byPath),
178
- ];
179
- return [...group(true), ...group(false)].map((sheet) => stripCharset(sheet.css)).join('');
174
+ return carried
175
+ .sort(stylesheetOrder)
176
+ .map((sheet) => stripCharset(sheet.css))
177
+ .join('');
178
+ }
179
+
180
+ const OWNER_RANK = (sheet: Stylesheet): number =>
181
+ sheet.surface === null ? 0 : sheet.surface === 'shared' ? 1 : 2;
182
+
183
+ /** Relative to the app root, so a container at `/app` and a laptop order one app alike. */
184
+ const orderPath = (sheet: Stylesheet): string => {
185
+ const root = stylesheetRoot ?? process.cwd();
186
+ return sheet.file.startsWith(`${root}/`) ? sheet.file.slice(root.length + 1) : sheet.file;
187
+ };
188
+
189
+ /** See `stylesFor`: global layer, then owner, then path. Exported for the tests that pin it. */
190
+ export function stylesheetOrder(a: Stylesheet, b: Stylesheet): number {
191
+ if (a.global !== b.global) return a.global ? -1 : 1;
192
+ const owner = OWNER_RANK(a) - OWNER_RANK(b);
193
+ if (owner !== 0) return owner;
194
+ const [x, y] = [orderPath(a), orderPath(b)];
195
+ return x < y ? -1 : x > y ? 1 : 0;
180
196
  }
181
197
 
182
198
  /**