From ae138cc32776f2793747ad0dba2d07cc483657a4 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Fri, 26 May 2023 18:50:23 -0400 Subject: [PATCH] next-asset-module --- .../01-installation/03-nodejs.md | 40 +- docz/docs/03-demos/04-static/08-nextjs.md | 504 +++++++++++++++--- docz/docs/03-demos/12-engines/01_duktape.md | 3 +- docz/docs/03-demos/12-engines/02_v8.md | 3 +- docz/static/next/[id].js | 30 +- docz/static/next/_app.js | 5 + docz/static/next/base64-loader.js | 7 + docz/static/next/getServerSideProps.js | 9 +- docz/static/next/getStaticPaths.js | 34 +- docz/static/next/getStaticProps.js | 32 +- docz/static/next/index.js | 30 +- docz/static/next/jsconfig.json | 8 + docz/static/next/next.config.js | 12 + docz/static/next/sheetjs.xlsx | Bin 10557 -> 10842 bytes docz/static/next/styles.css | 5 + 15 files changed, 571 insertions(+), 151 deletions(-) create mode 100644 docz/static/next/_app.js create mode 100644 docz/static/next/base64-loader.js create mode 100644 docz/static/next/jsconfig.json create mode 100644 docz/static/next/next.config.js create mode 100644 docz/static/next/styles.css diff --git a/docz/docs/02-getting-started/01-installation/03-nodejs.md b/docz/docs/02-getting-started/01-installation/03-nodejs.md index 389e081..5d60ab7 100644 --- a/docz/docs/02-getting-started/01-installation/03-nodejs.md +++ b/docz/docs/02-getting-started/01-installation/03-nodejs.md @@ -7,13 +7,12 @@ sidebar_custom_props: --- import current from '/version.js'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; # NodeJS -import Tabs from '@theme/Tabs'; -import TabItem from '@theme/TabItem'; - Tarballs are available on .

https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz is the URL for version {current}

