305 lines
6.8 KiB
Markdown
305 lines
6.8 KiB
Markdown
|
---
|
||
|
title: Webpack
|
||
|
pagination_prev: demos/net/index
|
||
|
pagination_next: demos/mobile/index
|
||
|
sidebar_custom_props:
|
||
|
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](/docs/demos/frontend/bundler#webpack) includes an example.
|
||
|
|
||
|
:::
|
||
|
|
||
|
The [NodeJS Module](/docs/getting-started/installation/nodejs) 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:
|
||
|
|
||
|
```mermaid
|
||
|
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`:
|
||
|
|
||
|
```js title="webpack.config.js"
|
||
|
// ...
|
||
|
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:
|
||
|
|
||
|
```js title="webpack.config.js"
|
||
|
// ...
|
||
|
module.exports = {
|
||
|
// ...
|
||
|
// highlight-start
|
||
|
devServer: {
|
||
|
static: './dist',
|
||
|
hot: true,
|
||
|
}
|
||
|
// highlight-end
|
||
|
};
|
||
|
```
|
||
|
|
||
|
It is strongly recommended to add an alias to simplify imports:
|
||
|
|
||
|
```js title="webpack.config.js"
|
||
|
// ...
|
||
|
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:
|
||
|
|
||
|
```js title="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;
|
||
|
```
|
||
|
|
||
|
### 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:
|
||
|
|
||
|
```js title="src/index.js"
|
||
|
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
|
||
|
|
||
|
0) Create a new skeleton project:
|
||
|
|
||
|
```bash
|
||
|
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:
|
||
|
|
||
|
<CodeBlock language="bash">{`\
|
||
|
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||
|
</CodeBlock>
|
||
|
|
||
|
2) Save the following to `dist/index.html`:
|
||
|
|
||
|
```html title="dist/index.html"
|
||
|
<!DOCTYPE html>
|
||
|
<html>
|
||
|
<head>
|
||
|
<title>SheetJS + Webpack 5</title>
|
||
|
</head>
|
||
|
<body>
|
||
|
<script src="main.js"></script>
|
||
|
</body>
|
||
|
</html>
|
||
|
```
|
||
|
|
||
|
3) Save the following to `src/index.js`:
|
||
|
|
||
|
```js title="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);
|
||
|
```
|
||
|
|
||
|
4) Save the following to `webpack.config.js`:
|
||
|
|
||
|
```js title="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' } ]
|
||
|
}
|
||
|
]
|
||
|
}
|
||
|
};
|
||
|
```
|
||
|
|
||
|
5) Save the following to `sheetjs-loader.js`:
|
||
|
|
||
|
```js title="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;
|
||
|
```
|
||
|
|
||
|
6) Download <https://sheetjs.com/pres.xlsx> and save to the `data` folder:
|
||
|
|
||
|
```bash
|
||
|
curl -L -o data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||
|
```
|
||
|
|
||
|
### Live Reload Test
|
||
|
|
||
|
7) Open the test file `data/pres.xlsx` in a spreadsheet editor like Excel.
|
||
|
|
||
|
8) Start the development server:
|
||
|
|
||
|
```bash
|
||
|
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/
|
||
|
```
|
||
|
|
||
|
9) Open the `Loopback` address (`http://localhost:8080`) in a web browser.
|
||
|
|
||
|
It should display a table of Presidents with "Name" and "Index" columns
|
||
|
|
||
|
10) Add a new row to the spreadsheet and save the file.
|
||
|
|
||
|
Upon saving, the page should refresh with the new data.
|
||
|
|
||
|
### Static Site Test
|
||
|
|
||
|
11) Stop Webpack and build the site:
|
||
|
|
||
|
```bash
|
||
|
npx webpack --mode=production
|
||
|
```
|
||
|
|
||
|
The final site will be placed in the `dist` folder.
|
||
|
|
||
|
12) Start a local web server to host the `dist` folder:
|
||
|
|
||
|
```bash
|
||
|
npx http-server dist
|
||
|
```
|
||
|
|
||
|
The command will print a list of URLs.
|
||
|
|
||
|
13) 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!
|