forked from sheetjs/docs.sheetjs.com
		
	NuxtJS workarounds
This commit is contained in:
		
							parent
							
								
									9af5473755
								
							
						
					
					
						commit
						d77a40c6bf
					
				| @ -118,20 +118,20 @@ importScripts("https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.mi | ||||
| 
 | ||||
| ### Type Checker | ||||
| 
 | ||||
| :::danger VSCode Telemetry and Data Exfiltration | ||||
| :::danger VS Code Telemetry and Data Exfiltration | ||||
| 
 | ||||
| The official Microsoft builds of Visual Studio Code ("VSCode") embed telemetry | ||||
| and send information to external servers. | ||||
| The official builds of Visual Studio Code ("VS Code" or "VSCode") embed | ||||
| telemetry and send information to Microsoft servers. | ||||
| 
 | ||||
| **[VSCodium](https://vscodium.com/) is a telemetry-free fork of VSCode.** | ||||
| **[VSCodium](https://vscodium.com/) is a telemetry-free fork of VS Code.** | ||||
| 
 | ||||
| When writing code that may process personally identifiable information (PII), | ||||
| the SheetJS team strongly encourages building VSCode from source or using IDEs | ||||
| the SheetJS team strongly encourages building VS Code from source or using IDEs | ||||
| that do not exfiltrate data. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| The type checker integrated in VSCodium and VSCode does not currently provide | ||||
| The type checker integrated in VSCodium and VS Code does not currently provide | ||||
| type hints when using the standalone build. Using the JSDoc `@type` directive | ||||
| coupled with type imports, VSCodium will recognize the types: | ||||
| 
 | ||||
| @ -176,7 +176,7 @@ The `.d.ts` file extension must be omitted. | ||||
| 
 | ||||
| JSDoc types using the `@import` directive are not supported in `<script>` tags. | ||||
| 
 | ||||
| **This is a known bug with VSCode!** | ||||
| **This is a known bug with VS Code!** | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -35,6 +35,7 @@ This demo was tested in the following configurations: | ||||
| 
 | ||||
| | Platform                                                          | Architecture | Date       | | ||||
| |:------------------------------------------------------------------|:-------------|:-----------| | ||||
| | NVIDIA RTX 5090 (32 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM)       | `win11-x64`  | 2025-05-17 | | ||||
| | NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM)       | `win11-x64`  | 2025-04-17 | | ||||
| | NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM)       | `linux-x64`  | 2025-01-28 | | ||||
| | AMD RX 7900 XTX (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM)       | `win11-x64`  | 2025-01-12 | | ||||
|  | ||||
| @ -49,7 +49,8 @@ This demo was tested in the following environments: | ||||
| | Nuxt Content | Nuxt       | Date       | | ||||
| |:-------------|:-----------|:-----------| | ||||
| | `1.15.1`     | `2.18.1`   | 2025-04-23 | | ||||
| | `2.13.4`     | `3.14.159` | 2024-11-14 | | ||||
| | `2.13.4`     | `3.17.2`   | 2025-05-12 | | ||||
| | `3.5.1`      | `3.17.3`   | 2025-05-18 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -525,8 +526,8 @@ script files. The module script is expected to export a module configured with | ||||
| - Add the transformer to Nuxt Content in the `content:context` hook | ||||
| 
 | ||||
| ```js title="sheetmodule.ts (Module)" | ||||
| import { resolve } from 'path' | ||||
| import { defineNuxtModule } from '@nuxt/kit' | ||||
| import { resolve } from 'path'; | ||||
| import { defineNuxtModule } from '@nuxt/kit'; | ||||
| 
 | ||||
| export default defineNuxtModule({ | ||||
|   /* module setup method */ | ||||
| @ -549,7 +550,7 @@ The module must be loaded in `nuxt.config.ts` and added to the `modules` array: | ||||
| 
 | ||||
| ```ts title="nuxt.config.ts" | ||||
| // highlight-next-line | ||||
| import SheetJSModule from './sheetmodule' | ||||
| import SheetJSModule from './sheetmodule'; | ||||
| 
 | ||||
| export default defineNuxtConfig({ | ||||
|   // @ts-ignore | ||||
| @ -606,7 +607,7 @@ from the script setup will be shaped like the return value from the transformer. | ||||
| :::caution pass | ||||
| 
 | ||||
| For some older versions, parts of the Nuxt dependency tree did not support | ||||
| NodeJS version 20. If the `yarn install` step fails with a message like | ||||
| NodeJS version 20. If the `pnpm install` step fails with a message like | ||||
| 
 | ||||
| ``` | ||||
| error @nuxt/kit@3.4.1: The engine "node" is incompatible with this module. | ||||
| @ -619,17 +620,18 @@ The recommended solution is to switch to Node 18. | ||||
| 1) Create a stock app and install dependencies: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y nuxi init -t content --packageManager yarn --no-gitInit sheetjs-nc2 | ||||
| npx -y nuxi init -t content --packageManager pnpm --no-gitInit sheetjs-nc2 -M , | ||||
| cd sheetjs-nc2 | ||||
| npx -y yarn install | ||||
| npx -y yarn add --dev @types/node | ||||
| npx -y pnpm install | ||||
| npx -y pnpm install @nuxt/content@2 --save | ||||
| npx -y pnpm install @types/node @nuxt/kit --save | ||||
| ``` | ||||
| 
 | ||||
| 2) Install the SheetJS library and start the server: | ||||
| 
 | ||||
| <CodeBlock language="bash">{`\ | ||||
| npx -y yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz | ||||
| npx -y yarn dev`} | ||||
| npx -y pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz | ||||
| npx -y pnpm dev`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 
 | ||||
| @ -639,7 +641,7 @@ When the build finishes, the terminal will display a URL like: | ||||
|   > Local:    http://localhost:3000/ | ||||
| ``` | ||||
| 
 | ||||
| The server is listening on that URL.  Open the link in a web browser. | ||||
| The server is listening on that URL. Open the link in a web browser. | ||||
| 
 | ||||
| 3) Download https://docs.sheetjs.com/pres.xlsx and move to the `content` folder. | ||||
| 
 | ||||
| @ -649,12 +651,12 @@ curl -L -o content/pres.xlsx https://docs.sheetjs.com/pres.xlsx | ||||
| 
 | ||||
| 4) Create the transformer. Two files must be saved at the root of the project: | ||||
| 
 | ||||
