Skip to content

Commit 81f09b9

Browse files
authored
build: extract vite plugins (@fehmer) (monkeytypegame#7103)
1 parent 8ee7e94 commit 81f09b9

File tree

10 files changed

+169
-118
lines changed

10 files changed

+169
-118
lines changed

frontend/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@
1313
"virtual:env-config": ["./src/ts/virtual-env-config.d.ts"]
1414
}
1515
},
16-
"include": ["./src/**/*.ts", "./scripts/**/*.ts"],
16+
"include": ["./src/**/*.ts", "./scripts/**/*.ts", "vite-plugins/**/*.ts"],
1717
"exclude": ["node_modules", "build", "setup-tests.ts", "**/*.spec.ts"]
1818
}
File renamed without changes.

frontend/scripts/font-preview.ts renamed to frontend/vite-plugins/font-preview.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Plugin } from "vite";
12
import * as fs from "fs";
23
import * as path from "path";
34
import { fileURLToPath } from "url";
@@ -9,9 +10,30 @@ import { KnownFontName } from "@monkeytype/schemas/fonts";
910
const __filename = fileURLToPath(import.meta.url);
1011
const __dirname = path.dirname(__filename);
1112

12-
export async function generatePreviewFonts(
13-
debug: boolean = false
14-
): Promise<void> {
13+
/**
14+
* Generate a preview file from each font in `static/webfonts` into `static/webfonts-preview`.
15+
* A preview file only contains the characters needed to show the preview.
16+
* @returns
17+
*/
18+
export function fontPreview(): Plugin {
19+
return {
20+
name: "vite-plugin-webfonts-preview",
21+
apply: "build",
22+
async buildStart() {
23+
const start = performance.now();
24+
console.log("\nCreating webfonts preview...");
25+
26+
await generatePreviewFonts();
27+
28+
const end = performance.now();
29+
console.log(
30+
`Creating webfonts preview took ${Math.round(end - start)} ms`
31+
);
32+
},
33+
};
34+
}
35+
36+
async function generatePreviewFonts(debug: boolean = false): Promise<void> {
1537
const srcDir = __dirname + "/../static/webfonts";
1638
const targetDir = __dirname + "/../static/webfonts-preview";
1739
fs.mkdirSync(targetDir, { recursive: true });

frontend/scripts/fontawesome.ts renamed to frontend/vite-plugins/fontawesome-subset.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,38 @@
1+
import { Plugin } from "vite";
12
import * as fs from "fs";
23
import { createRequire } from "module";
34
import * as path from "path";
5+
import { fontawesomeSubset as createFontawesomeSubset } from "fontawesome-subset";
6+
7+
/**
8+
* Detect fontawesome icons used by the application and creates subset font files only containing the used icons.
9+
* @param options
10+
* @returns
11+
*/
12+
export function fontawesomeSubset(): Plugin {
13+
return {
14+
name: "vite-plugin-fontawesome-subset",
15+
apply: "build",
16+
async buildStart() {
17+
const start = performance.now();
18+
console.log("\nCreating fontawesome subset...");
19+
20+
const fontawesomeClasses = getFontawesomeConfig();
21+
await createFontawesomeSubset(
22+
fontawesomeClasses,
23+
"src/webfonts-generated",
24+
{
25+
targetFormats: ["woff2"],
26+
}
27+
);
28+
29+
const end = performance.now();
30+
console.log(
31+
`Creating fontawesome subset took ${Math.round(end - start)} ms`
32+
);
33+
},
34+
};
35+
}
436

537
type FontawesomeConfig = {
638
/* used regular icons without `fa-` prefix*/
@@ -56,8 +88,7 @@ const modules2 = {
5688
* @param {boolean} debug - Enable debug output
5789
* @returns {FontawesomeConfig} - used icons
5890
*/
59-
60-
export function getFontawesomeConfig(debug = false): FontawesomeConfig {
91+
function getFontawesomeConfig(debug = false): FontawesomeConfig {
6192
const time = Date.now();
6293
const srcFiles = findAllFiles(
6394
"./src",
File renamed without changes.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Plugin } from "vite";
2+
import { readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
3+
import path from "node:path";
4+
5+
/**
6+
* Minifies all json files in the `dist` directory
7+
* @returns
8+
*/
9+
export function minifyJson(): Plugin {
10+
return {
11+
name: "minify-json",
12+
apply: "build",
13+
generateBundle() {
14+
let totalOriginalSize = 0;
15+
let totalMinifiedSize = 0;
16+
17+
const minifyJsonFiles = (dir: string): void => {
18+
readdirSync(dir).forEach((file) => {
19+
const sourcePath = path.join(dir, file);
20+
const stat = statSync(sourcePath);
21+
22+
if (stat.isDirectory()) {
23+
minifyJsonFiles(sourcePath);
24+
} else if (path.extname(file) === ".json") {
25+
const originalContent = readFileSync(sourcePath, "utf8");
26+
const originalSize = Buffer.byteLength(originalContent, "utf8");
27+
const minifiedContent = JSON.stringify(JSON.parse(originalContent));
28+
const minifiedSize = Buffer.byteLength(minifiedContent, "utf8");
29+
30+
totalOriginalSize += originalSize;
31+
totalMinifiedSize += minifiedSize;
32+
33+
writeFileSync(sourcePath, minifiedContent);
34+
35+
/*
36+
const savings =
37+
((originalSize - minifiedSize) / originalSize) * 100;
38+
console.log(
39+
`\x1b[0m \x1b[36m${sourcePath}\x1b[0m | ` +
40+
`\x1b[90mOriginal: ${originalSize} bytes\x1b[0m | ` +
41+
`\x1b[90mMinified: ${minifiedSize} bytes\x1b[0m | ` +
42+
`\x1b[32mSavings: ${savings.toFixed(2)}%\x1b[0m`
43+
);
44+
*/
45+
}
46+
});
47+
};
48+
49+
// console.log("\n\x1b[1mMinifying JSON files...\x1b[0m\n");
50+
const start = performance.now();
51+
52+
minifyJsonFiles("./dist");
53+
54+
const end = performance.now();
55+
const totalSavings =
56+
((totalOriginalSize - totalMinifiedSize) / totalOriginalSize) * 100;
57+
58+
console.log(
59+
`\n\n\x1b[1mJSON Minification Summary:\x1b[0m\n` +
60+
` \x1b[90mTotal original size: ${(
61+
totalOriginalSize /
62+
1024 /
63+
1024
64+
).toFixed(2)} mB\x1b[0m\n` +
65+
` \x1b[90mTotal minified size: ${(
66+
totalMinifiedSize /
67+
1024 /
68+
1024
69+
).toFixed(2)} mB\x1b[0m\n` +
70+
` \x1b[32mTotal savings: ${totalSavings.toFixed(
71+
2
72+
)}%\x1b[0m took ${Math.round(end - start)} ms\n`
73+
);
74+
},
75+
};
76+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Plugin } from "vite";
2+
import path from "node:path";
3+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
4+
export function versionFile(options: { clientVersion: string }): Plugin {
5+
return {
6+
name: "generate-version-json",
7+
apply: "build",
8+
9+
closeBundle() {
10+
const distPath = path.resolve("./dist");
11+
if (!existsSync(distPath)) {
12+
mkdirSync(distPath, { recursive: true });
13+
}
14+
15+
const versionJson = JSON.stringify({ version: options.clientVersion });
16+
const versionPath = path.resolve(distPath, "version.json");
17+
writeFileSync(versionPath, versionJson);
18+
},
19+
};
20+
}

frontend/vite.config.dev.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { checker } from "vite-plugin-checker";
22
import Inspect from "vite-plugin-inspect";
33
import path from "node:path";
44
import { getFontsConig } from "./vite.config";
5-
import { envConfig } from "./scripts/env-config";
6-
import { languageHashes } from "./scripts/language-hashes";
5+
import { envConfig } from "./vite-plugins/env-config";
6+
import { languageHashes } from "./vite-plugins/language-hashes";
77

88
/** @type {import("vite").UserConfig} */
99
export default {

frontend/vite.config.prod.js

Lines changed: 10 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,19 @@
1-
import { fontawesomeSubset } from "fontawesome-subset";
2-
import { getFontawesomeConfig } from "./scripts/fontawesome";
3-
import { generatePreviewFonts } from "./scripts/font-preview";
41
import { VitePWA } from "vite-plugin-pwa";
52
import replace from "vite-plugin-filter-replace";
63
import path from "node:path";
74
import childProcess from "child_process";
85
import { checker } from "vite-plugin-checker";
9-
import { writeFileSync } from "fs";
106
// eslint-disable-next-line import/no-unresolved
117
import UnpluginInjectPreload from "unplugin-inject-preload/vite";
12-
import {
13-
existsSync,
14-
mkdirSync,
15-
readdirSync,
16-
readFileSync,
17-
statSync,
18-
} from "node:fs";
198
import { ViteMinifyPlugin } from "vite-plugin-minify";
209
import { sentryVitePlugin } from "@sentry/vite-plugin";
2110
import { getFontsConig } from "./vite.config";
22-
import { envConfig } from "./scripts/env-config";
23-
import { languageHashes } from "./scripts/language-hashes";
11+
import { fontawesomeSubset } from "./vite-plugins/fontawesome-subset";
12+
import { fontPreview } from "./vite-plugins/font-preview";
13+
import { envConfig } from "./vite-plugins/env-config";
14+
import { languageHashes } from "./vite-plugins/language-hashes";
15+
import { minifyJson } from "./vite-plugins/minify-json";
16+
import { versionFile } from "./vite-plugins/version-file";
2417

2518
function pad(numbers, maxLength, fillString) {
2619
return numbers.map((number) =>
@@ -63,39 +56,9 @@ export default {
6356
plugins: [
6457
envConfig({ isDevelopment: false, clientVersion: CLIENT_VERSION }),
6558
languageHashes(),
66-
{
67-
name: "vite-plugin-fontawesome-subset",
68-
apply: "build",
69-
buildStart() {
70-
const fontawesomeClasses = getFontawesomeConfig();
71-
fontawesomeSubset(fontawesomeClasses, "src/webfonts-generated", {
72-
targetFormats: ["woff2"],
73-
});
74-
},
75-
},
76-
{
77-
name: "generate-version-json",
78-
apply: "build",
79-
80-
closeBundle() {
81-
const distPath = path.resolve(__dirname, "dist");
82-
if (!existsSync(distPath)) {
83-
mkdirSync(distPath, { recursive: true });
84-
}
85-
86-
const version = CLIENT_VERSION;
87-
const versionJson = JSON.stringify({ version });
88-
const versionPath = path.resolve(distPath, "version.json");
89-
writeFileSync(versionPath, versionJson);
90-
},
91-
},
92-
{
93-
name: "vite-plugin-webfonts-preview",
94-
apply: "build",
95-
buildStart() {
96-
generatePreviewFonts();
97-
},
98-
},
59+
fontawesomeSubset(),
60+
versionFile({ clientVersion: CLIENT_VERSION }),
61+
fontPreview(),
9962
checker({
10063
typescript: {
10164
tsconfigPath: path.resolve(__dirname, "./tsconfig.json"),
@@ -205,68 +168,7 @@ export default {
205168
],
206169
injectTo: "head-prepend",
207170
}),
208-
{
209-
name: "minify-json",
210-
apply: "build",
211-
generateBundle() {
212-
let totalOriginalSize = 0;
213-
let totalMinifiedSize = 0;
214-
215-
const minifyJsonFiles = (dir) => {
216-
readdirSync(dir).forEach((file) => {
217-
const sourcePath = path.join(dir, file);
218-
const stat = statSync(sourcePath);
219-
220-
if (stat.isDirectory()) {
221-
minifyJsonFiles(sourcePath);
222-
} else if (path.extname(file) === ".json") {
223-
const originalContent = readFileSync(sourcePath, "utf8");
224-
const originalSize = Buffer.byteLength(originalContent, "utf8");
225-
const minifiedContent = JSON.stringify(
226-
JSON.parse(originalContent)
227-
);
228-
const minifiedSize = Buffer.byteLength(minifiedContent, "utf8");
229-
230-
totalOriginalSize += originalSize;
231-
totalMinifiedSize += minifiedSize;
232-
233-
writeFileSync(sourcePath, minifiedContent);
234-
235-
// const savings =
236-
// ((originalSize - minifiedSize) / originalSize) * 100;
237-
// console.log(
238-
// `\x1b[0m \x1b[36m${sourcePath}\x1b[0m | ` +
239-
// `\x1b[90mOriginal: ${originalSize} bytes\x1b[0m | ` +
240-
// `\x1b[90mMinified: ${minifiedSize} bytes\x1b[0m | ` +
241-
// `\x1b[32mSavings: ${savings.toFixed(2)}%\x1b[0m`
242-
// );
243-
}
244-
});
245-
};
246-
247-
// console.log("\n\x1b[1mMinifying JSON files...\x1b[0m\n");
248-
249-
minifyJsonFiles("./dist");
250-
251-
const totalSavings =
252-
((totalOriginalSize - totalMinifiedSize) / totalOriginalSize) * 100;
253-
254-
console.log(
255-
`\n\n\x1b[1mJSON Minification Summary:\x1b[0m\n` +
256-
` \x1b[90mTotal original size: ${(
257-
totalOriginalSize /
258-
1024 /
259-
1024
260-
).toFixed(2)} mB\x1b[0m\n` +
261-
` \x1b[90mTotal minified size: ${(
262-
totalMinifiedSize /
263-
1024 /
264-
1024
265-
).toFixed(2)} mB\x1b[0m\n` +
266-
` \x1b[32mTotal savings: ${totalSavings.toFixed(2)}%\x1b[0m\n`
267-
);
268-
},
269-
},
171+
minifyJson(),
270172
],
271173
build: {
272174
sourcemap: process.env.SENTRY,

frontend/vitest.config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { defineConfig } from "vitest/config";
2-
import { languageHashes } from "./scripts/language-hashes";
3-
import { envConfig } from "./scripts/env-config";
2+
import { languageHashes } from "./vite-plugins/language-hashes";
3+
import { envConfig } from "./vite-plugins/env-config";
44

55
export default defineConfig({
66
test: {

0 commit comments

Comments
 (0)