forked from sheetjs/docs.sheetjs.com
		
	nuxxxt
This commit is contained in:
		
							parent
							
								
									3640bd8c1f
								
							
						
					
					
						commit
						8855895cad
					
				| @ -214,10 +214,9 @@ been tested against both application types. | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| NodeJS `v16` is required.  There are OS-specific tools for downgrading: | ||||
| 
 | ||||
| - [`nvm-windows`](https://github.com/coreybutler/nvm-windows/releases) Windows | ||||
| - [`n`](https://github.com/tj/n/) Linux, MacOS, WSL, etc. | ||||
| At the time of testing, NodeJS `v16` was required. A tool like | ||||
| [`nvm-windows`](https://github.com/coreybutler/nvm-windows/releases) should be | ||||
| used to switch the NodeJS version. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -436,10 +435,8 @@ This demo was tested against `v0.64.30` on 2023 January 04 in MacOS 12.4 | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| NodeJS `v16` is required.  There are OS-specific tools for downgrading: | ||||
| 
 | ||||
| - [`nvm-windows`](https://github.com/coreybutler/nvm-windows/releases) Windows | ||||
| - [`n`](https://github.com/tj/n/) Linux, MacOS, WSL, etc. | ||||
| At the time of testing, NodeJS `v16` was required. A tool like | ||||
| [`n`](https://github.com/tj/n/) should be used to switch the NodeJS version. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|  | ||||
| @ -4,17 +4,9 @@ pagination_prev: demos/extensions/index | ||||
| pagination_next: demos/gsheet | ||||
| --- | ||||
| 
 | ||||
| ### NuxtJS | ||||
| 
 | ||||
| `@nuxt/content` is a file-based CMS for Nuxt, enabling static-site generation | ||||
| and on-demand server rendering powered by spreadsheets. | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was tested on 2022 November 18 against Nuxt Content `v1.15.1`. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| :::warning | ||||
| 
 | ||||
| Nuxt Content `v2` (NuxtJS `v3`) employs a different architecture from `v1`. | ||||
| @ -25,7 +17,15 @@ until the issues are resolved. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## Configuration | ||||
| ## Nuxt Content v1 | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was tested on 2022 November 18 against Nuxt Content `v1.15.1`. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ### Configuration | ||||
| 
 | ||||
| Through an override in `nuxt.config.js`, Nuxt Content will use custom parsers. | ||||
| Differences from a stock `create-nuxt-app` config are shown below: | ||||
| @ -59,7 +59,7 @@ export default { | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ## Template Use | ||||
| ### Template Use | ||||
| 
 | ||||
| When a spreadsheet is placed in the `content` folder, Nuxt will find it.  The | ||||
| data can be referenced in a view with `asyncData`.  The name should not include | ||||
| @ -92,7 +92,7 @@ neatly with nested `v-for`: | ||||
|   </div> | ||||
| ``` | ||||
| 
 | ||||
| ## Nuxt Content Demo | ||||
| ### Nuxt Content Demo | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| @ -248,3 +248,235 @@ npx http-server dist | ||||
| Accessing the page http://localhost:8080 will show the page contents. Verifying | ||||
| the static nature is trivial: make another change in Excel and save.  The page | ||||
| will not change. | ||||
| 
 | ||||
| ## Nuxt Content v2 | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was tested on 2023 January 19 against Nuxt Content `v2.3.0`. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ### Overview | ||||
| 
 | ||||
| Nuxt Content `v2` supports custom transformers for controlling data.  Although | ||||
| the library hard-codes UTF-8 interpretations, the `_id` field currently uses | ||||
| the pattern `content:` followed by the filename (if files are placed in the | ||||
| `content` folder directly).  This enables a transformer to re-read the file: | ||||
| 
 | ||||
| ```ts | ||||
| import { defineTransformer } from "@nuxt/content/transformers/utils"; | ||||
| import { read, utils } from "xlsx"; | ||||
| import { readFileSync } from "node:fs"; | ||||
| import { resolve } from 'node:path'; | ||||
| 
 | ||||
| export default defineTransformer({ | ||||
|   name: 'sheetformer', | ||||
|   extensions: ['.xlsx'], | ||||
|   parse (_id: string, rawContent: string) { | ||||
|     const wb = read(readFileSync(resolve("./content/" + _id.slice(8)))); | ||||
|     const body = wb.SheetNames.map(name => ({ name, data: utils.sheet_to_json(wb.Sheets[name])})); | ||||
|     return { _id, body }; | ||||
|   } | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| Pages can pull data using `useAsyncData`: | ||||
| 
 | ||||
| ```html | ||||
| <script setup> | ||||
| const key = "pres"; // matches pres.xlsx | ||||
| const {data} = await useAsyncData('x', ()=>queryContent(`/${key}`).findOne()); | ||||
| // data.body is the output from the transformer and can be used in the template | ||||
| </script> | ||||
| ``` | ||||
| 
 | ||||
| Pages should use `ContentRenderer` to reference the data: | ||||
| 
 | ||||
| ```html | ||||
| <template><ContentRenderer :value="data"> | ||||
|   <!-- data.body is the array defined in the transformer --> | ||||
|   <div v-for="item in data.body" v-bind:key="item.name"> | ||||
|     <!-- each item has a "name" string for worsheet name --> | ||||
|     <h2>{{ item.name }}</h2> | ||||
|     <!-- each item has a "body" array of data rows --> | ||||
|     <table><thead><tr><th>Name</th><th>Index</th></tr></thead><tbody> | ||||
|       <tr v-for="row in item.data" v-bind:key="row.Index"> | ||||
|         <!-- Assuming the sheet uses the columns "Name" and "Index" --> | ||||
|         <td>{{ row.Name }}</td> | ||||
|         <td>{{ row.Index }}</td> | ||||
|       </tr> | ||||
|     </tbody></table> | ||||
|   </div> | ||||
| </ContentRenderer></template> | ||||
| ``` | ||||
| 
 | ||||
| ### Nuxt Content 2 Demo | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| This demo was tested on 2023 January 19 against Nuxt Content `v2.3.0`. | ||||
| 
 | ||||
| The generated project used Nuxt `v3.0.0`. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 1) Create a stock app and install dependencies: | ||||
| 
 | ||||
| ```bash | ||||
| npx nuxi init -t content sheetjs-nc2 | ||||
| cd sheetjs-nc2 | ||||
| npx yarn install | ||||
| ``` | ||||
| 
 | ||||
| 2) Install the SheetJS library and start the server: | ||||
| 
 | ||||
| ```bash | ||||
| npx yarn add https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz | ||||
| npx yarn dev | ||||
| ``` | ||||
| 
 | ||||
| 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://sheetjs.com/pres.xlsx> and move to the `content` folder. | ||||
| 
 | ||||
| ```bash | ||||
| curl -L -o content/pres.xlsx https://sheetjs.com/pres.xlsx | ||||
| ``` | ||||
| 
 | ||||
| 4) Create the transformer. | ||||
| 
 | ||||
| Two files must be written: | ||||
| 
 | ||||
| - `sheetformer.ts` (the raw transformer module): | ||||
| 
 | ||||
| ```ts title="sheetformer.ts" | ||||
| import { defineTransformer } from "@nuxt/content/transformers/utils"; | ||||
| import { read, utils } from "xlsx"; | ||||
| import { readFileSync } from "node:fs"; | ||||
| import { resolve } from 'node:path'; | ||||
| 
 | ||||
| export default defineTransformer({ | ||||
|   name: 'sheetformer', | ||||
|   extensions: ['.xlsx'], | ||||
|   parse (_id: string, rawContent: string) { | ||||
|     const wb = read(readFileSync(resolve("./content/" + _id.slice(8)))); | ||||
|     const body = wb.SheetNames.map(name => ({ name, data: utils.sheet_to_json(wb.Sheets[name])})); | ||||
|     return { _id, body }; | ||||
|   } | ||||
| }); | ||||
| ``` | ||||
| 
 | ||||
| - `sheetmodule.ts` (the nuxt configuration module): | ||||
| 
 | ||||
| ```ts title="sheetmodule.ts" | ||||
| import { resolve } from 'path' | ||||
| import { defineNuxtModule } from '@nuxt/kit' | ||||
| 
 | ||||
| export default defineNuxtModule({ | ||||
|   setup (_options, nuxt) { | ||||
|     nuxt.options.nitro.externals = nuxt.options.nitro.externals || {} | ||||
|     nuxt.options.nitro.externals.inline = nuxt.options.nitro.externals.inline || [] | ||||
|     nuxt.options.nitro.externals.inline.push(resolve('./sheetmodule')) | ||||
|     // @ts-ignore | ||||
|     nuxt.hook('content:context', (contentContext) => { | ||||
|       contentContext.transformers.push(resolve('./sheetformer.ts')) | ||||
|     }) | ||||
|   } | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| After creating the source files, the module must be added to `nuxt.config.ts`: | ||||
| 
 | ||||
| ```ts title="nuxt.config.ts" | ||||
| import SheetJSModule from './sheetmodule' | ||||
| 
 | ||||
| export default defineNuxtConfig({ | ||||
|   modules: [ | ||||
|     SheetJSModule, | ||||
|     '@nuxt/content' | ||||
|   ], | ||||
|   content: {} | ||||
| }) | ||||
| ``` | ||||
| 
 | ||||
| Restart the dev server by exiting the process (Control+C) and running: | ||||
| 
 | ||||
| ```bash | ||||
| rm -rf .nuxt/content-cache ## forcefully clear cache | ||||
| npx yarn 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) Create a page.  Save the following content to `pages/pres.vue`: | ||||
| 
 | ||||
| ```html | ||||
| <script setup> | ||||
| const {data} = await useAsyncData('s5s', () => queryContent('/pres').findOne()); | ||||
| </script> | ||||
| <template><ContentRenderer :value="data"> | ||||
|   <div v-for="item in data.body" v-bind:key="item.name"> | ||||
|     <h2>{{ item.name }}</h2> | ||||
|     <table><thead><tr><th>Name</th><th>Index</th></tr></thead><tbody> | ||||
|       <tr v-for="row in item.data" v-bind:key="row.Index"> | ||||
|         <td>{{ row.Name }}</td> | ||||
|         <td>{{ row.Index }}</td> | ||||
|       </tr> | ||||
|     </tbody></table> | ||||
|   </div> | ||||
| </ContentRenderer></template> | ||||
| ``` | ||||
| 
 | ||||
| Restart the dev server by exiting the process (Control+C) and running: | ||||
| 
 | ||||
| ```bash | ||||
| rm -rf .nuxt/content-cache ## forcefully clear cache | ||||
| npx yarn run dev | ||||
| ``` | ||||
| 
 | ||||
| The browser should now display an HTML table. | ||||
| 
 | ||||
| 6) To verify that hot loading works, open `pres.xlsx` from the `content` folder | ||||
| in Excel.  Add a new row to the bottom and save the file. | ||||
| 
 | ||||
| The page should automatically refresh with the new content. | ||||
| 
 | ||||
| 7) Stop the server (press `CTRL+C` in the terminal window) and run | ||||
| 
 | ||||
| ```bash | ||||
| npx yarn run generate | ||||
| ``` | ||||
| 
 | ||||
| This will create a static site in `.output/public`, which can be served with: | ||||
| 
 | ||||
| ```bash | ||||
| npx http-server .output/public | ||||
| ``` | ||||
| 
 | ||||
| Accessing http://localhost:8080/pres will show the page contents. Verifying | ||||
| the static nature is trivial: make another change in Excel and save.  The page | ||||
| will not change. | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user