---
title: ViteJS
pagination_prev: demos/extensions/index
pagination_next: demos/gsheet
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.