| - [`sheetformer.ts`](https://docs.sheetjs.com/nuxt/3/sheetformer.ts) (raw transformer module) | ||||
| - [`sheetformer.ts`](https://docs.sheetjs.com/nuxt/2/sheetformer.ts) (raw transformer module) | ||||
| - [`sheetmodule.ts`](https://docs.sheetjs.com/nuxt/3/sheetmodule.ts) (Nuxt configuration module) | ||||
| 
 | ||||
| ```bash | ||||
| curl -O https://docs.sheetjs.com/nuxt/3/sheetformer.ts | ||||
| curl -O https://docs.sheetjs.com/nuxt/3/sheetmodule.ts | ||||
| curl -O https://docs.sheetjs.com/nuxt/2/sheetformer.ts | ||||
| curl -O https://docs.sheetjs.com/nuxt/2/sheetmodule.ts | ||||
| ``` | ||||
| 
 | ||||
| After creating the source files, the module must be added to `nuxt.config.ts`: | ||||
| @ -668,14 +670,13 @@ export default defineNuxtConfig({ | ||||
|   // @ts-ignore | ||||
|   telemetry: false, | ||||
|   // highlight-end | ||||
|   devtools: { enabled: true }, | ||||
|   // highlight-start | ||||
|   modules: [ | ||||
|     // highlight-next-line | ||||
|     SheetJSModule, | ||||
|     '@nuxt/content' | ||||
|   ], | ||||
|   content: {} | ||||
|   // highlight-end | ||||
|   devtools: { enabled: true }, | ||||
|   // ... | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| @ -684,33 +685,13 @@ Stop the dev server (<kbd>CTRL</kbd>+<kbd>C</kbd>) and run the following: | ||||
| ```bash | ||||
| npx -y nuxi clean | ||||
| npx -y nuxi cleanup | ||||
| npx -y nuxi typecheck | ||||
| npx -y yarn run dev | ||||
| npx -y pnpm run dev | ||||
| ``` | ||||
| 
 | ||||
| Loading `http://localhost:3000/pres` should show some JSON data: | ||||
| 
 | ||||
| ```json | ||||
| { | ||||
|   // ... | ||||
|   "data": { | ||||
|     "_path": "/pres", | ||||
|     // ... | ||||
|     "_id": "content:pres.xlsx", | ||||
|     "body": [ | ||||
|       { | ||||
|         "name": "Sheet1", // <-- sheet name | ||||
|         "data": [ // <-- array of data objects | ||||
|           { | ||||
|             "Name": "Bill Clinton", | ||||
|             "Index": 42 | ||||
|           }, | ||||
| ``` | ||||
| 
 | ||||
| 5) Download [`pres.vue`](pathname:///nuxt/3/pres.vue) and save to `pages`: | ||||
| 5) Download [`pres.vue`](pathname:///nuxt/2/pres.vue) and save to `app/pages`: | ||||
| 
 | ||||
| ```bash | ||||
| curl -o pages/pres.vue https://docs.sheetjs.com/nuxt/3/pres.vue | ||||
| curl -o app/pages/pres.vue https://docs.sheetjs.com/nuxt/2/pres.vue | ||||
| ``` | ||||
| 
 | ||||
| Stop the dev server (<kbd>CTRL</kbd>+<kbd>C</kbd>) and run the following: | ||||
| @ -718,24 +699,247 @@ Stop the dev server (<kbd>CTRL</kbd>+<kbd>C</kbd>) and run the following: | ||||
| ```bash | ||||
| npx -y nuxi clean | ||||
| npx -y nuxi cleanup | ||||
| npx -y yarn run dev | ||||
| npx -y pnpm run dev | ||||
| ``` | ||||
| 
 | ||||
| The browser should now display an HTML table. | ||||
| 6) From the browser window in step 2, access `/pres` from the site. For example, | ||||
| if the URL in step 2 was `http://localhost:3000/`, the new page should be | ||||
| `http://localhost:3000/pres`. | ||||
| 
 | ||||
| 6) To verify that hot loading works, open `pres.xlsx` from the `content` folder | ||||
| This page should now display an HTML table. | ||||
| 
 | ||||
| 7) To verify that hot loading works, open `pres.xlsx` from the `content` folder | ||||
| with a spreadsheet editor. | ||||
| 
 | ||||
| Set cell `A7` to "SheetJS Dev" and set `B7` to `47`. Save the spreadsheet. | ||||
| 
 | ||||
| The page should automatically refresh with the new content. | ||||
| 
 | ||||
| 8) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window). | ||||
| 
 | ||||
| 9) Copy `app/pages/pres.vue` to `app/pages/index.vue`: | ||||
| 
 | ||||
| ```bash | ||||
| cp app/pages/pres.vue app/pages/index.vue | ||||
| ``` | ||||
| 
 | ||||
| :::info pass | ||||
| 
 | ||||
| In older test runs, the Nuxt starter created a default `/` page. The most recent | ||||
| test did not create the index page, resulting in build errors. This step ensures | ||||
| some sort of index page exists. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 10) Build the static site: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y pnpm run generate | ||||
| ``` | ||||
| 
 | ||||
| This will create a static site in `.output/public`, which can be served with: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y http-server .output/public | ||||
| ``` | ||||
| 
 | ||||
| Access the displayed URL (typically `http://localhost:8080`) in a web browser. | ||||
| 
 | ||||
| To confirm that the spreadsheet data is added to the site, view the page source. | ||||
| 
 | ||||
| Searching for `Bill Clinton` reveals the following encoded HTML row: | ||||
| 
 | ||||
| ```html | ||||
| <tr><td>Bill Clinton</td><td>42</td></tr> | ||||
| ``` | ||||
| 
 | ||||
| ## Nuxt Content v3 | ||||
| 
 | ||||
| :::danger pass | ||||
| 
 | ||||
