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

284 lines
7.0 KiB
Markdown
Raw Normal View History

2023-01-15 03:36:13 +00:00
---
title: ViteJS
pagination_prev: demos/extensions/index
2023-02-18 02:33:30 +00:00
pagination_next: demos/cli
2023-01-15 03:36:13 +00:00
sidebar_custom_props:
type: bundler
---
:::note
This demo covers static asset imports. For processing files in the browser, the
["Bundlers" demo](/docs/demos/bundler#vite) includes an example.
:::
## Loaders
ViteJS supports static asset imports, but the default raw loader interprets data
as UTF-8 strings. This corrupts binary formats like XLSX and XLS, but a custom
loader can override the default behavior.
:::note Recommendation
For simple tables of data, ["Pure Data Loader"](#pure-data-loader) is strongly
recommended. The heavy work is performed at build time and the generated site
only includes the raw data.
For more complex parsing or display logic, ["Base64 Loader"](#base64-loader) is
preferable. Since the raw parsing logic is performed in the page,
:::
### Pure Data Loader
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!
```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)}')`;
}
}
]
});
```
This loader uses the query `sheetjs`:
```js title="main.js"
import data from './data.xlsx?sheetjs';
document.querySelector('#app').innerHTML = `<div><pre>
${data.map(row => JSON.stringify(row)).join("\n")}
</pre></div>`;
```
### Base64 Loader
This loader pulls in data as a Base64 string that can be read with `XLSX.read`.
While this approach works, it is not recommended since it loads the library in
the front-end site.
```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.
This can be read directly with `XLSX.read` in JS code:
```js title="main.js"
import { read, utils } from "xlsx";
/* reference workbook */
import b64 from './data.xlsx?b64';
/* parse workbook and export first sheet to CSV */
const wb = read(b64);
const wsname = wb.SheetNames[0];
const csv = utils.sheet_to_csv(wb.Sheets[wsname]);
document.querySelector('#app').innerHTML = `<div><pre>
<b>${wsname}</b>
${csv}
</pre></div>`;
```
## Complete Demo
:::note
This demo was tested on 2023 January 14 against `vite v4.0.4`.
:::
### Initial Setup
1) Create a new site using the `vue-ts` template:
```bash
npm create vite@latest sheetjs-vite -- --template vue-ts
cd sheetjs-vite
npm install
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
```
2) Replace `vite.config.ts` with the following:
```js title="vite.config.ts"
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { readFileSync } from 'fs';
import { read, utils } from 'xlsx';
export default defineConfig({
assetsInclude: ['**/*.xlsx'], // xlsx file should be treated as assets
plugins: [
vue(),
{ // 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)}')`;
}
},
{ // 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}'`;
}
}
]
});
```
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
```
Open a browser window to the displayed URL (typically http://localhost:5173 )
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/
```
The terminal will display a url like http://127.0.0.1:8080. Access that page
with a web browser.
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`.
Open that script. Searching for `Bill Clinton` reveals the following:
```
JSON.parse('[{"Name":"Bill Clinton","Index":42}
```
Searching for `BESSELJ` should reveal no results. The SheetJS scripts are not
included in the final site!
### 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/
```
The terminal will display a url like http://127.0.0.1:8080. Access that page
with a web browser.
11) 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`.
Open that script. Searching for `Bill Clinton` should yield no results.
Searching for `BESSELJ` should match the code:
```
425:"BESSELJ"
```
The SheetJS library is embedded in the final site.