Skip to content

Commit 60f16ec

Browse files
feat: 增加自定义脚本执行后可应用 quill@2.0.3.patch 文件 (#381)
* feat: 增加自定义脚本在安装包时自动应用 Quill patches * feat: 增加自定义脚本在安装包时自动应用 Quill patches 2 * feat: 逻辑优化 * feat: pnpm 安装 patch 路径 * feat: pnpm 自动执行 patch 应用 * feat: pnpm 自动执行 patch 应用提示信息 * feat: 移除 postinstall * feat: 修正 npm、yarn 包管理器 patch 文件的 diff 路径 * feat: pnpm patch 执行后重新安装依赖 * feat: pnpm 应用 patch 只需要执行 pnpm i 即可 * feat: 逻辑修正完整 * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent ea98efd commit 60f16ec

3 files changed

Lines changed: 267 additions & 0 deletions

File tree

packages/docs/fluent-editor/docs/demo/collaborative-editing.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@
3030
pnpm i quill-cursors y-protocols y-quill yjs y-indexeddb y-websocket
3131
```
3232

33+
手动执行如下代码应用 `quill@2.0.3.patch` 优化中文输入体验
34+
35+
```bash
36+
node node_modules/@opentiny/fluent-editor/scripts/apply-patches.cjs
37+
```
38+
3339
引入协同编辑模块和依赖
3440

3541
```javascript
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
const { execSync } = require('node:child_process')
2+
const fs = require('node:fs')
3+
const path = require('node:path')
4+
5+
/*
6+
* 应用 Quill 补丁脚本
7+
* 功能:修复 Quill 编辑器输入法状态下的批处理问题,提升中文输入体验
8+
*
9+
* 自动应用:安装包时 postinstall 脚本自动应用,支持所有包管理器-受限于 postinstall 规则暂未实现
10+
*
11+
* 手动应用:在项目根目录执行
12+
* node node_modules/@opentiny/fluent-editor/scripts/apply-patches.cjs
13+
*
14+
* 工作原理:
15+
* 1. 检测包管理器类型(pnpm/npm/yarn)
16+
* 2. 自动检测 Quill 安装位置
17+
* 3. 根据包管理器类型应用不同的补丁策略
18+
*
19+
* 注意事项:
20+
* - 补丁是幂等的,多次运行无副作用
21+
* - 需要 node_modules 写入权限
22+
* - 不影响其他包或项目的补丁
23+
*/
24+
25+
// 获取包管理器
26+
function detectPackageManager() {
27+
try {
28+
const lockFiles = {
29+
'pnpm-lock.yaml': 'pnpm',
30+
'yarn.lock': 'yarn',
31+
'package-lock.json': 'npm',
32+
}
33+
34+
for (const [file, manager] of Object.entries(lockFiles)) {
35+
if (fs.existsSync(file)) return manager
36+
}
37+
38+
const userAgent = process.env.npm_config_user_agent || ''
39+
if (userAgent.includes('pnpm')) return 'pnpm'
40+
if (userAgent.includes('yarn')) return 'yarn'
41+
if (userAgent.includes('npm')) return 'npm'
42+
}
43+
catch {
44+
return 'npm'
45+
}
46+
47+
return 'npm'
48+
}
49+
50+
// 拷贝 patches 文件
51+
function copyPatchFile() {
52+
const packageManager = detectPackageManager()
53+
// 把 patch 文件复制到哪里
54+
const dest = `patches/${packageManager === 'pnpm' ? 'quill@2.0.3.patch' : 'quill+2.0.3.patch'}`
55+
56+
// 文件存在直接返回
57+
if (fs.existsSync(dest)) {
58+
return true
59+
}
60+
61+
// 复制 patch 文件的路径
62+
const src = path.resolve(__dirname, '../patches/quill@2.0.3.patch')
63+
64+
if (fs.existsSync(src)) {
65+
fs.mkdirSync('patches', { recursive: true })
66+
67+
if (packageManager === 'pnpm') {
68+
fs.copyFileSync(src, dest)
69+
}
70+
else {
71+
let content = fs.readFileSync(src, 'utf-8')
72+
content = content.replaceAll('core/editor.js', 'node_modules/quill/core/editor.js')
73+
fs.writeFileSync(dest, content)
74+
}
75+
76+
console.log(`✅ 已复制 patch 文件到 ${dest}`)
77+
return true
78+
}
79+
else {
80+
console.log(`⚠️ 未找到 patch 文件,请手动创建 ${dest}`)
81+
return false
82+
}
83+
}
84+
85+
// pnpm 应用 patch 文件
86+
function setupPnpmPatch() {
87+
try {
88+
const packageJsonPath = 'package.json'
89+
if (!fs.existsSync(packageJsonPath)) {
90+
console.log('⚠️ 未找到 package.json')
91+
return false
92+
}
93+
94+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
95+
96+
// 检查是否已经有 pnpm.patchedDependencies 配置
97+
if (packageJson.pnpm?.patchedDependencies?.['quill@2.0.3']) {
98+
console.log('✅ pnpm patchedDependencies 已配置')
99+
return true
100+
}
101+
102+
// 添加 pnpm.patchedDependencies 配置
103+
if (!packageJson.pnpm) {
104+
packageJson.pnpm = {}
105+
}
106+
107+
if (!packageJson.pnpm.patchedDependencies) {
108+
packageJson.pnpm.patchedDependencies = {}
109+
}
110+
111+
packageJson.pnpm.patchedDependencies['quill@2.0.3'] = 'patches/quill@2.0.3.patch'
112+
113+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
114+
console.log('✅ 已添加 pnpm patchedDependencies 配置')
115+
116+
try {
117+
execSync('pnpm install', { stdio: 'inherit' })
118+
console.log('✅ pnpm patch quill@2.0.3 应用成功!')
119+
}
120+
catch (error) {
121+
console.warn('❌ pnpm patch 命令执行失败:', error.message)
122+
}
123+
124+
return true
125+
}
126+
catch (error) {
127+
console.error('❌ pnpm 补丁配置失败:', error.message)
128+
return false
129+
}
130+
}
131+
132+
// npm、yarn 应用 patch 文件
133+
function applyPatchPackage() {
134+
try {
135+
const packageManager = detectPackageManager()
136+
137+
// 检查 patch-package 是否安装
138+
let patchPackageInstalled = false
139+
try {
140+
require.resolve('patch-package')
141+
patchPackageInstalled = true
142+
}
143+
catch (e) {
144+
// patch-package 未安装
145+
}
146+
147+
if (!patchPackageInstalled) {
148+
console.log('📦 正在安装 patch-package...')
149+
try {
150+
const installCommand = packageManager === 'yarn' ? 'yarn add --dev patch-package' : 'npm install --save-dev patch-package'
151+
execSync(installCommand, { stdio: 'inherit' })
152+
console.log('✅ patch-package 安装成功')
153+
}
154+
catch (error) {
155+
console.error('❌ patch-package 安装失败:', error.message)
156+
return false
157+
}
158+
}
159+
160+
// 应用补丁
161+
console.log('🔄 正在应用 patch...')
162+
try {
163+
execSync('npx patch-package', { stdio: 'inherit' })
164+
console.log('✅ 补丁应用成功')
165+
}
166+
catch (error) {
167+
console.error('❌ 补丁应用失败:', error.message)
168+
return false
169+
}
170+
171+
// 添加 postinstall 脚本
172+
const packageJsonPath = 'package.json'
173+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
174+
175+
if (!packageJson.scripts) {
176+
packageJson.scripts = {}
177+
}
178+
179+
if (!packageJson.scripts.postinstall || !packageJson.scripts.postinstall.includes('patch-package')) {
180+
const existingPostinstall = packageJson.scripts.postinstall || ''
181+
packageJson.scripts.postinstall = existingPostinstall ? `${existingPostinstall} && npx patch-package` : 'npx patch-package'
182+
183+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
184+
console.log('✅ 已更新 postinstall 脚本')
185+
}
186+
187+
return true
188+
}
189+
catch (error) {
190+
console.error('❌ patch-package 应用失败:', error.message)
191+
return false
192+
}
193+
}
194+
195+
function handlePatchFailure() {
196+
console.log(`
197+
❌ 补丁处理失败,请尝试手动安装
198+
199+
🔧 手动安装:
200+
在项目根目录执行:
201+
node node_modules/@opentiny/fluent-editor/scripts/apply-patches.cjs
202+
203+
⚠️ 注意:未应用补丁可能影响中文输入体验
204+
`)
205+
}
206+
207+
function applyQuillPatch() {
208+
const packageManager = detectPackageManager()
209+
console.log(`🔍 检测到包管理器: ${packageManager}`)
210+
console.log('📋 准备 patch 文件...')
211+
212+
if (!copyPatchFile()) return handlePatchFailure()
213+
214+
let strategy
215+
if (packageManager == 'pnpm') {
216+
strategy = {
217+
label: '📦 使用 pnpm 补丁策略...',
218+
handler: setupPnpmPatch,
219+
successMsg: '✅ quill@2.0.3.patch 补丁配置已完成',
220+
}
221+
}
222+
else {
223+
strategy = {
224+
label: '📦 使用 patch-package 补丁策略...',
225+
handler: applyPatchPackage,
226+
successMsg: '🎉 补丁处理完成',
227+
}
228+
}
229+
230+
if (!strategy) {
231+
console.log('❌ 不支持的包管理器,仅支持 pnpm、yarn、npm')
232+
handlePatchFailure()
233+
return
234+
}
235+
236+
console.log(strategy.label)
237+
// 调用处理函数
238+
const success = strategy.handler()
239+
240+
if (success) {
241+
console.log(strategy.successMsg)
242+
}
243+
else {
244+
handlePatchFailure()
245+
}
246+
}
247+
248+
applyQuillPatch()

packages/fluent-editor/scripts/pre-release.cjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,19 @@ function preRelease() {
4545
shelljs.sed('-i', `"module": "src/index.ts"`, `"module": "es/index.es.js"`, targetFile)
4646
shelljs.sed('-i', `"types": "dist/types/index.d.ts"`, `"types": "types/index.d.ts"`, targetFile)
4747
shelljs.cp('-rf', '../../README.md', 'dist')
48+
49+
// 创建 scripts 目录并复制自定义补丁脚本
50+
shelljs.mkdir('-p', path.resolve(__dirname, '../dist/scripts'))
51+
shelljs.cp('-rf', path.resolve(__dirname, 'apply-patches.cjs'), path.resolve(__dirname, '../dist/scripts/'))
52+
53+
// 复制 patches 目录到 dist
54+
const patchesSourceDir = path.resolve(__dirname, '../../../patches')
55+
const patchesTargetDir = path.resolve(__dirname, '../dist/patches')
56+
if (shelljs.test('-d', patchesSourceDir)) {
57+
shelljs.mkdir('-p', patchesTargetDir)
58+
shelljs.cp('-rf', `${patchesSourceDir}/*`, patchesTargetDir)
59+
console.log('✅ Patches copied to dist/patches')
60+
}
4861
}
4962

5063
preRelease()

0 commit comments

Comments
 (0)