| When this demo was last tested, the official Nuxt Content v3 custom transformers | ||||
| and custom collections examples did not work. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| [ViteJS modules](/docs/demos/static/vitejs) can be used in Nuxt v3. | ||||
| 
 | ||||
| ### Installation | ||||
| 
 | ||||
| The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be | ||||
| safely imported from `nuxt.config.ts` or transformer or module scripts. As long | ||||
| as the SheetJS modules are not imported in the various `.vue` pages, the library | ||||
| will not be added to the final page bundle! | ||||
| 
 | ||||
| ### Configuration | ||||
| 
 | ||||
| The `vite` property in the NuxtJS config is passed to ViteJS. Plugins and other | ||||
| configuration options can be copied to the object. `vite.config.js` for the | ||||
| [Pure Data Plugin](/docs/demos/static/vitejs#pure-data-plugin) is shown below: | ||||
| 
 | ||||
| ```js title="vite.config.js (raw ViteJS)" | ||||
| 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).replace(/\\/g, "\\\\")}')`; | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| The `assetsInclude` and `plugins` properties should be added within the `vite` | ||||
| property in the object passed to `defineNuxtConfig`. | ||||
| 
 | ||||
| :::danger pass | ||||
| 
 | ||||
| NuxtJS does not properly honor the `?sheetjs` tag! As a result, the transform | ||||
| explicitly tests for the `.xlsx` extension. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ```ts title="nuxt.config.ts" | ||||
| import { readFileSync } from 'fs'; | ||||
| import { read, utils } from 'xlsx'; | ||||
| 
 | ||||
| export default defineNuxtConfig({ | ||||
|   // highlight-next-line | ||||
|   vite: { // these options are passed to ViteJS | ||||
|     assetsInclude: ['**/*.xlsx'], // xlsx file should be treated as assets | ||||
| 
 | ||||
|     plugins: [ | ||||
|       { // this plugin handles .xlsx | ||||
|         name: "vite-sheet", | ||||
|         transform(_code, id) { | ||||
|           if(!id.match(/\.xlsx$/)) 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).replace(/\\/g, "\\\\")}')`; | ||||
|         } | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   // ... | ||||
| ``` | ||||
| 
 | ||||
| ### Template Use | ||||
| 
 | ||||
| Pages can reference spreadsheets using a relative file reference. The ViteJS | ||||
| plugin will transform files with the `.xlsx` extension. | ||||
| 
 | ||||
| ```js title="Script section of .vue VueJS page" | ||||
| import data from '../../pres.xlsx'; // data is an array of objects | ||||
| ``` | ||||
| 
 | ||||
| In the template, `data` is an array of objects that works with `v-for`[^4]: | ||||
| 
 | ||||
| ```xml title="Template section of .vue VueJS page" | ||||
| <table> | ||||
|   <thead><tr><th>Name</th><th>Index</th></tr></thead><tbody> | ||||
|   <!-- loop over the rows of each worksheet --> | ||||
|   <tr v-for="row in data" v-bind:key="row.Index"> | ||||
|     <!-- here `row` is a row object generated from sheet_to_json --> | ||||
|     <td>{{ row.Name }}</td> | ||||
|     <td>{{ row.Index }}</td> | ||||
|   </tr> | ||||
| </table> | ||||
| ``` | ||||
| 
 | ||||
| ### Nuxt Content 3 Demo | ||||
| 
 | ||||
| 1) Create a stock app and install dependencies: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y nuxi init -t content --packageManager pnpm --no-gitInit sheetjs-nc3 -M , | ||||
| cd sheetjs-nc3 | ||||
| npx -y pnpm install | ||||
| ``` | ||||
| 
 | ||||
| 2) Install the SheetJS library and start the server: | ||||
| 
 | ||||
| <CodeBlock language="bash">{`\ | ||||
| npx -y pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz | ||||
| npx -y pnpm dev`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| When the build finishes, the terminal will display a URL like: | ||||
| 
 | ||||
| ``` | ||||
|   > Local:    http://localhost:3000/ | ||||
| ``` | ||||
| 
 | ||||
| The server is listening on that URL. Open the link in a web browser. | ||||
| 
 | ||||
| 3) Download https://docs.sheetjs.com/pres.xlsx and move to the root folder: | ||||
| 
 | ||||
| ```bash | ||||
| curl -o pres.xlsx https://docs.sheetjs.com/pres.xlsx | ||||
| ``` | ||||
| 
 | ||||
| 4) Replace `nuxt.config.ts` with the following codeblock: | ||||
| 
 | ||||
| ```ts title="nuxt.config.ts" | ||||
| import { readFileSync } from 'fs'; | ||||
| import { read, utils } from 'xlsx'; | ||||
| 
 | ||||
| export default defineNuxtConfig({ | ||||
|   vite: { // these options are passed to ViteJS | ||||
|     assetsInclude: ['**/*.xlsx'], // xlsx file should be treated as assets | ||||
| 
 | ||||
|     plugins: [ | ||||
|       { // this plugin handles .xlsx | ||||
|         name: "vite-sheet", | ||||
|         transform(_code, id) { | ||||
|           if(!id.match(/\.xlsx$/)) 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).replace(/\\/g, "\\\\")}')`; | ||||
|         } | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|   modules: [ | ||||
|     '@nuxt/content', | ||||
|   ], | ||||
|   devtools: { enabled: true }, | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| 5) Create a new file `app.vue` with the following contents: | ||||
| 
 | ||||
| ```jsx title="app.vue (create new file)" | ||||
| <script setup> | ||||
| import data from '../../pres.xlsx' | ||||
| </script> | ||||
| <template> | ||||
|     <table><thead><tr><th>Name</th><th>Index</th></tr></thead><tbody> | ||||
|       <tr v-for="row in data" v-bind:key="row.Index"> | ||||
|         <td>{{ row.Name }}</td> | ||||
|         <td>{{ row.Index }}</td> | ||||
|       </tr> | ||||
|     </tbody></table> | ||||
| </template> | ||||
| ``` | ||||
| 
 | ||||
| 6) Refresh the browser window. This page should now display an HTML table. | ||||
| 
 | ||||
| 7) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window). | ||||
| 
 | ||||
