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-10-09 01:13:21 +00:00
:::info pass
2023-08-01 00:28:19 +00:00
2023-09-08 09:11:11 +00:00
This demo covers use cases where data is available at build time. This flow is
2023-10-09 01:13:21 +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-10-22 05:40:02 +00:00
[ViteJS "Bundlers" demo ](/docs/demos/frontend/bundler/vitejs ) shows client-side
bundling of the SheetJS library. The ["ReactJS" demo ](/docs/demos/frontend/react )
shows example sites using ViteJS with the ReactJS starter.
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
2023-12-05 03:46:54 +00:00
:::note Tested Deployments
2023-01-15 03:36:13 +00:00
2023-12-05 03:46:54 +00:00
This demo was tested in the following environments:
| ViteJS | Date |
|:---------|:-----------|
| `5.0.5` | 2023-12-04 |
| `4.5.0` | 2023-12-04 |
| `3.2.7` | 2023-12-04 |
| `2.9.16` | 2023-12-04 |
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-12-05 03:46:54 +00:00
:::note pass
To force an older major version of ViteJS, change the `vite@5` to the desired
major version. For example, `npm create vite@3` will use ViteJS major version 3.
:::
2023-04-30 12:27:09 +00:00
< CodeBlock language = "bash" > {`\
2023-12-05 03:46:54 +00:00
npm create vite@5 sheetjs-vite -- --template vue-ts
2023-01-15 03:36:13 +00:00
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
```
2024-04-26 04:16:13 +00:00
3) Make a `data` folder and download https://docs.sheetjs.com/pres.xlsx :
2023-01-15 03:36:13 +00:00
```bash
mkdir -p data
2024-04-26 04:16:13 +00:00
curl -L -o data/pres.xlsx https://docs.sheetjs.com/pres.xlsx
2023-01-15 03:36:13 +00:00
```
### 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.