Skip to main content

使用 Webpack 打包表

Webpack 是一个用于生成静态站点的现代构建工具。它有一个强大的 JavaScript 驱动的插件系统 [^1]

¥Webpack is a modern build tool for generating static sites. It has a robust JavaScript-powered plugin system[^1]

SheetJS 是一个用于从电子表格读取和写入数据的 JavaScript 库。

¥SheetJS is a JavaScript library for reading and writing data from spreadsheets.

该演示使用 Webpack 和 SheetJS 从电子表格中提取数据并在 HTML 表格中显示内容。我们将探讨如何在 Webpack 5 资源插件中加载 SheetJS 并生成在网页中使用的数据。

¥This demo uses Webpack and SheetJS to pull data from a spreadsheet and display the content in an HTML table. We'll explore how to load SheetJS in a Webpack 5 Asset Plugin and generate data for use in webpages.

"Webpack 5 演示" 创建了一个由 XLSX 电子表格支持的完整网站。

¥The "Webpack 5 Demo" creates a complete website powered by a XLSX spreadsheet.

该演示涵盖静态资源导入。为了在浏览器中处理文件,"打包器" 演示 包含在浏览器脚本中导入 SheetJS 库的示例。

¥This demo covers static asset imports. For processing files in the browser, the "Bundlers" demo includes an example of importing the SheetJS library in a browser script.

Webpack 5 资源模块

¥Webpack 5 Asset Module

Webpack 5 支持资源模块。通过一个特殊的选项,加载器将接收可以解析的 NodeJS 缓冲区。开发服务器甚至会在开发模式下查看文件并重新加载页面!

¥Webpack 5 supports asset modules. With a special option, the loader will receive NodeJS Buffers that can be parsed. The dev server will even watch the files and reload the page in development mode!

SheetJS NodeJS 模块 可以从 Webpack 加载器脚本导入。

¥The SheetJS NodeJS module can be imported from Webpack loader scripts.

下图描绘了练习册华尔兹:

¥The following diagram depicts the workbook waltz:

Webpack 配置

¥Webpack Config

Webpack 配置通常保存到 webpack.config.js

¥The Webpack configuration is normally saved to webpack.config.js.

所需设置

¥Required Settings

module.rules 是控制模块合成的规则对象数组。[^2] 对于 SheetJS Webpack 集成,需要以下属性:

¥module.rules is an array of rule objects that controls module synthesis.[^2] For the SheetJS Webpack integration, the following properties are required:

  • test 描述规则是否相关。如果该属性是正则表达式,Webpack 将根据 test 属性测试文件名。

    ¥test describes whether the rule is relevant. If the property is a regular expression, Webpack will test the filename against the test property.

  • use 列出了将处理与 test 匹配的文件的加载器。加载器是使用加载器对象的 loader 属性指定的。

    ¥use lists the loaders that will process files matching the test. The loaders are specified using the loader property of the loader object.

以下示例指示 Webpack 当文件名以 .numbers.xls.xlsx.xlsb 结尾时使用 sheetjs-loader.js 脚本:

¥The following example instructs Webpack to use the sheetjs-loader.js script when the file name ends in .numbers or .xls or .xlsx or .xlsb:

webpack.config.js (define loader)
// ...
module.exports = {
// ...
module: {
rules: [
{
/* `test` matches file extensions */
test: /\.(numbers|xls|xlsx|xlsb)$/,
/* use the loader script */
use: [ { loader: './sheetjs-loader' } ]
}
]
}
};

¥Recommended Settings

强烈建议启用其他 Webpack 功能:

¥It is strongly recommended to enable other Webpack features:

  • resolve.alias 定义路径别名。如果数据文件存储在一个文件夹中,则别名可确保每一页都可以引用使用相同名称的文件 [^3]。

    ¥resolve.alias defines path aliases. If data files are stored in one folder, an alias ensures that each page can reference the files using the same name[^3].

  • devServer.hot 启用 "热模块更换"[^4],确保保存电子表格时页面将在开发模式下刷新。

    ¥devServer.hot enables "hot module replacement"[^4], ensuring that pages will refresh in development mode when spreadsheets are saved.

以下示例指示 Webpack 将 ~ 视为项目的根(因此 ~/data/pres.xlsx 引用数据文件夹中的 pres.xlsx)并启用实时重新加载:

¥The following example instructs Webpack to treat ~ as the root of the project (so ~/data/pres.xlsx refers to pres.xlsx in the data folder) and to enable live reloading:

webpack.config.js (other recommended settings)
// ...
module.exports = {
// ...
resolve: {
alias: {
/* `~` root of the project */
"~": __dirname
}
},
// ...
/* enable live reloading in development mode */
devServer: { static: './dist', hot: true }
};

SheetJS 加载器

¥SheetJS Loader

SheetJS 加载器脚本必须保存到 Webpack 配置 (sheetjs-loader.js) 中引用的脚本中。

¥The SheetJS loader script must be saved to the script referenced in the Webpack configuration (sheetjs-loader.js).

ViteJS 一样,Webpack 会将数据解释为 UTF-8 字符串。这会损坏二进制格式,包括 XLSX 和 XLS。要抑制此行为并指示 Webpack 传递 NodeJS Buffer 对象,加载器脚本必须导出设置为 true[^5] 的 raw 属性。

¥As with ViteJS, Webpack will interpret data as UTF-8 strings. This corrupts binary formats including XLSX and XLS. To suppress this behavior and instruct Webpack to pass a NodeJS Buffer object, the loader script must export a raw property that is set to true[^5].

基本导出预计是加载函数。加载器接收文件字节作为缓冲区,可以使用 SheetJS read 方法 [^6] 对其进行解析。read 返回 SheetJS 工作簿对象 [^7]。

¥The base export is expected to be the loader function. The loader receives the file bytes as a Buffer, which can be parsed with the SheetJS read method[^6]. read returns a SheetJS workbook object[^7].

此演示中的加载器将解析工作簿,提取第一个工作表,并使用 sheet_to_json 方法 [^8] 生成行对象数组:

¥The loader in this demo will parse the workbook, pull the first worksheet, and generate an array of row objects using the sheet_to_json method[^8]:

sheetjs-loader.js (Webpack loader)
const XLSX = require("xlsx");

function loader(content) {
/* since `loader.raw` is true, `content` is a Buffer */
const wb = XLSX.read(content);
/* pull data from first worksheet */
var data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
return `export default JSON.parse('${JSON.stringify(data)}')`;
}

/* ensure the function receives a Buffer */
loader.raw = true;

/* export the loader */
module.exports = loader;

资源导入

¥Asset Imports

可以使用该插件导入电子表格。假设 pres.xlsx 存储在 data 子文件夹中,则可以从任何脚本导入 ~/data/pres.xlsx

¥Spreadsheets can be imported using the plugin. Assuming pres.xlsx is stored in the data subfolder, ~/data/pres.xlsx can be imported from any script:

src/index.js (main script)
import data from '~/data/pres.xlsx';
/* `data` is an array of objects from data/pres.xlsx */

const elt = document.createElement('div');
elt.innerHTML = "<table><tr><th>Name</th><th>Index</th></tr>" +
data.map((row) => `<tr>
<td>${row.Name}</td>
<td>${row.Index}</td>
</tr>`).join("") +
"</table>";
document.body.appendChild(elt);

Webpack 5 演示

¥Webpack 5 Demo

测试部署

该演示最后一次测试是在 2024 年 4 月 6 日,针对 Webpack 5.91.0

¥This demo was last tested on 2024 April 06 against Webpack 5.91.0

初始设置

¥Initial Setup

  1. 创建一个新的骨架项目:

    ¥Create a new skeleton project:

mkdir sheetjs-wp5
cd sheetjs-wp5
npm init -y
npm install webpack@5.91.0 webpack-cli@5.1.4 webpack-dev-server@5.0.4 --save
mkdir -p dist
mkdir -p src
mkdir -p data
  1. 安装 SheetJS NodeJS 模块:

    ¥Install the SheetJS NodeJS module:

npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
  1. 将以下内容保存到 dist/index.html

    ¥Save the following to dist/index.html:

dist/index.html
<!DOCTYPE html>
<html>


<head>
<title>SheetJS + Webpack 5</title>
</head>


<body>
<script src="main.js"></script>
</body>
</html>
  1. 将以下内容保存到 src/index.js

    ¥Save the following to src/index.js:

src/index.js
import data from '~/data/pres.xlsx';

const elt = document.createElement('div');
elt.innerHTML = "<table><tr><th>Name</th><th>Index</th></tr>" +
data.map((row) => `<tr>
<td>${row.Name}</td>
<td>${row.Index}</td>
</tr>`).join("") +
"</table>";
document.body.appendChild(elt);
  1. 将以下内容保存到 webpack.config.js

    ¥Save the following to webpack.config.js:

