Skip to content

Commit 99aedac

Browse files
BloomyInDevCopilot
andcommitted
feat: add/reconfigure vite plugins
Co-authored-by: Copilot <copilot@github.com>
1 parent dc36bd3 commit 99aedac

6 files changed

Lines changed: 367 additions & 60 deletions

File tree

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,6 @@ coverage
3434

3535
# Vitest
3636
__screenshots__/
37+
38+
# Custom
39+
.vite-webp-cache/

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,10 @@
4343
"svgo": "^4.0.1",
4444
"typescript": "~6.0.2",
4545
"vite": "^8.0.8",
46+
"vite-plugin-compression2": "^2.5.3",
4647
"vite-plugin-image-optimizer": "^2.0.3",
4748
"vite-plugin-vue-devtools": "^8.0.3",
49+
"vite-plugin-webfont-dl": "^3.12.0",
4850
"vite-ssg": "^28.2.2",
4951
"vite-ssg-sitemap": "^0.10.0",
5052
"vue-tsc": "^3.1.1"

plugins/convertToWebp.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { globSync } from "node:fs";
2+
import sharp from "sharp";
3+
import path from "node:path";
4+
import { access, mkdir, rm } from "node:fs/promises";
5+
import { PluginOption } from "vite";
6+
7+
const plugin: (webpOptions: sharp.WebpOptions) => PluginOption = (webpOptions) => {
8+
const generated: string[] = [];
9+
const cacheRoot = path.resolve(process.cwd(), ".vite-webp-cache");
10+
11+
const pathExists = async (file: string): Promise<boolean> => {
12+
try {
13+
await access(file);
14+
return true;
15+
} catch {
16+
return false;
17+
}
18+
};
19+
20+
const toWebpCachePath = (file: string): string => {
21+
const relative = path.relative(process.cwd(), file);
22+
return path.join(cacheRoot, relative).replace(/\.(jpg|jpeg|png)$/i, ".webp");
23+
};
24+
25+
return {
26+
name: "convert-to-webp",
27+
apply: "build",
28+
enforce: "pre",
29+
30+
buildStart: async () => {
31+
const files = globSync("src/**/*.{jpg,jpeg,png}");
32+
for (const file of files) {
33+
const out = toWebpCachePath(path.resolve(file));
34+
await mkdir(path.dirname(out), { recursive: true });
35+
const pathExistsInCache = await pathExists(out);
36+
if (!pathExistsInCache) {
37+
await sharp(file).webp(webpOptions).toFile(out);
38+
generated.push(out);
39+
console.log(`✓ ${path.basename(file)} → webp`);
40+
}
41+
}
42+
},
43+
44+
resolveId: async function (source, importer) {
45+
if (/\.(jpg|jpeg|png)$/i.test(source) && importer) {
46+
const resolved = await this.resolve(source, importer, { skipSelf: true });
47+
if (!resolved?.id) return;
48+
49+
const cleanId = resolved.id.split("?")[0];
50+
const webp = toWebpCachePath(path.resolve(cleanId));
51+
const isWebpPathValid = await pathExists(webp);
52+
if (isWebpPathValid) return webp;
53+
}
54+
},
55+
56+
closeBundle: async () => {
57+
for (const file of generated) {
58+
if (await pathExists(file)) {
59+
await rm(file, { force: true });
60+
console.log(`🗑 ${path.basename(file)} supprimé`);
61+
}
62+
}
63+
64+
const doesPathExist = await pathExists(cacheRoot);
65+
if (doesPathExist) {
66+
await rm(cacheRoot, { recursive: true, force: true });
67+
}
68+
},
69+
};
70+
};
71+
72+
export default plugin;

