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 389e0810..5d60ab70 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 487c4429..236c8eac 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 384c7e62..949cb0c1 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 aeb95039..fc2dcbfc 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 7ad71e9a..0a3bceda 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 00000000..29bfdcaa --- /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 00000000..632ddcf6 --- /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 139c7527..3f8a1995 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 69b12bc9..b511e207 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 280322bf..5906c4f6 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 ff0a8309..05a78181 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 00000000..f86ad072 --- /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 00000000..6682ade9 --- /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 beb3b2d5..53a4de3a 100644 Binary files a/docz/static/next/sheetjs.xlsx and b/docz/static/next/sheetjs.xlsx differ diff --git a/docz/static/next/styles.css b/docz/static/next/styles.css new file mode 100644 index 00000000..88169db3 --- /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