forked from sheetjs/docs.sheetjs.com
		
	ViteJS Static Demo refresh
This commit is contained in:
		
							parent
							
								
									1a80a55e76
								
							
						
					
					
						commit
						14bd6a4ed0
					
				| @ -86,16 +86,16 @@ | ||||
|    <Row> | ||||
|     <Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/nodesea#complete-example"><Data ss:Type="String">NodeJS SEA</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell> | ||||
|    </Row> | ||||
|    <Row> | ||||
|     <Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/bunsea#complete-example"><Data ss:Type="String">Bun SEA</Data></Cell> | ||||
|     <Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/bunsea#complete-example"><Data ss:Type="String">BunJS SEA</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell> | ||||
|     <Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell> | ||||
|  | ||||
| @ -12,15 +12,15 @@ sidebar_custom_props: | ||||
| import current from '/version.js'; | ||||
| import CodeBlock from '@theme/CodeBlock'; | ||||
| 
 | ||||
| [ViteJS](https://vitejs.dev/) is a modern build tool for generating static sites. | ||||
| It has a robust JavaScript-powered plugin system[^1] | ||||
| [ViteJS](https://vitejs.dev/) is a build tool for generating static websites. 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. | ||||
| plugin and evaluate data loading strategies. | ||||
| 
 | ||||
| The ["Complete Demo"](#complete-demo) section creates a complete website powered | ||||
| by a XLSX spreadsheet. | ||||
| @ -32,16 +32,97 @@ suitable for end of week or end of month (EOM) reports published in HTML tables. | ||||
| 
 | ||||
| For processing user-submitted files in the browser, the | ||||
| [ViteJS "Bundlers" demo](/docs/demos/frontend/bundler/vitejs) shows client-side | ||||
| bundling of the SheetJS library. The ["ReactJS" demo](/docs/demos/frontend/react) | ||||
| bundling of SheetJS libraries. The ["ReactJS" demo](/docs/demos/frontend/react) | ||||
| shows example sites using ViteJS with the ReactJS starter. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## Plugins | ||||
| 
 | ||||
| ViteJS supports static asset imports[^2], 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. | ||||
| ViteJS supports static asset imports[^2], but the default raw loader interprets | ||||
| data as UTF-8 strings. This corrupts binary formats including XLSX and XLS. A | ||||
| custom loader can bypass the raw loader and directly read files. | ||||
| 
 | ||||
| Since a custom loader must be used, some data processing work can be performed | ||||
| by the loader. Three approaches are explored in this demo. | ||||
| 
 | ||||
| The following diagrams show the ViteJS data flow. The pink "Main Script import" | ||||
| boxes represent the division between the loader and the main script. The green | ||||
| "SheetJS Operations" boxes represent the steps performed by SheetJS libraries. | ||||
| 
 | ||||
| <table> | ||||
|   <tr> | ||||
|     <th>[HTML](#html-plugin)</th> | ||||
|     <th>[Data](#pure-data-plugin)</th> | ||||
|     <th>[Base64](#base64-plugin)</th> | ||||
|   </tr> | ||||
|   <tr> | ||||
|     <td style={{verticalAlign: "top"}}> | ||||
| 
 | ||||
| ```mermaid | ||||
| flowchart TB | ||||
|   file[(workbook\nfile)] | ||||
|   buffer(NodeJS\nBuffer) | ||||
|   sheetjs[[SheetJS Operations]] | ||||
|   tabeller{{HTML\nString}} | ||||
|   handoff[[Main Script import]] | ||||
|   html{{HTML\nTABLE}} | ||||
|   style handoff fill:#FFC7CE | ||||
|   style sheetjs fill:#C6EFCE | ||||
|   file --> buffer | ||||
|   buffer --> sheetjs | ||||
|   sheetjs --> tabeller | ||||
|   tabeller --> handoff | ||||
|   handoff --------> html | ||||
| ``` | ||||
| 
 | ||||
|     </td> | ||||
|     <td style={{verticalAlign: "top"}}> | ||||
| 
 | ||||
| ```mermaid | ||||
| flowchart TB | ||||
|   file[(workbook\nfile)] | ||||
|   buffer(NodeJS\nBuffer) | ||||
|   sheetjs[[SheetJS Operations]] | ||||
|   aoo(array of\nobjects) | ||||
|   handoff[[Main Script import]] | ||||
|   import(array of\nobjects) | ||||
|   html{{HTML\nTABLE}} | ||||
|   style handoff fill:#FFC7CE | ||||
|   style sheetjs fill:#C6EFCE | ||||
|   file --> buffer | ||||
|   buffer --> sheetjs | ||||
|   sheetjs --> aoo | ||||
|   aoo --> handoff | ||||
|   handoff ------> import | ||||
|   import --> html | ||||
| ``` | ||||
| 
 | ||||
|     </td> | ||||
|     <td style={{verticalAlign: "top"}}> | ||||
| 
 | ||||
| ```mermaid | ||||
| flowchart TB | ||||
|   file[(workbook\nfile)] | ||||
|   base64(Base64\nString) | ||||
|   handoff[[Main Script import]] | ||||
|   import(Base64\nString) | ||||
|   sheetjs[[SheetJS Operations]] | ||||
|   aoo(array of\nobjects) | ||||
|   html{{HTML\nTABLE}} | ||||
|   style handoff fill:#FFC7CE | ||||
|   style sheetjs fill:#C6EFCE | ||||
|   file --> base64 | ||||
|   base64 ------> handoff | ||||
|   handoff --> import | ||||
|   import --> sheetjs | ||||
|   sheetjs --> aoo | ||||
|   aoo --> html | ||||
| ``` | ||||
| 
 | ||||
|     </td> | ||||
|   </tr> | ||||
| </table> | ||||
| 
 | ||||
| For simple tables of data, ["Pure Data Plugin"](#pure-data-plugin) is strongly | ||||
| recommended. The file processing is performed at build time and the generated | ||||
| @ -51,6 +132,9 @@ For more complex parsing or display logic, ["Base64 Plugin"](#base64-plugin) is | ||||
| preferable. Since the raw parsing logic is performed in the page, the library | ||||
| will be included in the final bundle. | ||||
| 
 | ||||
| The ["HTML Plugin"](#html-plugin) generates HTML in the loader script. The | ||||
| SheetJS HTML writer renders merged cells and other features. | ||||
| 
 | ||||
| ### Pure Data Plugin | ||||
| 
 | ||||
| For a pure static site, a plugin can load data into an array of row objects. The | ||||
| @ -72,7 +156,7 @@ flowchart LR | ||||
| ``` | ||||
| 
 | ||||
| This ViteJS plugin will read spreadsheets using the SheetJS `read` method[^3] | ||||
| and generate arrays of row objects with `sheet_to_json`[^4]: | ||||
| and generate arrays of row objects with the SheetJS `sheet_to_json`[^4] method: | ||||
| 
 | ||||
| ```js title="vite.config.js" | ||||
| import { readFileSync } from 'fs'; | ||||
| @ -89,13 +173,23 @@ export default defineConfig({ | ||||
|         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)}')`; | ||||
|         return `export default JSON.parse('${JSON.stringify(data).replace(/\\/g, "\\\\")}')`; | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| :::info pass | ||||
| 
 | ||||
| ViteJS plugins are expected to return strings representing ECMAScript modules. | ||||
| 
 | ||||
| The plugin uses `JSON.stringify` to encode the array of objects. The generated | ||||
| string is injected into the new module code. When ViteJS processes the module, | ||||
| `JSON.parse` recovers the array of objects. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| In frontend code, the loader will look for all modules with a `?sheetjs` | ||||
| query string. The default export is an array of row objects. | ||||
| 
 | ||||
| @ -115,9 +209,75 @@ document.querySelector('#app').innerHTML = `<table> | ||||
| </table>`; | ||||
| ``` | ||||
| 
 | ||||
| ### HTML Plugin | ||||
| 
 | ||||
| A plugin can generate raw HTML strings that can be added to a page. The SheetJS | ||||
| libraries are used in the plugin but will not be added to the site. | ||||
| 
 | ||||
| The following diagram depicts the workbook waltz: | ||||
| 
 | ||||
| ```mermaid | ||||
| flowchart LR | ||||
|   file[(workbook\nfile)] | ||||
|   subgraph SheetJS operations | ||||
|     buffer(NodeJS\nBuffer) | ||||
|     tavolo{{HTML\nString}} | ||||
|   end | ||||
|   html{{HTML\nTABLE}} | ||||
|   file --> |vite.config.js\ncustom plugin| buffer | ||||
|   buffer --> |vite.config.js\ncustom plugin| tavolo | ||||
|   tavolo --> |main.js\nfrontend code| html | ||||
| ``` | ||||
| 
 | ||||
| This ViteJS plugin will read spreadsheets using the SheetJS `read` method[^5] | ||||
| and generate HTML using the SheetJS `sheet_to_html`[^6] method: | ||||
| 
 | ||||
| ```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 ?html tags | ||||
|       name: "vite-sheet-html", | ||||
|       transform(code, id) { | ||||
|         if(!id.match(/\?html/)) return; | ||||
|         var wb = read(readFileSync(id.replace(/\?html/, ""))); | ||||
|         var html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); | ||||
|         return (`export default JSON.parse('${JSON.stringify(html).replace(/\\/g, "\\\\")}')`); | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| :::info pass | ||||
| 
 | ||||
| ViteJS plugins are expected to return strings representing ECMAScript modules. | ||||
| 
 | ||||
| The plugin uses `JSON.stringify` to encode the HTML string. The generated string | ||||
| is injected into the new module code. When ViteJS processes the module, | ||||
| `JSON.parse` recovers the original HTML string. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| In frontend code, the loader will look for all modules with a `?html` query | ||||
| string. The default export is a string that can be directly added to the page. | ||||
| 
 | ||||
| The following example script sets the `innerHTML` property of the container: | ||||
| 
 | ||||
| ```js title="main.js" | ||||
| import html from './data/pres.xlsx?html'; | ||||
| 
 | ||||
| document.querySelector('#app').innerHTML = html; | ||||
| ``` | ||||
| 
 | ||||
| ### Base64 Plugin | ||||
| 
 | ||||
| This plugin pulls in data as a Base64 string that can be read with `read`[^5]. | ||||
| This plugin pulls in data as a Base64 string that can be read with `read`[^7]. | ||||
| While this approach works, it is not recommended since it loads the library in | ||||
| the front-end site. | ||||
| 
 | ||||
| @ -161,7 +321,7 @@ export default defineConfig({ | ||||
| ``` | ||||
| 
 | ||||
| When importing using the `b64` query, the raw Base64 string will be exposed. | ||||
| `read` will process the Base64 string using the `base64` input type[^6]: | ||||
| `read` will process the Base64 string using the `base64` input type[^8]: | ||||
| 
 | ||||
| ```js title="main.js" | ||||
| import { read, utils } from "xlsx"; | ||||
| @ -187,22 +347,22 @@ document.querySelector('#app').innerHTML = `<table> | ||||
| 
 | ||||
| ## Complete Demo | ||||
| 
 | ||||
| The demo walks through the process of creating a new ViteJS website from scratch. | ||||
| A Git repository with the completed site can be cloned[^9]. | ||||
| 
 | ||||
| :::note Tested Deployments | ||||
| 
 | ||||
| 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 | | ||||
| | `5.2.12` | 2024-06-02 | | ||||
| | `4.5.3`  | 2024-06-02 | | ||||
| | `3.2.10` | 2024-06-02 | | ||||
| | `2.9.18` | 2024-06-02 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 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]. | ||||
| 
 | ||||
| ### Initial Setup | ||||
| 
 | ||||
| 1) Create a new site with the `vue-ts` template and install the SheetJS package: | ||||
| @ -275,9 +435,30 @@ npx http-server dist/ | ||||
| The terminal will display a URL, typically `http://127.0.0.1:8080` . Access | ||||
| that page with a web browser. | ||||
| 
 | ||||
| :::caution pass | ||||
| 
 | ||||
| When this demo was tested against ViteJS `2.9.18`, the build failed: | ||||
| 
 | ||||
| ``` | ||||
| src/App.vue:8:3 - error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists. | ||||
| 
 | ||||
| 8   <img alt="Vue logo" src="./assets/logo.png" /> | ||||
|     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
| ``` | ||||
| 
 | ||||
| **As it affects the project template, this is a bug in ViteJS.** | ||||
| 
 | ||||
| The simplest workaround is to force upgrade the `vue-tsc` dependency: | ||||
| 
 | ||||
| ```bash | ||||
| npm i vue-tsc@latest | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 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. | ||||
| source. The code will reference a script `/assets/index-HASH.js` where `HASH` is | ||||
| a string of characters. Open that script. | ||||
| 
 | ||||
| Searching for `Bill Clinton` reveals the following: | ||||
| 
 | ||||
| @ -291,11 +472,11 @@ included in the final site! | ||||
| :::info pass | ||||
| 
 | ||||
| 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]. | ||||
| would be added to the final page. Details are covered in the ViteJS docs[^10]. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ### Base64 Test | ||||
| ### HTML Test | ||||
| 
 | ||||
| 8) Run the dev server: | ||||
| 
 | ||||
| @ -303,10 +484,88 @@ would be added to the final page. Details are covered in the ViteJS docs[^8]. | ||||
| npm run dev | ||||
| ``` | ||||
| 
 | ||||
| Open a browser window to the displayed URL. | ||||
| Open a browser window to the displayed URL (typically `http://localhost:5173` ) | ||||
| 
 | ||||
| 9) Replace the component `src/components/HelloWorld.vue` with: | ||||
| 
 | ||||
| ```html title="src/components/HelloWorld.vue" | ||||
| <script setup lang="ts"> | ||||
| // @ts-ignore | ||||
| import html from '../../data/pres.xlsx?html'; | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div v-html="html"></div> | ||||
| </template> | ||||
| ``` | ||||
| 
 | ||||
| Save and refresh the page.  A data table should be displayed | ||||
| 
 | ||||
| 10) Stop the dev server and build the site | ||||
| 
 | ||||
| ```bash | ||||
| npm run build | ||||
| npx http-server dist/ | ||||
| ``` | ||||
| 
 | ||||
| The terminal will display a URL, typically `http://127.0.0.1:8080` . Access | ||||
| that page with a web browser. | ||||
| 
 | ||||
| :::caution pass | ||||
| 
 | ||||
| When this demo was tested against ViteJS `2.9.18`, the build failed: | ||||
| 
 | ||||
| ``` | ||||
| src/App.vue:8:3 - error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists. | ||||
| 
 | ||||
| 8   <img alt="Vue logo" src="./assets/logo.png" /> | ||||
|     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
| ``` | ||||
| 
 | ||||
| **As it affects the project template, this is a bug in ViteJS.** | ||||
| 
 | ||||
| The simplest workaround is to force upgrade the `vue-tsc` dependency: | ||||
| 
 | ||||
| ```bash | ||||
| npm i vue-tsc@latest | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 11) To confirm that only the raw HTML is present in the page, view the page | ||||
| source. The code will reference a script `/assets/index-HASH.js` where `HASH` is | ||||
| a string of characters. Open that script. | ||||
| 
 | ||||
| Searching for `Bill Clinton` reveals the following encoded HTML element: | ||||
| 
 | ||||
| ``` | ||||
| <td data-t=\\"s\\" data-v=\\"Bill Clinton\\" id=\\"sjs-A2\\">Bill Clinton</td> | ||||
| ``` | ||||
| 
 | ||||
| Searching for `BESSELJ` should reveal no results.  The SheetJS scripts are not | ||||
| included in the final site! | ||||
| 
 | ||||
| :::info pass | ||||
| 
 | ||||
| The HTML code is still stored in a script and is injected dynamically. | ||||
| 
 | ||||
| ViteJS "Server-Side Rendering" offers the option to render the site at build | ||||
| time, ensuring that the HTML table is directly added to the page. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ### Base64 Test | ||||
| 
 | ||||
| 12) Run the dev server: | ||||
| 
 | ||||
| ```bash | ||||
| npm run dev | ||||
| ``` | ||||
| 
 | ||||
| Open a browser window to the displayed URL (typically `http://localhost:5173` ) | ||||
| 
 | ||||
| 13) Replace the component `src/components/HelloWorld.vue` with: | ||||
| 
 | ||||
| ```html title="src/components/HelloWorld.vue" | ||||
| <script setup lang="ts"> | ||||
| // @ts-ignore | ||||
| @ -330,7 +589,7 @@ const data = utils.sheet_to_json<IPresident>(ws); | ||||
| </template> | ||||
| ``` | ||||
| 
 | ||||
| 10) Stop the dev server and build the site | ||||
| 14) Stop the dev server and build the site | ||||
| 
 | ||||
| ```bash | ||||
| npm run build | ||||
| @ -340,9 +599,30 @@ npx http-server dist/ | ||||
| The terminal will display a URL ( `http://127.0.0.1:8080` ).  Access that page | ||||
| with a web browser. | ||||
| 
 | ||||
| 11) To confirm that the object data is not present in the page, view the page | ||||
| source.  The code will reference some script like `/assets/index-HASH.js` with | ||||
| a different hash from the previous test. Open that script. | ||||
| :::caution pass | ||||
| 
 | ||||
| When this demo was tested against ViteJS `2.9.18`, the build failed: | ||||
| 
 | ||||
| ``` | ||||
| src/App.vue:8:3 - error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists. | ||||
| 
 | ||||
| 8   <img alt="Vue logo" src="./assets/logo.png" /> | ||||
|     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
| ``` | ||||
| 
 | ||||
| **As it affects the project template, this is a bug in ViteJS.** | ||||
| 
 | ||||
| The simplest workaround is to force upgrade the `vue-tsc` dependency: | ||||
| 
 | ||||
| ```bash | ||||
| npm i vue-tsc@latest | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 15) To confirm that the object data is not present in the page, view the page | ||||
| source. The code will reference a script `/assets/index-HASH.js` where `HASH` is | ||||
| a string of characters. Open that script. | ||||
| 
 | ||||
| Searching for `BESSELJ` should match the code: | ||||
| 
 | ||||
| @ -356,8 +636,10 @@ embedded in the final site and the data is parsed when the page is loaded. | ||||
| [^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. | ||||
| [^3]: See [`read` in "Reading Files"](/docs/api/parse-options) | ||||
| [^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output) | ||||
| [^4]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-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) | ||||
| [^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. | ||||
| [^6]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output) | ||||
| [^7]: See [`read` in "Reading Files"](/docs/api/parse-options) | ||||
| [^8]: See [the "base64" type in "Reading Files"](/docs/api/parse-options#input-type) | ||||
| [^9]: See [`examples/sheetjs-vite`](https://git.sheetjs.com/examples/sheetjs-vite/) on the SheetJS git server. | ||||
| [^10]: See ["Server-Side Rendering"](https://vitejs.dev/guide/ssr.html) in the ViteJS documentation. | ||||
| @ -159,6 +159,7 @@ This demo was tested in the following deployments: | ||||
| | Architecture | NodeJS    | Date       | | ||||
| |:-------------|:----------|:-----------| | ||||
| | `darwin-x64` | `22.2.0`  | 2024-05-28 | | ||||
| | `darwin-arm` | `22.2.0`  | 2024-05-29 | | ||||
| | `win10-x64`  | `20.12.0` | 2024-03-26 | | ||||
| | `win11-x64`  | `20.13.1` | 2024-05-22 | | ||||
| | `linux-x64`  | `20.11.1` | 2024-03-18 | | ||||
|  | ||||
| @ -80,6 +80,7 @@ This demo was last tested in the following deployments: | ||||
| | Architecture | BunJS    | Date       | | ||||
| |:-------------|:---------|:-----------| | ||||
| | `darwin-x64` | `1.1.10` | 2024-05-28 | | ||||
| | `darwin-arm` | `1.1.10` | 2024-05-29 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -14,7 +14,16 @@ export default defineConfig({ | ||||
|         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)}')`; | ||||
|         return `export default JSON.parse('${JSON.stringify(data).replace(/\\/g, "\\\\")}')`; | ||||
|       } | ||||
|     }, | ||||
|     { // this plugin handles ?html tags
 | ||||
|       name: "vite-sheet-html", | ||||
|       transform(code, id) { | ||||
|         if(!id.match(/\?html/)) return; | ||||
|         var wb = read(readFileSync(id.replace(/\?html/, ""))); | ||||
|         var html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); | ||||
|         return (`export default JSON.parse('${JSON.stringify(html).replace(/\\/g, "\\\\")}')`); | ||||
|       } | ||||
|     }, | ||||
|     { // this plugin handles ?b64 tags
 | ||||
|  | ||||
| @ -81,16 +81,16 @@ const express = require('express'); | ||||
| const app = express(); | ||||
| app.use(express.static('./')); | ||||
| app.listen(7262, async() => { | ||||
| 	await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   const browser = await puppeteer.launch(); | ||||
|   const page = await browser.newPage(); | ||||
|   page.on("console", msg => console.log("PAGE LOG:", msg.text())); | ||||
|   await page.setViewport({width: 1920, height: 1080}); | ||||
|   await page.goto('http://localhost:7262/'); | ||||
|   await page.click("#xport"); | ||||
| 	await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await browser.close(); | ||||
| 	process.exit(); | ||||
|   process.exit(); | ||||
| }); | ||||
| EOF | ||||
| 
 | ||||
|  | ||||
| @ -68,7 +68,7 @@ const express = require('express'); | ||||
| const app = express(); | ||||
| app.use(express.static('./')); | ||||
| app.listen(7262, async() => { | ||||
| 	await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   const browser = await puppeteer.launch(); | ||||
|   const page = await browser.newPage(); | ||||
|   page.on("console", msg => console.log("PAGE LOG:", msg.text())); | ||||
| @ -77,12 +77,12 @@ app.listen(7262, async() => { | ||||
| 
 | ||||
|   /* wait for requirejs to request xlsx.full.min.js */ | ||||
|   await page.waitForRequest(request => request.url().indexOf('xlsx.full.min.js') !== -1); | ||||
| 	await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
| 
 | ||||
|   await page.click("#xport"); | ||||
| 	await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await browser.close(); | ||||
| 	process.exit(); | ||||
|   process.exit(); | ||||
| }); | ||||
| EOF | ||||
| 
 | ||||
| @ -92,16 +92,16 @@ const express = require('express'); | ||||
| const app = express(); | ||||
| app.use(express.static('./')); | ||||
| app.listen(7262, async() => { | ||||
| 	await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   const browser = await puppeteer.launch(); | ||||
|   const page = await browser.newPage(); | ||||
|   page.on("console", msg => console.log("PAGE LOG:", msg.text())); | ||||
|   await page.setViewport({width: 1920, height: 1080}); | ||||
|   await page.goto('http://localhost:7262/optimized.html'); | ||||
|   await page.click("#xport"); | ||||
| 	await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   await browser.close(); | ||||
| 	process.exit(); | ||||
|   process.exit(); | ||||
| }); | ||||
| EOF | ||||
| 
 | ||||
|  | ||||
| @ -21,10 +21,10 @@ curl -LO https://sheetjs.com/pres.xlsx | ||||
| curl -LO https://docs.sheetjs.com/nashorn/SheetJSNashorn.java | ||||
| 
 | ||||
| for n in {17..22}; do | ||||
| 	export JAVA_HOME=`/usr/libexec/java_home -v $n` | ||||
| 	java -version | ||||
| 	rm -fr SheetJSNashorn.class SheetJSNashorn.jar sheethorn | ||||
| 	javac SheetJSNashorn.java | ||||
|   export JAVA_HOME=`/usr/libexec/java_home -v $n` | ||||
|   java -version | ||||
|   rm -fr SheetJSNashorn.class SheetJSNashorn.jar sheethorn | ||||
|   javac SheetJSNashorn.java | ||||
| 
 | ||||
|   java -cp ".:js-scriptengine-24.0.1.jar:js-language-24.0.1.jar:polyglot-24.0.1.jar:collections-24.0.1.jar:truffle-api-24.0.1.jar:nativeimage-24.0.1.jar:icu4j-24.0.1.jar:regex-24.0.1.jar" -Dpolyglot.js.nashorn-compat=true SheetJSNashorn pres.xlsx | ||||
| 
 | ||||
|  | ||||
| @ -19,31 +19,31 @@ curl -L -o asm-util-9.5.jar "https://search.maven.org/remotecontent?filepath=org | ||||
| 
 | ||||
| # Standalone Nashorn | ||||
| for n in {15..22}; do | ||||
| 	export JAVA_HOME=`/usr/libexec/java_home -v $n` | ||||
| 	java -version | ||||
| 	rm -fr SheetJSNashorn.class SheetJSNashorn.jar sheethorn | ||||
| 	javac SheetJSNashorn.java | ||||
| 	java -cp .:asm-9.5.jar:asm-tree-9.5.jar:asm-commons-9.5.jar:asm-analysis-9.5.jar:asm-util-9.5.jar:nashorn-core-15.4.jar SheetJSNashorn pres.xlsx | ||||
| 	jar -cf SheetJSNashorn.jar SheetJSNashorn.class xlsx.full.min.js shim.min.js | ||||
| 	mkdir -p sheethorn | ||||
| 	cp *.jar pres.xlsx sheethorn | ||||
| 	cd sheethorn | ||||
| 	java -cp .:asm-9.5.jar:asm-tree-9.5.jar:asm-commons-9.5.jar:asm-analysis-9.5.jar:asm-util-9.5.jar:nashorn-core-15.4.jar:SheetJSNashorn.jar SheetJSNashorn pres.xlsx | ||||
| 	cd - | ||||
|   export JAVA_HOME=`/usr/libexec/java_home -v $n` | ||||
|   java -version | ||||
|   rm -fr SheetJSNashorn.class SheetJSNashorn.jar sheethorn | ||||
|   javac SheetJSNashorn.java | ||||
|   java -cp .:asm-9.5.jar:asm-tree-9.5.jar:asm-commons-9.5.jar:asm-analysis-9.5.jar:asm-util-9.5.jar:nashorn-core-15.4.jar SheetJSNashorn pres.xlsx | ||||
|   jar -cf SheetJSNashorn.jar SheetJSNashorn.class xlsx.full.min.js shim.min.js | ||||
|   mkdir -p sheethorn | ||||
|   cp *.jar pres.xlsx sheethorn | ||||
|   cd sheethorn | ||||
|   java -cp .:asm-9.5.jar:asm-tree-9.5.jar:asm-commons-9.5.jar:asm-analysis-9.5.jar:asm-util-9.5.jar:nashorn-core-15.4.jar:SheetJSNashorn.jar SheetJSNashorn pres.xlsx | ||||
|   cd - | ||||
| done | ||||
| 
 | ||||
| # Built-in Nashorn | ||||
| for n in 1.8 {9..14}; do | ||||
| 	export JAVA_HOME=`/usr/libexec/java_home -v $n` | ||||
| 	java -version | ||||
| 	rm -fr SheetJSNashorn.class SheetJSNashorn.jar sheethorn | ||||
| 	javac SheetJSNashorn.java | ||||
| 	java SheetJSNashorn pres.xlsx | ||||
| 	jar -cf SheetJSNashorn.jar SheetJSNashorn.class xlsx.full.min.js shim.min.js | ||||
| 	mkdir -p sheethorn | ||||
| 	cp *.jar pres.xlsx sheethorn | ||||
| 	cd sheethorn | ||||
| 	java -cp .:SheetJSNashorn.jar SheetJSNashorn pres.xlsx | ||||
| 	cd - | ||||
|   export JAVA_HOME=`/usr/libexec/java_home -v $n` | ||||
|   java -version | ||||
|   rm -fr SheetJSNashorn.class SheetJSNashorn.jar sheethorn | ||||
|   javac SheetJSNashorn.java | ||||
|   java SheetJSNashorn pres.xlsx | ||||
|   jar -cf SheetJSNashorn.jar SheetJSNashorn.class xlsx.full.min.js shim.min.js | ||||
|   mkdir -p sheethorn | ||||
|   cp *.jar pres.xlsx sheethorn | ||||
|   cd sheethorn | ||||
|   java -cp .:SheetJSNashorn.jar SheetJSNashorn pres.xlsx | ||||
|   cd - | ||||
| done | ||||
| 
 | ||||
|  | ||||
| @ -43,8 +43,8 @@ public class SheetJSRhino { | ||||
| EOF | ||||
| 
 | ||||
| for n in 1.8 {9..22}; do | ||||
| 	export JAVA_HOME=`/usr/libexec/java_home -v $n` | ||||
| 	java -version | ||||
|   export JAVA_HOME=`/usr/libexec/java_home -v $n` | ||||
|   java -version | ||||
|   find . -name \*.class | while read x; do rm $x; done | ||||
| 
 | ||||
|   javac -cp ".:rhino.jar" SheetJSRhino.java | ||||
|  | ||||
							
								
								
									
										137
									
								
								tests/static-vite.sh
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										137
									
								
								tests/static-vite.sh
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,137 @@ | ||||
| #!/bin/bash | ||||
| # https://docs.sheetjs.com/docs/demos/static/vitejs | ||||
| # This script builds the Pure Data test and Base64 test. It does not test HMR! | ||||
| cd /tmp | ||||
| rm -rf sheetjs-vite-static | ||||
| mkdir sheetjs-vite-static | ||||
| cd sheetjs-vite-static | ||||
| 
 | ||||
| for n in {2..5}; do | ||||
| npm create -y vite@$n sheetjs-vite-$n -- --template vue-ts | ||||
| cd sheetjs-vite-$n | ||||
| npm i | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz | ||||
| npm i --save puppeteer express@4 | ||||
| if [[ "$n" == "2" ]]; then | ||||
|   # The default vitejs2 + vuejs project does not build | ||||
|   # | ||||
|   # src/App.vue:8:3 - error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists. | ||||
|   # | ||||
|   # 8   <img alt="Vue logo" src="./assets/logo.png" /> | ||||
|   #     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||
|   # | ||||
|   # Before the TS errors, there is a message: | ||||
|   # Please update to v0.35.0 or higher for TypeScript version: 4.9.5 | ||||
|   # | ||||
|   # Forcefully upgrading `vue-tsc` appears to be innocuous. | ||||
|   npm i --save vue-tsc@latest | ||||
| fi | ||||
| curl -O https://docs.sheetjs.com/vitejs/vite.config.ts | ||||
| mkdir -p data | ||||
| curl -L -o data/pres.xlsx https://docs.sheetjs.com/pres.xlsx | ||||
| 
 | ||||
| cat >test.cjs <<EOF | ||||
| const puppeteer = require('puppeteer'); | ||||
| const express = require('express'); | ||||
| const app = express(); | ||||
| app.use(express.static('./dist/')); | ||||
| app.listen(7262, async() => { | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   const browser = await puppeteer.launch(); | ||||
|   const page = await browser.newPage(); | ||||
|   page.on("console", msg => console.log("PAGE LOG:", msg.text())); | ||||
|   await page.setViewport({width: 1920, height: 1080}); | ||||
|   await page.goto('http://localhost:7262/'); | ||||
|   await page.addScriptTag({ url: 'https://cdn.sheetjs.com/xlsx-0.20.2/package/dist/xlsx.full.min.js' }); | ||||
|   await new Promise((res,rej) => setTimeout(res, 1000)); | ||||
|   const csv = await page.evaluate(() => { | ||||
|     const tbl = document.querySelector('table'); | ||||
|     const ws = XLSX.utils.table_to_sheet(tbl); | ||||
|     return XLSX.utils.sheet_to_csv(ws); | ||||
|   }); | ||||
|   console.log(csv); | ||||
|   await browser.close(); | ||||
|   process.exit(); | ||||
| }); | ||||
| EOF | ||||
| 
 | ||||
| ## Pure Data Test | ||||
| cat >src/components/HelloWorld.vue <<EOF | ||||
| <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> | ||||
| EOF | ||||
| 
 | ||||
| npm run build | ||||
| npm ls | grep "vite@" | ||||
| node test.cjs | ||||
| # Expected output: CSV contents of first sheet | ||||
| 
 | ||||
| echo "Clinton" $(grep Clinton dist/assets/*.js | wc -l) "BESSELJ" $(grep BESSELJ dist/assets/*.js | wc -l) | ||||
| # Expected output: Clinton 1 BESSELJ 0 | ||||
| 
 | ||||
| ## HTML Test | ||||
| cat >src/components/HelloWorld.vue <<EOF | ||||
| <script setup lang="ts"> | ||||
| // @ts-ignore | ||||
| import html from '../../data/pres.xlsx?html'; | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|   <div v-html="html"></div> | ||||
| </template> | ||||
| EOF | ||||
| 
 | ||||
| npm run build | ||||
| npm ls | grep "vite@" | ||||
| node test.cjs | ||||
| # Expected output: CSV contents of first sheet | ||||
| 
 | ||||
| echo "Clinton" $(grep Clinton dist/assets/*.js | wc -l) "BESSELJ" $(grep BESSELJ dist/assets/*.js | wc -l) | ||||
| # Expected output: Clinton 1 BESSELJ 0 | ||||
| 
 | ||||
| ## Base64 Test | ||||
| cat >src/components/HelloWorld.vue <<EOF | ||||
| <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> | ||||
| EOF | ||||
| 
 | ||||
| npm run build | ||||
| npm ls | grep "vite@" | ||||
| node test.cjs | ||||
| # Expected output: CSV contents of first sheet | ||||
| 
 | ||||
| echo "Clinton" $(grep Clinton dist/assets/*.js | wc -l) "BESSELJ" $(grep BESSELJ dist/assets/*.js | wc -l) | ||||
| # Expected output: Clinton 0 BESSELJ 1 | ||||
| 
 | ||||
| cd - | ||||
| done | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user