From 1068d6e060432cb6efc88b040e51b7a8732ef118 Mon Sep 17 00:00:00 2001
From: Steven Le <387282+stevenle@users.noreply.github.com>
Date: Tue, 24 Feb 2026 20:36:06 -0800
Subject: [PATCH 1/2] fix(root): prioritize configured stylesheet entries
---
packages/root/src/core/config.ts | 19 +++++++++++++++++++
packages/root/src/render/render.tsx | 21 +++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/packages/root/src/core/config.ts b/packages/root/src/core/config.ts
index a8059c8c0..83ee712d5 100644
--- a/packages/root/src/core/config.ts
+++ b/packages/root/src/core/config.ts
@@ -33,6 +33,25 @@ export interface RootUserConfig {
exclude?: RegExp[];
};
+ /**
+ * Config for manually injecting stylesheet entries as
+ * `` tags.
+ */
+ styles?: {
+ /**
+ * Project-root-relative stylesheet files to include on every rendered
+ * page, e.g. `styles/index.css`.
+ *
+ * Entries are normalized as URL paths, so both `styles/index.css` and
+ * `/styles/index.css` resolve to `/styles/index.css`.
+ *
+ * Manual entries are injected first, then auto-collected CSS
+ * dependencies are merged after. Duplicate URLs are de-duped so each
+ * stylesheet is only injected once.
+ */
+ entries?: string[];
+ };
+
/**
* Config options for localization and internationalization.
*/
diff --git a/packages/root/src/render/render.tsx b/packages/root/src/render/render.tsx
index bbe6e4f46..a41a0c806 100644
--- a/packages/root/src/render/render.tsx
+++ b/packages/root/src/render/render.tsx
@@ -227,6 +227,12 @@ export class Renderer {
});
}
+ // Merge user-configured stylesheet entries first. This allows global
+ // entries to appear before auto-collected stylesheets.
+ this.getConfiguredStyleEntries().forEach((styleEntry) => {
+ cssDeps.add(styleEntry);
+ });
+
// Parse the HTML for custom elements that are found within the project
// and automatically inject the script deps for them.
await this.collectElementDeps(mainHtml, jsDeps, cssDeps);
@@ -580,6 +586,16 @@ export class Renderer {
return orderedSitemap;
}
+
+ private getConfiguredStyleEntries() {
+ const styleEntries = this.rootConfig.styles?.entries || [];
+ const basePath = this.rootConfig.base || '/';
+ return styleEntries
+ .map((entry) => entry.trim())
+ .filter((entry) => entry)
+ .map((entry) => normalizeStyleEntry(entry, basePath));
+ }
+
private async renderHtml(html: string, options?: RenderHtmlOptions) {
const htmlAttrs = options?.htmlAttrs || {};
const headAttrs = options?.headAttrs || {};
@@ -860,6 +876,11 @@ function sortLocales(a: string, b: string) {
return a.localeCompare(b);
}
+function normalizeStyleEntry(entry: string, basePath: string) {
+ const normalizedEntry = normalizeUrlPath(entry.replace(/^\.\//, ''));
+ return normalizeUrlPath(`${basePath}/${normalizedEntry}`);
+}
+
function guessContentType(ext: string): string {
const normalized = ext.trim().toLowerCase().replace(/^\./, '');
return CONTENT_TYPES[normalized] || 'application/octet-stream';
From 7a811a5355a41817bf2b967ed45104136379d6d9 Mon Sep 17 00:00:00 2001
From: Steven Le
Date: Tue, 24 Feb 2026 21:19:37 -0800
Subject: [PATCH 2/2] chore: add changeset
---
.changeset/rare-lemons-whisper.md | 5 +++++
1 file changed, 5 insertions(+)
create mode 100644 .changeset/rare-lemons-whisper.md
diff --git a/.changeset/rare-lemons-whisper.md b/.changeset/rare-lemons-whisper.md
new file mode 100644
index 000000000..b280aeef5
--- /dev/null
+++ b/.changeset/rare-lemons-whisper.md
@@ -0,0 +1,5 @@
+---
+'@blinkk/root': patch
+---
+
+feat: add `styles.entries` config for injecting global stylesheets (#929)