Skip to main content

使用电子表格增强 SvelteKit 应用

SvelteKit 是一个生成静态站点的框架。它利用了包括 ViteJS 和 SvelteJS[^1] 在内的现代技术

¥SvelteKit is a framework for generating static sites. It leverages modern technologies including ViteJS and SvelteJS[^1]

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

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

该演示使用 SvelteKit 和 SheetJS 从电子表格中提取数据并在 HTML 表格中显示内容。我们将探讨如何使用插件从文件中提取原始数据以及如何组织页面脚本以在编译时处理文件。

¥This demo uses SvelteKit and SheetJS to pull data from a spreadsheet and display the content in an HTML table. We'll explore how to use a plugin to pull raw data from files and how to organize page scripts to process the files at compile time.

"完整示例" 部分包括一个由 XLSX 电子表格提供支持的完整网站。

¥The "Complete Example" section includes a complete website powered by an XLSX spreadsheet.

该演示重点介绍使用 SvelteKit 和 Svelte 进行服务器端处理。

¥This demo focuses on server-side processing with SvelteKit and Svelte.

Svelte 演示 涵盖一般客户端用法。

¥The Svelte demo covers general client-side usage.

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

¥The following diagram depicts the workbook waltz:

测试部署

本 demo 在以下环境下进行了测试:

¥This demo was tested in the following environments:

SvelteJS成套工具日期
4.2.172.5.102024-06-03
5.0.0-next.1492.5.102024-06-03

集成

¥Integration

可以通过从脚本导出 prerender 来预渲染 +page.server.js 脚本。如果在服务器脚本中执行 SheetJS 操作,则只有结果将添加到生成的页面中!

¥+page.server.js scripts can be pre-rendered by exporting prerender from the script. If the SheetJS operations are performed in the server script, only the results will be added to the generated pages!

对于静态站点生成,必须使用 @sveltejs/adapter-static

¥For static site generation, @sveltejs/adapter-static must be used.

加载器

¥Loader

SvelteKit 项目在底层使用 ViteJS。他们公开了 vite.config.js 脚本。ViteJS demo[^2] 中的 "Base64 加载器" 可以将文件中的数据提取到 Base64 字符串中,以便在 +page.server.js 脚本中进行处理。

¥SvelteKit projects use ViteJS under the hood. They expose the vite.config.js script. The "Base64 Loader" from the ViteJS demo[^2] can pull data from files into Base64 strings for processing in +page.server.js scripts.

ViteJS 演示使用查询 ?b64 来识别文件。为了更好地使用 SvelteKit,此演示直接匹配文件扩展名。

¥The ViteJS demo used the query ?b64 to identify files. To play nice with SvelteKit, this demo matches the file extensions directly.

加载程序应添加到 vite.config.js。该代码与 "Base64 加载器" ViteJS 示例几乎相同。

¥The loader should be added to vite.config.js. The code is nearly identical to the "Base64 Loader" ViteJS example.

vite.config.js
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { readFileSync } from 'fs';

export default defineConfig({
assetsInclude: ['**/*.numbers', '**/*.xlsx'],
plugins: [sveltekit(), {
name: "sheet-base64",
transform(code, id) {
if(!id.match(/\.(numbers|xlsx)$/)) return;
var data = readFileSync(id, "base64");
return `export default '${data}'`;
}
}]
});

类型

¥Types

对于 VSCodium 集成,可以在 src/app.d.ts 中指定类型。

¥For VSCodium integration, types can be specified in src/app.d.ts.

示例数据加载器返回 Base64 字符串。应为加载程序支持的每个文件扩展名添加声明:

¥The example data loader returns Base64 strings. Declarations should be added for each file extension supported in the loader:

src/app.d.ts
declare global {
declare module '*.numbers' { const data: string; export default data; }
declare module '*.xlsx' { const data: string; export default data; }
}

数据处理

¥Data Processing

对于静态站点,SheetJS 操作应在 +page.server.js[^3] 中运行。该脚本必须包含 export const prerender = true[^4]。

¥For static sites, SheetJS operations should be run in +page.server.js[^3]. The script must include export const prerender = true[^4].

假设 pres.xlsx 存放在项目根目录下的 data 目录下,则相对导入

¥Assuming pres.xlsx is stored in the data directory from the project root, the relative import

import b64 from "../../data/pres.xlsx"

