Files

116 lines
4.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { existsSync } from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
import react from "@vitejs/plugin-react";
import { defineConfig, type Plugin } from "vite";
import sourceIdentifierPlugin from "vite-plugin-source-identifier";
const rootDir = fileURLToPath(new URL(".", import.meta.url));
// 依赖预构建缓存被重建后(pnpm install / 重复启动 vite / --force),
// 残留的旧浏览器标签页仍会按旧版本号(?v=<hash>)请求已删除的 chunk,
// 每次都在终端刷 "The file does not exist ... in the optimize deps directory"。
// 该插件拦截这类「文件确实不存在」的 deps 请求,返回一段触发 location.reload()
// 的模块脚本,让旧页面自愈到新版本;sessionStorage 防止真正的坏页面无限刷新。
const staleDepsChunkSelfReload = (): Plugin => ({
name: "stale-deps-chunk-self-reload",
configureServer(server) {
const depsDir = path.join(rootDir, "node_modules", ".vite", "deps");
server.middlewares.use((req, res, next) => {
const match = /^\/node_modules\/\.vite\/deps\/([^?]+)/.exec(req.url ?? "");
if (!match) {
next();
return;
}
const filePath = path.join(depsDir, decodeURIComponent(match[1]));
if (existsSync(filePath)) {
next();
return;
}
res.setHeader("Content-Type", "application/javascript");
res.end(
"if(!sessionStorage.getItem('__vite_stale_chunk_reloaded__')){" +
"sessionStorage.setItem('__vite_stale_chunk_reloaded__','1');" +
"location.reload();}",
);
});
},
});
// Tailwind 4 emits CSS cascade layers, which require Chrome 99+. Chrome 100
// is therefore the practical lower bound for this Win7 legacy build.
const LEGACY_CHROME = 100 << 16;
export default defineConfig({
plugins: [staleDepsChunkSelfReload(), sourceIdentifierPlugin(), react()],
css: {
// Also used by the production CSS minifier. Development CSS is handled
// by the matching PostCSS compatibility pass in postcss.config.js.
lightningcss: {
targets: {
chrome: LEGACY_CHROME,
},
},
},
resolve: {
alias: [
{
// react-syntax-highlighter@16.1.1 exposes an async `sqlMore`
// loader, but its own highlight.js@10.x dependency has no
// `sql_more` module. Reuse the bundled SQL grammar so Rollup can
// resolve every generated language loader without leaving a broken
// browser-time external import.
find: /^highlight\.js\/lib\/languages\/sql_more$/,
replacement: "highlight.js/lib/languages/sql",
},
{
find: "@/env",
replacement: path.resolve(rootDir, "src/env.ts"),
},
{
find: "next/navigation",
replacement: path.resolve(rootDir, "src/shims/next-navigation.ts"),
},
{
find: "next/link",
replacement: path.resolve(rootDir, "src/shims/next-link.tsx"),
},
{
find: "@vite",
replacement: path.resolve(rootDir, "src"),
},
{
find: "@",
replacement: path.resolve(rootDir, "src"),
},
],
},
// 预打包语法高亮核心依赖:refractor/react-syntax-highlighter 只被
// react-syntax-highlighter/dist/esm/* 的二次 import 触达,属「迟发现依赖」——
// 运行中途才触发 Vite 重新预打包会重排全部 chunk 名,浏览器在同一个 ?v=hash
// 下混用新旧缓存 chunk,报 "does not provide an export named 'refractor'"
// 并整树白屏(清 node_modules/.vite + 重启 + 硬刷新才恢复)。启动即预打包可避免。
optimizeDeps: {
include: ["react-syntax-highlighter", "refractor"],
},
// Relative URLs make the same build work at the domain root and at any
// Nginx path prefix. A fixed prefix can still be supplied at release time.
base: process.env.VITE_ASSET_BASE ?? "./",
build: {
cssMinify: "lightningcss",
target: "chrome100",
rollupOptions: {
input: {
main: path.resolve(rootDir, "index.html"),
"task-entry": path.resolve(rootDir, "task-entry.html"),
},
},
},
server: {
// 与 scripts/env.sh FRONTEND_PORT=5174、圆桌 wujie 嵌入文档一致。
port: 5173,
// 无界宿主跨域 fetch 子应用静态资源时,Vite 需回显请求的 Origin。
cors: true,
},
});