@@ -158,3 +157,38 @@ XLSX.stream.set_readable(Readable); import * as cpexcel from 'xlsx/dist/cpexcel.full.mjs'; XLSX.set_cptable(cpexcel); ``` + +#### NextJS + +:::warning + +`fs` cannot be imported from the top level in NextJS pages. This will not work: + +```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 ! */ +// highlight-next-line +import * as fs from 'fs'; // this import will fail +set_fs(fs); +``` + +::: + +`fs` should be loaded with a dynamic import within a lifecycle function: + +```js title="index.js" +/* it is safe to import the library from the top level */ +import { readFile, utils, set_fs } from 'xlsx'; +import { join } from 'path'; +import { cwd } from 'process'; + +export async function getServerSideProps() { +// highlight-next-line + set_fs(await import("fs")); // dynamically import 'fs' in `getServerSideProps` + const wb = readFile(join(cwd(), "public", "sheetjs.xlsx")); + // ... +} +``` + +The [NextJS demo](/docs/demos/static/nextjs) includes complete examples. diff --git a/docz/docs/03-demos/04-static/08-nextjs.md b/docz/docs/03-demos/04-static/08-nextjs.md index 487c442..236c8ea 100644 --- a/docz/docs/03-demos/04-static/08-nextjs.md +++ b/docz/docs/03-demos/04-static/08-nextjs.md @@ -5,61 +5,36 @@ pagination_next: demos/mobile/index --- import current from '/version.js'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; import CodeBlock from '@theme/CodeBlock'; :::note -This was tested against `next v13.1.1` on 2023 January 14. +This was tested against `next v13.4.4` on 2023 May 26. ::: -:::info +The [NodeJS module](/docs/getting-started/installation/nodejs) can be imported +from pages or loaded in Webpack loaders. -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! +:::warning + +[`import`](/docs/getting-started/installation/nodejs#esm-import) does not load +NodeJS native modules. The Installation section includes a note on dynamic +import of `fs` within lifecycle methods. ::: -The general strategy with NextJS apps is to generate HTML snippets or data from -the lifecycle functions and reference them in the template. +NextJS best practices have evolved over time, but there are three key parts: -HTML output can be generated using `XLSX.utils.sheet_to_html` and inserted into -the document using the `dangerouslySetInnerHTML` attribute: +1) [Loading Data](#loading-data): NextJS can read files in lifecycle methods OR +custom Webpack loaders can create asset modules. -```jsx -export default function Index({html, type}) { return ( - // ... -// highlight-next-line -
- // ... -); } -``` +2) [Lifecycle Methods](#nextjs-strategies): NextJS includes strategies for +static pages (`getStaticProps`) as well as dynamic pages (`getServerSideProps`). -:::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 - // ... -} -``` - -::: +3) [Data Presentation](#data-presentation): Pages use React and JSX. :::caution Next 13+ and SWC @@ -75,6 +50,154 @@ module.exports = { ::: +## Loading Data + +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 methods. + +Asset modules are appropriate for static sites when the file names are known in +advance. Performing file read operations in lifecycle methods is more flexible +but does not support live reloading. + +### Asset Module + +:::caution + +When the demo was last tested, Turbopack did not support true raw loaders. For +development use, the normal `npx next dev` should be used. + +::: + +The following diagram depicts the workbook waltz: + +```mermaid +flowchart LR + file[(workbook\nfile)] + subgraph SheetJS operations + base64(base64\nstring) + aoo(array of\nobjects) + end + html{{HTML\nTABLE}} + file --> |base64-loader.js\ncustom plugin| base64 + base64 --> |page\nlifecycle method| aoo + aoo --> |page\nIndex method| html +``` + +In this flow, it is strongly recommended to make a loader return a Base64 string: + +```js title="base64-loader.js" +function loader(content) { + /* since `loader.raw` is true, `content` is a Buffer */ + return `export default '${content.toString("base64")}'`; +} +/* ensure the function receives a Buffer */ +loader.raw = true; +module.exports = loader; +``` + +The webpack configuration is controlled in `next.config.js`: + +```js title="next.config.js" +module.exports = { + webpack: (config) => { + // highlight-start + /* add to the webpack config module.rules array */ + config.module.rules.push({ + /* `test` matches file extensions */ + test: /\.(numbers|xls|xlsx|xlsb)/, + /* use the loader script */ + use: [ { loader: './base64-loader' } ] + }); + // highlight-end + return config; + } +}; +``` + +Module alias directories can be defined in `jsconfig.json` or `tsconfig.json`: + +```json title="jsconfig.json" +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + // highlight-next-line + "@/*": ["*"] + } + } +} +``` + +Pages can import the files directly. It is strongly recommended to store files +in a `data` folder. This example uses `getStaticProps` to parse `sheetjs.xlsx`: + +```jsx title="index.js" +import { read, utils } from 'xlsx'; +// highlight-next-line +import base64 from '@/data/sheetjs.xlsx'; + +export async function getStaticProps() { + /* parse base64 data */ + // highlight-next-line + const wb = read(base64, { type: "base64" }); + return { props: { + /* generate array of objects from the first sheet */ + data: utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]) + } }; +} +``` + +### Raw Operations + +Files can be read using `readFile` in lifecycle methods. The `cwd` method from +the `process` module will point to the root of the project. + +The following diagram depicts the workbook waltz: + +```mermaid +flowchart LR + file[(workbook\nfile)] + subgraph SheetJS operations + buffer(NodeJS\nBuffer) + aoo(array of\nobjects) + end + html{{HTML\nTABLE}} + file --> |page\nlifecycle method| buffer + buffer --> |page\nlifecycle method| aoo + aoo --> |page\nIndex method| html +``` + +This example reads the file `sheetjs.xlsx` in the `data` folder in the project: + +```js +import { readFile, utils, set_fs } from 'xlsx'; +import { join } from 'path'; +import { cwd } from 'process'; + +export async function getServerSideProps() { +// highlight-start + set_fs(await import("fs")); // dynamically import 'fs' when needed + const filename = join(cwd(), "data", "sheetjs.xlsx"); // /data/sheetjs.xlsx + const wb = readFile(filename); + // highlight-end + + /* generate and return the html from the first worksheet */ + const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]); + return { props: { data } }; +} +``` + +:::warning Reading and writing files during the build process + +As the NextJS workaround is non-traditional, it bears repeating: + +`fs` cannot be statically imported from the top level in NextJS pages. The +dynamic import must happen within a lifecycle function. + +::: + + ## NextJS Strategies NextJS currently provides 3 strategies: @@ -86,14 +209,17 @@ NextJS currently provides 3 strategies: ### Static Site Generation When using `getStaticProps`, the file will be read once during build time. +This example reads `sheetjs.xlsx` from the `data` folder: + + + ```js -import { readFile, set_fs, utils } from 'xlsx'; +import { read, utils } from 'xlsx'; +import base64 from '@/data/sheetjs.xlsx'; export async function getStaticProps() { - /* read file */ - set_fs(await import("fs")); - const wb = readFile(path_to_file) + const wb = read(base64, { type: "base64" }); /* generate and return the html from the first worksheet */ const html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); @@ -101,6 +227,28 @@ export async function getStaticProps() { }; ``` + + + +```js +import { readFile, set_fs, utils } from 'xlsx'; +import { join } from 'path'; +import { cwd } from 'process'; + +export async function getStaticProps() { + set_fs(await import("fs")); + const filename = join(cwd(), "data", "sheetjs.xlsx"); // /data/sheetjs.xlsx + const wb = readFile(filename); + + /* 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 @@ -108,10 +256,35 @@ implements both `getStaticPaths` and `getStaticProps`. - `getStaticPaths` should return an array of worksheet indices: + + + ```js +import { read } from 'xlsx'; +import base64 from '@/data/sheetjs.xlsx'; + +export async function getStaticPaths() { + /* read file */ + const wb = read(base64, { type: "base64" }); + + /* 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 }; +}; +``` + + + + +```js +import { readFile, set_fs } from 'xlsx'; +import { join } from 'path'; +import { cwd } from 'process'; + export async function getStaticPaths() { /* read file */ set_fs(await import("fs")); + const filename = join(cwd(), "data", "sheetjs.xlsx"); // /data/sheetjs.xlsx const wb = readFile(path); /* generate an array of objects that will be used for generating pages */ @@ -120,6 +293,9 @@ export async function getStaticPaths() { }; ``` + + + :::note For a pure static site, `fallback` must be set to `false`! @@ -128,10 +304,36 @@ For a pure static site, `fallback` must be set to `false`! - `getStaticProps` will generate the actual HTML for each page: + + + ```js +import { read, utils } from 'xlsx'; +import base64 from '@/data/sheetjs.xlsx'; + +export async function getStaticProps(ctx) { + /* read file */ + const wb = read(base64, { type: "base64" }); + + /* 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 } }; +}; +``` + + + + +```js +import { readFile, set_fs, utils } from 'xlsx'; +import { join } from 'path'; +import { cwd } from 'process'; + export async function getStaticProps(ctx) { /* read file */ set_fs(await import("fs")); + const filename = join(cwd(), "data", "sheetjs.xlsx"); // /data/sheetjs.xlsx const wb = readFile(path); /* get the corresponding worksheet and generate HTML */ @@ -141,6 +343,9 @@ export async function getStaticProps(ctx) { }; ``` + + + ### Server-Side Rendering :::caution Do not use on a static site @@ -156,13 +361,24 @@ changes frequently and a static site is undesirable. When using `getServerSideProps`, the file will be read on each request. + + + +:::caution Consider using a static strategy + +When using asset modules, the file names and file paths are processed during the +build step. The content is fixed. In this situation, a static approach such as +`getStaticProps` is strongly recommended. + +::: + ```js -import { readFile, set_fs, utils } from 'xlsx'; +import { read } from 'xlsx'; +import base64 from '@/data/sheetjs.xlsx'; export async function getServerSideProps() { /* read file */ - set_fs(await import("fs")); - const wb = readFile(path_to_file); + const wb = read(base64, { type: "base64" }); /* generate and return the html from the first worksheet */ const html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); @@ -170,24 +386,119 @@ export async function getServerSideProps() { }; ``` + + + + +```js +import { readFile, set_fs, utils } from 'xlsx'; +import { join } from 'path'; +import { cwd } from 'process'; + +export async function getServerSideProps() { + /* read file */ + set_fs(await import("fs")); + const filename = join(cwd(), "data", "sheetjs.xlsx"); // /data/sheetjs.xlsx + const wb = readFile(path); + + /* generate and return the html from the first worksheet */ + const html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]); + return { props: { html } }; +}; +``` + + + + +## Data Presentation + +[The React demo](/docs/demos/frontend/react) compares common approaches. + +### HTML + +HTML output can be generated using `XLSX.utils.sheet_to_html` and inserted into +the document using the `dangerouslySetInnerHTML` attribute: + +```mermaid +flowchart LR + subgraph SheetJS operations + data(File\nData) + code{{HTML\nTABLE}} + end + html{{Rendered\nPage}} + data --> |lifecycle\nsheet_to_html| code + code --> |Index\ninnerHTML| html +``` + +```jsx +export default function Index({html, type}) { return ( +
+); } +``` + +### Arrays of Objects + +Arrays of objects can be generated using `XLSX.utils.sheet_to_json` and inserted +into the document using standard JSX: + +```mermaid +flowchart LR + subgraph SheetJS operations + data(File\nData) + aoo(array of\nobjects) + end + html{{Rendered\nPage}} + data --> |lifecycle\nsheet_to_json| aoo + aoo --> |Index\nReact + JSX| html +``` + +```jsx +export default function Index({aoo, type}) { return ( + +// highlight-start + {aoo.map(row => ( + + + ))} +// highlight-end +
NameIndex
{row.Name}{row.Index}
+); } +``` + ## Demo +:::note + +This demo showcases the following SheetJS + NextJS flows: + +| Page | Loading Data | Lifecycle Method | SheetJS API | +|:----------------------|:-------------|:---------------------|:----------------| +| `/getStaticProps` | asset module | `getStaticProps` | `sheet_to_json` | +| `/sheets/[id]` | asset module | `getStaticPaths` | `sheet_to_html` | +| `/getServerSideProps` | lifecycle | `getServerSideProps` | `sheet_to_html` | + +::: + +### Initial Setup + 0) Disable NextJS telemetry: ```js -npx next@13.1.1 telemetry disable +npx next@13.4.4 telemetry disable ``` Confirm it is disabled by running ```js -npx next@13.1.1 telemetry status +npx next@13.4.4 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 sheetjs-next +cd sheetjs-next mkdir -p pages/sheets/ ``` @@ -201,13 +512,30 @@ curl -LO https://docs.sheetjs.com/next/sheetjs.xlsx 3) Install dependencies: {`\ -npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz next@13.1.1`} +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz next@13.4.4`} -4) Download test scripts: +4) Download NextJS config scripts and place in the root folder: + +- [`base64-loader.js`](pathname:///next/base64-loader.js) +- [`jsconfig.json`](pathname:///next/jsconfig.json) +- [`next.config.js`](pathname:///next/next.config.js) +- [`styles.css`](pathname:///next/styles.css) + +On Linux or MacOS or WSL: + +```bash +curl -LO https://docs.sheetjs.com/next/base64-loader.js +curl -LO https://docs.sheetjs.com/next/jsconfig.json +curl -LO https://docs.sheetjs.com/next/next.config.js +curl -LO https://docs.sheetjs.com/next/styles.css +``` + +5) Download test scripts: Download and place the following scripts in the `pages` subfolder: +- [`_app.js`](pathname:///next/_app.js) - [`index.js`](pathname:///next/index.js) - [`getServerSideProps.js`](pathname:///next/getServerSideProps.js) - [`getStaticPaths.js`](pathname:///next/getStaticPaths.js) @@ -227,6 +555,7 @@ On Linux or MacOS or WSL: ```bash cd pages +curl -LO https://docs.sheetjs.com/next/_app.js 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 @@ -236,10 +565,12 @@ curl -LOg 'https://docs.sheetjs.com/next/[id].js' cd ../.. ``` -5) Test the deployment: +### Testing + +6) Test the deployment: ```bash -npx next@13.1.1 +npx next@13.4.4 ``` Open a web browser and access: @@ -247,43 +578,50 @@ 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) +- `http://localhost:3000/getStaticPaths` shows a list (2 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: +7) While the development server is running, open the `/getStaticProps` page and +open `sheetjs.xlsx` with a spreadsheet editor. In the editor, add a row to the +bottom of the "Indices" worksheet. + +After saving the file, the website should refresh with the new row. + +### Production Build + +8) Stop the server and run a production build: ```bash -npx next@13.1.1 build +npx next@13.4.4 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 +┌ ○ / 563 B 74.4 kB +├ /_app 0 B 73.9 kB +├ ○ /404 182 B 74.1 kB +├ λ /getServerSideProps 522 B 74.4 kB +├ ● /getStaticPaths 2.89 kB 76.8 kB +├ ● /getStaticProps 586 B 74.5 kB +└ ● /sheets/[id] 522 B 74.4 kB ├ /sheets/0 - ├ /sheets/1 - └ /sheets/2 + └ /sheets/1 ``` As explained in the summary, the `/getStaticPaths` and `/getStaticProps` routes -are completely static. 3 `/sheets/#` pages were generated, corresponding to 3 +are completely static. 2 `/sheets/#` pages were generated, corresponding to 2 worksheets in the file. `/getServerSideProps` is server-rendered. -7) Try to build a static site: +9) Try to build a static site: ```bash -npx next@13.1.1 export +npx next@13.4.4 export ``` :::note The static export will fail! @@ -293,34 +631,38 @@ is still server-rendered. ::: -8) Delete `pages/getServerSideProps.js` and rebuild: +### Static Site + +10) Delete `pages/getServerSideProps.js` and rebuild: ```bash rm -f pages/getServerSideProps.js -npx next@13.1.1 build +npx next@13.4.4 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 +┌ ○ / 563 B 74.4 kB +├ /_app 0 B 73.9 kB +├ ○ /404 182 B 74.1 kB +├ ● /getStaticPaths 2.89 kB 76.8 kB +├ ● /getStaticProps 586 B 74.5 kB +└ ● /sheets/[id] 522 B 74.4 kB ├ /sheets/0 - ├ /sheets/1 - └ /sheets/2 + └ /sheets/1 ``` -9) Generate the static site: +11) Generate the static site: ```bash -npx next@13.1.1 export +npx next@13.4.4 export ``` -The static site will be written to the `out` subfolder, which can be hosted with +The static site will be written to the `out` subfolder + +12) Serve the static site: ```bash npx http-server out diff --git a/docz/docs/03-demos/12-engines/01_duktape.md b/docz/docs/03-demos/12-engines/01_duktape.md index 384c7e6..949cb0c 100644 --- a/docz/docs/03-demos/12-engines/01_duktape.md +++ b/docz/docs/03-demos/12-engines/01_duktape.md @@ -236,7 +236,8 @@ sequenceDiagram ## Bindings -Duktape is easily embeddable. Bindings exist for many languages. +Bindings exist for many languages. As these bindings require "native" code, they +may not work on every platform. ### Perl diff --git a/docz/docs/03-demos/12-engines/02_v8.md b/docz/docs/03-demos/12-engines/02_v8.md index aeb9503..fc2dcbf 100644 --- a/docz/docs/03-demos/12-engines/02_v8.md +++ b/docz/docs/03-demos/12-engines/02_v8.md @@ -263,7 +263,8 @@ file `sheetjsw.xlsb` will be created. That file can be opened with Excel. ## Bindings -V8 is easily embeddable. Bindings exist for many languages. +Bindings exist for many languages. As these bindings require "native" code, they +may not work on every platform. ### Rust diff --git a/docz/static/next/[id].js b/docz/static/next/[id].js index 7ad71e9..0a3bced 100644 --- a/docz/static/next/[id].js +++ b/docz/static/next/[id].js @@ -1,28 +1,25 @@ import Head from 'next/head'; -import { readFile, set_fs, utils } from 'xlsx'; -import { join } from 'path'; -import { cwd } from 'process'; +import { read, utils } from 'xlsx'; +import base64 from "@/sheetjs.xlsx"; -export default function Index({type, html, name}) { return (
+export default function Index({type, html, name}) { return ( <> {`SheetJS Next.JS ${type} Demo`} - -
-    

{`SheetJS Next.JS ${type} Demo`}

- This demo reads from /sheetjs.xlsx

- {name} -
-
-
); } +

{`SheetJS Next.JS ${type} Demo`}

+

+ This demo reads from /sheetjs.xlsx

+ Sheet name: {name}
+

+
+ ); } let cache = []; export async function getStaticProps(ctx) { if(!cache || !cache.length) { - set_fs(await import("fs")); - const wb = readFile(join(cwd(), "sheetjs.xlsx")); + const wb = read(base64, {type: "base64"}); cache = wb.SheetNames.map((name) => ({ name, sheet: wb.Sheets[name] })); } const entry = cache[ctx.params.id]; @@ -37,11 +34,10 @@ export async function getStaticProps(ctx) { } export async function getStaticPaths() { - set_fs(await import("fs")); - const wb = readFile(join(cwd(), "sheetjs.xlsx")); + const wb = read(base64, {type: "base64"}); cache = wb.SheetNames.map((name) => ({ name, sheet: wb.Sheets[name] })); return { - paths: wb.SheetNames.map((name, idx) => ({ params: { id: idx.toString() } })), + paths: wb.SheetNames.map((_, idx) => ({ params: { id: idx.toString() } })), fallback: false, }; } diff --git a/docz/static/next/_app.js b/docz/static/next/_app.js new file mode 100644 index 0000000..29bfdca --- /dev/null +++ b/docz/static/next/_app.js @@ -0,0 +1,5 @@ +import '../styles.css' + +export default function MyApp({ Component, pageProps }) { + return +} diff --git a/docz/static/next/base64-loader.js b/docz/static/next/base64-loader.js new file mode 100644 index 0000000..632ddcf --- /dev/null +++ b/docz/static/next/base64-loader.js @@ -0,0 +1,7 @@ +function loader(content) { + /* since `loader.raw` is true, `content` is a Buffer */ + return `export default '${content.toString("base64")}'`; +} +/* ensure the function receives a Buffer */ +loader.raw = true; +module.exports = loader; \ No newline at end of file diff --git a/docz/static/next/getServerSideProps.js b/docz/static/next/getServerSideProps.js index 139c752..3f8a199 100644 --- a/docz/static/next/getServerSideProps.js +++ b/docz/static/next/getServerSideProps.js @@ -7,14 +7,13 @@ export default function Index({type, html}) { return (
{`SheetJS Next.JS ${type} Demo`} - -
-    

{`SheetJS Next.JS ${type} Demo`}

+

{`SheetJS Next.JS ${type} Demo`}

+

This demo reads from /sheetjs.xlsx

It generates HTML from the first sheet.

-

-
+

+
); } export async function getServerSideProps() { diff --git a/docz/static/next/getStaticPaths.js b/docz/static/next/getStaticPaths.js index 69b12bc..b511e20 100644 --- a/docz/static/next/getStaticPaths.js +++ b/docz/static/next/getStaticPaths.js @@ -1,30 +1,28 @@ import Head from 'next/head'; import Link from "next/link"; -import { readFile, set_fs, utils } from 'xlsx'; -import { join } from 'path'; -import { cwd } from 'process'; +import { read } from 'xlsx'; +import base64 from "@/sheetjs.xlsx"; -export default function Index({type, snames}) { return (
+export default function Index({type, snames}) { return ( <> {`SheetJS Next.JS ${type} Demo`} - -
-    

{`SheetJS Next.JS ${type} Demo`}

- This demo reads from /sheetjs.xlsx

- Each worksheet maps to a path:

-
    -{snames.map((sname, idx) => (
  • - {`Sheet index=${idx} name="${sname}"`} -
  • ))} -
-
-
); } +

{`SheetJS Next.JS ${type} Demo`}

+

+ This demo reads from /sheetjs.xlsx

+ Each worksheet maps to a path:
+

+ + {snames.map((sname, idx) => ( + + + ))} +
Sheet NameURL
{sname}/sheets/{idx}
+ ); } export async function getStaticProps() { - set_fs(await import("fs")); - const wb = readFile(join(cwd(), "sheetjs.xlsx")) + const wb = read(base64, {type: "base64"}); return { props: { type: "getStaticPaths", diff --git a/docz/static/next/getStaticProps.js b/docz/static/next/getStaticProps.js index 280322b..5906c4f 100644 --- a/docz/static/next/getStaticProps.js +++ b/docz/static/next/getStaticProps.js @@ -1,29 +1,31 @@ import Head from 'next/head'; -import { readFile, set_fs, utils } from 'xlsx'; -import { join } from 'path'; -import { cwd } from 'process'; +import { read, utils } from 'xlsx'; +import base64 from "@/sheetjs.xlsx"; -export default function Index({type, html}) { return (
+export default function Index({type, aoo}) { return ( <> {`SheetJS Next.JS ${type} Demo`} - -
-    

{`SheetJS Next.JS ${type} Demo`}

- This demo reads from /sheetjs.xlsx

- It generates HTML from the first sheet.

-
-
-
); } +

{`SheetJS Next.JS ${type} Demo`}

+

+ This demo reads from /sheetjs.xlsx

+ It generates objects from the first sheet.

+

+ + {aoo.map((row, R) => ( + + + ))} +
NameIndex
{row.Name}{row.Index}
+ ); } export async function getStaticProps() { - set_fs(await import("fs")); - const wb = readFile(join(cwd(), "sheetjs.xlsx")) + const wb = read(base64, {type: "base64"}); return { props: { type: "getStaticProps", - html: utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]), + aoo: utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]), }, } } diff --git a/docz/static/next/index.js b/docz/static/next/index.js index ff0a830..05a7818 100644 --- a/docz/static/next/index.js +++ b/docz/static/next/index.js @@ -1,16 +1,26 @@ import Head from 'next/head'; -export default function Index() { return (
+export default function Index() { return ( <> SheetJS Next.JS Demo - -
-    

SheetJS Next.JS Demo

- This demo reads from /sheetjs.xlsx

- - getStaticProps

- - getServerSideProps

- - getStaticPaths
-
-
); } +

SheetJS Next.JS Demo

+

+ This demo reads from /sheetjs.xlsx
+

+ + + + + + + + + + + + + +
RouteNextJS Strategy
/getStaticPropsgetStaticProps
/getServerSidePropsgetServerSideProps
/getStaticPathsgetStaticPaths
+ ); } diff --git a/docz/static/next/jsconfig.json b/docz/static/next/jsconfig.json new file mode 100644 index 0000000..f86ad07 --- /dev/null +++ b/docz/static/next/jsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["*"] + } + } +} \ No newline at end of file diff --git a/docz/static/next/next.config.js b/docz/static/next/next.config.js new file mode 100644 index 0000000..6682ade --- /dev/null +++ b/docz/static/next/next.config.js @@ -0,0 +1,12 @@ +module.exports = { + webpack: (config) => { + /* add to the webpack config module.rules array */ + config.module.rules.push({ + /* `test` matches file extensions */ + test: /\.(numbers|xls|xlsx|xlsb)/, + /* use the loader script */ + use: [ { loader: './base64-loader' } ] + }); + return config; + } +}; \ No newline at end of file diff --git a/docz/static/next/sheetjs.xlsx b/docz/static/next/sheetjs.xlsx index beb3b2d5d35d6c35a305dae8e63f20aba1dbf4b9..53a4de3a6bd0d598e1d0b81cf9ad16dac79da71b 100644 GIT binary patch delta 6213 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 Tyz&SHBKv(`8D!xl`2G4n&2x9t diff --git a/docz/static/next/styles.css b/docz/static/next/styles.css new file mode 100644 index 0000000..88169db --- /dev/null +++ b/docz/static/next/styles.css @@ -0,0 +1,5 @@ +body, #app { + height: 100%; + font-size: 16px; + font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; +} \ No newline at end of file