docs.sheetjs.com/docz/docs/03-demos/04-static/05-vitejs.md

348 lines
9.8 KiB
Markdown
Raw Normal View History

2023-01-15 03:36:13 +00:00
---
2023-08-01 00:28:19 +00:00
title: ViteJS Spreadsheet Plugins
2023-06-07 03:48:13 +00:00
sidebar_class_name: red
sidebar_label: ViteJS
description: Make static websites from spreadsheets using ViteJS. Seamlessly integrate data into your website using SheetJS. Empower non-technical people to write content from Excel.
2023-02-28 11:40:44 +00:00
pagination_prev: demos/net/index
pagination_next: demos/mobile/index
2023-01-15 03:36:13 +00:00
sidebar_custom_props:
type: bundler
---
2023-04-27 09:12:19 +00:00
import current from '/version.js';
2023-04-30 12:27:09 +00:00
import CodeBlock from '@theme/CodeBlock';
2023-04-27 09:12:19 +00:00
2023-06-07 03:48:13 +00:00
[ViteJS](https://vitejs.dev/) is a modern build tool for generating static sites.
It has a robust JavaScript-powered plugin system[^1]
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses ViteJS 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 ViteJS
plugin and compare a few different data loading strategies.
2023-09-08 09:11:11 +00:00
The ["Complete Demo"](#complete-demo) section creates a complete website powered
by a XLSX spreadsheet.
2023-06-07 03:48:13 +00:00
2023-08-01 00:28:19 +00:00
:::tip pass
2023-09-08 09:11:11 +00:00
This demo covers use cases where data is available at build time. This flow is
2023-08-01 00:28:19 +00:00
suitable for end of week or end of month (EOM) reports published in HTML tables
2023-01-15 03:36:13 +00:00
2023-08-01 00:28:19 +00:00
For processing user-submitted files in the browser, the
2023-09-08 09:11:11 +00:00
["Bundlers" demo](/docs/demos/frontend/bundler#vite) shows client-side bundling
of the SheetJS library.
2023-01-15 03:36:13 +00:00
:::
2023-06-07 03:48:13 +00:00
## Plugins
2023-01-15 03:36:13 +00:00
2023-06-07 03:48:13 +00:00
ViteJS supports static asset imports[^2], but the default raw loader interprets data
2023-01-15 03:36:13 +00:00
as UTF-8 strings. This corrupts binary formats like XLSX and XLS, but a custom
loader can override the default behavior.
2023-06-07 03:48:13 +00:00
For simple tables of data, ["Pure Data Plugin"](#pure-data-plugin) is strongly
2023-09-08 09:11:11 +00:00
recommended. The file processing is performed at build time and the generated
site only includes the raw data.
2023-01-15 03:36:13 +00:00
2023-06-07 03:48:13 +00:00
For more complex parsing or display logic, ["Base64 Plugin"](#base64-plugin) is
2023-04-30 12:27:09 +00:00
preferable. Since the raw parsing logic is performed in the page, the library
will be included in the final bundle.
2023-01-15 03:36:13 +00:00
2023-06-07 03:48:13 +00:00
### Pure Data Plugin
2023-01-15 03:36:13 +00:00
For a pure static site, a plugin can load data into an array of row objects. The
SheetJS work is performed in the plugin. The library is not loaded in the page!
2023-05-25 01:36:15 +00:00
The following diagram depicts the workbook waltz:
```mermaid
flowchart LR
file[(workbook\nfile)]
subgraph SheetJS operations
buffer(NodeJS\nBuffer)
aoo(array of\nobjects)
end
html{{HTML\nTABLE}}
file --> |vite.config.js\ncustom plugin| buffer
buffer --> |vite.config.js\ncustom plugin| aoo
aoo --> |main.js\nfrontend code| html
```
2023-06-07 03:48:13 +00:00
This ViteJS plugin will read spreadsheets using the SheetJS `read` method[^3]
and generate arrays of row objects with `sheet_to_json`[^4]:
2023-05-25 01:36:15 +00:00
2023-01-15 03:36:13 +00:00
```js title="vite.config.js"
import { readFileSync } from 'fs';
import { read, utils } from 'xlsx';
import { defineConfig } from 'vite';
export default defineConfig({
assetsInclude: ['**/*.xlsx'], // xlsx file should be treated as assets
plugins: [
{ // this plugin handles ?sheetjs tags
name: "vite-sheet",
transform(code, id) {
if(!id.match(/\?sheetjs$/)) return;
var wb = read(readFileSync(id.replace(/\?sheetjs$/, "")));
var data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
return `export default JSON.parse('${JSON.stringify(data)}')`;
}
}
]
});
```
2023-06-07 03:48:13 +00:00
In frontend code, the loader will look for all modules with a `?sheetjs`
2023-06-20 01:21:34 +00:00
query string. The default export is an array of row objects.
2023-01-15 03:36:13 +00:00
2023-06-20 01:21:34 +00:00
The following example script displays the data in a table:
2023-01-15 03:36:13 +00:00
2023-06-20 01:21:34 +00:00
```js title="main.js"
import data from './data/pres.xlsx?sheetjs';
document.querySelector('#app').innerHTML = `<table>
<thead><tr><th>Name</th><th>Index</th></tr></thead>
<tbody>
${data.map(row => `<tr>
<td>${row.Name}</td>
<td>${row.Index}</td>
</tr>`).join("\n")}
</tbody>
</table>`;
2023-01-15 03:36:13 +00:00
```
2023-06-07 03:48:13 +00:00
### Base64 Plugin
2023-01-15 03:36:13 +00:00
2023-06-07 03:48:13 +00:00
This plugin pulls in data as a Base64 string that can be read with `read`[^5].
2023-01-15 03:36:13 +00:00
While this approach works, it is not recommended since it loads the library in
the front-end site.
2023-05-25 01:36:15 +00:00
The following diagram depicts the workbook waltz:
```mermaid
flowchart LR
file[(workbook\nfile)]
subgraph SheetJS operations
base64(base64\nstring)
aoo(array of\nobjects)
end
html{{HTML\nTABLE}}
file --> |vite.config.js\ncustom plugin| base64
base64 --> |main.js\nfrontend code| aoo
aoo --> |main.js\nfrontend code| html
```
2023-06-07 03:48:13 +00:00
This ViteJS plugin will read spreadsheet files and export the data as a Base64
string. SheetJS is not imported in the plugin:
2023-01-15 03:36:13 +00:00
```js title="vite.config.js"
import { readFileSync } from 'fs';
import { defineConfig } from 'vite';
export default defineConfig({
assetsInclude: ['**/*.xlsx'], // mark that xlsx file should be treated as assets
plugins: [
{ // this plugin handles ?b64 tags
name: "vite-b64-plugin",
transform(code, id) {
if(!id.match(/\?b64$/)) return;
var path = id.replace(/\?b64/, "");
var data = readFileSync(path, "base64");
return `export default '${data}'`;
}
}
]
});
```
When importing using the `b64` query, the raw Base64 string will be exposed.
2023-06-07 03:48:13 +00:00
`read` will process the Base64 string using the `base64` input type[^6]:
2023-01-15 03:36:13 +00:00
```js title="main.js"
import { read, utils } from "xlsx";
2023-06-20 01:21:34 +00:00
/* import workbook data */
2023-01-15 03:36:13 +00:00
import b64 from './data.xlsx?b64';
2023-06-20 01:21:34 +00:00
/* parse workbook and pull data from the first worksheet */
2023-06-07 03:48:13 +00:00
const wb = read(b64, { type: "base64" });
2023-01-15 03:36:13 +00:00
const wsname = wb.SheetNames[0];
2023-06-20 01:21:34 +00:00
const data = utils.sheet_to_json(wb.Sheets[wsname]);
document.querySelector('#app').innerHTML = `<table>
<thead><tr><th>Name</th><th>Index</th></tr></thead>
<tbody>
${data.map(row => `<tr>
<td>${row.Name}</td>
<td>${row.Index}</td>
</tr>`).join("\n")}
</tbody>
</table>`;
2023-01-15 03:36:13 +00:00
```
## Complete Demo
:::note
2023-09-08 09:11:11 +00:00
This demo was tested on 2023 September 07 with ViteJS version `4.4.9`.
2023-01-15 03:36:13 +00:00
:::
2023-06-07 03:48:13 +00:00
The demo walks through the process of creating a new ViteJS website from scratch.
A Git repository with the completed site can be cloned[^7].
2023-01-15 03:36:13 +00:00
### Initial Setup
2023-04-30 12:27:09 +00:00
1) Create a new site with the `vue-ts` template and install the SheetJS package:
2023-01-15 03:36:13 +00:00
2023-04-30 12:27:09 +00:00
<CodeBlock language="bash">{`\
2023-01-15 03:36:13 +00:00
npm create vite@latest sheetjs-vite -- --template vue-ts
cd sheetjs-vite
2023-05-07 13:58:36 +00:00
npm i
2023-04-30 12:27:09 +00:00
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>
2023-01-15 03:36:13 +00:00
2023-08-01 00:28:19 +00:00
2) Download and replace [`vite.config.ts`](pathname:///vitejs/vite.config.ts)
2023-01-15 03:36:13 +00:00
2023-08-01 00:28:19 +00:00
```bash
curl -O https://docs.sheetjs.com/vitejs/vite.config.ts
2023-01-15 03:36:13 +00:00
```
3) Make a `data` folder and download <https://sheetjs.com/pres.xlsx> :
```bash
mkdir -p data
curl -L -o data/pres.xlsx https://sheetjs.com/pres.xlsx
```
### Pure Data Test
4) Run the dev server:
```bash
npm run dev
```
2023-05-03 03:40:40 +00:00
Open a browser window to the displayed URL (typically `http://localhost:5173` )
2023-01-15 03:36:13 +00:00
5) Replace the component `src/components/HelloWorld.vue` with:
```html title="src/components/HelloWorld.vue"
<script setup lang="ts">
// @ts-ignore
import data from '../../data/pres.xlsx?sheetjs';
</script>
<template>
<table>
<tr><th>Name</th><th>Index</th></tr>
<tr v-for="(row,R) in data" v-bind:key="R">
<td>{{row.Name}}</td>
<td>{{row.Index}}</td>
</tr>
</table>
</template>
```
Save and refresh the page. A data table should be displayed
6) Stop the dev server and build the site
```bash
npm run build
npx http-server dist/
```
2023-07-06 07:21:41 +00:00
The terminal will display a URL, typically `http://127.0.0.1:8080` . Access
that page with a web browser.
2023-01-15 03:36:13 +00:00
7) To confirm that only the raw data is present in the page, view the page
source. The code will reference some script like `/assets/index-HASH.js`.
2023-08-01 00:28:19 +00:00
Open that script.
Searching for `Bill Clinton` reveals the following:
2023-01-15 03:36:13 +00:00
2023-08-20 20:39:35 +00:00
```js
2023-06-20 01:21:34 +00:00
{"Name":"Bill Clinton","Index":42}
2023-01-15 03:36:13 +00:00
```
Searching for `BESSELJ` should reveal no results. The SheetJS scripts are not
included in the final site!
2023-09-08 09:11:11 +00:00
:::info pass
2023-06-07 03:48:13 +00:00
ViteJS also supports "Server-Side Rendering". In SSR, only the HTML table
would be added to the final page. Details are covered in the ViteJS docs[^8].
:::
2023-01-15 03:36:13 +00:00
### Base64 Test
8) Run the dev server:
```bash
npm run dev
```
Open a browser window to the displayed URL.
9) Replace the component `src/components/HelloWorld.vue` with:
```html title="src/components/HelloWorld.vue"
<script setup lang="ts">
// @ts-ignore
import b64 from '../../data/pres.xlsx?b64';
import { read, utils } from "xlsx";
/* parse workbook and convert first sheet to row array */
const wb = read(b64);
const ws = wb.Sheets[wb.SheetNames[0]];
interface IPresident { Name: string; Index: number; };
const data = utils.sheet_to_json<IPresident>(ws);
</script>
<template>
<table>
<tr><th>Name</th><th>Index</th></tr>
<tr v-for="(row,R) in data" v-bind:key="R">
<td>{{row.Name}}</td>
<td>{{row.Index}}</td>
</tr>
</table>
</template>
```
10) Stop the dev server and build the site
```bash
npm run build
npx http-server dist/
```
2023-05-03 03:40:40 +00:00
The terminal will display a URL ( `http://127.0.0.1:8080` ). Access that page
2023-01-15 03:36:13 +00:00
with a web browser.
2023-06-14 19:32:34 +00:00
11) To confirm that the object data is not present in the page, view the page
2023-08-01 00:28:19 +00:00
source. The code will reference some script like `/assets/index-HASH.js` with
a different hash from the previous test. Open that script.
2023-01-15 03:36:13 +00:00
Searching for `BESSELJ` should match the code:
```
425:"BESSELJ"
```
2023-08-01 00:28:19 +00:00
Searching for `Bill Clinton` should yield no results. The SheetJS library is
embedded in the final site and the data is parsed when the page is loaded.
2023-06-07 03:48:13 +00:00
[^1]: See ["Using Plugins"](https://vitejs.dev/guide/using-plugins.html) in the ViteJS documentation.
[^2]: See ["Static Asset Handling"](https://vitejs.dev/guide/assets.html) in the ViteJS documentation.
2023-06-20 01:21:34 +00:00
[^3]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
[^5]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^6]: See [the "base64" type in "Reading Files"](/docs/api/parse-options#input-type)
2023-06-07 03:48:13 +00:00
[^7]: See [`SheetJS/sheetjs-vite`](https://git.sheetjs.com/sheetjs/sheetjs-vite/) on the SheetJS git server.
[^8]: See ["Server-Side Rendering"](https://vitejs.dev/guide/ssr.html) in the ViteJS documentation.