diff --git a/docz/docs/03-demos/01-frontend/08-bundler.md b/docz/docs/03-demos/01-frontend/08-bundler.md index f519073..e2cd211 100644 --- a/docz/docs/03-demos/01-frontend/08-bundler.md +++ b/docz/docs/03-demos/01-frontend/08-bundler.md @@ -1496,6 +1496,13 @@ Click on "Click here to export" to generate a file. +:::note + +The [Webpack section of the Content demo](/docs/demos/static/webpack) covers asset +loaders. They are ideal for static sites pulling data from sheets at build time. + +::: + ## WMR WMR works with no caveats. diff --git a/docz/docs/03-demos/04-static/05-vitejs.md b/docz/docs/03-demos/04-static/05-vitejs.md index f1c37ec..4c91731 100644 --- a/docz/docs/03-demos/04-static/05-vitejs.md +++ b/docz/docs/03-demos/04-static/05-vitejs.md @@ -12,7 +12,7 @@ import CodeBlock from '@theme/CodeBlock'; :::note This demo covers static asset imports. For processing files in the browser, the -["Bundlers" demo](/docs/demos/bundler#vite) includes an example. +["Bundlers" demo](/docs/demos/frontend/bundler#vite) includes an example. ::: @@ -39,6 +39,22 @@ will be included in the final bundle. For a pure static site, a plugin can load data into an array of row objects. The SheetJS work is performed in the plugin. The library is not loaded in the page! +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 --> |vite.config.js\ncustom plugin| buffer + buffer --> |vite.config.js\ncustom plugin| aoo + aoo --> |main.js\nfrontend code| html +``` + + ```js title="vite.config.js" import { readFileSync } from 'fs'; import { read, utils } from 'xlsx'; @@ -77,6 +93,21 @@ This loader pulls in data as a Base64 string that can be read with `XLSX.read`. While this approach works, it is not recommended since it loads the library in the front-end site. +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 --> |vite.config.js\ncustom plugin| base64 + base64 --> |main.js\nfrontend code| aoo + aoo --> |main.js\nfrontend code| html +``` + ```js title="vite.config.js" import { readFileSync } from 'fs'; import { defineConfig } from 'vite'; @@ -121,7 +152,7 @@ ${csv} :::note -This demo was tested on 2023 April 30 against `vite v4.3.3`. +This demo was tested on 2023 May 24 against `vite v4.3.8`. ::: diff --git a/docz/docs/03-demos/04-static/06-webpack.md b/docz/docs/03-demos/04-static/06-webpack.md new file mode 100644 index 0000000..03de037 --- /dev/null +++ b/docz/docs/03-demos/04-static/06-webpack.md @@ -0,0 +1,304 @@ +--- +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 = "" + + data.map((row) => ` + + + `).join("") + +"
NameIndex
${row.Name}${row.Index}
"; +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: + +{`\ +npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} + + +2) Save the following to `dist/index.html`: + +```html title="dist/index.html" + + + + SheetJS + Webpack 5 + + + + + +``` + +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 = "" + + data.map((row) => ` + + + `).join("") + +"
NameIndex
${row.Name}${row.Index}
"; +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 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: + +``` + [webpack-dev-server] Project is running at: + [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! diff --git a/docz/docs/03-demos/04-static/07-eleventy.md b/docz/docs/03-demos/04-static/07-eleventy.md index 37cab45..2cc0ae8 100644 --- a/docz/docs/03-demos/04-static/07-eleventy.md +++ b/docz/docs/03-demos/04-static/07-eleventy.md @@ -12,6 +12,21 @@ Eleventy is a static site generator. The [NodeJS module](/docs/getting-started/installation/nodejs) can be loaded in `.eleventy.js` and used in custom data file format parsers. +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 --> |.eleventy.js\ncustom parser| buffer + buffer --> |.eleventy.js\ncustom parser| aoo + aoo --> |index.njk\ntemplate| html +``` + ## Integration Details ### Data File Parser diff --git a/docz/docs/03-demos/04-static/09-nuxtjs.md b/docz/docs/03-demos/04-static/09-nuxtjs.md index 2f0d716..96cf1e4 100644 --- a/docz/docs/03-demos/04-static/09-nuxtjs.md +++ b/docz/docs/03-demos/04-static/09-nuxtjs.md @@ -25,6 +25,21 @@ The following deployments were tested: Nuxt Content v1 is designed to work with Nuxt v2. +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 --> |nuxt.config.js\ncustom parser| buffer + buffer --> |nuxt.config.js\ncustom parser| aoo + aoo --> |index.vue\ntemplate| html +``` + ### Configuration Through an override in `nuxt.config.js`, Nuxt Content will use custom parsers. @@ -246,6 +261,21 @@ will not change. Nuxt Content v2 is designed to work with Nuxt v3. +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 --> |custom module\ntransformer| buffer + buffer --> |custom module\ntransformer| aoo + aoo --> |index.vue\nContentRenderer| html +``` + ### Overview Nuxt Content `v2` supports custom transformers for controlling data. Although diff --git a/docz/docs/03-demos/04-static/11-svelte.md b/docz/docs/03-demos/04-static/11-svelte.md index f9a6747..9879eea 100644 --- a/docz/docs/03-demos/04-static/11-svelte.md +++ b/docz/docs/03-demos/04-static/11-svelte.md @@ -27,12 +27,12 @@ flowchart LR file[(workbook\nfile)] subgraph SheetJS operations base64(base64\nstring) - aoa(array of\nobjects) + aoo(array of\nobjects) end html{{HTML\nTABLE}} file --> |vite.config.js\ndata loader| base64 - base64 --> |+page.server.js\nload function| aoa - aoa --> |+page.svelte\ncomponent| html + base64 --> |+page.server.js\nload function| aoo + aoo --> |+page.svelte\ncomponent| html ``` ## Integration diff --git a/docz/docs/03-demos/04-static/12-astro.md b/docz/docs/03-demos/04-static/12-astro.md index 4d71ace..52cfad7 100644 --- a/docz/docs/03-demos/04-static/12-astro.md +++ b/docz/docs/03-demos/04-static/12-astro.md @@ -18,6 +18,21 @@ Astro is a site generator. Astro projects use ViteJS under the hood. They expose project configuration through the `vite` property in `astro.config.mjs`. The [ViteJS demo](/docs/demos/static/vitejs) examples work as expected! +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 --> |astro.config.mjs\nvite data loader| base64 + base64 --> |index.astro\nfrontmatter| aoo + aoo --> |index.astro\ntemplate body| html +``` + ## Integration :::note diff --git a/docz/docs/03-demos/05-mobile/04-ionic.md b/docz/docs/03-demos/05-mobile/04-ionic.md index 6fc1bcd..dda3eea 100644 --- a/docz/docs/03-demos/05-mobile/04-ionic.md +++ b/docz/docs/03-demos/05-mobile/04-ionic.md @@ -60,6 +60,7 @@ npx @capacitor/cli telemetry :::caution The latest version of Ionic uses CapacitorJS. These notes are for Cordova apps. +The [CapacitorJS demo](/docs/demos/mobile/capacitor) covers CapacitorJS apps. ::: diff --git a/docz/docs/03-demos/06-desktop/09-cli.md b/docz/docs/03-demos/06-desktop/09-cli.md index dc33631..980684d 100644 --- a/docz/docs/03-demos/06-desktop/09-cli.md +++ b/docz/docs/03-demos/06-desktop/09-cli.md @@ -17,68 +17,6 @@ it is feasible to build command-line tools for various workflows. This demo covers a number of strategies for building standalone processors. The goal is to generate CSV output from an arbitrary spreadsheet file. -## V8 - -The [V8](/docs/demos/engines/v8) demo covers standalone programs that embed the -V8 engine. This demo uses the Rust integration to generate a command line tool. - -
Tested Deployments (click to show) - -This demo was last tested in the following deployments: - -| Architecture | V8 Version | Date | -|:-------------|:-------------|:-----------| -| `darwin-x64` | `11.4.183.2` | 2023-05-22 | - -
- -0) Make a new folder for the project: - -```bash -mkdir sheetjs2csv -cd sheetjs2csv -``` - -1) Download the following scripts: - -- [`Cargo.toml`](pathname:///cli/Cargo.toml) -- [`snapshot.rs`](pathname:///cli/snapshot.rs) -- [`sheet2csv.rs`](pathname:///cli/sheet2csv.rs) - -```bash -curl -LO https://docs.sheetjs.com/cli/Cargo.toml -curl -LO https://docs.sheetjs.com/cli/snapshot.rs -curl -LO https://docs.sheetjs.com/cli/sheet2csv.rs -``` - -2) Download the [standalone build](/docs/getting-started/installation/standalone): - -{`\ -curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`} - - -3) Build the V8 snapshot: - -```bash -cargo build --bin snapshot -cargo run --bin snapshot -``` - -4) Build `sheet2csv`: - -```bash -cargo build --release --bin sheet2csv -mv target/release/sheet2csv . -``` - -5) Download the test file : - -```bash -curl -LO https://sheetjs.com/pres.numbers -``` - -Test by running `./sheet2csv pres.numbers` - ## NodeJS There are a few popular tools for compiling NodeJS scripts to CLI programs. @@ -200,6 +138,88 @@ example, on an Intel Mac, `nexe` generates `xlsx-cli` so the command is: ./xlsx-cli pres.numbers ``` +## V8 + +The [V8](/docs/demos/engines/v8) demo covers standalone programs that embed the +V8 engine. This demo uses the Rust integration to generate a command line tool. + +
Tested Deployments (click to show) + +This demo was last tested in the following deployments: + +| Architecture | V8 Version | Date | +|:-------------|:-------------|:-----------| +| `darwin-x64` | `11.4.183.2` | 2023-05-22 | +| `linux-x64` | `11.4.183.2` | 2023-05-23 | +| `win32-x64` | `11.4.183.2` | 2023-05-23 | + +
+ +0) Make a new folder for the project: + +```bash +mkdir sheetjs2csv +cd sheetjs2csv +``` + +1) Download the following scripts: + +- [`Cargo.toml`](pathname:///cli/Cargo.toml) +- [`snapshot.rs`](pathname:///cli/snapshot.rs) +- [`sheet2csv.rs`](pathname:///cli/sheet2csv.rs) + +```bash +curl -LO https://docs.sheetjs.com/cli/Cargo.toml +curl -LO https://docs.sheetjs.com/cli/snapshot.rs +curl -LO https://docs.sheetjs.com/cli/sheet2csv.rs +``` + +2) Download the [standalone build](/docs/getting-started/installation/standalone): + +{`\ +curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`} + + +3) Build the V8 snapshot: + +```bash +cargo build --bin snapshot +cargo run --bin snapshot +``` + +4) Build `sheet2csv` (`sheet2csv.exe` in Windows): + +```bash +cargo build --release --bin sheet2csv +``` + +5) Download the test file : + +```bash +curl -LO https://sheetjs.com/pres.numbers +``` + +6) Test the application: + + + + +```bash +mv target/release/sheet2csv . +./sheet2csv pres.numbers +``` + + + + +```bash +mv target/release/sheet2csv.exe . +./sheet2csv pres.numbers +``` + + + + ## Deno `deno compile` generates a standalone executable that includes the entire JS diff --git a/docz/docs/03-demos/12-engines/02_v8.md b/docz/docs/03-demos/12-engines/02_v8.md index c489c28..aeb9503 100644 --- a/docz/docs/03-demos/12-engines/02_v8.md +++ b/docz/docs/03-demos/12-engines/02_v8.md @@ -289,6 +289,14 @@ fn eval_code_ab(scope: &mut v8::HandleScope, code: &str) -> Vec { :::note +This demo was last tested in the following deployments: + +| Architecture | V8 Crate | Date | +|:-------------|:---------|:-----------| +| `darwin-x64` | `0.71.2` | 2023-05-22 | +| `linux-x64` | `0.71.2` | 2023-05-23 | +| `win32-x64` | `0.71.2` | 2023-05-23 | + This demo was last tested on 2023 May 22 against `v8` crate version `0.71.2` ::: diff --git a/docz/docs/03-demos/12-engines/04_jsc.md b/docz/docs/03-demos/12-engines/04_jsc.md index fefb8cb..433ece5 100644 --- a/docz/docs/03-demos/12-engines/04_jsc.md +++ b/docz/docs/03-demos/12-engines/04_jsc.md @@ -17,8 +17,8 @@ parsed and evaluated in a JSC context. :::warning Platform Limitations JavaScriptCore is primarily deployed in MacOS and iOS applications. There is -some experimental support through the Bun runtime, but production applications -intending to support Windows / Linux / Android should try to embed V8. +some experimental support through the Bun runtime, but apps intending to support +Windows / Linux / Android should try to embed [V8](/docs/demos/engines/v8). ::: @@ -77,6 +77,32 @@ context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectPro context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});"); ``` +
Direct Read (click to show) + +`Uint8Array` data can be passed directly, skipping string encoding and decoding: + +```swift +let url = URL(fileURLWithPath: file) +var data: Data! = try Data(contentsOf: url); +let count = data.count; +/* Note: the operations must be performed in the closure! */ +let wb: JSValue! = data.withUnsafeMutableBytes { (dataPtr: UnsafeMutableRawBufferPointer) in +// highlight-next-line + let ab: JSValue! = JSValue(jsValueRef: JSObjectMakeTypedArrayWithBytesNoCopy(context.jsGlobalContextRef, kJSTypedArrayTypeUint8Array, dataPtr.baseAddress, count, nil, nil, nil), in: context) + /* prepare options argument */ + context.evaluateScript(String(format: "var readopts = {type:'array', dense:true}")); + let readopts: JSValue = context.objectForKeyedSubscript("readopts"); + /* call XLSX.read */ + let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX"); + let readfunc: JSValue = XLSX.objectForKeyedSubscript("read"); + return readfunc.call(withArguments: [ab, readopts]); +} +``` + +For broad compatibility with Swift versions, the demo uses the String method. + +
+ ### Writing Files When writing to binary string in JavaScriptCore, the result should be stored in diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js index b64ce49..4ec9308 100644 --- a/docz/docusaurus.config.js +++ b/docz/docusaurus.config.js @@ -34,17 +34,13 @@ const config = { ({ docs: { sidebarPath: require.resolve('./sidebars.js'), - // Please change this to your repo. - // Remove this to remove the "edit this page" links. - // editUrl: - // 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + // editUrl: 'https://git.sheetjs.com/sheetjs/docs.sheetjs.com/src/branch/master/docz', }, //blog: { // showReadingTime: true, // Please change this to your repo. // Remove this to remove the "edit this page" links. - // editUrl: - // 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/', + // editUrl: 'https://git.sheetjs.com/sheetjs/docs.sheetjs.com/src/branch/master/docz/', //}, theme: { customCss: require.resolve('./src/css/custom.css'), @@ -60,6 +56,13 @@ const config = { themeConfig: /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ + mermaid: { + options: { + themeVariables: { + edgeLabelBackground: "" + } + } + }, navbar: { title: 'SheetJS CE Docs', logo: {