forked from sheetjs/docs.sheetjs.com
statique
This commit is contained in:
parent
89ddafaaeb
commit
3640bd8c1f
@ -12,7 +12,7 @@ familiarity is assumed.
|
||||
|
||||
Other demos cover general React deployments, including:
|
||||
|
||||
- [Static Site Generation powered by NextJS](/docs/demos/content#nextjs)
|
||||
- [Static Site Generation powered by NextJS](/docs/demos/static/nextjs)
|
||||
- [iOS and Android applications powered by React Native](/docs/demos/mobile/reactnative)
|
||||
- [Desktop application powered by React Native Windows + macOS](/docs/demos/desktop/reactnative)
|
||||
- [React Data Grid UI component](/docs/demos/grid#react-data-grid)
|
||||
|
@ -12,7 +12,7 @@ Components (SFC) and VueJS familiarity is assumed.
|
||||
|
||||
Other demos cover general VueJS deployments, including:
|
||||
|
||||
- [Static Site Generation powered by NuxtJS](/docs/demos/content#nuxtjs)
|
||||
- [Static Site Generation powered by NuxtJS](/docs/demos/static/nuxtjs)
|
||||
- [iOS and Android applications powered by Quasar](/docs/demos/mobile/quasar)
|
||||
- [Desktop application powered by Tauri](/docs/demos/desktop/tauri)
|
||||
- [`vue3-table-lite` UI component](/docs/demos/grid#vue3-table-lite)
|
||||
|
@ -1066,7 +1066,7 @@ Access http://localhost:8080 in your web browser.
|
||||
|
||||
:::note
|
||||
|
||||
The [Vite section of the Content demo](/docs/demos/content#vitejs) covers asset
|
||||
The [Vite section of the Content demo](/docs/demos/static/vitejs) covers asset
|
||||
loaders. They are ideal for static sites pulling data from sheets at build time.
|
||||
|
||||
:::
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Photoshop and Creative Suite
|
||||
pagination_prev: demos/server
|
||||
pagination_next: demos/gsheet
|
||||
pagination_next: demos/static/index
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Chrome and Chromium
|
||||
pagination_prev: demos/server
|
||||
pagination_next: demos/gsheet
|
||||
pagination_next: demos/static/index
|
||||
---
|
||||
|
||||
:::warning
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Excel JavaScript API
|
||||
pagination_prev: demos/server
|
||||
pagination_next: demos/gsheet
|
||||
pagination_next: demos/static/index
|
||||
---
|
||||
|
||||
:::info
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Extensions
|
||||
pagination_prev: demos/server
|
||||
pagination_next: demos/gsheet
|
||||
pagination_next: demos/static/index
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
90
docz/docs/03-demos/11-static/01-lume.md
Normal file
90
docz/docs/03-demos/11-static/01-lume.md
Normal file
@ -0,0 +1,90 @@
|
||||
---
|
||||
title: Lume
|
||||
pagination_prev: demos/extensions/index
|
||||
pagination_next: demos/gsheet
|
||||
sidebar_custom_props:
|
||||
type: native
|
||||
---
|
||||
|
||||
Lume is a lightweight, fast and flexible static site generator.
|
||||
|
||||
The official [Sheets plugin](https://lume.land/plugins/sheets/) uses SheetJS to
|
||||
load data from spreadsheets. New users should consult the official docs.
|
||||
|
||||
Lume supports refreshing data during development. The generated static sites
|
||||
include the raw data without referencing the underlying spreadsheet files.
|
||||
|
||||
## Lume Demo
|
||||
|
||||
:::note
|
||||
|
||||
This was tested against `lume v1.14.2` on 2022 December 27.
|
||||
|
||||
This example uses the Nunjucks template format. Lume plugins support additional
|
||||
template formats, including Markdown and JSX.
|
||||
|
||||
:::
|
||||
|
||||
1) Create a stock site:
|
||||
|
||||
```bash
|
||||
mkdir -p sheetjs-lume
|
||||
cd sheetjs-lume
|
||||
deno run -Ar https://deno.land/x/lume/init.ts
|
||||
```
|
||||
|
||||
When prompted, enter the following options:
|
||||
|
||||
- `Use TypeScript for the configuration file`: press Enter (use default `N`)
|
||||
- `Do you want to use plugins`: type `sheets` and press Enter
|
||||
|
||||
The project will be configured and modules will be installed.
|
||||
|
||||
2) Download <https://sheetjs.com/pres.numbers> and place in a `_data` folder:
|
||||
|
||||
```bash
|
||||
mkdir -p _data
|
||||
curl -L -o _data/pres.numbers https://sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
3) Create a `index.njk` file that references the file. Since the file is
|
||||
`pres.numbers`, the parameter name is `pres`:
|
||||
|
||||
```liquid title="index.njk"
|
||||
<h2>Presidents</h2>
|
||||
<table><thead><th>Name</th><th>Index</th></thead>
|
||||
<tbody>
|
||||
{% for row in pres %}{% if (loop.index >= 1) %}
|
||||
<tr>
|
||||
<td>{{ row.Name }}</td>
|
||||
<td>{{ row.Index }}</td>
|
||||
</tr>
|
||||
{% endif %}{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
|
||||
4) Run the development server:
|
||||
|
||||
```bash
|
||||
deno task lume --serve
|
||||
```
|
||||
|
||||
To verify it works, access http://localhost:3000 from your web browser.
|
||||
Adding a new row and saving `pres.numbers` should refresh the data
|
||||
|
||||
5) Stop the server (press `CTRL+C` in the terminal window) and run
|
||||
|
||||
```bash
|
||||
deno task lume
|
||||
```
|
||||
|
||||
This will create a static site in the `_site` folder, which can be served with:
|
||||
|
||||
```bash
|
||||
npx http-server _site
|
||||
```
|
||||
|
||||
Accessing the page http://localhost:8080 will show the page contents.
|
||||
|
||||
This site is self-contained and ready for deployment!
|
292
docz/docs/03-demos/11-static/02-gatsbyjs.md
Normal file
292
docz/docs/03-demos/11-static/02-gatsbyjs.md
Normal file
@ -0,0 +1,292 @@
|
||||
---
|
||||
title: GatsbyJS
|
||||
pagination_prev: demos/extensions/index
|
||||
pagination_next: demos/gsheet
|
||||
sidebar_custom_props:
|
||||
type: native
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
|
||||
Gatsby is a framework for creating websites. It uses React components for page
|
||||
templates and GraphQL for loading data.
|
||||
|
||||
[`gatsby-transformer-excel`](https://www.gatsbyjs.com/plugins/gatsby-transformer-excel/)
|
||||
is a transformer that generates GraphQL nodes for each row of each worksheet.
|
||||
The plugin is officially supported by the Gatsby team. The plugin documentation
|
||||
includes examples and more detailed usage instructions.
|
||||
|
||||
:::note
|
||||
|
||||
`gatsby-transformer-excel` is maintained by the Gatsby core team and all bugs
|
||||
should be directed to the main Gatsby project. If it is determined to be a bug
|
||||
in the parsing logic, issues should then be raised with the SheetJS project.
|
||||
|
||||
:::
|
||||
|
||||
:::caution
|
||||
|
||||
`gatsby-transformer-excel` uses an older version of the library. It can be
|
||||
overridden through a `package.json` override in the latest versions of NodeJS:
|
||||
|
||||
<pre><code parentName="pre" {...{"className": "language-json"}}>{`\
|
||||
{
|
||||
"overrides": {
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz"
|
||||
}
|
||||
}`}
|
||||
</code></pre>
|
||||
|
||||
:::
|
||||
|
||||
## GraphQL details
|
||||
|
||||
`gatsby-transformer-excel` generates nodes for each data row of each worksheet.
|
||||
Under the hood, it uses [`sheet_to_json`](/docs/api/utilities#array-output)
|
||||
to generate row objects using the headers in the first row as keys.
|
||||
|
||||
![pres.xlsx](pathname:///pres.png)
|
||||
|
||||
Assuming the file name is `pres.xlsx` and the data is stored in "Sheet1", the
|
||||
following nodes will be created:
|
||||
|
||||
```js
|
||||
[
|
||||
{ Name: "Bill Clinton", Index: 42, type: "PresXlsxSheet1" },
|
||||
{ Name: "GeorgeW Bush", Index: 43, type: "PresXlsxSheet1" },
|
||||
{ Name: "Barack Obama", Index: 44, type: "PresXlsxSheet1" },
|
||||
{ Name: "Donald Trump", Index: 45, type: "PresXlsxSheet1" },
|
||||
{ Name: "Joseph Biden", Index: 46, type: "PresXlsxSheet1" },
|
||||
]
|
||||
```
|
||||
|
||||
The type is a proper casing of the file name concatenated with the sheet name.
|
||||
|
||||
The following query pulls the `Name` and `Index` fields from each row:
|
||||
|
||||
```graphql
|
||||
{
|
||||
allPresXlsxSheet1 { # "all" followed by type
|
||||
edges {
|
||||
node { # each line in this block should be a field in the data
|
||||
Name
|
||||
Index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## GatsbyJS Demo
|
||||
|
||||
:::note
|
||||
|
||||
This demo was tested on 2022 November 11 against `create-gatsby@3.0.0`. The
|
||||
generated project used `gatsby@5.0.0` and `react@18.2.0`.
|
||||
|
||||
:::
|
||||
|
||||
### Project setup
|
||||
|
||||
1) Run `npm init gatsby -- -y sheetjs-gatsby` to create the template site.
|
||||
|
||||
2) Follow the on-screen instructions for starting the local development server:
|
||||
|
||||
```bash
|
||||
cd sheetjs-gatsby
|
||||
npm run develop
|
||||
```
|
||||
|
||||
Open a web browser to the displayed URL (typically `http://localhost:8000/`)
|
||||
|
||||
3) Edit `package.json` and add the highlighted lines in the JSON object:
|
||||
|
||||
<pre><code parentName="pre" {...{"className": "language-json"}}>{`\
|
||||
{
|
||||
// highlight-start
|
||||
"overrides": {
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz"
|
||||
},
|
||||
// highlight-end
|
||||
"name": "sheetjs-gatsby",
|
||||
"version": "1.0.0",
|
||||
`}
|
||||
</code></pre>
|
||||
|
||||
4) Install the library and plugins:
|
||||
|
||||
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm i --save gatsby-transformer-excel gatsby-source-filesystem
|
||||
`}
|
||||
</code></pre>
|
||||
|
||||
5) Edit `gatsby-config.js` and add the following lines to the `plugins` array:
|
||||
|
||||
```js
|
||||
plugins: [
|
||||
{
|
||||
resolve: `gatsby-source-filesystem`,
|
||||
options: {
|
||||
name: `data`,
|
||||
path: `${__dirname}/src/data/`,
|
||||
},
|
||||
},
|
||||
`gatsby-transformer-excel`,
|
||||
],
|
||||
```
|
||||
|
||||
Stop and restart the development server process (`npm run develop`).
|
||||
|
||||
6) Make a `src/data` directory, download <https://sheetjs.com/pres.xlsx>, and
|
||||
move the downloaded file into the new folder:
|
||||
|
||||
```bash
|
||||
mkdir -p src/data
|
||||
curl -L -o src/data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
### GraphiQL test
|
||||
|
||||
7) Open the GraphiQL editor at `http://localhost:8000/___graphql`.
|
||||
|
||||
There is an editor in the left pane. Paste the following query into the editor:
|
||||
|
||||
```graphql
|
||||
{
|
||||
allPresXlsxSheet1 {
|
||||
edges {
|
||||
node {
|
||||
Name
|
||||
Index
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Press the Execute Query button and data should show up in the right pane:
|
||||
|
||||
![GraphiQL Screenshot](pathname:///gatsby/graphiql.png)
|
||||
|
||||
### React page
|
||||
|
||||
8) Create a new file `src/pages/pres.js` that uses the query and displays the result:
|
||||
|
||||
```jsx title="src/pages/pres.js"
|
||||
import { graphql } from "gatsby"
|
||||
import * as React from "react"
|
||||
|
||||
export const query = graphql`query {
|
||||
allPresXlsxSheet1 {
|
||||
edges {
|
||||
node {
|
||||
Name
|
||||
Index
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
const PageComponent = ({data}) => {
|
||||
return ( <pre>{JSON.stringify(data, 2, 2)}</pre> );
|
||||
};
|
||||
export default PageComponent;
|
||||
```
|
||||
|
||||
After saving the file, access `http://localhost:8000/pres`. The displayed JSON
|
||||
is the data that the component receives:
|
||||
|
||||
```js
|
||||
{
|
||||
"allPresXlsxSheet1": {
|
||||
"edges": [
|
||||
{
|
||||
"node": {
|
||||
"Name": "Bill Clinton",
|
||||
"Index": 42
|
||||
}
|
||||
},
|
||||
// ....
|
||||
```
|
||||
|
||||
9) Change `PageComponent` to display a table based on the data:
|
||||
|
||||
```jsx title="src/pages/pres.js"
|
||||
import { graphql } from "gatsby"
|
||||
import * as React from "react"
|
||||
|
||||
export const query = graphql`query {
|
||||
allPresXlsxSheet1 {
|
||||
edges {
|
||||
node {
|
||||
Name
|
||||
Index
|
||||
}
|
||||
}
|
||||
}
|
||||
}`;
|
||||
|
||||
// highlight-start
|
||||
const PageComponent = ({data}) => {
|
||||
const rows = data.allPresXlsxSheet1.edges.map(r => r.node);
|
||||
return ( <table>
|
||||
<thead><tr><th>Name</th><th>Index</th></tr></thead>
|
||||
<tbody>{rows.map(row => ( <tr>
|
||||
<td>{row.Name}</td>
|
||||
<td>{row.Index}</td>
|
||||
</tr> ))}</tbody>
|
||||
</table> );
|
||||
};
|
||||
// highlight-end
|
||||
|
||||
export default PageComponent;
|
||||
```
|
||||
|
||||
Going back to the browser, `http://localhost:8000/pres` will show a table:
|
||||
|
||||
![Data in Table](pathname:///gatsby/table1.png)
|
||||
|
||||
### Live refresh
|
||||
|
||||
10) Open the file `src/data/pres.xlsx` in Excel or LibreOffice or Numbers.
|
||||
Add a new row at the end of the file:
|
||||
|
||||
![New Row in File](pathname:///gatsby/pres2.png)
|
||||
|
||||
Save the file and notice that the table has refreshed with the new data:
|
||||
|
||||
![Updated Table](pathname:///gatsby/table2.png)
|
||||
|
||||
### Static site
|
||||
|
||||
11) Stop the development server and run `npm run build`. Once the build is
|
||||
finished, the display will confirm that the `/pres` route is static:
|
||||
|
||||
```
|
||||
Pages
|
||||
|
||||
┌ src/pages/404.js
|
||||
│ ├ /404/
|
||||
│ └ /404.html
|
||||
├ src/pages/index.js
|
||||
│ └ /
|
||||
└ src/pages/pres.js
|
||||
└ /pres/
|
||||
|
||||
╭────────────────────────────────────────────────────────────────╮
|
||||
│ │
|
||||
│ (SSG) Generated at build time │
|
||||
│ D (DSG) Deferred static generation - page generated at runtime │
|
||||
│ ∞ (SSR) Server-side renders at runtime (uses getServerData) │
|
||||
│ λ (Function) Gatsby function │
|
||||
│ │
|
||||
╰────────────────────────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
The built page will be placed in `public/pres/index.html`. Open the page with a
|
||||
text editor and search for "SheetJS" to verify raw HTML was generated:
|
||||
|
||||
```html
|
||||
<tr><td>SheetJS Dev</td><td>47</td></tr>
|
||||
```
|
283
docz/docs/03-demos/11-static/05-vitejs.md
Normal file
283
docz/docs/03-demos/11-static/05-vitejs.md
Normal file
@ -0,0 +1,283 @@
|
||||
---
|
||||
title: ViteJS
|
||||
pagination_prev: demos/extensions/index
|
||||
pagination_next: demos/gsheet
|
||||
sidebar_custom_props:
|
||||
type: bundler
|
||||
---
|
||||
|
||||
:::note
|
||||
|
||||
This demo covers static asset imports. For processing files in the browser, the
|
||||
["Bundlers" demo](/docs/demos/bundler#vite) includes an example.
|
||||
|
||||
:::
|
||||
|
||||
## Loaders
|
||||
|
||||
ViteJS supports static asset imports, 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.
|
||||
|
||||
:::note Recommendation
|
||||
|
||||
For simple tables of data, ["Pure Data Loader"](#pure-data-loader) is strongly
|
||||
recommended. The heavy work is performed at build time and the generated site
|
||||
only includes the raw data.
|
||||
|
||||
For more complex parsing or display logic, ["Base64 Loader"](#base64-loader) is
|
||||
preferable. Since the raw parsing logic is performed in the page,
|
||||
|
||||
:::
|
||||
|
||||
### Pure Data Loader
|
||||
|
||||
For a pure static site, a plugin can load data into an array of row objects. The
|
||||
SheetJS work is performed in the plugin. The library is not loaded in the page!
|
||||
|
||||
```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 ?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)}')`;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
This loader uses the query `sheetjs`:
|
||||
|
||||
```js title="main.js"
|
||||
import data from './data.xlsx?sheetjs';
|
||||
|
||||
document.querySelector('#app').innerHTML = `<div><pre>
|
||||
${data.map(row => JSON.stringify(row)).join("\n")}
|
||||
</pre></div>`;
|
||||
```
|
||||
|
||||
### Base64 Loader
|
||||
|
||||
This loader pulls in data as a Base64 string that can be read with `XLSX.read`.
|
||||
While this approach works, it is not recommended since it loads the library in
|
||||
the front-end site.
|
||||
|
||||
```js title="vite.config.js"
|
||||
import { readFileSync } from 'fs';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
assetsInclude: ['**/*.xlsx'], // mark that xlsx file should be treated as assets
|
||||
|
||||
plugins: [
|
||||
{ // this plugin handles ?b64 tags
|
||||
name: "vite-b64-plugin",
|
||||
transform(code, id) {
|
||||
if(!id.match(/\?b64$/)) return;
|
||||
var path = id.replace(/\?b64/, "");
|
||||
var data = readFileSync(path, "base64");
|
||||
return `export default '${data}'`;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
When importing using the `b64` query, the raw Base64 string will be exposed.
|
||||
This can be read directly with `XLSX.read` in JS code:
|
||||
|
||||
```js title="main.js"
|
||||
import { read, utils } from "xlsx";
|
||||
|
||||
/* reference workbook */
|
||||
import b64 from './data.xlsx?b64';
|
||||
/* parse workbook and export first sheet to CSV */
|
||||
const wb = read(b64);
|
||||
const wsname = wb.SheetNames[0];
|
||||
const csv = utils.sheet_to_csv(wb.Sheets[wsname]);
|
||||
|
||||
document.querySelector('#app').innerHTML = `<div><pre>
|
||||
<b>${wsname}</b>
|
||||
${csv}
|
||||
</pre></div>`;
|
||||
```
|
||||
|
||||
## Complete Demo
|
||||
|
||||
:::note
|
||||
|
||||
This demo was tested on 2023 January 14 against `vite v4.0.4`.
|
||||
|
||||
:::
|
||||
|
||||
### Initial Setup
|
||||
|
||||
1) Create a new site using the `vue-ts` template:
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-vite -- --template vue-ts
|
||||
cd sheetjs-vite
|
||||
npm install
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
|
||||
```
|
||||
|
||||
2) Replace `vite.config.ts` with the following:
|
||||
|
||||
```js title="vite.config.ts"
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import { readFileSync } from 'fs';
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
export default defineConfig({
|
||||
assetsInclude: ['**/*.xlsx'], // xlsx file should be treated as assets
|
||||
|
||||
plugins: [
|
||||
vue(),
|
||||
{ // 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)}')`;
|
||||
}
|
||||
},
|
||||
{ // this plugin handles ?b64 tags
|
||||
name: "vite-b64-plugin",
|
||||
transform(code, id) {
|
||||
if(!id.match(/\?b64$/)) return;
|
||||
var path = id.replace(/\?b64/, "");
|
||||
var data = readFileSync(path, "base64");
|
||||
return `export default '${data}'`;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
3) Make a `data` folder and download <https://sheetjs.com/pres.xlsx> :
|
||||
|
||||
```bash
|
||||
mkdir -p data
|
||||
curl -L -o data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
### Pure Data Test
|
||||
|
||||
4) Run the dev server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open a browser window to the displayed URL (typically http://localhost:5173 )
|
||||
|
||||
5) Replace the component `src/components/HelloWorld.vue` with:
|
||||
|
||||
```html title="src/components/HelloWorld.vue"
|
||||
<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>
|
||||
```
|
||||
|
||||
Save and refresh the page. A data table should be displayed
|
||||
|
||||
6) Stop the dev server and build the site
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx http-server dist/
|
||||
```
|
||||
|
||||
The terminal will display a url like http://127.0.0.1:8080. Access that page
|
||||
with a web browser.
|
||||
|
||||
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. Searching for `Bill Clinton` reveals the following:
|
||||
|
||||
```
|
||||
JSON.parse('[{"Name":"Bill Clinton","Index":42}
|
||||
```
|
||||
|
||||
Searching for `BESSELJ` should reveal no results. The SheetJS scripts are not
|
||||
included in the final site!
|
||||
|
||||
### Base64 Test
|
||||
|
||||
8) Run the dev server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open a browser window to the displayed URL.
|
||||
|
||||
9) Replace the component `src/components/HelloWorld.vue` with:
|
||||
|
||||
```html title="src/components/HelloWorld.vue"
|
||||
<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>
|
||||
```
|
||||
|
||||
10) Stop the dev server and build the site
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx http-server dist/
|
||||
```
|
||||
|
||||
The terminal will display a url like http://127.0.0.1:8080. Access that page
|
||||
with a web browser.
|
||||
|
||||
11) 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. Searching for `Bill Clinton` should yield no results.
|
||||
Searching for `BESSELJ` should match the code:
|
||||
|
||||
```
|
||||
425:"BESSELJ"
|
||||
```
|
||||
|
||||
The SheetJS library is embedded in the final site.
|
327
docz/docs/03-demos/11-static/08-nextjs.md
Normal file
327
docz/docs/03-demos/11-static/08-nextjs.md
Normal file
@ -0,0 +1,327 @@
|
||||
---
|
||||
title: NextJS
|
||||
pagination_prev: demos/extensions/index
|
||||
pagination_next: demos/gsheet
|
||||
---
|
||||
|
||||
:::note
|
||||
|
||||
This was tested against `next v13.1.1` on 2023 January 14.
|
||||
|
||||
:::
|
||||
|
||||
:::info
|
||||
|
||||
At a high level, there are two ways to pull spreadsheet data into NextJS apps:
|
||||
loading an asset module or performing the file read operations from the NextJS
|
||||
lifecycle. At the time of writing, NextJS does not offer an out-of-the-box
|
||||
asset module solution, so this demo focuses on raw operations. NextJS does not
|
||||
watch the spreadsheets, so `next dev` hot reloading will not work!
|
||||
|
||||
:::
|
||||
|
||||
The general strategy with NextJS apps is to generate HTML snippets or data from
|
||||
the lifecycle functions and reference them in the template.
|
||||
|
||||
HTML output can be generated using `XLSX.utils.sheet_to_html` and inserted into
|
||||
the document using the `dangerouslySetInnerHTML` attribute:
|
||||
|
||||
```jsx
|
||||
export default function Index({html, type}) { return (
|
||||
// ...
|
||||
// highlight-next-line
|
||||
<div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
// ...
|
||||
); }
|
||||
```
|
||||
|
||||
:::warning Reading and writing files during the build process
|
||||
|
||||
`fs` cannot be statically imported from the top level in NextJS pages. The
|
||||
dynamic import must happen within a lifecycle function. For example:
|
||||
|
||||
```js
|
||||
/* it is safe to import the library from the top level */
|
||||
import { readFile, utils, set_fs } from 'xlsx';
|
||||
/* it is not safe to import 'fs' from the top level ! */
|
||||
// import * as fs from 'fs'; // this will fail
|
||||
import { join } from 'path';
|
||||
import { cwd } from 'process';
|
||||
|
||||
export async function getServerSideProps() {
|
||||
// highlight-next-line
|
||||
set_fs(await import("fs")); // dynamically import 'fs' when needed
|
||||
const wb = readFile(join(cwd(), "public", "sheetjs.xlsx")); // works
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::caution Next 13+ and SWC
|
||||
|
||||
Next 13 switched to the SWC minifier. There are known issues with the minifier.
|
||||
Until those issues are resolved, SWC should be disabled in `next.config.js`:
|
||||
|
||||
```js title="next.config.js"
|
||||
module.exports = {
|
||||
// highlight-next-line
|
||||
swcMinify: false
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## NextJS Strategies
|
||||
|
||||
NextJS currently provides 3 strategies:
|
||||
|
||||
- "Static Site Generation" using `getStaticProps`
|
||||
- "SSG with Dynamic Routes" using `getStaticPaths`
|
||||
- "Server-Side Rendering" using `getServerSideProps`
|
||||
|
||||
### Static Site Generation
|
||||
|
||||
When using `getStaticProps`, the file will be read once during build time.
|
||||
|
||||
```js
|
||||
import { readFile, set_fs, utils } from 'xlsx';
|
||||
|
||||
export async function getStaticProps() {
|
||||
/* read file */
|
||||
set_fs(await import("fs"));
|
||||
const wb = readFile(path_to_file)
|
||||
|
||||
/* generate and return the html from the first worksheet */
|
||||
const html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
|
||||
return { props: { html } };
|
||||
};
|
||||
```
|
||||
|
||||
### Dynamic Routes
|
||||
|
||||
Typically a static site with dynamic routes has an endpoint `/sheets/[id]` that
|
||||
implements both `getStaticPaths` and `getStaticProps`.
|
||||
|
||||
- `getStaticPaths` should return an array of worksheet indices:
|
||||
|
||||
```js
|
||||
export async function getStaticPaths() {
|
||||
/* read file */
|
||||
set_fs(await import("fs"));
|
||||
const wb = readFile(path);
|
||||
|
||||
/* generate an array of objects that will be used for generating pages */
|
||||
const paths = wb.SheetNames.map((name, idx) => ({ params: { id: idx.toString() } }));
|
||||
return { paths, fallback: false };
|
||||
};
|
||||
```
|
||||
|
||||
:::note
|
||||
|
||||
For a pure static site, `fallback` must be set to `false`!
|
||||
|
||||
:::
|
||||
|
||||
- `getStaticProps` will generate the actual HTML for each page:
|
||||
|
||||
```js
|
||||
export async function getStaticProps(ctx) {
|
||||
/* read file */
|
||||
set_fs(await import("fs"));
|
||||
const wb = readFile(path);
|
||||
|
||||
/* get the corresponding worksheet and generate HTML */
|
||||
const ws = wb.Sheets[wb.SheetNames[ctx.params.id]]; // id from getStaticPaths
|
||||
const html = utils.sheet_to_html(ws);
|
||||
return { props: { html } };
|
||||
};
|
||||
```
|
||||
|
||||
### Server-Side Rendering
|
||||
|
||||
:::caution Do not use on a static site
|
||||
|
||||
These routes require a NodeJS dynamic server. Static page generation will fail!
|
||||
|
||||
`getStaticProps` and `getStaticPaths` support static site generation (SSG).
|
||||
|
||||
`getServerSideProps` is suited for NodeJS hosted deployments where the workbook
|
||||
changes frequently and a static site is undesirable.
|
||||
|
||||
:::
|
||||
|
||||
When using `getServerSideProps`, the file will be read on each request.
|
||||
|
||||
```js
|
||||
import { readFile, set_fs, utils } from 'xlsx';
|
||||
|
||||
export async function getServerSideProps() {
|
||||
/* read file */
|
||||
set_fs(await import("fs"));
|
||||
const wb = readFile(path_to_file);
|
||||
|
||||
/* generate and return the html from the first worksheet */
|
||||
const html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
|
||||
return { props: { html } };
|
||||
};
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
0) Disable NextJS telemetry:
|
||||
|
||||
```js
|
||||
npx next@13.1.1 telemetry disable
|
||||
```
|
||||
|
||||
Confirm it is disabled by running
|
||||
|
||||
```js
|
||||
npx next@13.1.1 telemetry status
|
||||
```
|
||||
|
||||
1) Set up folder structure. At the end, a `pages` folder with a `sheets`
|
||||
subfolder must be created. On Linux or MacOS or WSL:
|
||||
|
||||
```bash
|
||||
mkdir -p pages/sheets/
|
||||
```
|
||||
|
||||
2) Download the [test file](pathname:///next/sheetjs.xlsx) and place in the
|
||||
project root. On Linux or MacOS or WSL:
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/next/sheetjs.xlsx
|
||||
```
|
||||
|
||||
3) Install dependencies:
|
||||
|
||||
```bash
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz next@13.1.1
|
||||
```
|
||||
|
||||
4) Download test scripts:
|
||||
|
||||
Download and place the following scripts in the `pages` subfolder:
|
||||
|
||||
- [`index.js`](pathname:///next/index.js)
|
||||
- [`getServerSideProps.js`](pathname:///next/getServerSideProps.js)
|
||||
- [`getStaticPaths.js`](pathname:///next/getStaticPaths.js)
|
||||
- [`getStaticProps.js`](pathname:///next/getStaticProps.js)
|
||||
|
||||
Download [`[id].js`](pathname:///next/%5Bid%5D.js) and place in the
|
||||
`pages/sheets` subfolder.
|
||||
|
||||
:::caution Percent-Encoding in the script name
|
||||
|
||||
The `[id].js` script must have the literal square brackets in the name. If your
|
||||
browser saved the file to `%5Bid%5D.js`. rename the file.
|
||||
|
||||
:::
|
||||
|
||||
On Linux or MacOS or WSL:
|
||||
|
||||
```bash
|
||||
cd pages
|
||||
curl -LO https://docs.sheetjs.com/next/index.js
|
||||
curl -LO https://docs.sheetjs.com/next/getServerSideProps.js
|
||||
curl -LO https://docs.sheetjs.com/next/getStaticPaths.js
|
||||
curl -LO https://docs.sheetjs.com/next/getStaticProps.js
|
||||
cd sheets
|
||||
curl -LOg 'https://docs.sheetjs.com/next/[id].js'
|
||||
cd ../..
|
||||
```
|
||||
|
||||
5) Test the deployment:
|
||||
|
||||
```bash
|
||||
npx next@13.1.1
|
||||
```
|
||||
|
||||
Open a web browser and access:
|
||||
|
||||
- http://localhost:3000 landing page
|
||||
- http://localhost:3000/getStaticProps shows data from the first sheet
|
||||
- http://localhost:3000/getServerSideProps shows data from the first sheet
|
||||
- http://localhost:3000/getStaticPaths shows a list (3 sheets)
|
||||
|
||||
The individual worksheets are available at
|
||||
|
||||
- http://localhost:3000/sheets/0
|
||||
- http://localhost:3000/sheets/1
|
||||
- http://localhost:3000/sheets/2
|
||||
|
||||
6) Stop the server and run a production build:
|
||||
|
||||
```bash
|
||||
npx next@13.1.1 build
|
||||
```
|
||||
|
||||
The final output will show a list of the routes and types:
|
||||
|
||||
```
|
||||
Route (pages) Size First Load JS
|
||||
┌ ○ / 541 B 77.4 kB
|
||||
├ ○ /404 181 B 73.7 kB
|
||||
├ λ /getServerSideProps 594 B 77.4 kB
|
||||
├ ● /getStaticPaths 2.56 kB 79.4 kB
|
||||
├ ● /getStaticProps 591 B 77.4 kB
|
||||
└ ● /sheets/[id] (447 ms) 569 B 77.4 kB
|
||||
├ /sheets/0
|
||||
├ /sheets/1
|
||||
└ /sheets/2
|
||||
```
|
||||
|
||||
As explained in the summary, the `/getStaticPaths` and `/getStaticProps` routes
|
||||
are completely static. 3 `/sheets/#` pages were generated, corresponding to 3
|
||||
worksheets in the file. `/getServerSideProps` is server-rendered.
|
||||
|
||||
7) Try to build a static site:
|
||||
|
||||
```bash
|
||||
npx next@13.1.1 export
|
||||
```
|
||||
|
||||
:::note The static export will fail!
|
||||
|
||||
A static page cannot be generated at this point because `/getServerSideProps`
|
||||
is still server-rendered.
|
||||
|
||||
:::
|
||||
|
||||
8) Delete `pages/getServerSideProps.js` and rebuild:
|
||||
|
||||
```bash
|
||||
rm -f pages/getServerSideProps.js
|
||||
npx next@13.1.1 build
|
||||
```
|
||||
|
||||
Inspecting the output, there should be no lines with the `λ` symbol:
|
||||
|
||||
```
|
||||
Route (pages) Size First Load JS
|
||||
┌ ○ / 541 B 77.4 kB
|
||||
├ ○ /404 181 B 73.7 kB
|
||||
├ ● /getStaticPaths 2.56 kB 79.4 kB
|
||||
├ ● /getStaticProps 591 B 77.4 kB
|
||||
└ ● /sheets/[id] (459 ms) 569 B 77.4 kB
|
||||
├ /sheets/0
|
||||
├ /sheets/1
|
||||
└ /sheets/2
|
||||
```
|
||||
|
||||
9) Generate the static site:
|
||||
|
||||
```bash
|
||||
npx next@13.1.1 export
|
||||
```
|
||||
|
||||
The static site will be written to the `out` subfolder, which can be hosted with
|
||||
|
||||
```bash
|
||||
npx http-server out
|
||||
```
|
||||
|
||||
The command will start a local HTTP server for testing the generated site. Note
|
||||
that `/getServerSideProps` will 404 since the page was removed.
|
250
docz/docs/03-demos/11-static/09-nuxtjs.md
Normal file
250
docz/docs/03-demos/11-static/09-nuxtjs.md
Normal file
@ -0,0 +1,250 @@
|
||||
---
|
||||
title: NuxtJS
|
||||
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`.
|
||||
There are known bugs related to corrupted binary spreadsheet files.
|
||||
|
||||
Greenfield projects should stick to the stable NuxtJS + Nuxt Content versions
|
||||
until the issues are resolved.
|
||||
|
||||
:::
|
||||
|
||||
## 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:
|
||||
|
||||
```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
|
||||
}
|
||||
},
|
||||
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## 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
|
||||
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>
|
||||
```
|
||||
|
||||
## Nuxt Content Demo
|
||||
|
||||
:::note
|
||||
|
||||
The project was generated using `create-nuxt-app v4.0.0`. The generated project
|
||||
used Nuxt `v2.15.8` and Nuxt Content `v1.15.1`.
|
||||
|
||||
:::
|
||||
|
||||
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:
|
||||
|
||||
```bash
|
||||
cd SheetJSNuxt
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
|
||||
npm run dev
|
||||
```
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
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.
|
4
docz/docs/03-demos/11-static/_category_.json
Normal file
4
docz/docs/03-demos/11-static/_category_.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"label": "Content and Static Sites",
|
||||
"position": 11
|
||||
}
|
86
docz/docs/03-demos/11-static/index.md
Normal file
86
docz/docs/03-demos/11-static/index.md
Normal file
@ -0,0 +1,86 @@
|
||||
---
|
||||
title: Content and Static Sites
|
||||
pagination_prev: demos/extensions/index
|
||||
pagination_next: demos/gsheet
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
With the advent of server-side frameworks and content management systems, it is
|
||||
possible to build sites whose source of truth is a spreadsheet! This demo
|
||||
explores a number of approaches.
|
||||
|
||||
## Flow
|
||||
|
||||
At its core, the site generators provide a structure for supplying content and
|
||||
templates. During a publish step, the generators will analyze the content and
|
||||
generate web pages by applying the template to the content. It is spiritually
|
||||
similar to "Mail Merge".
|
||||
|
||||
This separation of content and presentation makes it easy for analysts and other
|
||||
spreadsheet users to generate files with their data and quickly update websites!
|
||||
|
||||
#### Live Reload
|
||||
|
||||
Many frameworks offer a development flow which watches files for changes. When
|
||||
using a spreadsheet as the data source, this allows the content creators to see
|
||||
updates in a preview environment as they make changes to the spreadsheet!
|
||||
|
||||
The following GIF animation shows a static site generator in development mode.
|
||||
The user is editing a spreadsheet with Numbers. Every time the page is saved,
|
||||
the browser refreshes to show the new content.
|
||||
|
||||
![Live example](pathname:///static/live.gif)
|
||||
|
||||
## Ecosystem
|
||||
|
||||
:::note Recommendation
|
||||
|
||||
It is strongly recommended to use a framework that provides an official plugin
|
||||
for working with SheetJS. Lume is a great choice for getting started. GatsbyJS
|
||||
is excellent for teams well-versed in the React JS framework.
|
||||
|
||||
:::
|
||||
|
||||
### Official
|
||||
|
||||
Some frameworks provide official extensions They are strongly recommended for
|
||||
greenfield projects. Demos:
|
||||
|
||||
<ul>{useCurrentSidebarCategory().items.filter(item => item.customProps?.type == "native").map(item => {
|
||||
const listyle = (item.customProps?.icon) ? {
|
||||
listStyleImage: `url("${item.customProps.icon}")`
|
||||
} : {};
|
||||
return (<li style={listyle} {...(item.customProps?.class ? {className: item.customProps.class}: {})}>
|
||||
<a href={item.href}>{item.label}</a>{item.customProps?.summary && (" - " + item.customProps.summary)}
|
||||
</li>);
|
||||
})}</ul>
|
||||
|
||||
|
||||
### Bundlers
|
||||
|
||||
Bundlers can run JS code and process assets during development and during site
|
||||
builds. Custom plugins can extract data from spreadsheets. Demos:
|
||||
|
||||
<ul>{useCurrentSidebarCategory().items.filter(item => item.customProps?.type == "bundler").map(item => {
|
||||
const listyle = (item.customProps?.icon) ? {
|
||||
listStyleImage: `url("${item.customProps.icon}")`
|
||||
} : {};
|
||||
return (<li style={listyle} {...(item.customProps?.class ? {className: item.customProps.class}: {})}>
|
||||
<a href={item.href}>{item.label}</a>{item.customProps?.summary && (" - " + item.customProps.summary)}
|
||||
</li>);
|
||||
})}</ul>
|
||||
|
||||
### Workarounds
|
||||
|
||||
Other site generators require workarounds for various limitations and assumptions:
|
||||
|
||||
<ul>{useCurrentSidebarCategory().items.filter(item => !item?.customProps?.type).map(item => {
|
||||
const listyle = (item.customProps?.icon) ? {
|
||||
listStyleImage: `url("${item.customProps.icon}")`
|
||||
} : {};
|
||||
return (<li style={listyle} {...(item.customProps?.class ? {className: item.customProps.class}: {})}>
|
||||
<a href={item.href}>{item.label}</a>{item.customProps?.summary && (" - " + item.customProps.summary)}
|
||||
</li>);
|
||||
})}</ul>
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Google Sheets
|
||||
pagination_prev: demos/extensions/index
|
||||
pagination_prev: demos/static/index
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
|
@ -55,23 +55,35 @@ run in the web browser, demos will include interactive examples.
|
||||
- [`NeutralinoJS`](/docs/demos/desktop/neutralino)
|
||||
- [`React Native for Desktop`](/docs/demos/desktop/reactnative)
|
||||
|
||||
### Content Management and Static Sites
|
||||
|
||||
- [`Lume`](/docs/demos/static/lume)
|
||||
- [`GatsbyJS`](/docs/demos/static/gatsbyjs)
|
||||
- [`ViteJS`](/docs/demos/static/vitejs)
|
||||
- [`NextJS`](/docs/demos/static/nextjs)
|
||||
- [`NuxtJS`](/docs/demos/static/nuxtjs)
|
||||
|
||||
### App Extensions
|
||||
|
||||
- [`Excel JavaScript API`](/docs/demos/extensions/excelapi)
|
||||
- [`ExtendScript for Adobe Apps`](/docs/demos/extensions/extendscript)
|
||||
- [`Chrome and Chromium Extensions`](/docs/demos/extensions/chromium)
|
||||
|
||||
### Cloud Platforms
|
||||
|
||||
- [`Amazon Web Services`](/docs/demos/cloud/aws)
|
||||
- [`Azure Functions and Storage`](/docs/demos/cloud/azure)
|
||||
- [`NetSuite SuiteScript`](/docs/demos/cloud/netsuite)
|
||||
- [`Salesforce Lightning Web Components`](/docs/demos/cloud/salesforce)
|
||||
|
||||
### Platforms and Integrations
|
||||
|
||||
- [`Command-Line Tools`](/docs/demos/cli)
|
||||
- [`iOS and Android Mobile Applications`](/docs/demos/mobile)
|
||||
- [`NodeJS Server-Side Processing`](/docs/demos/server#nodejs)
|
||||
- [`Deno Server-Side Processing`](/docs/demos/server#deno)
|
||||
- [`Content Management and Static Sites`](/docs/demos/content)
|
||||
- [`Chrome and Chromium Extensions`](/docs/demos/chromium)
|
||||
- [`Google Sheets API`](/docs/demos/gsheet)
|
||||
- [`ExtendScript for Adobe Apps`](/docs/demos/extendscript)
|
||||
- [`NetSuite SuiteScript`](/docs/demos/cloud/netsuite)
|
||||
- [`Salesforce Lightning Web Components`](/docs/demos/cloud/salesforce)
|
||||
- [`Excel JavaScript API`](/docs/demos/excelapi)
|
||||
- [`Headless Automation`](/docs/demos/headless)
|
||||
- [`Other JavaScript Engines`](/docs/demos/engines)
|
||||
- [`Azure Functions and Storage`](/docs/demos/cloud/azure)
|
||||
- [`Amazon Web Services`](/docs/demos/cloud/aws)
|
||||
- [`Databases and Structured Data Stores`](/docs/demos/database)
|
||||
- [`NoSQL and Unstructured Data Stores`](/docs/demos/nosql)
|
||||
- [`Legacy Internet Explorer`](/docs/demos/frontend/legacy#internet-explorer)
|
||||
|
@ -171,6 +171,7 @@ const config = {
|
||||
{ from: '/docs/demos/excel', to: '/docs/demos/' },
|
||||
{ from: '/docs/getting-started/demos/', to: '/docs/demos/' },
|
||||
{ from: '/docs/getting-started/demos/excel', to: '/docs/demos/' },
|
||||
{ from: '/docs/demos/content', to: '/docs/demos/static/' },
|
||||
/* frontend */
|
||||
{ from: '/docs/demos/angular', to: '/docs/demos/frontend/angular/' },
|
||||
{ from: '/docs/demos/react', to: '/docs/demos/frontend/react/' },
|
||||
|
BIN
docz/static/static/live.gif
Normal file
BIN
docz/static/static/live.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 624 KiB |
Loading…
Reference in New Issue
Block a user