Vue3文档模板Webpack打包后无法在Express服务导入的SSR问题
Vue SSR文档模板服务构建问题
我正在开发一个文档模板服务,其中包含大量用Vue编写的合同、协议类文档模板。核心逻辑是:客户端在请求体中传入props,这些props会传递给对应的Vue组件(文档模板),渲染后的文档将作为响应返回给客户端。Vue非常适配这个场景——它上手简单,且能支撑复杂模板所需的灵活逻辑环境。
棘手的点在于,每个文档的script部分逻辑都比较复杂,因此我不能只提取组件的template部分结合上下文渲染,必须将Vue模板的所有部分(script setup + TypeScript、template、css)完整转译,再为组件指定上下文(props)。
转译环节我采用了Webpack(搭配vue-loader、ts-loader),并使用CommonJS配置——因为我的Express应用规模较大,切换到ESM需要大量重构,所以无法使用ESM。但Webpack生成的bundle始终无法正常导入,尝试了以下代码:
export async function loadSSRTemplate(templateName: string) { // 注:我用的是CommonJS,但这里是未编译的TypeScript代码 // @ts-ignore const bundle = await import('@/ssr/dist/main.js'); console.log(bundle.default); // 始终返回undefined return bundle[templateName]; // 同样无法获取到组件 }
我找不到从bundle中导入转译后Vue组件的方式,也就无法配合createSSRApp和h()方法进行渲染。
我知道没有明确的报错信息(不想让你纠结所有配置和组件结构细节),但想请教有相关经验的人:这种方案是否可行?我是不是在做无用功?
另外,如果有其他可行技术方案也可以推荐,但出于性能考虑,我更倾向于在构建阶段预先完成转译。
技术栈详情
- 模板侧:Vue 3 + TypeScript + Composition API(script setup) + Webpack 5.9
- 服务侧:Node 18(Express) + TypeScript,基于Node:18镜像Docker化部署,使用ts-node-dev运行,采用CommonJS配置
补充配置细节
Webpack配置
const path = require('path'); const nodeExternals = require('webpack-node-externals'); const { VueLoaderPlugin } = require('vue-loader/dist/index'); module.exports = { target: 'node', mode: 'development', entry: './webpack-entry-point.js', output: { path: path.resolve(__dirname, 'dist'), filename: '[name].js', libraryTarget: 'commonjs2', }, externals: nodeExternals({ allowlist: /\.css$/, }), module: { rules: [ { test: /\.ts$/, loader: 'ts-loader', options: { appendTsSuffixTo: [/\.vue$/] }, }, { test: /\.vue$/, loader: 'vue-loader', }, ], }, resolve: { alias: { '@templates': path.resolve(__dirname, './templates'), }, extensions: ['.ts', '.js', '.vue', '.json'], }, plugins: [new VueLoaderPlugin()], optimization: { splitChunks: { chunks: 'all', }, }, };
Webpack入口文件
import NajomnaZmluva from '@templates/reality_module/NajomnaZmluva.vue'; export { NajomnaZmluva };
模板服务的render方法实现
async render(id: string, data: any): Promise<string> { if (!process.env.SSR_DOCUMENT_TEMPLATE_PATH) { console.error('SSR_DOCUMENT_TEMPLATE_PATH is not defined'); throw new UnknownServerError(); } const documentTemplate = await this.retrieve(id); if (!documentTemplate.schema) { throw new BadRequestError( responsesConstants.errors.badRequestError.schemaNotDefined, ); } this.validateSchema( documentTemplate.schema as Record<string, schemaType>, data, ); // 模板名称后续会动态指定,此处仅为测试硬编码 const Template = await loadSSRTemplate('NajomnaZmluva'); // 因卡在bundle加载环节,以下代码暂未验证可行性 const ssrDocument = createSSRApp({ template: h(Template, { props: data }), }); return await renderToString(ssrDocument); }
进展更新
我已经取得了突破,几小时后会发布完整解决方案。
内容的提问来源于stack exchange,提问作者Daniel Klimek
相关产品推荐
相关产品推荐