将返回一个可以在脚本中解析的 Base64 字符串。可以使用实用函数对工作簿对象进行后处理。

¥will return a Base64 string which can be parsed in the script. The workbook object can be post-processed using utility functions.

以下示例使用 SheetJS read 方法 [^5] 来解析电子表格文件,并使用 sheet_to_json 方法 [^6] 为每个工作表生成行对象数组。渲染给页面的数据将是一个对象,其键是工作表名称:

¥The following example uses the SheetJS read method[^5] to parse spreadsheet files and the sheet_to_json method[^6] to generate arrays of row objects for each worksheet. The data presented to the page will be an object whose keys are worksheet names:

src/routes/+page.server.js
import b64 from "../../data/pres.xlsx";
import { read, utils } from "xlsx";

export const prerender = true;

/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
const wb = read(b64);
/** @type {[string, any[]][]} */
const data = wb.SheetNames.map(n => [n, utils.sheet_to_json(wb.Sheets[n])]);
return Object.fromEntries(data);
}

数据渲染

¥Data Rendering

数据的形状由加载器决定。示例加载程序返回一个对象,其键是工作表名称,其值是对象数组。

¥The shape of the data is determined by the loader. The example loader returns an object whose keys are worksheet names and whose values are arrays of objects.

使用标准 Svelte 模式,可以从数据生成 HTML 表格:

¥Using standard Svelte patterns, HTML tables can be generated from the data:

src/routes/+page.svelte
<script>
/** @type {import('./$types').PageData} */
export let data;

/* `pres` will be the data from Sheet1 */
/** @type {Array<{Name: string, Index: number}>}*/
export let pres = data["Sheet1"];
</script>

<h1>Presidents</h1>


<table><thead><tr><th>Name</th><th>Index</th></tr></thead>

<tbody>
{#each pres as p}<tr>
<td>{p.Name}</td>
<td>{p.Index}</td>
</tr>{/each}
</tbody>

</table>


当使用 npm run build 构建时,SvelteKit 将执行转换并触发一个简单的 HTML 表格,而无需引用现有的电子表格文件!

¥When built using npm run build, SvelteKit will perform the conversion and emit a simple HTML table without any reference to the existing spreadsheet file!

完整示例

¥Complete Example

上次测试此演示时,SvelteKit 需要 NodeJS 主版本 20。

¥When this demo was last tested, SvelteKit required NodeJS major version 20.

初始设置

¥Initial Setup

  1. 创建一个新站点:

    ¥Create a new site:

npm create svelte@latest sheetjs-svelte

提示时:

¥When prompted:

  • Which Svelte app template? 选择 Skeleton Project

    ¥Which Svelte app template? select Skeleton Project

  • Add type checking with TypeScript? 选择 Yes, using JavaScript with JSDoc

    ¥Add type checking with TypeScript? select Yes, using JavaScript with JSDoc

  • Select additional optionsEnter(不选择选项)

    ¥Select additional options press Enter (do not select options)

要测试 Svelte 5 测试版,请选择 Try the Svelte 5 preview (unstable!)

¥To test the Svelte 5 beta, select Try the Svelte 5 preview (unstable!)

  1. 进入项目文件夹并安装依赖:

    ¥Enter the project folder and install dependencies:

cd sheetjs-svelte
npm i
  1. 获取示例文件 pres.xlsx 并移动到项目根目录中的 data 子目录:

    ¥Fetch the example file pres.xlsx and move to a data subdirectory in the root of the project:

mkdir -p data
curl -Lo data/pres.xlsx https://xlsx.nodejs.cn/pres.xlsx
  1. 安装 SheetJS 库:

    ¥Install the SheetJS library:

npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
  1. 用以下代码块替换 vite.config.js 的内容:

    ¥Replace the contents of vite.config.js with the following codeblock:

vite.config.js
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
import { readFileSync } from 'fs';

export default defineConfig({
assetsInclude: ['**/*.numbers', '**/*.xlsx'],
plugins: [sveltekit(), {
name: "sheet-base64",
transform(code, id) {
if(!id.match(/\.(numbers|xlsx)$/)) return;
var data = readFileSync(id, "base64");
return `export default '${data}'`;
}
}]
});
  1. 将以下行附加到 src/app.d.ts

    ¥Append the following lines to src/app.d.ts:

src/app.d.ts (add to end of file)
declare global {
declare module '*.numbers' { const data: string; export default data; }
declare module '*.xlsx' { const data: string; export default data; }
}
  1. 用以下代码替换 src/routes/+page.server.js 的内容。如果文件不存在,则创建该文件。

    ¥Replace the contents of src/routes/+page.server.js with the following code. Create the file if it does not exist.

src/routes/+page.server.js
import b64 from "../../data/pres.xlsx";
import { read, utils } from "xlsx";

export const prerender = true;

/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
const wb = read(b64);
/** @type {[string, any[]][]} */
const data = wb.SheetNames.map(n => [n, utils.sheet_to_json(wb.Sheets[n])]);
return Object.fromEntries(data);
}
  1. 用以下代码替换 src/routes/+page.svelte 的内容。如果文件不存在,则创建该文件。

    ¥Replace the contents of src/routes/+page.svelte with the following code. Create the file if it does not exist.

