docs.sheetjs.com/docz/docs/03-demos/11-static/09-nuxtjs.md
2023-01-14 22:36:13 -05:00

6.7 KiB
Raw Blame History

title pagination_prev pagination_next
NuxtJS demos/extensions/index 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:

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":

  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:

  <!-- 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:
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.

  1. Install the SheetJS library and start the server:
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.

  1. Download https://sheetjs.com/pres.xlsx and move to the content folder.
curl -L -o content/pres.xlsx https://sheetjs.com/pres.xlsx
  1. Modify nuxt.config.js as follows:
  • Add the following to the top of the script:
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:
  // Content module configuration: https://go.nuxtjs.dev/config-content
  content: {},

Replace the property with the following definition:

  // 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)

  1. Replace pages/index.vue with the following:
<!-- 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

  1. 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

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

  1. Stop the server (press CTRL+C in the terminal window) and run
npm run generate

This will create a static site in the dist folder, which can be served with:

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.