--- title: NextJS pagination_prev: demos/net/index pagination_next: demos/mobile/index --- import current from '/version.js'; import CodeBlock from '@theme/CodeBlock'; :::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
// ... ); } ``` :::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: