forked from sheetjs/docs.sheetjs.com
		
	
		
			
	
	
		
			237 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			237 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|  | --- | ||
|  | title: SvelteKit | ||
|  | pagination_prev: demos/net/index | ||
|  | pagination_next: demos/mobile/index | ||
|  | --- | ||
|  | 
 | ||
|  | import current from '/version.js'; | ||
|  | 
 | ||
|  | :::note | ||
|  | 
 | ||
|  | This demo covers SvelteKit. The [Svelte demo](/docs/demos/frontend/svelte) | ||
|  | covers general client-side strategies. | ||
|  | 
 | ||
|  | This demo uses ["Base64 Loader"](/docs/demos/static/vitejs#base64-loader) | ||
|  | from the ViteJS demo. | ||
|  | 
 | ||
|  | ::: | ||
|  | 
 | ||
|  | SvelteKit projects use ViteJS under the hood. They expose the `vite.config.js` | ||
|  | script. The [ViteJS demo](/docs/demos/static/vitejs) examples work as expected! | ||
|  | 
 | ||
|  | The following diagram depicts the workbook waltz: | ||
|  | 
 | ||
|  | ```mermaid | ||
|  | flowchart LR | ||
|  |   file[(workbook\nfile)] | ||
|  |   subgraph SheetJS operations | ||
|  |     base64(base64\nstring) | ||
|  |     aoa(array of\nobjects) | ||
|  |   end | ||
|  |   html{{HTML\nTABLE}} | ||
|  |   file --> |vite.config.js\ndata loader| base64 | ||
|  |   base64 --> |+page.server.js\nload function| aoa | ||
|  |   aoa --> |+page.svelte\ncomponent| html | ||
|  | ``` | ||
|  | 
 | ||
|  | ## Integration
 | ||
|  | 
 | ||
|  | `+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! | ||
|  | 
 | ||
|  | For static site generation, `@sveltejs/adapter-static` must be used. | ||
|  | 
 | ||
|  | ### Loader
 | ||
|  | 
 | ||
|  | :::note | ||
|  | 
 | ||
|  | The ViteJS demo used the query `?b64` to identify files. To play nice with | ||
|  | SvelteKit, this demo matches the file extensions directly. | ||
|  | 
 | ||
|  | ::: | ||
|  | 
 | ||
|  | The loader should be added to `vite.config.js`. The code is nearly identical to | ||
|  | the ["Base64 Loader" ViteJS example.](/docs/demos/static/vitejs#base64-loader) | ||
|  | 
 | ||
|  | ```js title="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
 | ||
|  | 
 | ||
|  | For VSCodium integration, types can be specified in `src/app.d.ts`. | ||
|  | 
 | ||
|  | The example data loader returns Base64 strings. Declarations should be added for | ||
|  | each file extension supported in the loader: | ||
|  | 
 | ||
|  | ```ts title="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
 | ||
|  | 
 | ||
|  | For static sites, SheetJS operations should be run in `+page.server.js` . | ||
|  | 
 | ||
|  | Assuming `pres.xlsx` is stored in the `data` directory from the project root, | ||
|  | the relative import | ||
|  | 
 | ||
|  | ```js | ||
|  | import b64 from "../../data/pres.xlsx" | ||
|  | ``` | ||
|  | 
 | ||
|  | will return a Base64 string which can be parsed in the script. The workbook | ||
|  | object can be post-processed using utility functions.  The following example | ||
|  | uses `sheet_to_json` to generate arrays of row objects for each worksheet. The | ||
|  | data presented to the page will be an object whose keys are worksheet names: | ||
|  | 
 | ||
|  | ```js title="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. | ||
|  | 
 | ||
|  | Using standard Svelte patterns, HTML tables can be generated from the data: | ||
|  | 
 | ||
|  | ```html title="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><th>Name</th><th>Index</th></thead><tbody> | ||
|  |   {#each pres as p}<tr> | ||
|  |     <td>{p.Name}</td> | ||
|  |     <td>{p.Index}</td> | ||
|  |   </tr>{/each} | ||
|  | </tbody></table> | ||
|  | ``` | ||
|  | 
 | ||
|  | 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
 | ||
|  | 
 | ||
|  | :::note | ||
|  | 
 | ||
|  | This demo was tested on 2023 April 30 using SvelteKit `1.15.9` | ||
|  | 
 | ||
|  | ::: | ||
|  | 
 | ||
|  | ### Initial Setup
 | ||
|  | 
 | ||
|  | 1) Create a new site: | ||
|  | 
 | ||
|  | ```bash | ||
|  | npm create svelte@latest sheetjs-svelte | ||
|  | cd sheetjs-svelte | ||
|  | npm i | ||
|  | ``` | ||
|  | 
 | ||
|  | 2) Fetch the example file [`pres.xlsx`](https://sheetjs.com/pres.xlsx) and move | ||
|  | to a `data` subdirectory in the root of the project: | ||
|  | 
 | ||
|  | ```bash | ||
|  | mkdir -p data | ||
|  | curl -Lo data/pres.xlsx https://sheetjs.com/pres.xlsx | ||
|  | ``` | ||
|  | 
 | ||
|  | 3) Install the SheetJS library: | ||
|  | 
 | ||
|  | <pre><code parentName="pre" {...{"className": "language-bash"}}>{`\ | ||
|  | npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} | ||
|  | </code></pre> | ||
|  | 
 | ||
|  | 4) Replace the contents of `vite.config.js` with the contents of the code block | ||
|  | named [`vite.config.js` in the "Loader" section](#loader) | ||
|  | 
 | ||
|  | 5) Append the lines from [`src/app.d.ts` snippet in the "Types" section](#types) | ||
|  | to the `src/app.d.ts` file. | ||
|  | 
 | ||
|  | 6) Replace the contents of `src/routes/+page.server.ts` with the contents of the | ||
|  | code block named [`src/routes/+page.server.ts` in "Data Processing"](#data-processing) | ||
|  | 
 | ||
|  | 7) Replace the contents of `src/routes/+page.svelte` with the contents of the | ||
|  | code block named [`src/routes/+page.svelte` in "Data Rendering"](#data-rendering) | ||
|  | 
 | ||
|  | ### Live Reload
 | ||
|  | 
 | ||
|  | 8) Open `data/pres.xlsx` in a spreadsheet editor like Apple Numbers or Excel. | ||
|  | 
 | ||
|  | 9) Start the development server: | ||
|  | 
 | ||
|  | ```bash | ||
|  | npm run dev | ||
|  | ``` | ||
|  | 
 | ||
|  | 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. | ||
|  | 
 | ||
|  | 10) 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
 | ||
|  | 
 | ||
|  | 11) Stop the development server and install the static adapter: | ||
|  | 
 | ||
|  | ```bash | ||
|  | npm install --save @sveltejs/adapter-static | ||
|  | ``` | ||
|  | 
 | ||
|  | 12) Edit `svelte.config.js` to use the new adapter: | ||
|  | 
 | ||
|  | ```diff title="svelte.config.js" | ||
|  | -import adapter from '@sveltejs/adapter-auto'; | ||
|  | +import adapter from '@sveltejs/adapter-static'; | ||
|  | ``` | ||
|  | 
 | ||
|  | 13) Build the static site: | ||
|  | 
 | ||
|  | ```bash | ||
|  | npm run build | ||
|  | ``` | ||
|  | 
 | ||
|  | 14) 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. |