webpack.config.js
const path = require('path');

module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
devServer: {
static: './dist',
hot: true,
},
resolve: {
alias: {
"~": __dirname
}
},
module: {
rules: [
{
test: /\.(numbers|xls|xlsx|xlsb)$/,
use: [ { loader: './sheetjs-loader' } ]
}
]
}
};
  1. 将以下内容保存到 sheetjs-loader.js

    ¥Save the following to sheetjs-loader.js:

sheetjs-loader.js
const XLSX = require("xlsx");

function loader(content) {
/* since `loader.raw` is true, `content` is a Buffer */
const wb = XLSX.read(content);
/* pull data from first worksheet */
var data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
return `export default JSON.parse('${JSON.stringify(data)}')`;
}
/* ensure the function receives a Buffer */
loader.raw = true;
module.exports = loader;
  1. 下载 https://xlsx.nodejs.cn/pres.xlsx 并保存到 data 文件夹:

    ¥Download https://xlsx.nodejs.cn/pres.xlsx and save to the data folder:

curl -L -o data/pres.xlsx https://xlsx.nodejs.cn/pres.xlsx

实时重载测试

¥Live Reload Test

  1. 在 Excel 等电子表格编辑器中打开测试文件 data/pres.xlsx

    ¥Open the test file data/pres.xlsx in a spreadsheet editor like Excel.

  2. 启动开发服务器:

    ¥Start the development server:

npx webpack serve --mode=development

终端将打印开发服务器的 URL:

¥The terminal will print URLs for the development server:

<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
  1. 在网络浏览器中打开 Loopback 地址 (http://localhost:8080)。

    ¥Open the Loopback address (http://localhost:8080) in a web browser.

它应该显示一个包含 "名称" 和 "索引" 列的总统表格

¥It should display a table of Presidents with "Name" and "Index" columns

  1. 向电子表格添加新行(将 A7 设置为 "SheetJS 开发",将 B7 设置为 47)并保存文件。

    ¥Add a new row to the spreadsheet (set A7 to "SheetJS Dev" and B7 to 47) and save the file.

保存文件后,页面应自动刷新以显示新数据。

¥After saving the file, the page should automatically refresh with the new data.

静态站点测试

¥Static Site Test

  1. 停止 Webpack 并构建站点:

    ¥Stop Webpack and build the site:

npx webpack --mode=production

最终站点将放置在 dist 文件夹中。

¥The final site will be placed in the dist folder.

  1. 启动本地 Web 服务器来托管 dist 文件夹:

    ¥Start a local web server to host the dist folder:

npx http-server dist

该命令将打印 URL 列表。

¥The command will print a list of URLs.

  1. 打开上一步 (http://localhost:8080) 中打印的 URL 之一并确认显示相同的数据。

    ¥Open one of the URLs printed in the previous step (http://localhost:8080) and confirm that the same data is displayed.

要验证该页面是否独立于电子表格,请对文件进行一些更改并保存。该页面不会自动更新。

¥To verify that the page is independent of the spreadsheet, make some changes to the file and save. The page will not automatically update.

要验证数据是否已添加到页面,请将 main.js 附加到 URL (http://localhost:8080/main.js) 并查看源。来源将包括总统名称。它不会包含 SheetJS 库引用!

¥To verify that the data was added to the page, append main.js to the URL (http://localhost:8080/main.js) and view the source. The source will include president names. It will not include SheetJS library references!

[^1]: 请参阅 Webpack 文档中的 "插件"

¥See "Plugins" in the Webpack documentation.

[^2]: 请参阅 Webpack 文档中的 module.rules

¥See module.rules in the Webpack documentation.

[^3]: 请参阅 Webpack 文档中的 resolve.alias

¥See resolve.alias in the Webpack documentation.

[^4]: 请参阅 Webpack 文档中的 "模块热更换"

¥See "Hot Module Replacement" in the Webpack documentation.

[^5]: 请参阅 Webpack 文档中的 "生的" 加载器

¥See "Raw" Loader in the Webpack documentation.

[^6]: 见 read 于 "读取文件"

¥See read in "Reading Files"

[^7]: 见 "工作簿对象"

¥See "Workbook Object"

[^8]: 见 sheet_to_json 于 "实用工具"

¥See sheet_to_json in "Utilities"