Quasar SSR(Vite)项目中lowlight库ESM兼容问题解决咨询
问题场景
使用Vite构建Quasar SSR项目,引入@tiptap/extension-code-block-lowlight扩展并完成构建后,执行node dist/ssr/index.js时触发如下错误:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /home/whatever/devotto/devotto.com/node_modules/lowlight/lib/common.js
require() of ES modules is not supported.
require() of /home/whatever/devotto/devotto.com/node_modules/lowlight/lib/common.js from /home/whatever/devotto/devotto.com/dist/ssr/server/server-entry.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename common.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /home/whatever/devotto/devotto.com/node_modules/lowlight/package.json.
问题根源为@tiptap/extension-code-block-lowlight依赖的lowlight库是ES模块,但SSR构建后的代码使用require()加载该模块,导致模块系统冲突。手动删除node_modules/@tiptap/extension-code-block-lowlight/package.json和node_modules/lowlight/package.json中的"type": "module"字段可临时解决问题,但修改node_modules目录并非长期合理方案。
用户尝试过的无效Vite配置:
module.exports = function() { return { build: { extendViteConf (viteConf, { isClient, isServer }) { if (isServer) { viteConf.optimizeDeps = viteConf.optimizeDeps || {}; viteConf.optimizeDeps.include = ['./node_modules/highlight.js']; viteConf.build.commonjsOptions = viteConf.build.commonjsOptions || {}; viteConf.build.commonjsOptions.include = [/highlight.js/, /node_modules/]; // viteConf.optimizeDeps.entries = [ // 'node_modules/@tiptap/extension-code-block-lowlight/dist/tiptap-extension-code-block-lowlight.cjs', // 'node_modules/highlight.js' // ]; } }, } } }
可行解决方案
方案1:用vite-plugin-commonjs强制转译ES模块为CommonJS
这是最推荐的无侵入方案,通过插件将目标ES模块转译为服务端可识别的CommonJS格式:
- 安装插件:
yarn add vite-plugin-commonjs -D # 或 npm install vite-plugin-commonjs --save-dev
- 修改Quasar的Vite配置:
const { viteCommonjs } = require('vite-plugin-commonjs'); module.exports = function() { return { build: { extendViteConf (viteConf, { isClient, isServer }) { if (isServer) { viteConf.plugins = viteConf.plugins || []; // 为服务端构建添加转译插件,处理lowlight和tiptap相关模块 viteConf.plugins.push(viteCommonjs({ include: [ /lowlight/, /@tiptap\/extension-code-block-lowlight/ ] })); // 确保优化依赖包含目标库 viteConf.optimizeDeps = viteConf.optimizeDeps || {}; viteConf.optimizeDeps.include = [ ...(viteConf.optimizeDeps.include || []), 'lowlight', '@tiptap/extension-code-block-lowlight' ]; } }, } } }
方案2:将服务端切换为ES模块模式
如果项目本身适合转向ES模块,可通过以下步骤解决冲突:
- 在项目根目录的
package.json中添加"type": "module" - 确保服务端所有代码使用
import而非require导入模块 - 构建后直接执行
node dist/ssr/index.js,Node.js会以ES模块模式加载代码,避免模块加载方式冲突
方案3:用patch-package持久化依赖修改
这是手动修改node_modules的替代方案,可将修改持久化到版本控制:
- 安装
patch-package:
yarn add patch-package -D # 或 npm install patch-package --save-dev
- 手动删除
node_modules/lowlight/package.json和node_modules/@tiptap/extension-code-block-lowlight/package.json中的"type": "module"字段 - 生成补丁文件:
yarn patch-package lowlight @tiptap/extension-code-block-lowlight # 或 npx patch-package lowlight @tiptap/extension-code-block-lowlight
- 将生成的
patches/目录提交到版本控制,后续安装依赖时会自动应用补丁
内容的提问来源于stack exchange,提问作者Bruno Francisco