src/styles/main.css

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
@import url("https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap");
2-
31
:root {
42
background-image: linear-gradient(115deg, #004094 50%, #00f7ff);
53
font-family: "Fira Sans", sans-serif;

vite.config.ts

Lines changed: 12 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
import { fileURLToPath, URL } from "node:url"
22
import fs from "fs/promises"
33

4-
import { PluginOption, UserConfig } from "vite"
4+
import { UserConfig } from "vite"
55
import { ViteSSGOptions } from "vite-ssg"
66
import generateSitemap from "vite-ssg-sitemap"
77
import vue from "@vitejs/plugin-vue"
88
import vueDevTools from "vite-plugin-vue-devtools"
99
import { ViteImageOptimizer as viteImageOptimizer } from "vite-plugin-image-optimizer"
10+
import convertToWebp from "./plugins/convertToWebp"
11+
import webfontDownload from "vite-plugin-webfont-dl"
12+
import { compression, defineAlgorithm } from "vite-plugin-compression2"
13+
import zlib from "zlib"
1014

1115
import { projects } from "./src/script/projects"
1216
import type { CustomRouteMetadata } from "./src/types"
1317
import type { RouteRecordRaw } from "vue-router"
1418

1519
import * as child from "child_process"
16-
import { globSync } from "node:fs"
17-
import path from "node:path"
18-
import sharp from "sharp"
1920

2021
type ViteImageOptimizerOptions = Required<NonNullable<Parameters<typeof viteImageOptimizer>[0]>>
2122

@@ -30,57 +31,6 @@ const imageOptimizerOptions: Pick<
3031
avif: { quality: 75 },
3132
}
3233

33-
const convertToWebp: (webpOptions: sharp.WebpOptions) => PluginOption = (webpOptions) => {
34-
const generated: string[] = []
35-
36-
return {
37-
name: "convert-to-webp",
38-
apply: "build",
39-
enforce: "pre",
40-
41-
buildStart: async () => {
42-
const files = globSync("src/**/*.{jpg,jpeg,png}")
43-
for (const file of files) {
44-
const out = file.replace(/\.(jpg|jpeg|png)$/, ".webp")
45-
46-
try {
47-
await fs.access(out)
48-
// File exists, do nothing
49-
} catch {
50-
// File doesn't exist, generate it
51-
await sharp(file).webp(webpOptions).toFile(out)
52-
generated.push(out)
53-
console.log(`✓ ${path.basename(file)} → webp`)
54-
}
55-
}
56-
},
57-
58-
resolveId: async (source, importer) => {
59-
if (/\.(jpg|jpeg|png)$/.test(source) && importer) {
60-
const dir = path.dirname(importer)
61-
const resolved = path.resolve(dir, source)
62-
const webp = resolved.replace(/\.(jpg|jpeg|png)$/, ".webp")
63-
64-
try {
65-
await fs.access(webp)
66-
// File exists, redirect to webp version
67-
return webp
68-
} catch {
69-
// File doesn't exist, do nothing
70-
}
71-
}
72-
},
73-
74-
closeBundle: async () => {
75-
await Promise.all(
76-
generated.map((file) =>
77-
fs.rm(file).then(() => console.log(`🗑 ${path.basename(file)} deleted`)),
78-
),
79-
)
80-
},
81-
}
82-
}
83-
8434
const badUA = await fs.readFile("src/knownBadUA.txt", "utf-8")
8535

8636
process.env.VITE_GIT_COMMIT_HASH = child.execSync("git rev-parse --short HEAD").toString()
@@ -95,6 +45,13 @@ export default {
9545
vueDevTools(),
9646
convertToWebp(imageOptimizerOptions.webp),
9747
viteImageOptimizer(imageOptimizerOptions),
48+
webfontDownload(["https://fonts.googleapis.com/css2?family=Fira+Sans&display=swap"]),
49+
compression({
50+
algorithms: [
51+
"gzip",
52+
defineAlgorithm("br", { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 11 } }),
53+
],
54+
}),
9855
],
9956
resolve: {
10057
alias: {

0 commit comments

Comments
 (0)