@opentiny/fluent-editor
Version:
A rich text editor based on Quill 2.0, which extends rich modules and formats on the basis of Quill. It's powerful and out-of-the-box.
249 lines (209 loc) • 6.88 kB
JavaScript
const { execSync } = require('node:child_process')
const fs = require('node:fs')
const path = require('node:path')
/*
* 应用 Quill 补丁脚本
* 功能:修复 Quill 编辑器输入法状态下的批处理问题,提升中文输入体验
*
* 自动应用:安装包时 postinstall 脚本自动应用,支持所有包管理器-受限于 postinstall 规则暂未实现
*
* 手动应用:在项目根目录执行
* node node_modules/@opentiny/fluent-editor/scripts/apply-patches.cjs
*
* 工作原理:
* 1. 检测包管理器类型(pnpm/npm/yarn)
* 2. 自动检测 Quill 安装位置
* 3. 根据包管理器类型应用不同的补丁策略
*
* 注意事项:
* - 补丁是幂等的,多次运行无副作用
* - 需要 node_modules 写入权限
* - 不影响其他包或项目的补丁
*/
// 获取包管理器
function detectPackageManager() {
try {
const lockFiles = {
'pnpm-lock.yaml': 'pnpm',
'yarn.lock': 'yarn',
'package-lock.json': 'npm',
}
for (const [file, manager] of Object.entries(lockFiles)) {
if (fs.existsSync(file)) return manager
}
const userAgent = process.env.npm_config_user_agent || ''
if (userAgent.includes('pnpm')) return 'pnpm'
if (userAgent.includes('yarn')) return 'yarn'
if (userAgent.includes('npm')) return 'npm'
}
catch {
return 'npm'
}
return 'npm'
}
// 拷贝 patches 文件
function copyPatchFile() {
const packageManager = detectPackageManager()
// 把 patch 文件复制到哪里
const dest = `patches/${packageManager === 'pnpm' ? 'quill@2.0.3.patch' : 'quill+2.0.3.patch'}`
// 文件存在直接返回
if (fs.existsSync(dest)) {
return true
}
// 复制 patch 文件的路径
const src = path.resolve(__dirname, '../patches/quill@2.0.3.patch')
if (fs.existsSync(src)) {
fs.mkdirSync('patches', { recursive: true })
if (packageManager === 'pnpm') {
fs.copyFileSync(src, dest)
}
else {
let content = fs.readFileSync(src, 'utf-8')
content = content.replaceAll('core/editor.js', 'node_modules/quill/core/editor.js')
fs.writeFileSync(dest, content)
}
console.log(`✅ 已复制 patch 文件到 ${dest}`)
return true
}
else {
console.log(`⚠️ 未找到 patch 文件,请手动创建 ${dest}`)
return false
}
}
// pnpm 应用 patch 文件
function setupPnpmPatch() {
try {
const packageJsonPath = 'package.json'
if (!fs.existsSync(packageJsonPath)) {
console.log('⚠️ 未找到 package.json')
return false
}
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
// 检查是否已经有 pnpm.patchedDependencies 配置
if (packageJson.pnpm?.patchedDependencies?.['quill@2.0.3']) {
console.log('✅ pnpm patchedDependencies 已配置')
return true
}
// 添加 pnpm.patchedDependencies 配置
if (!packageJson.pnpm) {
packageJson.pnpm = {}
}
if (!packageJson.pnpm.patchedDependencies) {
packageJson.pnpm.patchedDependencies = {}
}
packageJson.pnpm.patchedDependencies['quill@2.0.3'] = 'patches/quill@2.0.3.patch'
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
console.log('✅ 已添加 pnpm patchedDependencies 配置')
try {
execSync('pnpm install', { stdio: 'inherit' })
console.log('✅ pnpm patch quill@2.0.3 应用成功!')
}
catch (error) {
console.warn('❌ pnpm patch 命令执行失败:', error.message)
}
return true
}
catch (error) {
console.error('❌ pnpm 补丁配置失败:', error.message)
return false
}
}
// npm、yarn 应用 patch 文件
function applyPatchPackage() {
try {
const packageManager = detectPackageManager()
// 检查 patch-package 是否安装
let patchPackageInstalled = false
try {
require.resolve('patch-package')
patchPackageInstalled = true
}
catch (e) {
// patch-package 未安装
}
if (!patchPackageInstalled) {
console.log('📦 正在安装 patch-package...')
try {
const installCommand = packageManager === 'yarn' ? 'yarn add --dev patch-package' : 'npm install --save-dev patch-package'
execSync(installCommand, { stdio: 'inherit' })
console.log('✅ patch-package 安装成功')
}
catch (error) {
console.error('❌ patch-package 安装失败:', error.message)
return false
}
}
// 应用补丁
console.log('🔄 正在应用 patch...')
try {
execSync('npx patch-package', { stdio: 'inherit' })
console.log('✅ 补丁应用成功')
}
catch (error) {
console.error('❌ 补丁应用失败:', error.message)
return false
}
// 添加 postinstall 脚本
const packageJsonPath = 'package.json'
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'))
if (!packageJson.scripts) {
packageJson.scripts = {}
}
if (!packageJson.scripts.postinstall || !packageJson.scripts.postinstall.includes('patch-package')) {
const existingPostinstall = packageJson.scripts.postinstall || ''
packageJson.scripts.postinstall = existingPostinstall ? `${existingPostinstall} && npx patch-package` : 'npx patch-package'
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2))
console.log('✅ 已更新 postinstall 脚本')
}
return true
}
catch (error) {
console.error('❌ patch-package 应用失败:', error.message)
return false
}
}
function handlePatchFailure() {
console.log(`
❌ 补丁处理失败,请尝试手动安装
🔧 手动安装:
在项目根目录执行:
node node_modules/@opentiny/fluent-editor/scripts/apply-patches.cjs
⚠️ 注意:未应用补丁可能影响中文输入体验
`)
}
function applyQuillPatch() {
const packageManager = detectPackageManager()
console.log(`🔍 检测到包管理器: ${packageManager}`)
console.log('📋 准备 patch 文件...')
if (!copyPatchFile()) return handlePatchFailure()
let strategy
if (packageManager == 'pnpm') {
strategy = {
label: '📦 使用 pnpm 补丁策略...',
handler: setupPnpmPatch,
successMsg: '✅ quill@2.0.3.patch 补丁配置已完成',
}
}
else {
strategy = {
label: '📦 使用 patch-package 补丁策略...',
handler: applyPatchPackage,
successMsg: '🎉 补丁处理完成',
}
}
if (!strategy) {
console.log('❌ 不支持的包管理器,仅支持 pnpm、yarn、npm')
handlePatchFailure()
return
}
console.log(strategy.label)
// 调用处理函数
const success = strategy.handler()
if (success) {
console.log(strategy.successMsg)
}
else {
handlePatchFailure()
}
}
applyQuillPatch()