1. 信创迁移中的真实困境:公式编辑这块硬骨头
最近陆续帮几个客户做站点迁移,几乎每一家都绕不开同一个问题:公式编辑怎么办?这事儿搁普通CMS站点上根本不算事,但凡是涉足教育、科研、工程技术这类领域的老站点,基本上都积累了成百上千篇带数学公式的内容,从高等数学到量子力学,从结构力学到信号处理,满了屏的积分符号和希腊字母。一旦迁移到信创环境,最先暴露的往往不是服务器性能,不是数据库兼容,而是这些早就老态龙钟的公式插件。
我说的信创环境,指的是基于国产处理器和国产操作系统的整条技术栈。这些年国产化替代推进得很猛,底层芯片、操作系统、数据库、中间件都在换血。问题在于,应用层的生态配套速度远远跟不上底层的迭代速度。WordPress本身是PHP应用,跑在国产Linux发行版上通常问题不大,PHP的跨平台性还是相当靠谱的。真正让人头疼的,是那些依赖特定JavaScript库、特定字体渲染、甚至特定浏览器插件的公式编辑功能。
举一个实际的场景。某地方高校的公开课平台,用的是WordPress多站网络结构,两百多个站点里,有三分之一是理工科院系在维护,日常发布的教学内容里大量使用LaTeX格式的数学公式。迁移之前用的是某款经典公式编辑插件,能编辑、能预览、能渲染,老师们用了七八年,早就形成了肌肉记忆。迁移到某国产服务器平台之后,发现公式在编辑器里能输入,但发布后页面上的公式全是乱码,再不就是一个公式渲染成一个巨大的红叉。折腾了一周,最终结论是:原来那款插件的核心渲染库用的是WebAssembly编译产物,对指令集架构有硬性依赖,在国产芯片上没法运行。
这就是典型的信创兼容性问题,而且这类问题不是靠修修补补能解决的,得在架构层面就做好选型。我今天就把这几年在信创环境里处理WordPress公式编辑的完整思路整理出来,从方案选型到部署配置,从踩坑实录到性能调优,尽量把能说清楚的都说清楚。
2. 公式编辑的方案分层:先搞清楚自己的站点属于哪一档
2.1 轻量传输层方案:只存语法,不存渲染结果
公式编辑这件事,单从技术实现路径来看,其实可以拆成三个独立环节:输入编辑、存储传输、前端渲染。成熟的做法是这三个环节各自选型,不要被某一个全家桶方案绑死。从信创兼容的角度讲,最稳妥的路线是:编辑时用LaTeX语法输入,存储时只存LaTeX源码,渲染时在浏览器端用纯JavaScript库完成。这套路线的最大优点是把渲染压力全部移到浏览器端,服务器端不承担任何公式渲染计算,对CPU架构完全不敏感。
我调查过目前还在正常维护的几个主流方案,可以说MathJax和KaTeX是当前两座绕不开的大山。MathJax的兼容性极佳,远古浏览器都能跑,缺点是加载体积大、渲染速度慢,尤其公式密集的页面会出现明显的白屏等待。KaTeX的渲染速度是MathJax的好几倍,体积也小得多,但它的兼容性稍微挑剔一点,对较老的浏览器不支持。在信创环境里,用户的浏览器很可能是在国产操作系统上跑的适配版Chromium,或者是360等双核浏览器的兼容模式,这给前端方案选型增加了不少变数。
另一个你没得选的关键点是:信创环境的浏览器普遍禁用了部分本地字体接口。公式渲染依赖的并非普通文本字体,而是专门的数学字体,像TeX的Computer Modern、Latin Modern,还有STIX系列。MathJax因为是纯JavaScript的排版引擎,它有一套自带的web字体方案,从服务器拉取字体文件到浏览器端渲染,不太依赖操作系统内置字体。这就是它在信创环境里更稳的根本原因。
既然MathJax渲染依赖从服务器加载字体,那问题就变成了:服务器能不能稳定、快速地把字体文件吐出来?在国产服务器上,这又牵扯到静态资源的缓存策略、CDN回源、压缩传输等一系列问题,后面我会详细展开。
2.2 重交互编辑方案:桌面级体验背后的兼容风险
如果站点不光是展示公式,还需要频繁的在线编辑,那轻量方案就不够用了。这类站点通常是教学平台或题库系统,需要的是类似桌面Office里公式编辑器的体验,所见即所得。目前主流的实现方式有两类:一类是基于MathQuill的富文本公式编辑器,它把LaTeX语法和可视化编辑流畅地结合到一起,光标移动、选择删除都跟着直觉走;另一类是直接把LATEX源码编辑器和右侧实时预览做在一起,相当于在浏览器里嵌了一个迷你版TeX系统。
这两种方案在普通x86服务器上没有任何问题,但在信创环境里,我遇到过几个很典型的坑。MathQuill在部分国产浏览器的兼容模式下,选区获取会出现异常,表现为:光标移到公式里就消失了,或者选中公式一部分的时候整个公式跟着闪。这其实是浏览器对ContentEditable区域的原生Selection API实现不够标准导致的。LATEX源码编辑器这类的方案,问题相对少一些,尤其是基于CodeMirror或Monaco的,这两款编辑器都自带完整的语法高亮和光标管理逻辑,不太依赖浏览器的ContentEditable行为。
这里我必须补一句经验之谈:凡是要信创环境重度使用的公式编辑场景,优先考虑纯源码编辑加预览的方案,别迷信可视化编辑。老师们嘴上说要可视化,实际用起来,尤其是输入的公式一旦开始变复杂,纯源码编辑配合及时预览的效率反而更高。把LaTeX源码区做得大一点,预览放在右侧或下方,滚动跟手,体验完全不输可视化编辑。
2.3 可信部署的隐形门槛:自建服务与离线资源包
信创环境有一个和公网常规环境很不一样的特点:很多内网环境是物理隔离的,根本没有外网访问权限。这意味着一切依赖公共CDN的方案都不可用,包括Google Fonts、jsDelivr、unpkg这些都要排除。你可能觉得这不算什么大问题,换个内网源不就行了。真到实施的时候就明白了,麻烦事一串接一串:MathJax的字体包好几十兆,KaTeX也有十来兆,这些资源文件要完整搬运到内网服务器上,还得保证路径全部相对化,否则一个绝对路径就全瞎了。
更隐性的门槛是版本锁定。在外网环境里,插件和前端库升级是自动的,CDN上永远是维护方发布的最新版本,就算某个版本有问题,官方也会很快修复。内网隔离环境可没有这个待遇,资源包搬进去就是孤岛,一旦有安全漏洞或兼容性问题,就得组织一次人工升级流程。我见过有个单位,MathJax版本三年没动过,后来因为渲染库里的一个xss漏洞被打,整个系统临时下线整改。所以我的建议是:在内网环境部署公式编辑功能,第一件事就是把所有前端库版本写死,并建立内网更新机制,哪怕一年更新一次也行。
WordPress生态里还有一个经常被忽略的麻烦:插件市场拉取和更新需要连接WordPress官方服务器,内网环境默认是禁止这种外联的。所以很多国产化项目干脆放弃了插件市场,直接用自定义插件满足需求,或者把官方插件整体打包到内网自己的更新源里。公式编辑这种功能,如果也被打包在某个插件里,它的前端静态资源是否同步打包完整,就成了能否在信创环境顺利工作的关键。
3. 选型拆解:MathJax与KaTeX在信创场景下的详细对比
3.1 渲染机制的差异决定了兼容性边界
MathJax和KaTeX虽然都是前端公式渲染方案,但底层思路完全是两回事。MathJax从3.0版本开始全面拥抱WebAssembly加速,但它保留了完整的纯JavaScript回退路径,浏览器不支持WASM的时候自动切换回JS模式。这个设计在信创环境里特别重要,因为某些国产芯片的浏览器虽然号称支持WASM,实际跑起来会出现内存溢出的诡异情况。MathJax的回退机制能兜底,不至于公式直接崩掉。
KaTeX则完全是另一条路线,它从头到尾都是纯JavaScript渲染策略。没有WASM优化,也就不存在指令集架构的兼容性问题。但KaTeX为了追求极致的渲染速度,对HTML/CSS的要求相对严格,一些老旧的国产浏览器版本对CSS变量支持不完整,会出现公式里的分数横线渲染偏了半个像素、上下标层次错乱这类肉眼可见的问题,但好在公式不会不见,只是长得丑。
3.2 性能表现的真实差异:密集公式页面的生死之战
用真实数据说事。我曾经在一台国产CPU服务器上做过一次压力测试,配置是某国产四核处理器、16GB内存,跑着Nginx加PHP。测试页面上一共挂了80个公式,包含积分、求和、矩阵这种重型结构。
MathJax的完整渲染时间大概在4.2秒,首屏只出来一半公式,后面那些是滚动到可视区域的时候才渲染的,这是MathJax的懒加载特性,能明显提升首屏感知速度。KaTeX在同样页面上的完整渲染时间是1.1秒,几乎是一瞬间全部出来。差异非常显著,但代价是KaTeX在低端CPU上渲染时,主线程会被长时间占用,浏览器滚动会出现肉眼可察觉的掉帧。
这个差异在面对密集型公式页面时是决定性的。比如某理工科课程的课件页,一页PPT内容转成网页后密密麻麻全是公式,MathJax的懒加载策略反而成了优势,它把渲染压力打散了,浏览器不卡。KaTeX则是一次性把全部公式渲染完,CPU弱的机器上浏览器会有持续两三秒的假死感。所以我的结论是:查询密集型知识库网站上KaTeX更合适,课件、讲义这种长篇大论用MathJax更稳。
3.3 和编辑器插件的集成深度
WordPress生态里现成的公式支持插件多多少少都能和MathJax或KaTeX联动。但信创环境里选插件有一个额外的筛选条件:插件的作者是否还在活跃维护。很多经典插件最后一版是五六年前更新的,它们的默认配置里写死了指向某个公共CDN的地址,你必须能钻进插件源码里去改这些资源地址。
我踩过的坑是:某款经典公式插件里硬编码了某个版本的MathJax CDN地址,修改它得直接改动插件文件。问题是插件一更新就会覆盖掉你的改动。正确做法是用WordPress的wp_enqueue_script机制配合勾子去替换资源URL,或者直接把CDN地址换成内网地址后锁定插件版本,禁止自动更新。前者优雅但需要写代码,后者省事但有风险。考虑到信创环境里维护人员的技术水平参差不齐,我更推荐后者:锁定插件版本,把改动写在单独的mu-plugin里,这样即使有人手动点了更新,改动也不会丢,因为mu-plugin优先级最高,是强制加载的。
4. 信创环境中落地WordPress公式编辑:完整配置步骤
4.1 环境准备与前置检查
先别急着装插件。在信创环境里部署任何东西,第一步永远是检查基础环境,公式编辑这种依赖前端渲染库的功能尤其如此。我建议按这个顺序排查:
- 确认PHP版本和扩展。WordPress 6.x建议PHP 7.4以上,实测国产平台的PHP 8.1和8.2兼容性都不错。别用PHP 8.0,官方已经放弃维护,而且和某些老插件有兼容问题。
- 检查OpenSSL扩展。内网环境经常用的是自签名证书,PHP的OpenSSL扩展缺失会直接导致WordPress后台无法正常白屏。
- 确认Nginx或Apache的静态资源MIME类型配置正确。尤其要确保
.woff2、.ttf、.wasm这些文件不会被错误拦截。MathJax 3.x的字体文件是woff2格式,Nginx默认配置不一定包含这个MIME类型,需要在配置里显式加上。 - 把可写目录权限捋一遍:
wp-content目录及其子目录对Web用户必须有写权限,很多国产系统默认的安全策略会对wp-content/uploads做只读限制,公式编辑器上传图片会静默失败。
4.2 部署MathJax到内网:完整操作记录
最干净的做法是放弃插件,直接在主题里手动引入MathJax。这样可控性最强,也方便锁定版本。我的推荐流程是:
在能访问外网的机器上下载MathJax 3.2.2版本的完整包,注意是包含
es5目录的完整包,别只下精简版,精简版会缺失部分字体,导致国内内网环境下某些生僻数学符号渲染不出来。把整个
mathjax文件夹上传到服务器的/var/www/html/wp-content/mathjax目录,或者任意一个Web能访问的静态目录。在WordPress主题的
functions.php里注册前端资源:
function custom_mathjax_enqueue() { wp_enqueue_script('mathjax', '/wp-content/mathjax/es5/tex-chtml.js', array(), '3.2.2', true); wp_add_inline_script('mathjax', 'window.MathJax = { tex: { inlineMath: [["\\(", "\\)"]], displayMath: [["\\[", "\\]"]] }, options: { skipHtmlTags: ["script", "noscript", "style", "textarea", "pre", "code"], ignoreHtmlClass: "no-mathjax" }, startup: { ready: () => { MathJax.startup.defaultReady(); MathJax.startup.promise.then(() => { document.querySelectorAll("mjx-container").forEach(el => { el.style.overflowX = "auto"; el.style.maxWidth = "100%"; }); }); } }, loader: {load: ["[tex]/ams", "[tex]/noerrors", "[tex]/noundefined"]} };', 'before'); } add_action('wp_enqueue_scripts', 'custom_mathjax_enqueue');这里有几个细节很关键。inlineMath和displayMath决定了哪些符号会被当作公式边界,默认配置里通常包含$...$,但这在中文文章里会引起大量误判,因为中文文本里到处都有$符号,比如金额。我一般只保留\\(...\\)和\\[...\\]两种边界,后端输出文章内容时,编辑器自动把用户输入的$...$转换为\\(...\\形式。skipHtmlTags这个选项也很重要,如果你不加,MathJax会把代码块里的LaTeX内容也渲染成公式,造成灾难性后果。ignoreHtmlClass则是提供一个开关,某个段落加个no-mathjax类,就可以明确告诉MathJax这段别碰。
- 在编辑器里插入公式时,用古腾堡编辑器或经典编辑器都可以,只要输出内容里包含LaTeX源码。需要特别注意的是,内容里的反斜杠必须全角转义,否则PHP输出时会丢反斜杠。这个坑我遇到过不止一次,用户辛辛苦苦写的公式,保存进数据库再读出来时所有反斜杠都没了,原因往往是编辑器的某些过滤钩子做了
stripslashes操作。解决办法是在保存内容时用wp_slash或esc_sql处理,或者写一个简单的自定义函数,在the_content过滤器里对公式部分做反转义处理。
4.3 为内网环境配置KaTeX方案
如果你想要更快的渲染速度,KaTeX是更优选。部署逻辑和MathJax类似,先在能访问外网的环境下载KaTeX的dist包,只保留dist目录下的东西,上传到内网服务器,然后在functions.php里注册:
function custom_katex_assets() { wp_enqueue_style('katex', '/wp-content/katex/dist/katex.min.css', array(), '0.16.9'); wp_enqueue_script('katex', '/wp-content/katex/dist/katex.min.js', array(), '0.16.9', true); wp_enqueue_script('katex-auto', '/wp-content/katex/dist/contrib/auto-render.min.js', array('katex'), '0.16.9', true); wp_add_inline_script('katex-auto', 'document.addEventListener("DOMContentLoaded", function() { renderMathInElement(document.body, { delimiters: [ {left: "\\\\(", right: "\\\\)", display: false}, {left: "\\\\[", right: "\\\\]", display: true} ], throwOnError: false, strict: false }); });'); } add_action('wp_enqueue_scripts', 'custom_katex_assets');throwOnError: false非常关键。公式写错了、渲染失败了,页面只会显示红色报错文本,不会导致整个页面白屏。strict: false则是关闭KaTeX对语法不规范的报错,信创环境里的老旧文章格式五花八门,有些公式本来就不符合KaTeX的严格语法,但内容本身是有价值的,不能让渲染失败毁了整篇文章。
4.4 输入端的适配:让编辑器默认输出安全格式
公式编辑器的选型和配置同样重要。如果直接用文本编辑器输入LaTeX源码,对普通用户是很不友好的,尤其是文科背景的管理员,他们连\frac{}{}都容易写错括号。所以我们需要在前端编辑器里嵌一个公式输入工具,我实际推荐的做法是:
在编辑器工具栏加一个按钮,点击弹出小窗口,里面是一个简化的LaTeX输入区和一个实时预览区。这个不需要额外的重型库,只要引入MathJax或KaTeX就能实现,成本极低。逻辑是:输入区每次keyup触发预览区的重新渲染,确认无误后把源码插入编辑器。
这个工具的实现不复杂。我把完整代码挂在一个独立的mu-plugin里,不打算在这里贴全部,但核心思路可以讲清楚:
- 用
mce_external_plugins过滤器给TinyMCE注册一个外部插件; - 插件JS里在工具栏添加一个自定义按钮,点击打开一个模态框;
- 模态框里左右分栏,左边textarea输入LaTeX源码,右边div做预览;
- 每次输入触发预览区域重新调用
MathJax.typesetPromise()或katex.render; - 点击确认时,把源码以
\\(...\\)包裹后插入编辑器内容中。
这活儿看着简单,但有几个细节要注意。预览区域的样式要覆盖MathJax默认的mx容器,否则预览区显示正常,插入编辑器后因为样式隔离又变样了。另外,输入区要关闭浏览器自动拼写检查,否则一整排红色波浪线会严重影响输入体验。在textarea上加spellcheck="false"是必须的。
5. 踩坑实录:字体加载、数据库迁移和插件更新的连锁问题
5.1 字体加载失败:深入网络层排查
有一次在某单位的内网部署环境中,MathJax已经配置好了,公式也能在编辑器预览里正常显示,但发布后页面上却全是方框。方框是典型的字体渲染失败:浏览器在尝试加载MathJax的web字体时被拦截了。
我顺着排查了一遍。字体文件本身在服务器上确实存在,直接在浏览器地址栏输入woff2文件的URL也能打开下载。问题出在HTTP响应头里的CORS设置。MathJax的字体加载是跨域请求的,因为页面域名和静态资源域名往往是分离的,页面跑在https://course.example.com,静态资源在https://static.example.com,而MathJax渲染公式时,会通过fetch从静态域加载字体。如果静态域没有配置Access-Control-Allow-Origin,浏览器会拦截字体请求,页面回退到系统字体,中文字符能显示,但数学符号全是方框。
解决方法是在Nginx静态资源配置里加上:
location /wp-content/mathjax/ { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods "GET, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; expires 30d; add_header Cache-Control "public, max-age=2592000"; }这里有个小陷阱:Access-Control-Allow-Origin *是通配符,看似没问题,但如果你的站点启用了Cookie或需要鉴权头,就用不了通配符,得改成具体域名。好在MathJax字体加载不带Cookie,所以通配符是安全的。顺带一提,expires 30d加上去之后,内网员工刷新页面的速度会明显提升,因为字体文件会被浏览器缓存很久。
5.2 老文章的公式内容在迁移后大面积损坏
英特尔的x86平台迁移到国产平台,通常不是只迁移服务器代码,数据库也要跟着走。很多站点是从老的MySQL 5.6或5.7迁移到国产数据库或更新的MySQL 8.0系列的。一迁移完,文章里公式全乱了。这个现象太常见了,根因反而是字符集的锅。
老站点的数据库很可能是latin1或utf8字符集,而LaTeX源码里的\alpha、\beta这类ASCII字符还好,真正致命的是希腊字母的Unicode表示形式,比如α、β这种直接存成Unicode字符,在latin1字符集下存储时会被拆成两个字节,迁到新库之后字符集一旦不匹配,就变成乱码或问号。
排查和修复的方法是先检查字符集对齐:
SELECT table_name, table_collation FROM information_schema.tables WHERE table_schema = '你的库名'; SHOW CREATE TABLE wp_posts;如果发现wp_posts表的字符集是latin1或utf8,而新库默认是utf8mb4,那就要做字符集转换。最高效的做法是:
- 先把wp_posts及相关表备份;
- 用
ALTER TABLE CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci转换; - 转换后检查包含LaTeX源码的post_content字段,确认反斜杠、花括号、尖括号都没有被转义或替换;
- 重新跑一遍MathJax渲染测试页面。
这里有一个我已经踩熟了的坑:unicode_ci排序规则虽然能正确存储数学符号,但如果你原本用的是general_ci,转换后索引可能失效,导致查询变慢,需要重新构建索引。
5.3 插件自动更新的灾难:兼容性被静默打破
信创环境里批量管理WordPress站点的时候,插件自动更新是真正的隐形杀手。某次运维巡检发现三个站点公式全挂了,查了半天原因:某个插件三天前自动更新到了新版本,新版本里把MathJax从3.x升级到了4.x,而4.x默认启用了WebAssembly渲染,在国产CPU上,这个WASM模块无法加载,于是全站公式回到文本源码裸奔状态。
这个问题的根源在于原生MathJax 4.x放弃了对老旧环境的回退支持,而绝大多数WordPress公式类插件并不会检查浏览器或CPU对WASM的支持情况。在x86环境里,这个升级是无感的,到国产芯片上才爆炸。
解决办法有两条路。稳的路:给所有站点设置DISALLOW_FILE_MODS为true,彻底禁止后台自动更新任何插件和主题,把更新流程挪到测试环境验证后再手动推送到生产环境。更好一点的做法是:在所有前端资源加载逻辑里加上版本检测,如果MathJax版本号大于3.x,就强制降级到3.x的静态资源。具体实现是用一个mu-plugin覆盖式地重新注册脚本源,优先级压过原插件。
5.4 编辑器内预览正常但前端不渲染:作用域被污染
最后再提一个排查起来能逼疯人的问题:编辑器内公式预览完全正常,发布后前端页面死活不渲染。这种问题通常是页面上还有其他JavaScript代码干扰了MathJax的初始化流程。最常见的是某个统计脚本或分析工具在DOMContentLoaded事件里做了document.write操作,导致MathJax的启动时序错乱。
排查思路:打开浏览器控制台,看有没有报错;在Network面板里确认tex-chtml.js是否加载成功;再检查MathJax的状态,在控制台执行MathJax.startup.document看是否有状态信息。如果确定是脚本冲突,最粗暴可靠的解法是:在wp_enqueue_script里给MathJax脚本设置defer属性并放到页脚加载,让MathJax在DOM建完之后再启动。另一个更干脆的方案是给MathJax脚本设置async,然后手动触发typesetPromise,让页面根据生命周期自己决定什么时候渲染公式,从源头隔离其他脚本的干扰。
我在实际项目中最终采取的方案,是单独写一个只有几十行的mu-plugin,专门托管MathJax的初始化逻辑,不依赖任何主题和任何第三方插件,所有资源和配置全部自己管理。这个方法虽然看起来冗余了,但确实是在复杂的信创环境内保证公式功能长期稳定的最实用策略。
6. 性能调优和功能扩展的方向
公式渲染的最终体验,不取决于首屏速度,而取决于不同页面类型下的综合表现。就MathJax而言,开启fastPreview机制后,输入编辑器时可以用轻量替换快速展示近似效果,在光标停止输入后再进行完整渲染。这个机制的实现要么升级到4.x系列,要么用KaTeX的render配合防抖处理。
在高并发环境下,公式功能本身不构成性能瓶颈,真正吃CPU的是页面整体渲染。Nginx开启gzip压缩,尤其对woff2以外的文本类资源效果显著。PHP侧开启Opcache,缓存PHP字节码,能减少约30%的响应时间。数据库层面,把含有大量公式的文章内容从text类型升级为longtext,避免长文章被截断。对于公式特别多的页面,建议开启Redis对象缓存,因为WordPress的查询开销在复杂文章上会急剧上升。
从扩展角度看,如果能接受轻微的维护成本,MathJax的自动渲染机制和KaTeX的renderMathInElement可以并存在同一个站内:文章列表页用KaTeX快速渲染摘要里的小公式,详情页用MathJax完整渲染正文里的重型公式。两种渲染器针对不同的内容密度做适配,能换来真实可感知的性能提升。唯一的成本是两套前端库的静态资源都要维护,磁盘空间倒是无所谓,但升级流程得上心。
最后说个切身的经验。信创环境的本质是一个长期演进的生态,换完一批芯片、换完一批系统,下一批组件又会是新东西。公式编辑这种看似不起眼的小功能,其实是对整个技术栈兼容性的一次微体检,从PHP到JavaScript,从字体到数据库字符集,任何一环有短板都会原形毕露。所以别想着上线后就撒手不管,把公式功能的回归测试写进每次环境变更的上线清单里,哪怕只是改了个Nginx配置,也花一分钟打开一个公式页面看一眼。这个习惯,能在关键的时候省下好几个通宵。
7. 迁移过程中的组织协作:谁说技术问题纯粹是技术问题
7.1 摸清家底:给老站点的公式内容做一次全面体检
实战中最容易被低估的环节,恰恰是最前期的现状摸底。很多单位说迁就迁,备份完数据库就开跑,公式格式问题到了生产环境才集中爆发。我的建议是,在迁移前花两三天做一个全面的公式内容体检,先把家底摸清楚,能筛掉后面绝大部分排错事故。
体检工作本质上是一次形式化扫描:把所有历史文章内容导出,用正则或写个PHP脚本识别公式类型,统计LaTeX格式的公式占比、图片型公式占比、MathML格式占比。图片型公式是最需要警惕的,它们虽然看起来整整齐齐,但本质是静态PNG,缩放后模糊,也无法被屏幕阅读器访问。信创环境的很多业务场景,比如教育平台,对无障碍访问是有明确要求的,图片型公式在合规层面就站不住脚。
扫描结果里还应该包含公式中的字体编码信息。老的公式编辑器可能输出过一些特殊实体字符,像∞这种HTML实体编码,在新环境里可能会被过滤掉或渲染成乱码。了解这些风险点之后,就可以在迁移方案里专门安排一个清洗环节,提前用脚本批量替换。一次性做好这些事,比事后文章被零散报障的体验要好得太多。
7.2 内容方和技术方的共识:公式是内容资产,不是页面装饰品
在这个问题上,我最深的体会是:公式编辑的兼容性,表面是个技术问题,根子里是个协作问题。内容管理员关心的是公式能不能正常输入和显示,他们不关心底层是MathJax还是KaTeX,也不关心数据库字符集。运维工程师关心的是系统稳定性、可维护性,他们不希望为某一个插件单独做兼容性适配。这双方的需求往往是对着干的。
我见过比较成功的沟通方式,是把公式统一视为内容资产,而不是页面装饰品。这意味着:所有公式必须有可读的文本源码存在数据库里,无论是LaTeX还是MathML格式,而不是只有一张渲染后的图片;公式所在的文章必须能导出、能回溯、能被搜索到;公式的显示效果必须在迁移前后做逐项对比,而不是“拷过去能跑就算成功”。
把公式定性为内容资产,还有一个直接的好处:它强迫你选择存储层格式的正确方案。如果只把公式当作一个渲染装饰,那么存储不存储源码都无所谓——但一旦牵扯到内容检索、编辑、二次加工,源码的重要性就瞬间体现出来了。
7.3 给迁移专班的可操作提示
我把这几年从迁移项目里沉淀下来的实操提示按对象拆开,各取所需。
对内容管理员:
- 迁移前两周开始限制编辑公式的数量,减少在途变更;
- 重点关注高频更新的课程页和题库页,优先做这些页面的公式对比测试;
- 记录一份“重点公式页面”清单,迁移完成后按清单逐页验收。
对运维工程师:
- 提前确认内网代码托管平台和依赖仓库的可用性,MathJax这类前端库不要指望从外网拉取;
- 检查目标服务器上PHP的
mbstring扩展是否启用,信创发行版里这个扩展有时默认关闭,WordPress对中文内容处理会异常; - 配置一份静态资源路径白名单,防止新环境的安全策略把woff2字体文件当作可执行文件拦截。
对开发工程师:
- 先在开发环境模拟一套信创环境的用户代理和渲染上下文,提前揭露兼容问题;
- 公式渲染相关的代码全部独立成插件或模块,避免和主题耦合;
- 每次提交代码前跑一遍公式回归用例,哪怕只是一个包含公式的简单页面。
最后再说一个谁都会忘、但谁都想起来就拍大腿的细节:迁移完记得打开WordPress设置里的“站点地址”和“WordPress地址”确认没有残留旧域名,否则公式资源会从旧域名拉取,白屏或者方框问题会让你以为资源没传上去。这个属于最冤枉的排错方式,没有之一。
迁移这事,说到底是个耐心活儿。公式编辑兼容性只是整个国产化替代过程中一个很小的切面,但它牵扯了前端渲染、数据库存储、编辑器交互、运维配置、内容协作好几个层面。把标准定高一点,把过程做细一点,后面上线后的痛苦就会小很多。