@pyreon/zero 0.19.0 → 0.20.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.
- package/lib/{api-routes-CQiOi3q5.js → api-routes-CMsLztoj.js} +1 -1
- package/lib/favicon.js +57 -3
- package/lib/{fs-router-BVY4lTH_.js → fs-router-Bacdhsq-.js} +2 -2
- package/lib/image-plugin.js +13 -6
- package/lib/server.js +2716 -179
- package/lib/types/favicon.d.ts +17 -1
- package/lib/types/i18n-routing.d.ts +2 -4
- package/lib/types/index.d.ts +3 -5
- package/lib/types/link.d.ts +2 -4
- package/lib/types/server.d.ts +2 -4
- package/lib/types/theme.d.ts +1 -2
- package/package.json +10 -10
- package/src/favicon.ts +84 -2
- package/src/image-plugin.ts +43 -12
- package/lib/vite-plugin-8TXXFqdP.js +0 -2491
|
@@ -145,4 +145,4 @@ function generateApiRouteModule(files, routesDir) {
|
|
|
145
145
|
|
|
146
146
|
//#endregion
|
|
147
147
|
export { matchApiRoute as i, createApiMiddleware as n, generateApiRouteModule as r, api_routes_exports as t };
|
|
148
|
-
//# sourceMappingURL=api-routes-
|
|
148
|
+
//# sourceMappingURL=api-routes-CMsLztoj.js.map
|
package/lib/favicon.js
CHANGED
|
@@ -1,8 +1,42 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
|
|
5
5
|
//#region src/favicon.ts
|
|
6
|
+
/**
|
|
7
|
+
* Stable content hash (FNV-1a, 32-bit) of the favicon source file(s),
|
|
8
|
+
* rendered as a `?v=<hex>` cache-bust query for the injected `<head>`
|
|
9
|
+
* links. Browsers cache favicons extremely aggressively (often per-
|
|
10
|
+
* session / effectively forever), so with a stable URL a changed icon
|
|
11
|
+
* is never re-fetched by returning visitors. Same source bytes →
|
|
12
|
+
* identical query (no needless cache churn); changed bytes → new query
|
|
13
|
+
* → browser re-downloads. Falls back to `''` (no query, prior
|
|
14
|
+
* behaviour) if a source can't be read — never break the build over a
|
|
15
|
+
* cache-bust nicety. NOTE: this versions everything referenced via
|
|
16
|
+
* `<link>` (svg/png/apple-touch/manifest). The bare `/favicon.ico`
|
|
17
|
+
* convention request (browsers fetch it with no link tag) and the
|
|
18
|
+
* `site.webmanifest`'s internal icon entries keep stable URLs — those
|
|
19
|
+
* rely on host cache headers / are re-resolved on PWA (re)install.
|
|
20
|
+
*/
|
|
21
|
+
function faviconVersionQuery(paths) {
|
|
22
|
+
let h = 2166136261;
|
|
23
|
+
let any = false;
|
|
24
|
+
for (const p of paths) {
|
|
25
|
+
let buf;
|
|
26
|
+
try {
|
|
27
|
+
buf = readFileSync(p);
|
|
28
|
+
} catch {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
any = true;
|
|
32
|
+
for (let i = 0; i < buf.length; i++) {
|
|
33
|
+
h ^= buf[i];
|
|
34
|
+
h = Math.imul(h, 16777619);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (!any) return "";
|
|
38
|
+
return `?v=${(h >>> 0).toString(16).padStart(8, "0")}`;
|
|
39
|
+
}
|
|
6
40
|
let sharpWarned = false;
|
|
7
41
|
function warnSharpMissing() {
|
|
8
42
|
if (sharpWarned) return;
|
|
@@ -53,6 +87,15 @@ function faviconPlugin(config) {
|
|
|
53
87
|
const generateManifest = config.manifest !== false;
|
|
54
88
|
let root = "";
|
|
55
89
|
let isBuild = false;
|
|
90
|
+
let versionQuery = null;
|
|
91
|
+
function getVersionQuery() {
|
|
92
|
+
if (versionQuery === null) {
|
|
93
|
+
const paths = [join(root, config.source)];
|
|
94
|
+
if (config.darkSource) paths.push(join(root, config.darkSource));
|
|
95
|
+
versionQuery = faviconVersionQuery(paths);
|
|
96
|
+
}
|
|
97
|
+
return versionQuery;
|
|
98
|
+
}
|
|
56
99
|
return {
|
|
57
100
|
name: "pyreon-zero-favicon",
|
|
58
101
|
enforce: "pre",
|
|
@@ -73,7 +116,7 @@ function faviconPlugin(config) {
|
|
|
73
116
|
return defaultSource;
|
|
74
117
|
}
|
|
75
118
|
server.middlewares.use(async (req, res, next) => {
|
|
76
|
-
const url = req.url ?? "";
|
|
119
|
+
const url = (req.url ?? "").split("?")[0];
|
|
77
120
|
const localeSource = resolveLocaleSource(url, config, root);
|
|
78
121
|
const svgUrl = localeSource ? localeSource.url : url;
|
|
79
122
|
const svgPath = localeSource ? localeSource.sourcePath : sourcePath;
|
|
@@ -277,10 +320,21 @@ function faviconPlugin(config) {
|
|
|
277
320
|
injectTo: "head",
|
|
278
321
|
children: `(function(){try{var t=localStorage.getItem("zero-theme");var r=t==="light"?"light":t==="dark"?"dark":window.matchMedia("(prefers-color-scheme:dark)").matches?"dark":"light";document.querySelectorAll("[data-favicon-theme]").forEach(function(l){l.media=l.dataset.faviconTheme===r?"":"not all"})}catch(e){}})()`
|
|
279
322
|
});
|
|
323
|
+
const v = getVersionQuery();
|
|
324
|
+
if (v) {
|
|
325
|
+
for (const t of tags) if (t.tag === "link" && t.attrs.href) t.attrs.href += v;
|
|
326
|
+
}
|
|
280
327
|
return tags;
|
|
281
328
|
},
|
|
282
329
|
async generateBundle() {
|
|
283
330
|
if (!isBuild) return;
|
|
331
|
+
try {
|
|
332
|
+
await import("sharp");
|
|
333
|
+
} catch {
|
|
334
|
+
this.error(`[Pyreon] faviconPlugin: a favicon \`source\` is configured but \`sharp\` is not installed — NO favicons would be generated and the production build would silently ship none.
|
|
335
|
+
Fix: bun add -D sharp (or: npm i -D sharp)
|
|
336
|
+
Source: ${config.source}\nTo intentionally build without favicons, remove faviconPlugin() from your Vite plugins.`);
|
|
337
|
+
}
|
|
284
338
|
await generateFaviconSet.call(this, root, config.source, config.darkSource, "", config, themeColor, backgroundColor, generateManifest);
|
|
285
339
|
if (config.locales) for (const [locale, localeConfig] of Object.entries(config.locales)) await generateFaviconSet.call(this, root, localeConfig.source, localeConfig.darkSource, `${locale}/`, config, themeColor, backgroundColor, generateManifest);
|
|
286
340
|
}
|
|
@@ -571,5 +625,5 @@ async function addDevBadgeToPng(pngBuffer, size) {
|
|
|
571
625
|
}
|
|
572
626
|
|
|
573
627
|
//#endregion
|
|
574
|
-
export { createIcoFromPngs, faviconLinks, faviconPlugin };
|
|
628
|
+
export { createIcoFromPngs, faviconLinks, faviconPlugin, faviconVersionQuery };
|
|
575
629
|
//# sourceMappingURL=favicon.js.map
|
|
@@ -969,7 +969,7 @@ async function scanRouteFiles(routesDir) {
|
|
|
969
969
|
*/
|
|
970
970
|
async function scanRouteFilesWithExports(routesDir, defaultMode = "ssr") {
|
|
971
971
|
const { readFile } = await import("node:fs/promises");
|
|
972
|
-
const { isApiRoute } = await import("./api-routes-
|
|
972
|
+
const { isApiRoute } = await import("./api-routes-CMsLztoj.js").then((n) => n.t);
|
|
973
973
|
const files = (await scanRouteFiles(routesDir)).filter((f) => !isApiRoute(f));
|
|
974
974
|
const exportsMap = /* @__PURE__ */ new Map();
|
|
975
975
|
await Promise.all(files.map(async (filePath) => {
|
|
@@ -985,4 +985,4 @@ async function scanRouteFilesWithExports(routesDir, defaultMode = "ssr") {
|
|
|
985
985
|
|
|
986
986
|
//#endregion
|
|
987
987
|
export { generateRouteModuleFromRoutes as a, scanRouteFilesWithExports as c, generateRouteModule as i, fs_router_exports as n, parseFileRoutes as o, generateMiddlewareModule as r, scanRouteFiles as s, filePathToUrlPath as t };
|
|
988
|
-
//# sourceMappingURL=fs-router-
|
|
988
|
+
//# sourceMappingURL=fs-router-Bacdhsq-.js.map
|
package/lib/image-plugin.js
CHANGED
|
@@ -77,15 +77,22 @@ function imagePlugin(config = {}) {
|
|
|
77
77
|
outDir = resolvedConfig.build.outDir;
|
|
78
78
|
isBuild = resolvedConfig.command === "build";
|
|
79
79
|
},
|
|
80
|
-
async resolveId(id) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return null;
|
|
80
|
+
async resolveId(id, importer) {
|
|
81
|
+
const isSvgComponent = svgOpts && id.includes("?component") && id.split("?")[0].endsWith(".svg");
|
|
82
|
+
const isOptimize = id.includes("?optimize") && include.test(id.split("?")[0]);
|
|
83
|
+
if (!isSvgComponent && !isOptimize) return null;
|
|
84
|
+
const qIdx = id.indexOf("?");
|
|
85
|
+
const bare = qIdx === -1 ? id : id.slice(0, qIdx);
|
|
86
|
+
const query = qIdx === -1 ? "" : id.slice(qIdx);
|
|
87
|
+
const resolved = await this.resolve(bare, importer, { skipSelf: true });
|
|
88
|
+
const carried = resolved ? `${resolved.id}${query}` : id;
|
|
89
|
+
if (isSvgComponent) return `\0virtual:zero-svg:${carried}`;
|
|
90
|
+
return `\0virtual:zero-image:${carried}`;
|
|
84
91
|
},
|
|
85
92
|
async load(id) {
|
|
86
93
|
if (id.startsWith("\0virtual:zero-svg:")) {
|
|
87
94
|
const rawPath = id.replace("\0virtual:zero-svg:", "").split("?")[0] ?? id;
|
|
88
|
-
const absPath = rawPath.startsWith("/") ? join(root, rawPath) : rawPath;
|
|
95
|
+
const absPath = existsSync(rawPath) ? rawPath : rawPath.startsWith("/") ? join(root, rawPath) : rawPath;
|
|
89
96
|
if (!existsSync(absPath)) return null;
|
|
90
97
|
let svg = await readFile(absPath, "utf-8");
|
|
91
98
|
if (svgOpts && svgOpts.currentColor !== false) svg = svg.replace(/fill="(?!none)[^"]*"/g, "fill=\"currentColor\"").replace(/stroke="(?!none)[^"]*"/g, "stroke=\"currentColor\"");
|
|
@@ -111,7 +118,7 @@ export default function SvgComponent(props) {
|
|
|
111
118
|
}
|
|
112
119
|
if (!id.startsWith("\0virtual:zero-image:")) return null;
|
|
113
120
|
const rawPath = id.replace("\0virtual:zero-image:", "").split("?")[0] ?? id;
|
|
114
|
-
const absPath = rawPath.startsWith("/") ? join(root, "public", rawPath) : rawPath;
|
|
121
|
+
const absPath = existsSync(rawPath) ? rawPath : rawPath.startsWith("/") ? join(root, "public", rawPath) : rawPath;
|
|
115
122
|
if (cdn) {
|
|
116
123
|
const metadata = await getImageMetadata(absPath);
|
|
117
124
|
const sources = defaultWidths.map((w) => ({
|