docs.sheetjs.com/docz/docs/03-demos/04-static/06-webpack.md
2023-05-24 21:36:15 -04:00

6.8 KiB

title pagination_prev pagination_next sidebar_custom_props
Webpack demos/net/index demos/mobile/index
type
bundler

import current from '/version.js'; import CodeBlock from '@theme/CodeBlock';

:::note

This demo covers static asset imports. For processing files in the browser, the "Bundlers" demo includes an example.

:::

The NodeJS Module can be imported from Webpack loader scripts.

Webpack 5 Asset Module

Webpack 5 supports asset modules. With a special option, the loader will receive NodeJS Buffers that can be parsed. The dev server will even watch the files and reload the page in development mode!

The following diagram depicts the workbook waltz:

flowchart LR
  file[(workbook\nfile)]
  subgraph SheetJS operations
    buffer(NodeJS\nBuffer)
    aoo(array of\nobjects)
  end
  html{{HTML\nTABLE}}
  file --> |webpack.config.js\ncustom rule| buffer
  buffer --> |sheetjs-loader.js\ncustom plugin| aoo
  aoo --> |src/index.js\nfrontend code| html

Webpack Config

A special rule should be added to module.rules:

// ...
module.exports = {
  // ...
  module: {
    rules: [
      // highlight-start
      {
        /* `test` matches file extensions */
        test: /\.(numbers|xls|xlsx|xlsb)/,
        /* use the loader script */
        use: [ { loader: './sheetjs-loader' } ]
      }
      // highlight-end
    ]
  }
};

Hot Module Replacement enables reloading when files are updated:

// ...
module.exports = {
  // ...
  // highlight-start
  devServer: {
    static: './dist',
    hot: true,
  }
  // highlight-end
};

It is strongly recommended to add an alias to simplify imports:

// ...
module.exports = {
  // ...
  // highlight-start
  resolve: {
    alias: {
      /* `~` root of the project */
      "~": __dirname
    }
  },
  // highlight-end
};

SheetJS Loader

The SheetJS loader script must export a raw property that is set to true.

The base export is expected to be the loader function. That function receives the file contents as a Buffer, which can be parsed with XLSX.read. Typically this script is CommonJS so the require form should be used.

The loader in this demo will parse the first worksheet:

const XLSX = require("xlsx");

function loader(content) {
  /* since `loader.raw` is true, `content` is a Buffer */
  const wb = XLSX.read(content);
  /* pull data from first worksheet */
  var data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
  return `export default JSON.parse('${JSON.stringify(data)}')`;
}
/* ensure the function receives a Buffer */
loader.raw = true;
module.exports = loader;

Asset Imports

Spreadsheets can be imported using the plugin. Assuming pres.xlsx is stored in the data subfolder, ~/data/pres.xlsx can be imported from any script:

import data from '~/data/pres.xlsx';
/* `data` is an array of objects from data/pres.xlsx */

const elt = document.createElement('div');
elt.innerHTML = "<table><tr><th>Name</th><th>Index</th></tr>" +
  data.map((row) => `<tr>
    <td>${row.Name}</td>
    <td>${row.Index}</td>
  </tr>`).join("") +
"</table>";
document.body.appendChild(elt);

Webpack 5 Demo

:::note

This demo was last tested on 2023 May 24 against Webpack 5.84.0

:::

Initial Setup

  1. Create a new skeleton project:
mkdir sheetjs-wp5
cd sheetjs-wp5
npm init -y
npm install webpack@5.84.0 webpack-cli@5.1.1 webpack-dev-server@4.15.0 --save
mkdir -p dist
mkdir -p src
mkdir -p data
  1. Install the SheetJS NodeJS module:

{\ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz}

  1. Save the following to dist/index.html:
<!DOCTYPE html>
<html>
  <head>
    <title>SheetJS + Webpack 5</title>
  </head>
  <body>
   <script src="main.js"></script>
  </body>
</html>
  1. Save the following to src/index.js:
import data from '~/data/pres.xlsx';

const elt = document.createElement('div');
elt.innerHTML = "<table><tr><th>Name</th><th>Index</th></tr>" +
  data.map((row) => `<tr>
    <td>${row.Name}</td>
    <td>${row.Index}</td>
  </tr>`).join("") +
"</table>";
document.body.appendChild(elt);
  1. Save the following to webpack.config.js:
const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  devServer: {
    static: './dist',
    hot: true,
  },
  resolve: {
    alias: {
      "~": __dirname
    }
  },
  module: {
    rules: [
      {
        test: /\.(numbers|xls|xlsx|xlsb)/,
        use: [ { loader: './sheetjs-loader' } ]
      }
    ]
  }
};
  1. Save the following to sheetjs-loader.js:
const XLSX = require("xlsx");

function loader(content) {
  /* since `loader.raw` is true, `content` is a Buffer */
  const wb = XLSX.read(content);
  /* pull data from first worksheet */
  var data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
  return `export default JSON.parse('${JSON.stringify(data)}')`;
}
/* ensure the function receives a Buffer */
loader.raw = true;
module.exports = loader;
  1. Download https://sheetjs.com/pres.xlsx and save to the data folder:
curl -L -o data/pres.xlsx https://sheetjs.com/pres.xlsx

Live Reload Test

  1. Open the test file data/pres.xlsx in a spreadsheet editor like Excel.

  2. Start the development server:

npx webpack serve --mode=development

The terminal will print URLs for the development server:

<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:8080/
  1. Open the Loopback address (http://localhost:8080) in a web browser.

It should display a table of Presidents with "Name" and "Index" columns

  1. Add a new row to the spreadsheet and save the file.

Upon saving, the page should refresh with the new data.

Static Site Test

  1. Stop Webpack and build the site:
npx webpack --mode=production

The final site will be placed in the dist folder.

  1. Start a local web server to host the dist folder:
npx http-server dist

The command will print a list of URLs.

  1. Open one of the URLs printed in the previous step (http://localhost:8080) and confirm that the same data is displayed.

To verify that the page is independent of the spreadsheet, make some changes to the file and save. The page will not automatically update.

To verify that the data was added to the page, append main.js to the URL (http://localhost:8080/main.js) and view the source. The source will include president names. It will not include SheetJS library references!