-
Notifications
You must be signed in to change notification settings - Fork 125
Expand file tree
/
Copy pathelectron.vite.config.ts
More file actions
142 lines (134 loc) · 5.46 KB
/
Copy pathelectron.vite.config.ts
File metadata and controls
142 lines (134 loc) · 5.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
import { resolve } from 'node:path'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
import type { Plugin } from 'vite'
/**
* ★ electron-vite 5 的 `vite:isolate-entries` 插件在 stdout **不是 TTY** 时崩:
* 它无条件调 `process.stdout.moveCursor()` 去擦一行进度,而这几个方法只在
* TTY 上才存在。真终端里看不出来,CI、`npm run e2e`、任何把输出重定向到文件的
* 调用都会挂在 `process.stdout.moveCursor is not a function` 上 ——
* 而报错文案完全不提 TTY,看起来像 preload 打包坏了。
*
* 补三个空实现。只在缺席时定义,所以真 TTY 下的行为一个字节都没变。
* 这比在每个调用点套 `script -q /dev/null` 伪终端可靠:忘一次就是一次假失败。
*/
function shimNonTtyCursor(): void {
const out = process.stdout as unknown as Record<string, unknown>
if (typeof out['moveCursor'] !== 'function') out['moveCursor'] = () => true
if (typeof out['clearLine'] !== 'function') out['clearLine'] = () => true
if (typeof out['cursorTo'] !== 'function') out['cursorTo'] = () => true
}
shimNonTtyCursor()
/**
* index.html 里写死的是**生产用的严格 CSP**;dev 下 react-refresh 会注入内联
* <script>、HMR 要连 ws://localhost —— 严格 CSP 会把它们全挡掉。
*
* 这里在 dev 时整段替换成放宽版。故意做成「替换」而不是「注入」:
* 插件哪天没生效,留在页面里的就是严格版,失败方向朝安全那边倒。
*/
function cspDevPlugin(): Plugin {
const DEV_CSP = [
"default-src 'self'",
"script-src 'self' 'unsafe-inline'",
"style-src 'self' 'unsafe-inline'",
/*
★ `ncw:` 必须显式列出,**`*` 覆盖不到它**。CSP 的 `*` 通配符只匹配
网络 scheme(http/https/ws/ftp),自定义 scheme 一律要点名。
所以这行看着已经很宽,少了 `ncw:` 照样把附件图全挡掉。
*/
'img-src * data: blob: ncw:',
"media-src 'self' ncw:",
"font-src 'self' data:",
"connect-src 'self' ncw: ws://localhost:* http://localhost:* ws://127.0.0.1:* http://127.0.0.1:*",
/*
★ 插件视图的 iframe。**不能省**:没有 frame-src 时回退到
`default-src 'self'`,`ncw-plugin://` 直接被拦 —— 自定义编辑器的
标签页开得出来却一片空白(同 src/renderer/index.html 里那段说明)。
自定义 scheme 同样要点名,`*` 覆盖不到。
*/
'frame-src ncw-plugin:',
"object-src 'none'",
"base-uri 'none'"
].join('; ')
return {
name: 'nextcowork:csp-dev',
apply: 'serve',
transformIndexHtml(html: string) {
return html.replace(
/<meta\s+http-equiv="Content-Security-Policy"[\s\S]*?\/>/,
`<meta http-equiv="Content-Security-Policy" content="${DEV_CSP}" />`
)
}
}
}
export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()],
resolve: {
alias: {
'@shared': resolve('src/shared'),
'@main': resolve('src/main')
}
},
build: {
rollupOptions: {
/*
★ 第二个入口是**插件宿主窗口**的 preload。
它在 main 这一段构建而不是 preload 那一段:`preload` 段开着
`isolatedEntries`(沙箱 preload 必须打成单文件),而那个模式下第二个
入口不会产出任何东西。main 段的产物同样是可以直接当 preload 加载的
单文件,而这个文件只 import `electron` —— 沙箱 preload 允许的就是它。
★ 它必须和主窗口那份 preload **分开**:两者的信任级别不一样
(主窗口是我们的代码,插件宿主跑的是第三方代码),共用一份意味着
主窗口的每一条频道都顺带对插件开放,而那个口子不会有人注意到。
见 `src/preload/plugin-preload.ts`。
*/
input: { index: resolve('src/main/entry.ts') },
output: { chunkFileNames: '[name]-[hash].js' }
}
}
},
preload: {
resolve: {
alias: {
'@shared': resolve('src/shared')
}
},
build: {
// ★ 沙箱化 preload 无法 require 多文件,必须完整打包成单文件。
// isolatedEntries 是 electron-vite 5 为 Electron sandbox 提供的前提开关。
isolatedEntries: true,
externalizeDeps: false,
rollupOptions: {
input: { index: resolve('src/preload/index.ts') }
}
}
},
renderer: {
root: 'src/renderer',
plugins: [react(), tailwindcss(), cspDevPlugin()],
resolve: {
alias: {
'@shared': resolve('src/shared'),
'@renderer': resolve('src/renderer/src')
},
/*
* ★ @lobehub/streamdown 声明 katex ^0.18,仓库其余部分(rehype-katex /
* remark-math / mermaid)统一在 0.16,npm 因此在 streamdown 下嵌套了第二份。
* 两份 katex 各 ~590K 源码,不去重就都进 renderer bundle。
*
* streamdown 只用 katex 的 `renderToString` 做「尾部公式能不能渲染」的
* 布尔探测(latex.ts `isLastFormulaRenderable`),渲染结果直接丢弃 ——
* 不产出任何进入 DOM 的 markup,所以降到 0.16 不存在 markup 与
* katex.min.css 版本错配的风险,这正是能安全 dedupe 的前提。
*/
dedupe: ['katex']
},
build: {
rollupOptions: {
input: { index: resolve('src/renderer/index.html') }
}
}
}
})