src/routes/+page.svelte
<script>
/** @type {import('./$types').PageData} */
export let data;

/* `pres` will be the data from Sheet1 */
/** @type {Array<{Name: string, Index: number}>}*/
export let pres = data["Sheet1"];
</script>

<h1>Presidents</h1>


<table><thead><tr><th>Name</th><th>Index</th></tr></thead>

<tbody>
{#each pres as p}<tr>
<td>{p.Name}</td>
<td>{p.Index}</td>
</tr>{/each}
</tbody>

</table>


实时重新加载

¥Live Reload

  1. 在 Apple Numbers 或 Excel 等电子表格编辑器中打开 data/pres.xlsx

    ¥Open data/pres.xlsx in a spreadsheet editor like Apple Numbers or Excel.

  2. 启动开发服务器:

    ¥Start the development server:

npm run dev

在 Web 浏览器中打开显示的 URL(通常为 http://localhost:5173),并观察电子表格中的数据显示在页面中。

¥Open the displayed URL (typically http://localhost:5173) in a web browser and observe that the data from the spreadsheet is displayed in the page.

  1. 在电子表格中,将单元格 A7 设置为 SheetJS Dev,将单元格 B7 设置为 47。保存文件。保存后,浏览器应自动刷新新数据。

    ¥In the spreadsheet, set cell A7 to SheetJS Dev and cell B7 to 47. Save the file. After saving, the browser should automatically refresh with new data.

静态站点

¥Static Site

  1. 停止开发服务器并安装静态适配器:

    ¥Stop the development server and install the static adapter:

npm i --save @sveltejs/adapter-static
  1. 编辑 svelte.config.js 以使用新适配器。

    ¥Edit svelte.config.js to use the new adapter.

该配置当前应使用 adapter-auto

¥The config should currently use adapter-auto:

svelte.config.js (default configuration)
import adapter from '@sveltejs/adapter-auto';

将模块名称替换为 @sveltejs/adapter-static

¥Replace the module name with @sveltejs/adapter-static:

svelte.config.js (change dependency)
import adapter from '@sveltejs/adapter-static';
  1. 构建静态站点:

    ¥Build the static site:

npm run build
  1. 启动将托管生产版本的本地 Web 服务器:

    ¥Start a local web server that will host the production build:

npx -y http-server build
  1. 打开 Web 浏览器并访问显示的 URL (http://localhost:8080)。查看页面源代码并确认原始 HTML 表包含数据。

    ¥Open a web browser and access the displayed URL (http://localhost:8080). View the page source and confirm that the raw HTML table includes the data.

搜索 Bill Clinton 应显示以下行:

¥Searching for Bill Clinton should reveal the following row:

<tr><td>Bill Clinton</td><td>42</td></tr>

[^1]: 请参阅 SvelteKit 文档中的 "SvelteKit 与 Svelte"

¥See "SvelteKit vs Svelte" in the SvelteKit documentation.

[^2]: 见 ViteJS 演示中的 "Base64 插件"

¥See "Base64 Plugin" in the ViteJS demo

[^3]: 请参阅 SvelteKit 文档中的 "通用与服务器"

¥See "Universal vs server" in the SvelteKit documentation.

[^4]: 请参阅 SvelteKit 文档中的 "prerender"

¥See "prerender" in the SvelteKit documentation.

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

¥See read in "Reading Files"

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

¥See sheet_to_json in "Utilities"