| 8) Build the static site: | ||||
| 
 | ||||
| ```bash | ||||
| npx -y yarn run generate | ||||
| npx -y pnpm run generate | ||||
| ``` | ||||
| 
 | ||||
| This will create a static site in `.output/public`, which can be served with: | ||||
|  | ||||
| @ -111,6 +111,7 @@ const jwt = new google.auth.JWT({ | ||||
|   key: creds.private_key, | ||||
|   scopes: [ | ||||
|     'https://www.googleapis.com/auth/spreadsheets', // Google Sheets | ||||
|     'https://www.googleapis.com/auth/drive', // Google Drive | ||||
|     'https://www.googleapis.com/auth/drive.file', // Google Drive | ||||
|   ] | ||||
| }); | ||||
| @ -495,7 +496,7 @@ At this point `wb` is a SheetJS workbook object[^10]. | ||||
| 
 | ||||
| :::note Tested Deployments | ||||
| 
 | ||||
| This demo was last tested on 2024-06-08 using `googleapis` version `140.0.0`. | ||||
| This demo was last tested on 2025-05-14 using `googleapis` version `148.0.0`. | ||||
| The demo uses Sheets v4 and Drive v3 APIs. | ||||
| 
 | ||||
| ::: | ||||
| @ -551,10 +552,10 @@ be a selection box. Click the `▼` icon to show the modal. | ||||
| 
 | ||||
| If the selection box is missing, expand the browser window. | ||||
| 
 | ||||
| 3) Click "NEW PROJECT" in the top right corner of the modal. | ||||
| 3) Click "New project" in the top right corner of the modal. | ||||
| 
 | ||||
| 4) In the New Project screen, enter "SheetJS Test" in the Project name textbox | ||||
| and select "No organization" in the Location box. Click "CREATE". | ||||
| and select "No organization" in the Location box. Click "Create". | ||||
| 
 | ||||
| A notification will confirm that the project was created: | ||||
| 
 | ||||
| @ -569,14 +570,13 @@ The goal of this section is to enable Google Sheets API and Google Drive API. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 5) Open the Project Selector (`▼` icon) and select "SheetJS Test" | ||||
| 5) Click "Select a project" and select "SheetJS Test" from the Recent tab. | ||||
| 
 | ||||
| 6) In the search bar, type "Enabled" and select "Enabled APIs & services". This | ||||
| item will be in the "PRODUCTS & PAGES" part of the search results. | ||||
| 6) In the search bar, type "Enabled" and select "Enabled APIs & services". | ||||
| 
 | ||||
| #### Enable Google Sheets API | ||||
| 
 | ||||
| 7) Near the top of the page, click "+ ENABLE APIS AND SERVICES". | ||||
| 7) Near the top of the page, click "+ Enable APIs and services". | ||||
| 
 | ||||
| 8) In the search bar near the middle of the page (not the search bar at the top), | ||||
| type "Sheets" and press <kbd>Enter</kbd>. | ||||
| @ -585,11 +585,11 @@ In the results page, look for "Google Sheets API". Click the card | ||||
| 
 | ||||
| 9) In the Product Details screen, click the blue "ENABLE" button. | ||||
| 
 | ||||
| 10) Click the left arrow (`<-`) next to "API/Service details". | ||||
| 10) Click the left arrow (`<-`) next to "API/Service Details". | ||||
| 
 | ||||
| #### Enable Google Drive API | ||||
| 
 | ||||
| 11) Near the top of the page, click "+ ENABLE APIS AND SERVICES". | ||||
| 11) Near the top of the page, click "+ Enable APIs and services". | ||||
| 
 | ||||
| 12) In the search bar near the middle of the page (not the search bar at the top), | ||||
| type "Drive" and press <kbd>Enter</kbd>. | ||||
| @ -614,13 +614,13 @@ the top bar. | ||||
| 15) Click the Project Selector (`:·` icon) and select "SheetJS Test". | ||||
| 
 | ||||
| 16) In the search bar, type "Credentials" and select the "Credentials" item with | ||||
| subtitle "APIs & Services". This item will be in the "PRODUCTS & PAGES" group: | ||||
| subtitle "APIs & Services": | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 17) Click "+ CREATE CREDENTIALS". In the dropdown, select "Service Account" | ||||
| 17) Click "+ Create credentials". In the dropdown, select "Service account" | ||||
| 
 | ||||
| 18) Enter "SheetJService" for Service account name. Click "CREATE AND CONTINUE" | ||||
| 18) Enter "SheetJService" for Service account name. Click "Create and continue". | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| @ -628,24 +628,24 @@ The Service account ID is generated automatically. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 19) In Step 2 "Grant this service account access to project", click CONTINUE | ||||
| 19) In Step 2 "Grant this service account access to project", click Continue. | ||||
| 
 | ||||
| 20) In Step 3 click "DONE". You will be taken back to the credentials screen | ||||
| 20) In Step 3 click "Done". You will be taken back to the credentials screen | ||||
| 
 | ||||
| #### Create JSON Key | ||||
| 
 | ||||
| 21) Look for "SheetJService" in the "Service Accounts" table and click the email | ||||
| address in the row. | ||||
| 
 | ||||
| 22) Click "KEYS" in the horizontal bar near the top of the page. | ||||
| 22) Click "Keys" in the horizontal bar near the top of the page. | ||||
| 
 | ||||
| 23) Click "ADD KEY" and select "Create new key" in the dropdown. | ||||
| 23) Click "Add key" and select "Create new key" in the dropdown. | ||||
| 
 | ||||
| 24) In the popup, select the "JSON" radio button and click "CREATE". | ||||
| 24) In the popup, select the "JSON" radio button and click "Create". | ||||
| 
 | ||||
| The page will download a JSON file. If prompted, allow the download. | ||||
| 
 | ||||
| 25) Click "CLOSE" | ||||
| 25) Click "Close" | ||||
| 
 | ||||
| ### Create Document | ||||
| 
 | ||||
