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:
1 parent
8bbc716d17
commit
f872333df6
5 files changed
+58
-5
No files matched your search
@@ -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",
|
||||
|
||||
Generated
+11
@@ -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:
|
||||
|
||||
Vendored
+12
@@ -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 || '合同',
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in new issue
Block a user