fix(web-admin): polyfill Buffer/global for contract Word export in Vite

html-to-docx still reads Node globals after Vite rebundles; inject buffer polyfill, map global to globalThis, and alias the package to the browser build.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-09-05 15:06:20 +08:00
1 parent 8bbc716d17
commit f872333df6
5 files changed
+58 -5

No files matched your search

+1
View File
@@ -67,6 +67,7 @@
"@wangeditor/editor": "^5.1.23",
"@wangeditor/editor-for-vue": "next",
"axios": "^1.12.2",
"buffer": "^6.0.3",
"crypto-js": "^4.2.0",
"dagre": "^0.8.5",
"echarts": "^6.0.0",
+11
View File
@@ -47,6 +47,9 @@ importers:
axios:
specifier: ^1.12.2
version: 1.12.2
buffer:
specifier: ^6.0.3
version: 6.0.3
crypto-js:
specifier: ^4.2.0
version: 4.2.0
@@ -1743,6 +1746,9 @@ packages:
buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
buffer@6.0.3:
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
buffers@0.1.1:
resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==}
engines: {node: '>=0.2.0'}
@@ -6089,6 +6095,11 @@ snapshots:
base64-js: 1.5.1
ieee754: 1.2.1
buffer@6.0.3:
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
buffers@0.1.1: {}
bundle-name@4.1.0:
+12
View File
@@ -17,6 +17,18 @@ declare module 'vue-img-cutter'
declare module 'file-saver'
declare module 'buffer'
declare module '@turbodocx/html-to-docx' {
const HTMLtoDOCX: (
htmlString: string,
headerHTMLString?: string | null,
documentOptions?: Record<string, unknown>,
footerHTMLString?: string | null
) => Promise<Blob | ArrayBuffer>
export default HTMLtoDOCX
}
declare module '@turbodocx/html-to-docx/dist/html-to-docx.browser.esm.js' {
const HTMLtoDOCX: (
htmlString: string,
@@ -1,5 +1,7 @@
/** 合同打印弹窗:HTML → DOCX 预处理与生成 */
import { Buffer } from 'buffer'
const DOCX_MIME = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
type HtmlToDocxFn = (
@@ -9,13 +11,30 @@ type HtmlToDocxFn = (
footerHTMLString?: string | null
) => Promise<Blob | ArrayBuffer>
/**
* html-to-docx(含 browser 包)在 Vite 二次打包后仍会直接读全局 Buffer/global。
* 必须在调用转换前注入,否则 buildImage 报 Buffer is not defined,随后 global is not defined。
*/
function ensureDocxNodeGlobals(): void {
const g = globalThis as typeof globalThis & {
Buffer?: typeof Buffer
global?: typeof globalThis
process?: { env?: Record<string, string | undefined> }
}
if (!g.Buffer) g.Buffer = Buffer
if (!g.global) g.global = g
if (!g.process) g.process = { env: {} }
else if (!g.process.env) g.process.env = {}
}
/**
* 懒加载 browser 构建。
* Vite 默认会解析到 Node ESM(依赖 Buffer/global),浏览器会报错;
* 顶层静态 import browser 包又会让 Node 单测因 XMLHttpRequest 初始化失败。
* Vite 默认会解析到 Node ESM(依赖 Buffer/global);显式 browser 入口 + 上方 globals 注入。
*/
async function loadHtmlToDocx(): Promise<HtmlToDocxFn> {
const mod = await import('@turbodocx/html-to-docx/dist/html-to-docx.browser.esm.js')
ensureDocxNodeGlobals()
// 经 vite alias 指向 browser.esm.js
const mod = await import('@turbodocx/html-to-docx')
const candidate = typeof mod === 'function' ? mod : (mod as { default?: unknown }).default
if (typeof candidate !== 'function') {
throw new Error('html-to-docx 加载失败:未获得可调用的转换函数')
@@ -84,9 +103,11 @@ export async function generateContractDocxBlob(
preparedHtml: string,
title?: string
): Promise<Blob> {
ensureDocxNodeGlobals()
const HTMLtoDOCX = await loadHtmlToDocx()
const htmlWithImages = await inlineRemoteImagesAsDataUrls(preparedHtml)
const fullHtml = `<!DOCTYPE html><html><head><meta charset="UTF-8" /></head><body>${htmlWithImages}</body></html>`
ensureDocxNodeGlobals()
const result = await HTMLtoDOCX(fullHtml, null, {
orientation: 'portrait',
title: title || '合同',
+10 -2
View File
@@ -22,7 +22,9 @@ export default ({ mode }: { mode: string }) => {
return defineConfig({
define: {
__APP_VERSION__: JSON.stringify(VITE_VERSION)
__APP_VERSION__: JSON.stringify(VITE_VERSION),
// html-to-docx 等依赖会读 Node 全局;浏览器映射到 globalThis
global: 'globalThis'
},
base: VITE_BASE_URL,
server: {
@@ -56,7 +58,12 @@ export default ({ mode }: { mode: string }) => {
'@icons': resolvePath('src/assets/icons'),
'@utils': resolvePath('src/utils'),
'@stores': resolvePath('src/store'),
'@styles': resolvePath('src/assets/styles')
'@styles': resolvePath('src/assets/styles'),
// 合同 Word 导出:强制 browser 构建,避免 Vite 落到 Node ESM
'@turbodocx/html-to-docx': resolvePath(
'node_modules/@turbodocx/html-to-docx/dist/html-to-docx.browser.esm.js'
),
buffer: 'buffer/'
}
},
build: {
@@ -140,6 +147,7 @@ export default ({ mode }: { mode: string }) => {
'xgplayer',
'crypto-js',
'file-saver',
'buffer',
'vue-img-cutter',
'element-plus/es',
'element-plus/es/components/*/style/css',