| @ -675,7 +675,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz googlea | ||||
| 29) Download [`init.mjs`](pathname:///gsheet/init.mjs): | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://docs.sheetjs.com/gsheet/init.mjs | ||||
| curl -o init.mjs https://docs.sheetjs.com/gsheet/init.mjs | ||||
| ``` | ||||
| 
 | ||||
| Edit the marked lines near the top of the file: | ||||
| @ -713,11 +713,12 @@ Shared a-long-string-of-characters with YOUR_ACCOUNT@gmail.com | ||||
| The long string of characters after "Created Google Workbook" is the ID. Take | ||||
| note of this ID. | ||||
| 
 | ||||
| 31) Sign into Google Sheets. A shared document "SheetJS Test" should be | ||||
| displayed in the table. It will be owned by the service account. | ||||
| 31) Sign into Google Drive and select "Shared with me" from the left sidebar. A | ||||
| shared document "SheetJS Test" should be displayed in the table. It will be | ||||
| owned by the service account. | ||||
| 
 | ||||
| 32) Open the shared document from step 31 and confirm that the document has two | ||||
| worksheets named "SheetJS1" and "SheetJS2". | ||||
| 32) Click `⋮` next to "SheetJS Test" and select "Open with" > "Google Sheets". | ||||
| Confirm that the document has two worksheets named "SheetJS1" and "SheetJS2". | ||||
| 
 | ||||
| Confirm the worksheet data matches the following screenshots: | ||||
| 
 | ||||
| @ -786,13 +787,13 @@ NUMBERS file. | ||||
| 34) Download the [test file `pres.numbers`](https://docs.sheetjs.com/pres.numbers): | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://docs.sheetjs.com/pres.numbers | ||||
| curl -o pres.numbers https://docs.sheetjs.com/pres.numbers | ||||
| ``` | ||||
| 
 | ||||
| 35) Download [`load.mjs`](pathname:///gsheet/load.mjs): | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://docs.sheetjs.com/gsheet/load.mjs | ||||
| curl -o load.mjs https://docs.sheetjs.com/gsheet/load.mjs | ||||
| ``` | ||||
| 
 | ||||
| Edit the marked lines near the top of the file: | ||||
| @ -830,7 +831,7 @@ The goal of this section is to export the raw data from Google Sheets to XLSB. | ||||
| 38) Download [`dump.mjs`](pathname:///gsheet/dump.mjs): | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://docs.sheetjs.com/gsheet/dump.mjs | ||||
| curl -o dump.mjs https://docs.sheetjs.com/gsheet/dump.mjs | ||||
| ``` | ||||
| 
 | ||||
| Edit the marked lines near the top of the file: | ||||
| @ -876,7 +877,7 @@ assign a grid of values | ||||
| 43) Download [`raw.mjs`](pathname:///gsheet/raw.mjs): | ||||
| 
 | ||||
| ```bash | ||||
| curl -LO https://docs.sheetjs.com/gsheet/raw.mjs | ||||
| curl -o raw.mjs https://docs.sheetjs.com/gsheet/raw.mjs | ||||
| ``` | ||||
| 
 | ||||
| Edit the marked lines near the top of the file: | ||||
|  | ||||
| @ -266,7 +266,7 @@ function SheetJSEnregistrez() { | ||||
| 
 | ||||
| :::note Tested Deployments | ||||
| 
 | ||||
| This demo was last tested on 2024-05-27. | ||||
| This demo was last tested on 2025-05-14. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| --- | ||||
| title: Excel Viewer in Visual Studio Code | ||||
| title: Visualizing Data in VS Code | ||||
| sidebar_label: Visual Studio Code | ||||
| description: View Excel files directly in VS Code. Seamlessly browse spreadsheet data without leaving your editor using SheetJS. Navigate between worksheets and pages of data with a responsive | ||||
| pagination_prev: demos/cloud/index | ||||
| @ -16,50 +16,68 @@ import CodeBlock from '@theme/CodeBlock'; | ||||
| [SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing | ||||
| data from spreadsheets. | ||||
| 
 | ||||
| [Visual Studio Code](https://code.visualstudio.com) is a popular code editor that supports extensions for customizing | ||||
| and enhancing functionality. | ||||
| [Visual Studio Code](https://code.visualstudio.com) is a popular code editor | ||||
| that supports JavaScript extensions for customizing and enhancing functionality. | ||||
| 
 | ||||
| This demo uses SheetJS in a VS Code extension to view Excel files directly within the editor. The extension leverages | ||||
| VS Code's `Custom Editor API`[^2] and `WebView API`[^1] to display XLSX data as HTML tables. | ||||
| The ["Complete Example"](#complete-example) uses SheetJS in a VS Code extension | ||||
| to view Excel files directly within the editor. The extension leverages the VS | ||||
| Code "Custom Editor API"[^2] and "WebView API"[^1] to display spreadsheet data | ||||
| as HTML tables. | ||||
| 
 | ||||
| The demo includes the full source code for the extension and installation instructions. | ||||
| :::tip pass | ||||
| 
 | ||||
| ["SheetJS Spreadsheet Viewer"](https://marketplace.visualstudio.com/items?itemName=asadbek.sheetjs-demo) | ||||
| is a sample extension based on this demo. | ||||
| 
 | ||||
| [The source code](https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension) | ||||
| is available on the SheetJS Git server. Feedback and contributions are welcome! | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| :::note Tested Deployments | ||||
| 
 | ||||
| This demo was verified in the following deployments: | ||||
| 
 | ||||
| | Platform        | OS Version              | Architecture     | Date       | | ||||
| |:----------------|:------------------------|:------------------|:-----------| | ||||
| | VS Code 1.100.0 | macOS 15.3.1    | Darwin (arm64) | 2025-05-15 | | ||||
| | Platform         | Architecture | Date       | | ||||
| |:-----------------|:-------------|:-----------| | ||||
| | VS Code 1.100.0  | `darwin-arm` | 2025-05-15 | TODO | ||||
| | VSCodium 1.100.0 | `darwin-arm` | 2025-05-15 | TODO | ||||
| | Cursor           | `win11-arm`  | 2025-05-15 | TODO | ||||
| | Windsurf         | `win11-arm`  | 2025-05-15 | TODO | ||||
| | Void             | `win11-arm`  | 2025-05-15 | TODO | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## Integration Details | ||||
| The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be imported from any component or script in the extension. | ||||
| 
 | ||||
| :::note | ||||
| The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be | ||||
| imported from any component or script in the extension. | ||||
| 
 | ||||
| > Install the package as a developer dependency. | ||||
| > Otherwise, `vsce`[^5] (Visual Studio Code Extension Manager) will **fail to package or publish** your extension correctly. | ||||
| :::caution pass | ||||
| 
 | ||||
| The module must be installed as a development dependency. If the module is | ||||
| installed as a normal dependency, `vsce`[^5] (Visual Studio Code Extension | ||||
| Manager) will fail to package or publish your extension correctly. | ||||
| 
 | ||||
|   <Tabs groupId="pm"> | ||||
|     <TabItem value="npm" label="npm"> | ||||
|   <CodeBlock language="bash">{`\ | ||||
|   npm rm --save xlsx | ||||
|   npm i --save-dev https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} | ||||
| npm rm --save xlsx | ||||
| npm i --save-dev https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} | ||||
|   </CodeBlock> | ||||
|     </TabItem> | ||||
|     <TabItem value="pnpm" label="pnpm"> | ||||
|   <CodeBlock language="bash">{`\ | ||||
|   pnpm rm xlsx | ||||
|   pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} | ||||
| pnpm rm xlsx | ||||
| pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} | ||||
|   </CodeBlock> | ||||
|     </TabItem> | ||||
|     <TabItem value="yarn" label="Yarn" default> | ||||
|   <CodeBlock language="bash">{`\ | ||||
|   yarn remove xlsx | ||||
|   yarn add -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} | ||||
| yarn remove xlsx | ||||
| yarn add -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} | ||||
|   </CodeBlock> | ||||
|   </TabItem> | ||||
|   </Tabs> | ||||
| @ -77,28 +95,25 @@ The VS Code Spreadsheet viewer extension has three main components: | ||||
| The extension uses VS Code's `Custom Editor API`[^2]  to register as a handler for Excel files. When a file is opened, | ||||
| SheetJS parses it and displays the data in a WebView component. | ||||
| 
 | ||||
| ## Building the Extension | ||||
| 
 | ||||
| 
 | ||||
| ### Extension Entry Point | ||||
| 
 | ||||
| The main entry point registers the custom editor provider: | ||||
| 
 | ||||
| <CodeBlock language="typescript" value="typescript" title="src/extension.ts"> | ||||
| {`import * as vscode from 'vscode'; | ||||
|   // highlight-start | ||||
|   import { ExcelEditorProvider } from './excelEditorProvider'; | ||||
|   // highlight-end | ||||
| ```ts title="src/extension.ts" | ||||
| import * as vscode from 'vscode'; | ||||
| // highlight-start | ||||
| import { ExcelEditorProvider } from './excelEditorProvider'; | ||||
| // highlight-end | ||||
| 
 | ||||
|   export function activate(context: vscode.ExtensionContext) { | ||||
|     // SheetJS Spreadsheet Viewer extension activating... | ||||
|     // highlight-start | ||||
|     const provider = ExcelEditorProvider.register(context); | ||||
|     context.subscriptions.push(provider); | ||||
|     // highlight-end | ||||
|   } | ||||
|   export function deactivate() {}`} | ||||
| </CodeBlock> | ||||
| export function activate(context: vscode.ExtensionContext) { | ||||
|   // SheetJS Spreadsheet Viewer extension activating... | ||||
|   // highlight-start | ||||
|   const provider = ExcelEditorProvider.register(context); | ||||
|   context.subscriptions.push(provider); | ||||
|   // highlight-end | ||||
| } | ||||
| export function deactivate() {}`} | ||||
| ``` | ||||
| 
 | ||||
| The `custom editor`[^3] is configured to support specific file types, giving us complete control over how each file is | ||||
| presented to the user. Additionally, `custom document`[^4] enables us to maintain and persist the state of each individual | ||||
| @ -122,7 +137,7 @@ file that's opened. | ||||
|     public static register(context: vscode.ExtensionContext): vscode.Disposable { | ||||
|     return vscode.window.registerCustomEditorProvider( | ||||
|         'excelViewer.spreadsheet', | ||||
|         new ExcelEditorProvider(context), | ||||
|         new ExcelEditorProvider(), | ||||
|         { webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden | ||||
|       ); | ||||
|     } | ||||
| @ -131,6 +146,7 @@ file that's opened. | ||||
| </CodeBlock> | ||||
| 
 | ||||
| ### Reading Files | ||||
| 
 | ||||
| The extension reads Excel files using the VS Code filesystem API and passes | ||||
| the data to SheetJS for parsing: | ||||
| 
 | ||||
| @ -189,7 +205,7 @@ sequenceDiagram | ||||
| 
 | ||||
| ## Complete Example | ||||
| 
 | ||||
| 1. Create a new VS Code extension | ||||
| 1) Create a new VS Code extension | ||||
| 
 | ||||
| ```bash | ||||
| npx --package yo --package generator-code -- yo code | ||||
| @ -209,78 +225,78 @@ When prompted, enter the following options: | ||||
| 
 | ||||
| - `Do you want to open the new folder with Visual Studio Code?`: Press <kbd>Enter</kbd> | ||||
| 
 | ||||
| 2. [Install the dependencies](#integration-details) and start: | ||||
| 2) [Install the dependencies](#integration-details) and start the dev server: | ||||
| 
 | ||||
| <CodeBlock language="bash">{`\ | ||||
| cd sheetjs-demo | ||||
| pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz | ||||
| pnpm run watch | ||||
| `} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 3. Create a new provider `excelEditorProivder.ts` and paste the following: | ||||
| 3) Save the following code snippet to `src/excelEditorProvider.ts`: | ||||
| 
 | ||||
| <CodeBlock language="typescript" value="typescript" title="src/excelEditorProvider.ts"> | ||||
| {`import * as vscode from 'vscode'; | ||||
|   import * as XLSX from 'xlsx'; | ||||
| <CodeBlock language="typescript" value="typescript" title="src/excelEditorProvider.ts">{`\ | ||||
| import * as vscode from 'vscode'; | ||||
| import * as XLSX from 'xlsx'; | ||||
| 
 | ||||
|   class ExcelDocument implements vscode.CustomDocument { | ||||
|     constructor(public readonly uri: vscode.Uri) { } | ||||
|     dispose() { } | ||||
|   } | ||||
| class ExcelDocument implements vscode.CustomDocument { | ||||
|   constructor(public readonly uri: vscode.Uri) { } | ||||
|   dispose() { } | ||||
| } | ||||
| 
 | ||||
| export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<ExcelDocument> { | ||||
|     public static register(context: vscode.ExtensionContext): vscode.Disposable { | ||||
|       return vscode.window.registerCustomEditorProvider( | ||||
|         'excelViewer.spreadsheet', | ||||
|         new ExcelEditorProvider(context), | ||||
|         { webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden | ||||
|       ); | ||||
|     } | ||||
| 
 | ||||
|     private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<XLSX.WorkBook> { | ||||
|       const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri); | ||||
| 
 | ||||
|       const options: XLSX.ParsingOptions = { | ||||
|         type: 'array', | ||||
|         cellStyles: true, | ||||
|         cellDates: true, | ||||
|       }; | ||||
| 
 | ||||
|       return XLSX.read(new Uint8Array(data), options); // returns a XLSX.WorkBook | ||||
|     } | ||||
| 
 | ||||
|     // This is called when the first time an editor for a given resource is opened | ||||
|     async openCustomDocument(uri: vscode.Uri): Promise<ExcelDocument> { | ||||
|       return new ExcelDocument(uri); | ||||
|     } | ||||
| 
 | ||||
|     // This is called whenever the user opens a new editor | ||||
|     async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<void> { | ||||
|       const wb: XLSX.WorkBook = await this.loadWorkbook(document, webviewPanel); | ||||
|       const htmlTable = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); | ||||
|       webviewPanel.webview.html = \`<!DOCTYPE html><html><body>\${htmlTable}</body></html>\`; | ||||
|     } | ||||
|   }`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 4. Register the custom editor provider with the main entry point `extension.ts` | ||||
| 
 | ||||
| <CodeBlock language="typescript" value="typescript" title="src/extension.ts"> | ||||
| {`import * as vscode from 'vscode'; | ||||
|   import { ExcelEditorProvider } from './excelEditorProvider'; | ||||
| 
 | ||||
|   export function activate(context: vscode.ExtensionContext) { | ||||
|     // SheetJS Spreadsheet Viewer extension activating... | ||||
|     const provider = ExcelEditorProvider.register(context); | ||||
|     context.subscriptions.push(provider); | ||||
|   public static register(context: vscode.ExtensionContext): vscode.Disposable { | ||||
|     return vscode.window.registerCustomEditorProvider( | ||||
|       'excelViewer.spreadsheet', | ||||
|       new ExcelEditorProvider(), | ||||
|       { webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden | ||||
|     ); | ||||
|   } | ||||
|   export function deactivate() {}`} | ||||
| 
 | ||||
|   private async loadWorkbook(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<XLSX.WorkBook> { | ||||
|     const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri); | ||||
| 
 | ||||
|     const options: XLSX.ParsingOptions = { | ||||
|       type: 'array', | ||||
|       cellStyles: true, | ||||
|       cellDates: true, | ||||
|     }; | ||||
| 
 | ||||
|     return XLSX.read(new Uint8Array(data), options); // returns a XLSX.WorkBook | ||||
|   } | ||||
| 
 | ||||
|   // This is called when the first time an editor for a given resource is opened | ||||
|   async openCustomDocument(uri: vscode.Uri): Promise<ExcelDocument> { | ||||
|     return new ExcelDocument(uri); | ||||
|   } | ||||
| 
 | ||||
|   // This is called whenever the user opens a new editor | ||||
|   async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<void> { | ||||
|     const wb: XLSX.WorkBook = await this.loadWorkbook(document, webviewPanel); | ||||
|     const htmlTable = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); | ||||
|     webviewPanel.webview.html = \`<!DOCTYPE html><html><body>\${htmlTable}</body></html>\`; | ||||
|   } | ||||
| }`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 4) Register the custom editor provider in `src/extension.ts`: | ||||
| 
 | ||||
| 5. Registering the custom editor in your `package.json` file. | ||||
| <CodeBlock language="typescript" value="typescript" title="src/extension.ts (replace contents)">{`\ | ||||
| import * as vscode from 'vscode'; | ||||
| import { ExcelEditorProvider } from './excelEditorProvider'; | ||||
| 
 | ||||
| <CodeBlock language="json" value="json" title="./package.json">{`\ | ||||
| export function activate(context: vscode.ExtensionContext) { | ||||
|   // SheetJS Spreadsheet Viewer extension activating... | ||||
|   const provider = ExcelEditorProvider.register(context); | ||||
|   context.subscriptions.push(provider); | ||||
| } | ||||
| export function deactivate() {}`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 5) Register the custom editor in the `contributes` section of `package.json`: | ||||
| 
 | ||||
| <CodeBlock language="json" value="json" title="package.json (add highlighted lines)">{`\ | ||||
|   "main": "./dist/extension.js", | ||||
|   "contributes": { | ||||
|     // highlight-start | ||||
| @ -306,18 +322,13 @@ export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider< | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 6. Inside the editor, open `src/extension.ts` and press <kbd>F5</kbd> or run the command **Debug: Start Debugging** | ||||
| from the Command Pallet (<kbd>⇧⌘P</kbd>). This will compile and run the extension in a new Extension Development Host window. | ||||
| from the Command Palette (<kbd>⇧⌘P</kbd>). This will compile and run the extension in a new Extension Development Host window. | ||||
| 
 | ||||
| 7. Select the new VSCode Window and open a `.xlsx` or `.xls` file. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| ### Learn More | ||||
| 
 | ||||
| You can check out [the complete SheetJS VS Code extension demo repository](https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension) - your feedback and contributions are welcome! | ||||
| 
 | ||||
| [^1]: See [`Webview API`](https://code.visualstudio.com/api/extension-guides/webview) for more details. | ||||
| [^2]: See [`Custom Editor API`](https://code.visualstudio.com/api/extension-guides/custom-editors) documentation for more details. | ||||
| [^3]: See [`Custom Editor`](https://code.visualstudio.com/api/extension-guides/custom-editors#custom-editor) for more details. | ||||
| @ -367,7 +367,7 @@ This,is,a,Test | ||||
| The test suite is regularly run against a number of modern and legacy browsers | ||||
| using [Sauce Labs](https://saucelabs.com/). | ||||
| 
 | ||||
| The following chart shows test results on 2024-10-20 for version `0.20.3`: | ||||
| The following chart shows test results on 2025-05-15 for version `0.20.3`: | ||||
| 
 | ||||
| [](https://saucelabs.com/u/sheetjs) | ||||
| 
 | ||||
|  | ||||
| @ -15,6 +15,10 @@ | ||||
|   }, | ||||
|   "overrides": { | ||||
|     "@cmfcmf/docusaurus-search-local": { | ||||
|       "@algolia/autocomplete-theme-classic": "1.19.1", | ||||
|       "@algolia/autocomplete-js": "1.19.1", | ||||
|       "@algolia/client-search": "5.25.0", | ||||
|       "algoliasearch": "5.25.0", | ||||
|       "@docusaurus/core": "3.7.0" | ||||
|     } | ||||
|   }, | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| import SheetJSModule from './sheetmodule' | ||||
| import SheetJSModule from './sheetmodule'; | ||||
| 
 | ||||
| export default defineNuxtConfig({ | ||||
|   // @ts-ignore
 | ||||
| @ -2,7 +2,7 @@ | ||||
| import { defineTransformer } from "@nuxt/content/transformers/utils"; | ||||
| import { read, utils } from "xlsx"; | ||||
| import { readFileSync } from "node:fs"; | ||||
| import { resolve } from 'node:path'; | ||||
| import { resolve } from "node:path"; | ||||
| 
 | ||||
| export default defineTransformer({ | ||||
|   name: 'sheetformer', | ||||
| @ -1,4 +1,4 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="890" height="480" data-created="2024-10-20T20:28:10.455635"> | ||||
| <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="890" height="480" data-created="2025-05-16T06:48:51.357946"> | ||||
|   <defs> | ||||
|     <style> | ||||
|       @font-face { | ||||
| @ -114,7 +114,7 @@ | ||||
|        | ||||
|         <svg x="5" y="68" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">131</text> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">138</text> | ||||
|   <use xlink:href="#windows" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| @ -123,7 +123,7 @@ | ||||
|      | ||||
|   </svg> | ||||
|    | ||||
|   <svg x="220" y="0" width="119" height="280"> | ||||
|   <svg x="220" y="0" width="119" height="315"> | ||||
|     <use x="12" y="7" width="20" height="20" xlink:href="#chrome" fill="#333f4b"></use> | ||||
|     <text x="42" y="24" text-anchor="left" class="head">Chrome</text> | ||||
|      | ||||
| @ -197,6 +197,16 @@ | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="272" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">136</text> | ||||
|   <use xlink:href="#windows" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|   </svg> | ||||
|    | ||||
|   <svg x="330" y="0" width="119" height="105"> | ||||
| @ -225,33 +235,13 @@ | ||||
|      | ||||
|   </svg> | ||||
|    | ||||
|   <svg x="440" y="0" width="119" height="140"> | ||||
|   <svg x="440" y="0" width="119" height="70"> | ||||
|     <use x="12" y="7" width="20" height="20" xlink:href="#ios" fill="#333f4b"></use> | ||||
|     <text x="42" y="24" text-anchor="left" class="head">iPad</text> | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="34" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">11</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.13</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="68" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">13</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.15</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="102" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">15</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">12</text> | ||||
| @ -261,36 +251,16 @@ | ||||
|      | ||||
|   </svg> | ||||
|    | ||||
|   <svg x="550" y="0" width="119" height="140"> | ||||
|   <svg x="550" y="0" width="119" height="70"> | ||||
|     <use x="12" y="7" width="20" height="20" xlink:href="#ios" fill="#333f4b"></use> | ||||
|     <text x="42" y="24" text-anchor="left" class="head">iPhone</text> | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="34" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">10</text> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">15</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.12</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="68" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">12</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.15</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="102" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">14</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">11</text> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">12</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
| @ -414,7 +384,7 @@ | ||||
|        | ||||
|         <svg x="5" y="408" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">130</text> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">135</text> | ||||
|   <use xlink:href="#windows" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| @ -423,83 +393,13 @@ | ||||
|      | ||||
|   </svg> | ||||
|    | ||||
|   <svg x="770" y="0" width="119" height="350"> | ||||
|   <svg x="770" y="0" width="119" height="105"> | ||||
|     <use x="12" y="7" width="20" height="20" xlink:href="#safari" fill="#333f4b"></use> | ||||
|     <text x="42" y="24" text-anchor="left" class="head">Safari</text> | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="34" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">8</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.10</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="68" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">9</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.11</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="102" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">10</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.12</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="136" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">11</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.13</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="170" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">12</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.13</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="204" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">13</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">10.15</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="238" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">14</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">11</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
| </svg> | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="272" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">15</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">12</text> | ||||
| @ -508,9 +408,9 @@ | ||||
|        | ||||
|      | ||||
|        | ||||
|         <svg x="5" y="306" width="109" height="33" viewBox="0 0 109 33"> | ||||
|         <svg x="5" y="68" width="109" height="33" viewBox="0 0 109 33"> | ||||
|   <rect x="0" y="0" fill="#69cc01" width="109" height="33" /> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">16</text> | ||||
|   <text x="7" y="22" text-anchor="left" class="browser_version">17</text> | ||||
|   <use xlink:href="#mac" x="34" width="15" fill="#000"></use> | ||||
|   <text x="53" y="22" text-anchor="left" class="platform_version">13</text> | ||||
|   <use xlink:href="#passing" x="90" width="10"></use> | ||||
|  | ||||
| Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 105 KiB | 
		Loading…
	
		Reference in New Issue
	
	Block a user