2023-01-15 03:36:13 +00:00
|
|
|
|
---
|
|
|
|
|
title: NuxtJS
|
2023-02-28 11:40:44 +00:00
|
|
|
|
pagination_prev: demos/net/index
|
|
|
|
|
pagination_next: demos/mobile/index
|
2023-01-15 03:36:13 +00:00
|
|
|
|
---
|
|
|
|
|
|
2023-04-27 09:12:19 +00:00
|
|
|
|
import current from '/version.js';
|
2023-05-01 01:27:02 +00:00
|
|
|
|
import CodeBlock from '@theme/CodeBlock';
|
2023-04-27 09:12:19 +00:00
|
|
|
|
|
2023-01-15 03:36:13 +00:00
|
|
|
|
`@nuxt/content` is a file-based CMS for Nuxt, enabling static-site generation
|
|
|
|
|
and on-demand server rendering powered by spreadsheets.
|
|
|
|
|
|
2023-01-20 02:25:16 +00:00
|
|
|
|
:::note
|
|
|
|
|
|
2023-05-01 01:27:02 +00:00
|
|
|
|
The following deployments were tested:
|
|
|
|
|
|
|
|
|
|
| Nuxt Content | Nuxt | Date |
|
|
|
|
|
|:-------------|:---------|:-----------|
|
|
|
|
|
| `1.15.1` | `2.16.3` | 2023-04-06 |
|
|
|
|
|
| `2.3.0` | `3.0.0` | 2023-01-19 |
|
2023-01-20 02:25:16 +00:00
|
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
2023-05-01 01:27:02 +00:00
|
|
|
|
## Nuxt Content v1
|
|
|
|
|
|
|
|
|
|
Nuxt Content v1 is designed to work with Nuxt v2.
|
|
|
|
|
|
2023-01-20 02:25:16 +00:00
|
|
|
|
### Configuration
|
2023-01-15 03:36:13 +00:00
|
|
|
|
|
|
|
|
|
Through an override in `nuxt.config.js`, Nuxt Content will use custom parsers.
|
|
|
|
|
Differences from a stock `create-nuxt-app` config are shown below:
|
|
|
|
|
|
|
|
|
|
```js title="nuxt.config.js"
|
|
|
|
|
import { readFile, utils } from 'xlsx';
|
|
|
|
|
|
|
|
|
|
// This will be called when the files change
|
|
|
|
|
const parseSheet = (file, { path }) => {
|
|
|
|
|
// `path` is a path that can be read with `XLSX.readFile`
|
|
|
|
|
const wb = readFile(path);
|
|
|
|
|
const o = wb.SheetNames.map(name => ({ name, data: utils.sheet_to_json(wb.Sheets[name])}));
|
|
|
|
|
return { data: o };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
// ...
|
|
|
|
|
|
|
|
|
|
// content.extendParser allows us to hook into the parsing step
|
|
|
|
|
content: {
|
|
|
|
|
extendParser: {
|
|
|
|
|
// the keys are the extensions that will be matched. The "." is required
|
|
|
|
|
".numbers": parseSheet,
|
|
|
|
|
".xlsx": parseSheet,
|
|
|
|
|
".xls": parseSheet,
|
|
|
|
|
// can add other extensions like ".fods" as desired
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
// ...
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2023-01-20 02:25:16 +00:00
|
|
|
|
### Template Use
|
2023-01-15 03:36:13 +00:00
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
the extension, so `"sheetjs.numbers"` would be referenced as `"sheetjs"`:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
async asyncData ({$content}) {
|
|
|
|
|
return {
|
|
|
|
|
// $content('sheetjs') will match files with extensions in nuxt.config.js
|
|
|
|
|
data: await $content('sheetjs').fetch()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
In the template, `data.data` is an array of objects. Each object has a `name`
|
|
|
|
|
property for the worksheet name and a `data` array of row objects. This maps
|
|
|
|
|
neatly with nested `v-for`:
|
|
|
|
|
|
|
|
|
|
```xml
|
|
|
|
|
<!-- loop over the worksheets -->
|
|
|
|
|
<div v-for="item in data.data" v-bind:key="item.name">
|
|
|
|
|
<table>
|
|
|
|
|
<!-- loop over the rows of each worksheet -->
|
|
|
|
|
<tr v-for="row in item.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>
|
|
|
|
|
</div>
|
|
|
|
|
```
|
|
|
|
|
|
2023-01-20 02:25:16 +00:00
|
|
|
|
### Nuxt Content Demo
|
2023-01-15 03:36:13 +00:00
|
|
|
|
|
|
|
|
|
1) Create a stock app:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
npx create-nuxt-app@4.0.0 SheetJSNuxt
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
When prompted, enter the following options:
|
|
|
|
|
|
|
|
|
|
- `Project name`: press Enter (use default `SheetJSNuxt`)
|
|
|
|
|
- `Programming language`: press Down Arrow (`TypeScript` selected) then Enter
|
|
|
|
|
- `Package manager`: select `Npm` and press Enter
|
|
|
|
|
- `UI framework`: select `None` and press Enter
|
|
|
|
|
- `Nuxt.js modules`: scroll to `Content`, select with Space, then press Enter
|
|
|
|
|
- `Linting tools`: press Enter (do not select any Linting tools)
|
|
|
|
|
- `Testing framework`: select `None` and press Enter
|
|
|
|
|
- `Rendering mode`: select `Universal (SSR / SSG)` and press Enter
|
|
|
|
|
- `Deployment target`: select `Static (Static/Jamstack hosting)` and press Enter
|
|
|
|
|
- `Development tools`: press Enter (do not select any Development tools)
|
|
|
|
|
- `What is your GitHub username?`: press Enter
|
|
|
|
|
- `Version control system`: select `None`
|
|
|
|
|
|
|
|
|
|
The project will be configured and modules will be installed.
|
|
|
|
|
|
|
|
|
|
2) Install the SheetJS library and start the server:
|
|
|
|
|
|
2023-05-01 01:27:02 +00:00
|
|
|
|
<CodeBlock language="bash">{`\
|
2023-01-15 03:36:13 +00:00
|
|
|
|
cd SheetJSNuxt
|
2023-05-01 01:27:02 +00:00
|
|
|
|
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
|
|
|
|
npm run dev`}
|
|
|
|
|
</CodeBlock>
|
2023-01-15 03:36:13 +00:00
|
|
|
|
|
|
|
|
|
When the build finishes, the terminal will display a URL like:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
ℹ Listening on: http://localhost:64688/
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
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) Modify `nuxt.config.js` as follows:
|
|
|
|
|
|
|
|
|
|
- Add the following to the top of the script:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
import { readFile, utils } from 'xlsx';
|
|
|
|
|
|
|
|
|
|
// This will be called when the files change
|
|
|
|
|
const parseSheet = (file, { path }) => {
|
|
|
|
|
// `path` is a path that can be read with `XLSX.readFile`
|
|
|
|
|
const wb = readFile(path);
|
|
|
|
|
const o = wb.SheetNames.map(name => ({ name, data: utils.sheet_to_json(wb.Sheets[name])}));
|
|
|
|
|
return { data: o };
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
- Look for the exported object. There should be a `content` property:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
// Content module configuration: https://go.nuxtjs.dev/config-content
|
|
|
|
|
content: {},
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Replace the property with the following definition:
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
// content.extendParser allows us to hook into the parsing step
|
|
|
|
|
content: {
|
|
|
|
|
extendParser: {
|
|
|
|
|
// the keys are the extensions that will be matched. The "." is required
|
|
|
|
|
".numbers": parseSheet,
|
|
|
|
|
".xlsx": parseSheet,
|
|
|
|
|
".xls": parseSheet,
|
|
|
|
|
// can add other extensions like ".fods" as desired
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
(If the property is missing, add it to the end of the exported object)
|
|
|
|
|
|
|
|
|
|
5) Replace `pages/index.vue` with the following:
|
|
|
|
|
|
|
|
|
|
```html
|
|
|
|
|
<!-- sheetjs (C) 2013-present SheetJS -- https://sheetjs.com -->
|
|
|
|
|
<template><div>
|
|
|
|
|
<div v-for="item in data.data" 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>
|
|
|
|
|
</div></template>
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
export default {
|
|
|
|
|
async asyncData ({$content}) {
|
|
|
|
|
return {
|
|
|
|
|
data: await $content('pres').fetch()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
</script>
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The browser should refresh to show the contents of the spreadsheet. If it does
|
|
|
|
|
not, click Refresh manually or open a new browser window.
|
|
|
|
|
|
|
|
|
|
![Nuxt Demo end of step 5](pathname:///nuxt/nuxt5.png)
|
|
|
|
|
|
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
![Adding a new line to `pres.xlsx`](pathname:///nuxt/nuxl6.png)
|
|
|
|
|
|
|
|
|
|
The server terminal window should show a line like:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
ℹ Updated ./content/pres.xlsx @nuxt/content 05:43:37
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The page should automatically refresh with the new content:
|
|
|
|
|
|
|
|
|
|
![Nuxt Demo end of step 6](pathname:///nuxt/nuxt6.png)
|
|
|
|
|
|
|
|
|
|
7) Stop the server (press `CTRL+C` in the terminal window) and run
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
npm run generate
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
This will create a static site in the `dist` folder, which can be served with:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
npx http-server dist
|
|
|
|
|
```
|
|
|
|
|
|
2023-05-03 03:40:40 +00:00
|
|
|
|
Accessing the page `http://localhost:8080` will show the page contents. Verifying
|
2023-01-15 03:36:13 +00:00
|
|
|
|
the static nature is trivial: make another change in Excel and save. The page
|
|
|
|
|
will not change.
|
2023-01-20 02:25:16 +00:00
|
|
|
|
|
|
|
|
|
## Nuxt Content v2
|
|
|
|
|
|
2023-05-01 01:27:02 +00:00
|
|
|
|
Nuxt Content v2 is designed to work with Nuxt v3.
|
2023-01-20 02:25:16 +00:00
|
|
|
|
|
|
|
|
|
### 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
|
|
|
|
|
|
|
|
|
|
1) Create a stock app and install dependencies:
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
npx nuxi init -t content sheetjs-nc2
|
|
|
|
|
cd sheetjs-nc2
|
|
|
|
|
npx yarn install
|
2023-02-04 23:53:30 +00:00
|
|
|
|
npx yarn add --dev @types/node
|
2023-01-20 02:25:16 +00:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
2) Install the SheetJS library and start the server:
|
|
|
|
|
|
2023-05-01 01:27:02 +00:00
|
|
|
|
<CodeBlock language="bash">{`\
|
|
|
|
|
npx yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
|
|
|
|
npx yarn dev`}
|
|
|
|
|
</CodeBlock>
|
|
|
|
|
|
2023-01-20 02:25:16 +00:00
|
|
|
|
|
|
|
|
|
When the build finishes, the terminal will display a URL like:
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
> Local: http://localhost:3000/
|
2023-05-01 01:27:02 +00:00
|
|
|
|
```
|
2023-01-20 02:25:16 +00:00
|
|
|
|
|
|
|
|
|
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"
|
2023-01-22 04:23:58 +00:00
|
|
|
|
// @ts-ignore
|
2023-01-20 02:25:16 +00:00
|
|
|
|
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 };
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
2023-04-19 20:03:23 +00:00
|
|
|
|
- `sheetmodule.ts` (the Nuxt configuration module):
|
2023-01-20 02:25:16 +00:00
|
|
|
|
|
|
|
|
|
```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
|
2023-01-21 10:50:57 +00:00
|
|
|
|
npx nuxi clean
|
2023-02-04 23:53:30 +00:00
|
|
|
|
npx nuxi typecheck
|
2023-01-20 02:25:16 +00:00
|
|
|
|
npx yarn run dev
|
|
|
|
|
```
|
|
|
|
|
|
2023-05-03 03:40:40 +00:00
|
|
|
|
Loading `http://localhost:3000/pres` should show some JSON data:
|
2023-01-20 02:25:16 +00:00
|
|
|
|
|
|
|
|
|
```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`:
|
|
|
|
|
|
2023-01-22 04:23:58 +00:00
|
|
|
|
```html title="pages/pres.vue"
|
2023-01-20 02:25:16 +00:00
|
|
|
|
<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
|
2023-01-21 10:50:57 +00:00
|
|
|
|
npx nuxi clean
|
2023-01-20 02:25:16 +00:00
|
|
|
|
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
|
|
|
|
|
```
|
|
|
|
|
|
2023-05-03 03:40:40 +00:00
|
|
|
|
Accessing `http://localhost:8080/pres` will show the page contents. Verifying
|
2023-01-20 02:25:16 +00:00
|
|
|
|
the static nature is trivial: make another change in Excel and save. The page
|
|
|
|
|
will not change.
|