@homebound/truss 2.14.0 → 2.15.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.
@@ -101,6 +101,7 @@ interface TrussVitePlugin {
101
101
  transformIndexHtml?: (html: string) => string;
102
102
  handleHotUpdate?: (ctx: any) => void;
103
103
  generateBundle?: (options: any, bundle: any) => void;
104
+ writeBundle?: (options: any, bundle: any) => void;
104
105
  }
105
106
  /**
106
107
  * Vite plugin that transforms `Css.*.$` expressions from truss's CssBuilder DSL
@@ -111,7 +112,7 @@ interface TrussVitePlugin {
111
112
  * while imports are supplemented with a virtual CSS side-effect module.
112
113
  *
113
114
  * In dev mode, serves CSS via a virtual endpoint that the injected runtime keeps in sync.
114
- * In production, emits a single `truss.css` asset with all atomic rules.
115
+ * In production, emits a content-hashed CSS asset (e.g. `assets/truss-abc123.css`) for long-term caching.
115
116
  */
116
117
  declare function trussPlugin(opts: TrussPluginOptions): TrussVitePlugin;
117
118
  /** Load a truss mapping file synchronously (for tests). */
@@ -1,6 +1,7 @@
1
1
  // src/plugin/index.ts
2
- import { readFileSync as readFileSync3, existsSync } from "fs";
3
- import { resolve as resolve2, dirname, isAbsolute } from "path";
2
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync, readdirSync } from "fs";
3
+ import { resolve as resolve2, dirname, isAbsolute, join as join2 } from "path";
4
+ import { createHash } from "crypto";
4
5
 
5
6
  // src/plugin/emit-truss.ts
6
7
  import * as t from "@babel/types";
@@ -3483,6 +3484,7 @@ function loaderForPath(filePath) {
3483
3484
  // src/plugin/index.ts
3484
3485
  var VIRTUAL_CSS_PREFIX = "\0truss-css:";
3485
3486
  var CSS_TS_QUERY = "?truss-css";
3487
+ var TRUSS_CSS_PLACEHOLDER = "__TRUSS_CSS_HASH__";
3486
3488
  var VIRTUAL_CSS_ENDPOINT = "/virtual:truss.css";
3487
3489
  var VIRTUAL_RUNTIME_ID = "virtual:truss:runtime";
3488
3490
  var RESOLVED_VIRTUAL_RUNTIME_ID = "\0" + VIRTUAL_RUNTIME_ID;
@@ -3495,6 +3497,7 @@ function trussPlugin(opts) {
3495
3497
  let isTest = false;
3496
3498
  let isBuild = false;
3497
3499
  const libraryPaths = opts.libraries ?? [];
3500
+ let emittedCssFileName = null;
3498
3501
  const cssRegistry = /* @__PURE__ */ new Map();
3499
3502
  let cssVersion = 0;
3500
3503
  let lastSentVersion = 0;
@@ -3562,8 +3565,9 @@ function trussPlugin(opts) {
3562
3565
  },
3563
3566
  transformIndexHtml(html) {
3564
3567
  if (isBuild) {
3565
- const link = `<link rel="stylesheet" href="./truss.css">`;
3566
- return html.replace("</head>", ` ${link}
3568
+ const stripped = html.replace(/\s*<link[^>]*href=["'][^"']*virtual:truss\.css["'][^>]*\/?>/, "");
3569
+ const link = `<link rel="stylesheet" href="${TRUSS_CSS_PLACEHOLDER}">`;
3570
+ return stripped.replace("</head>", ` ${link}
3567
3571
  </head>`);
3568
3572
  }
3569
3573
  const tag = `<script type="module" src="/${VIRTUAL_RUNTIME_ID}"></script>`;
@@ -3680,11 +3684,27 @@ __injectTrussCSS(${JSON.stringify(css)});
3680
3684
  if (!isBuild) return;
3681
3685
  const css = collectCss();
3682
3686
  if (!css) return;
3687
+ const hash = createHash("sha256").update(css).digest("hex").slice(0, 8);
3688
+ const fileName = `assets/truss-${hash}.css`;
3689
+ emittedCssFileName = fileName;
3683
3690
  this.emitFile({
3684
3691
  type: "asset",
3685
- fileName: "truss.css",
3692
+ fileName,
3686
3693
  source: css
3687
3694
  });
3695
+ },
3696
+ /** Patch HTML files on disk to replace the CSS placeholder with the hashed filename. */
3697
+ writeBundle(options, _bundle) {
3698
+ if (!emittedCssFileName) return;
3699
+ const outDir = options.dir || join2(projectRoot, "dist");
3700
+ for (const entry of readdirSync(outDir)) {
3701
+ if (!entry.endsWith(".html")) continue;
3702
+ const htmlPath = join2(outDir, entry);
3703
+ const html = readFileSync3(htmlPath, "utf8");
3704
+ if (html.includes(TRUSS_CSS_PLACEHOLDER)) {
3705
+ writeFileSync2(htmlPath, html.replace(TRUSS_CSS_PLACEHOLDER, `/${emittedCssFileName}`), "utf8");
3706
+ }
3707
+ }
3688
3708
  }
3689
3709
  };
3690
3710
  }