update
This commit is contained in:
182
electron.vite.config.ts
Normal file
182
electron.vite.config.ts
Normal file
@@ -0,0 +1,182 @@
|
||||
import { defineConfig, externalizeDepsPlugin } from 'electron-vite';
|
||||
import react from '@vitejs/plugin-react';
|
||||
import { resolve } from 'path';
|
||||
import { existsSync, realpathSync } from 'fs';
|
||||
import { cp } from 'fs/promises';
|
||||
|
||||
// audit r44 (2026-10-15):src/main/db/migrations/*.sql 是 r44 WIP 落地后
|
||||
// `applyMigrations` 的输入。electron-vite 主进程构建只 emit TS 入口的 JS 产物,
|
||||
// 静态 .sql 不在入口依赖图里,默认不会被拷贝到 out/main/。运行时 sqlite.ts
|
||||
// 走 `applyMigrations(db, join(__dirname, 'migrations'))`(`__dirname` =
|
||||
// packaged 形态下 `resources/app/out/main/`),目录不存在 → `readdirSync` 抛
|
||||
// ENOENT → `initDB` 拒 → 致命对话框 → 应用无法启动。inline rollup 插件
|
||||
// 在 closeBundle 阶段把 SQL 拷到 `out/main/migrations/`(r50 修正:原本
|
||||
// 写 `out/main/db/migrations/` 多一段 `db/`,与 `__dirname/migrations/` 解析
|
||||
// 路径不一致 → 启动 ENOENT),无需新增 vite-plugin-static-copy 依赖。
|
||||
|
||||
const sharedAlias = { '@shared': resolve(__dirname, 'src/shared') };
|
||||
|
||||
// start.cjs 在 Windows + CJK 项目路径下会 chdir 到 ASCII junction。
|
||||
// rollup 内部对 input 走 realpathSync,把 junction 解析回真实 CJK 路径。
|
||||
// vite 的 html 插件用 path.relative(config.root, normalizedId) 算 emit
|
||||
// fileName,root 和 normalizedId 必须同盘才能算出相对路径 'index.html';
|
||||
// 否则跨盘返回绝对路径,触发 "fileName must be neither absolute nor
|
||||
// relative paths"。所以把 root 和 input 都钉到 realpath 后的 CJK 路径。
|
||||
const projectRoot = realpathSync(process.cwd());
|
||||
|
||||
export default defineConfig({
|
||||
main: {
|
||||
plugins: [
|
||||
externalizeDepsPlugin(),
|
||||
{
|
||||
// audit r44 + r50:把 src/main/db/migrations/*.sql 拷到 out/main/migrations/,
|
||||
// 让 `applyMigrations(db, join(__dirname, 'migrations'))` 在 packaged
|
||||
// 形态下能找到 SQL 入口(`__dirname` = `out/main/`,join 'migrations'
|
||||
// = `out/main/migrations/`;r50 修正:原 dst 写 `out/main/db/migrations/`
|
||||
// 多一段 `db/`,与 __dirname 对齐失败 → 启动 ENOENT)。closeBundle 在
|
||||
// emit 完成、产物已写盘后跑;cp({ recursive: true }) 是幂等的(目标目录
|
||||
// 不存在则创建,存在则覆盖同名文件 + 保留新增文件——和 bundler 产物
|
||||
// 语义对齐)。
|
||||
name: 'copy-migrations',
|
||||
closeBundle: async () => {
|
||||
const src = resolve(projectRoot, 'src/main/db/migrations');
|
||||
const dst = resolve(projectRoot, 'out/main/migrations');
|
||||
if (!existsSync(src)) return; // r44 WIP 未落地时 src 不存在,静默跳过
|
||||
await cp(src, dst, { recursive: true });
|
||||
},
|
||||
},
|
||||
],
|
||||
resolve: { alias: sharedAlias },
|
||||
build: {
|
||||
sourcemap: false, // 主进程产物不外发,关 sourcemap 减小
|
||||
minify: true,
|
||||
rollupOptions: {
|
||||
input: { index: resolve(__dirname, 'src/main/index.ts') },
|
||||
},
|
||||
},
|
||||
},
|
||||
preload: {
|
||||
plugins: [externalizeDepsPlugin()],
|
||||
resolve: { alias: sharedAlias },
|
||||
build: {
|
||||
sourcemap: false,
|
||||
minify: true,
|
||||
rollupOptions: {
|
||||
input: { index: resolve(__dirname, 'src/preload/index.ts') },
|
||||
},
|
||||
},
|
||||
},
|
||||
renderer: {
|
||||
// 见 projectRoot 注释:rollup 内部把 input realpath 回 CJK 路径,
|
||||
// root 必须同盘才能让 path.relative 算出 'index.html'。
|
||||
root: resolve(projectRoot, 'src/renderer'),
|
||||
// fix(2026-08-27):Vite 5.4 自带 esbuild 0.21.5,在 Node 24 + Windows CJK
|
||||
// 项目路径下会触发 TypeError: Cannot read properties of undefined
|
||||
// (reading 'imports') (发生在 optimizeDeps 的 depsInfo 合并阶段)。
|
||||
// 不升级 esbuild —— vite@5.4.21 的兼容矩阵锁在 ^0.21.3,顶包升级会破坏
|
||||
// vite 内部假设。三层兜底走 vite 配置:
|
||||
// 1) entries 锁死只扫 main.tsx + i18n,不让 vite 自动扫整个图触发 race
|
||||
// 2) include 强制列出真正被顶层引用的 bare deps,跳过自动发现
|
||||
// 3) esbuildOptions 显式钉住 vite 默认的 browser/esnext(见下方注释)
|
||||
// 副作用:首屏 esbuild 预构建略慢 200~500ms;后面 transform 不受影响。
|
||||
// 注:根治手段是清缓存(`npm run dev:clean`)—— 该 race 一旦写坏
|
||||
// node_modules/.vite/deps/_metadata.json,后续启动会持续复现。
|
||||
optimizeDeps: {
|
||||
entries: [
|
||||
resolve(projectRoot, 'src/renderer/src/main.tsx'),
|
||||
resolve(projectRoot, 'src/renderer/src/i18n/index.ts'),
|
||||
].filter((p) => existsSync(p)) as string[],
|
||||
include: [
|
||||
'react',
|
||||
'react-dom',
|
||||
'react-dom/client',
|
||||
'react-i18next',
|
||||
'i18next',
|
||||
'zustand/shallow',
|
||||
// 动态 import 的重 dep 必须显式 include — Vite 5.4.21 的 dep
|
||||
// optimizer 在 on-the-fly discovery 阶段(markdown-it / codemirror /
|
||||
// highlight.js 这些 dynamic import 触发的预构建)会撞到
|
||||
// dep-BK3b2jBa.js:50835 的 race,输出 undefined.imports 抛错。
|
||||
// 启动期强制 pre-bundle 就绕开 discovery 路径。这是 5.4.x 已知
|
||||
// bug,Vite 6 才修。
|
||||
'markdown-it',
|
||||
'highlight.js/lib/core',
|
||||
'@codemirror/state',
|
||||
'@codemirror/view',
|
||||
'@codemirror/commands',
|
||||
'@codemirror/lang-markdown',
|
||||
// lucide-react — 整个 renderer 用得最广的图标库(40 个文件 import,
|
||||
// 每个图标单独 ESM)。任何 lazy-loaded 路由/视图加载都会触发它的
|
||||
// on-the-fly 优化,5.4.21 在它身上稳定撞 dep-BK3b2jBa.js:50835。
|
||||
// 预 bundle 解决。
|
||||
// audit 2026-09 (V1.9):原注释举例 "Dashboard / Sidebar / RecentView"
|
||||
// —— 三个组件均已下线(Sidebar 被 master-detail + 顶栏取代,
|
||||
// RecentView 随 recent module 一并删除,Dashboard 从未是单一
|
||||
// 组件)。改为泛化描述 "任何 lazy-loaded 路由/视图"。
|
||||
'lucide-react',
|
||||
// audit r40 (2026-10-15):react-virtuoso — 虚拟列表,用于 FavoritesList /
|
||||
// NotesList 等列表组件,首次访问触发 dep discovery race,与
|
||||
// lucide-react 同款机制(5.4.21 dep-BK3b2jBa.js:50835)。预 bundle
|
||||
// 避免首屏「new dependencies optimized」+ 整页 reload(+1-2s 卡顿)。
|
||||
'react-virtuoso',
|
||||
],
|
||||
esbuildOptions: {
|
||||
target: 'esnext',
|
||||
// platform 与 target 都只是显式钉住 vite 的默认值(browser/esnext),
|
||||
// 防止未来改动或插件把 renderer 的预构建误推到 node 分支。
|
||||
// 注:renderer 跑在 Electron 30 的 Chromium 里,esnext 完全安全。
|
||||
platform: 'browser',
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
...sharedAlias,
|
||||
'@': resolve(__dirname, 'src/renderer/src'),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
// 修复:vite dev server 启动时 pre-transform HTML 引用的入口脚本
|
||||
// (index.html → /src/main.tsx),在 Windows + CJK 项目路径下抛
|
||||
// "Failed to load url /src/main.tsx ... Does the file exist?"。
|
||||
// 根因:vite 的 searchForWorkspaceRoot 走 fs.realpathSync 把
|
||||
// ASCII junction 解析回真实 CJK 路径,pre-transform 拿到 CJK
|
||||
// 绝对路径后,在 worker 里读文件失败。把 server.fs.allow 显式
|
||||
// 扩到 junction + 真实路径,让 vite 接受两种路径表达。
|
||||
fs: {
|
||||
strict: false,
|
||||
allow: [
|
||||
resolve(__dirname, 'src/renderer'),
|
||||
// start.cjs 在 chdir 到 junction 后会设置这个环境变量。
|
||||
// dev 时 vite 的 cwd 实际是 junction,所以允许这个路径即可。
|
||||
...(process.env.RKMS_JUNCTION_PATH ? [process.env.RKMS_JUNCTION_PATH] : []),
|
||||
],
|
||||
},
|
||||
},
|
||||
build: {
|
||||
// perf (2026-09-06):sourcemap 改 hidden —— 仍 emit .map 文件给线上
|
||||
// stack trace 反解(主进程 / 渲染进程出错能定位源码),但产物
|
||||
// JS 不再带 `//# sourceMappingURL=` 注释 → Sentry / 用户浏览器
|
||||
// devtools 不会自动尝试拉远程 sourcemap(默认行为)。
|
||||
// 省:主 bundle 内嵌 sourcemap-data 体积 + 网络请求一个 .map。
|
||||
sourcemap: 'hidden',
|
||||
// 现代 Electron 内核(Chrome 120+)
|
||||
target: 'chrome120',
|
||||
// chunk 大小阈值, 超过 1500KB 才告警
|
||||
chunkSizeWarningLimit: 1500,
|
||||
rollupOptions: {
|
||||
// 用 projectRoot(realpath 后)算 input,跟 root 同盘才能让
|
||||
// html 插件的 path.relative(config.root, normalizedId) 算出
|
||||
// 相对路径 'index.html',否则跨盘返回绝对路径触发 rollup 报错。
|
||||
input: { index: resolve(projectRoot, 'src/renderer/index.html') },
|
||||
// 不设 vendor manualChunks — vite 的 dynamic import 已经做 code-splitting;
|
||||
// 强制 vendor 反让 index.html 解析路径出错。
|
||||
},
|
||||
// perf(2026-08-22):polyfill:false — 现代 Chrome 120+ 原生支持 ESM dynamic
|
||||
// import + import.meta,无需 vite 注入 ~3KB polyfill。settings 必须保留
|
||||
// 显式 modulePreload(真),否则 modulepreload 链接不会生成 → 关键 chunk
|
||||
// 串行下载,首屏 FCP 退化。
|
||||
modulePreload: { polyfill: false },
|
||||
},
|
||||
plugins: [react()],
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user