最近在开发时遇到了CKEditor 5的一个本地化问题,项目是用Vue CLI创建的,使用的是Vue 2版本。项目中使用了CKEditor 5富文本编辑器,采用的是从源码构建的安装方案,具体可以参见官方文档“Using CKEditor from source”。
刚开始我们使用的是11.x版本,最近我们升级到了34.x版本,发现编辑器界面的本地化不起作用了,原来我们配置的是中文,升级后发现又变回英文了。而且很奇怪,如果删掉项目目录下的node_modules重新安装构建,本地化就起作用,但是后面再重新构建,本地化就又不起作用了。
CKEditor 5的本地化是通过CKEditorWebpackPlugin实现的,需要在vue.config.js中进行如下配置:
// 将下面这段代码添加到configureWebpack.plugins中
new CKEditorWebpackPlugin( {
language: 'zh-cn',
translationsOutputFile: /app/
} ),
该插件来自@ckeditor/ckeditor5-dev-webpack-plugin,升级之前我们使用的是8.0.5版本,升级之后使用的是30.1.3版本。看了一下该插件的源码,该插件的功能主要是对webpack进行配置,使webpack在打包的时候对CKEditor 5编辑器进行本地化处理,大致的处理流程是从编辑器的各个模块下找到语言翻译数据(po文件),再从各个模块的js源文件中抽取待翻译文本,然后生成最终的可供界面使用的翻译数据。
经过调试,问题出在第二步,即从js源文件抽取待翻译文本,删掉node_modules第一次构建时,webpack会执行第二步,后续再进行构建则不会执行第二步。第二步是由ckeditor5-dev-webpack-plugin添加的一个loader执行的,理论上webpack每次构建应该都会调用该loader,怀疑是有什么缓存机制。看了一下webpack,webpack 5添加了缓存功能,但是我们使用的是webpack 4,webpack 4并没有缓存功能。难道是vue cli添加的缓存?
于是我们使用vue inspect命令看了一下vue cli生成的webpack配置文件,发现了如下一段配置:
/* config.module.rule('js') */
{
test: /\.m?jsx?$/,
exclude: [
function () { /* omitted long function */ }
],
use: [
{
loader: '/path-to-your-project/node_modules/cache-loader/dist/cjs.js',
options: {
cacheDirectory: '/path-to-your-project/node_modules/.cache/babel-loader',
cacheIdentifier: '2808bd8e'
}
},
{
loader: '/path-to-your-project/node_modules/babel-loader/lib/index.js'
}
]
}
该配置使用babel-loader对js文件进行转译,但在转译之前添加了cache-loader对转译结果进行缓存,以加快构建速度。当缓存生效时,webpack不会再调用后续loader,包括ckeditor5-dev-webpack-plugin添加的loader,导致本地化不起作用。
原因找到了,后面就是如何解决了。有两种解决方案:
- 为CKEditor 5的js文件单独配置babel-loader,不使用cache-loader
- 直接将vue cli配置的cache-loader删掉
第一种方案对应的vue.config.js配置如下:
transpileDependencies: [
// 将下面这个注释掉
// /ckeditor5-[^/\\]+[/\\]src[/\\].+\.js$/,
],
chainWebpack: config => {
// 添加如下代码
config.module.rule('cke-js')
.test(/ckeditor5-[^/\\]+[/\\]src[/\\].+\.js$/)
.use('babel-loader')
.loader('babel-loader');
}
第二种方案对应的vue.config.js配置如下:
chainWebpack: config => {
// 添加如下代码
config.module.rule('js').uses.delete('cache-loader')
}
第一种方案只影响CKEditor 5的js文件的构建速度,第二种方案会影响所有js文件的构建速度,因此推荐使用第一种方案。