Skip to content

Commit de95f00

Browse files
committed
Hash the dynamic icon file so that cach is refreshed when new icons are used
emove console log
1 parent 8466c88 commit de95f00

File tree

2 files changed

+95
-35
lines changed

2 files changed

+95
-35
lines changed

src/bin/only-include-used-icons.ts

Lines changed: 87 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@ import * as fs from "fs";
2424
import { join as pathJoin, relative as pathRelative } from "path";
2525
import { assert } from "tsafe/assert";
2626
import { exclude } from "tsafe/exclude";
27-
import { writeFile, readFile, rm } from "fs/promises";
27+
import { writeFile, readFile, rm, cp } from "fs/promises";
2828
import { crawl } from "./tools/crawl";
2929
import { basename as pathBasename, sep as pathSep, dirname as pathDirname } from "path";
3030
import type { Equals } from "tsafe";
3131
import yargsParser from "yargs-parser";
3232
import { getAbsoluteAndInOsFormatPath } from "./tools/getAbsoluteAndInOsFormatPath";
3333
import { readPublicDirPath } from "./readPublicDirPath";
3434
import { existsAsync } from "./tools/fs.existsAsync";
35+
import { fnv1aHashToHex } from "./tools/fnv1aHashToHex";
3536

3637
export const pathOfIconsJson = pathJoin("utility", "icons", "icons.json");
3738

@@ -460,55 +461,106 @@ async function main() {
460461
"utf8"
461462
);
462463

463-
const onConfirmedChange = async () => {
464-
const nextCacheDir = pathJoin(projectDirPath, ".next", "cache");
464+
let hasChanged = false;
465465

466-
if (!fs.existsSync(nextCacheDir)) {
467-
return;
468-
}
466+
const utilityIconsRelativeDirPath = pathJoin("utility", "icons");
469467

470-
await rm(nextCacheDir, { "recursive": true, "force": true });
471-
};
468+
await Promise.all(
469+
[dsfrDistInNodeModulesDirPath, dsfrDistInPublicDirPath]
470+
.filter(exclude(undefined))
471+
.map(async dsfrDistDirPath => {
472+
const cssFilePath = pathJoin(
473+
dsfrDistDirPath,
474+
utilityIconsRelativeDirPath,
475+
"icons.min.css"
476+
);
472477

473-
console.log({ dsfrDistInPublicDirPath });
478+
if (!fs.existsSync(cssFilePath)) {
479+
return;
480+
}
474481

475-
[dsfrDistInNodeModulesDirPath, dsfrDistInPublicDirPath]
476-
.filter(exclude(undefined))
477-
.forEach(async dsfrDistDirPath => {
478-
const cssFilePath = pathJoin(dsfrDistDirPath, "utility", "icons", "icons.min.css");
482+
const remixiconDirPath = pathJoin(dsfrDistDirPath, "icons", "remixicon");
479483

480-
if (!fs.existsSync(cssFilePath)) {
481-
return;
482-
}
484+
if (!fs.existsSync(remixiconDirPath)) {
485+
fs.mkdirSync(remixiconDirPath);
486+
}
483487

484-
const remixiconDirPath = pathJoin(dsfrDistDirPath, "icons", "remixicon");
488+
usedIcons
489+
.map(icon => (icon.prefix !== "ri-" ? undefined : icon))
490+
.filter(exclude(undefined))
491+
.map(({ iconId, rawSvgCode }) =>
492+
writeFile(
493+
pathJoin(remixiconDirPath, `${iconId}.svg`),
494+
Buffer.from(rawSvgCode, "utf8")
495+
)
496+
);
485497

486-
if (!fs.existsSync(remixiconDirPath)) {
487-
fs.mkdirSync(remixiconDirPath);
488-
}
498+
log?.(`Patching ${pathRelative(projectDirPath, cssFilePath)}`);
489499

490-
usedIcons
491-
.map(icon => (icon.prefix !== "ri-" ? undefined : icon))
492-
.filter(exclude(undefined))
493-
.map(({ iconId, rawSvgCode }) =>
500+
const dynamicFilePath = pathJoin(
501+
pathDirname(cssFilePath),
502+
`icons.${fnv1aHashToHex(rawIconCssCodeBuffer.toString("utf8"))}.css`
503+
);
504+
505+
if (fs.existsSync(dynamicFilePath)) {
506+
return;
507+
}
508+
509+
fs.readdirSync(pathDirname(cssFilePath))
510+
.filter(
511+
fileBasename =>
512+
fileBasename.startsWith("icons.") && fileBasename.endsWith(".css")
513+
)
514+
.map(fileBasename => pathJoin(pathDirname(cssFilePath), fileBasename))
515+
.forEach(filePath => fs.unlinkSync(filePath));
516+
517+
await Promise.all([
518+
writeFile(dynamicFilePath, rawIconCssCodeBuffer),
494519
writeFile(
495-
pathJoin(remixiconDirPath, `${iconId}.svg`),
496-
Buffer.from(rawSvgCode, "utf8")
520+
cssFilePath,
521+
Buffer.from(`@import url("./${pathBasename(dynamicFilePath)}");`, "utf8")
497522
)
498-
);
523+
]);
499524

500-
log?.(`Patching ${pathRelative(projectDirPath, cssFilePath)}`);
525+
hasChanged = true;
526+
})
527+
);
501528

502-
const currentCode = await readFile(cssFilePath);
529+
clear_next_cache: {
530+
if (!hasChanged) {
531+
break clear_next_cache;
532+
}
503533

504-
if (Buffer.compare(rawIconCssCodeBuffer, currentCode) === 0) {
505-
return;
506-
}
534+
const nextCacheDir = pathJoin(projectDirPath, ".next", "cache");
535+
536+
if (!fs.existsSync(nextCacheDir)) {
537+
break clear_next_cache;
538+
}
539+
540+
await rm(nextCacheDir, { "recursive": true, "force": true });
541+
}
507542

508-
onConfirmedChange();
543+
copy_used_dsfr_icons_to_public: {
544+
if (!hasChanged) {
545+
break copy_used_dsfr_icons_to_public;
546+
}
509547

510-
writeFile(cssFilePath, rawIconCssCodeBuffer);
511-
});
548+
if (dsfrDistInPublicDirPath === undefined || dsfrDistInNodeModulesDirPath === undefined) {
549+
break copy_used_dsfr_icons_to_public;
550+
}
551+
552+
await Promise.all(
553+
usedIcons
554+
.filter(icon => icon.prefix === "fr-icon-")
555+
.map(({ svgRelativePath }) =>
556+
([dsfrDistInNodeModulesDirPath, dsfrDistInPublicDirPath] as const).map(
557+
baseDirPath =>
558+
pathJoin(baseDirPath, utilityIconsRelativeDirPath, svgRelativePath)
559+
)
560+
)
561+
.map(([srcFilePath, destFilePath]) => cp(srcFilePath, destFilePath))
562+
);
563+
}
512564
}
513565

514566
if (require.main === module) {

src/bin/tools/fnv1aHashToHex.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function fnv1aHashToHex(str: string) {
2+
let hash = 2166136261;
3+
for (let i = 0; i < str.length; i++) {
4+
hash ^= str.charCodeAt(i);
5+
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
6+
}
7+
return (hash >>> 0).toString(16); // Convert to unsigned 32-bit integer and then to hexadecimal
8+
}

0 commit comments

Comments
 (0)