為什么有這種需求
有時(shí)候我們需要在網(wǎng)頁進(jìn)行 office 文本編輯,但是 office 文件的編輯選項(xiàng)過多且不開源,一定需要集成其它在線編輯方案才可以,比如金山文檔的在線協(xié)作方案
但是有時(shí)候我們并不需要如此健壯的成熟方案,很多時(shí)候我們對(duì)一個(gè)現(xiàn)在 office 模版只需要修改其中幾項(xiàng)的文字就可以了。這種情況下,我們只需要寫一個(gè)現(xiàn)成的表單,像問卷一樣填寫相關(guān)內(nèi)容,把填寫的內(nèi)容再轉(zhuǎn)入到 office 文件中就可以了。

如上,現(xiàn)在我希望用戶在我的網(wǎng)頁上只填寫 name 與 id
之后網(wǎng)頁會(huì)將 xlsx 文件中對(duì)應(yīng)占位符替換成用戶填寫的對(duì)應(yīng)內(nèi)容,這個(gè)需求可以通過 xlsx-template 來實(shí)現(xiàn)
項(xiàng)目版本
測(cè)試項(xiàng)目為Vue項(xiàng)目,Vue版本為3,webpack版本為5(重點(diǎn),xlsx-template庫與這個(gè)版本有沖突,后面講解決方案),包管理器為 yarn(npm也可以),測(cè)試文件類型為 typeScript(使用javaScript也可以,稍作修改即可)
代碼
安裝 xlsx-template:
npm i xlsx-template 或 yarn add xlsx-template
安裝 jszip-utils:
npm i jszip-utils 或 yarn add jszip-utils
安裝 file-saver:
npm i file-saver 或 yarn add file-saver
// @ts-ignore
import JSZipUtils from 'jszip-utils'
import {saveAs} from 'file-saver'
執(zhí)行代碼:
const XlsxTemplate = require('xlsx-template');
JSZipUtils.getBinaryContent('/xlsx/template1.xlsx',(err: any, data: Buffer) => {
const template = new XlsxTemplate(data);
// Replacements take place on first sheet
const sheetNumber = 1;
// Set up some placeholder values matching the placeholders in the template
const values = {
name: '人人人',
id: 888888
};
// Perform substitution
template.substitute(sheetNumber, values);
// Get binary data
let templateData = template.generate({type: 'blob'});
saveAs(templateData, 'new.xlsx')
})
vue.config.js 設(shè)置
const {defineConfig} = require('@vue/cli-service')
const webpack = require('webpack')
module.exports = defineConfig({
lintOnSave: false,
transpileDependencies: true,
configureWebpack: {
plugins: [
new webpack.ProvidePlugin({
process: 'process/browser',
Buffer: ['buffer', 'Buffer']
})
],
resolve: {
fallback: {
"path": require.resolve('path-browserify'),
"util": require.resolve("util/"),
"stream": require.resolve("stream-browserify"),
"constants": require.resolve("constants-browserify"),
"assert": require.resolve("assert/"),
"fs": false,
}
}
}
})
注意:上文中類似庫名的地方,除了fs和buffer外都需要使用 npm 或 yarn 安裝對(duì)應(yīng)的庫
比如:npm i util 與 yarn add assert
需要加載的庫名如下:
webpack process path-browserify util stream-browserify constants-browserify assert
vue.config.js 講解
因?yàn)?xlsx-template 庫是在 webpack4 的基礎(chǔ)上打包的,在 webpack5 的項(xiàng)目上出現(xiàn)在非常多的錯(cuò)誤,故需要如上 vue.config.js 的設(shè)置。
上面的設(shè)置雖少,但是解決了至少4個(gè)類型的錯(cuò)誤,共數(shù)十個(gè)具體錯(cuò)誤
- Can't resolve 'fs' 問題
這個(gè)問題其實(shí)是因?yàn)?fs 庫已經(jīng)無法直接調(diào)用,而在 xlsx-template 代碼卻有調(diào)用
使用 resolve.fallback: { fs: false } 可以跳過編譯檢測(cè)

解決自:https://github.com/webpack-contrib/css-loader/issues/447#issuecomment-761853289
- process is not defined 問題
這個(gè)問題可能是因?yàn)樵?webpack5 中 process 已經(jīng)無法在項(xiàng)目獲取,需要使用外部引用并轉(zhuǎn)換成同名引用
使用 new webpack.ProvidePlugin({ process: 'process/browser' }) 可以解決

- 各種 webpack < 5 開頭的問題
這種問題在控制臺(tái)已經(jīng)說明了解決方法,只是可能很多人不知道具體應(yīng)該把解決代碼寫在哪里,上圖中的 resolve.fallback: { ... } 中除了 fs:false 其它都是會(huì)出現(xiàn)問題的部分的解決方法
這個(gè)問題仍然是 webpack 版本造成的,但是不能像 fs 一樣忽略,必須注入

解決自:https://stackoverflow.com/questions/64557638/how-to-polyfill-node-core-modules-in-webpack-5
- Cannot read properties of undefined (reading 'filename') 或 buffer 問題
在vue3項(xiàng)目上會(huì)報(bào) “Cannot read properties of undefined”,但是在我的另一個(gè)vue2項(xiàng)目中會(huì)直接報(bào)找不到 buffer 函數(shù)問題,所以這是個(gè)無法調(diào)用到 buffer api 的問題

解決自:https://stackoverflow.com/questions/66156756/how-to-polylfill-buffer-for-jsonwebtoken-in-wepack-5
成果

寫在后面
上文中的測(cè)試代碼只有加載本地 xlsx 文件,如果需要從服務(wù)器下載再替換,無論您使用什么網(wǎng)絡(luò)加載框架都需要注意:
xlsx-template 框架需要傳入 buffer 類型數(shù)據(jù),所以請(qǐng)做轉(zhuǎn)換,或直接找以 buffer 類型下載的網(wǎng)絡(luò)框架
xlsx-template 的 generate 函數(shù)注意傳入 { type: 'blob' } 這樣直接可以保存成 blob 類型數(shù)據(jù),方便后面向服務(wù)器進(jìn)行網(wǎng)絡(luò)上傳
為了避免后續(xù)文中出現(xiàn)的庫有更新,使本文內(nèi)容出現(xiàn)偏差,提供本測(cè)試項(xiàng)目的 package.json 中各個(gè)庫的版本號(hào):
"assert": "^2.0.0",
"constants-browserify": "^1.0.0",
"core-js": "^3.8.3",
"docxtemplater": "^3.37.11",
"file-saver": "^2.0.5",
"jszip-utils": "^0.1.0",
"path": "^0.12.7",
"pizzip": "^3.1.4",
"stream-browserify": "^3.0.0",
"util": "^0.12.5",
"vue": "^3.2.13",
"vue-router": "^4.0.3",
"webpack": "^5.88.1",
"xlsx-template": "^1.4.3"