forked from sheetjs/docs.sheetjs.com
Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
a768b7ce8c | |||
5c895ea38b | |||
04d513b889 | |||
9d9478e6e5 | |||
9c0d1bc162 | |||
11d9dc7440 | |||
201f3d48fc | |||
55ce74bf8c | |||
a5e01f9476 | |||
67294eeeae | |||
5f443931f8 | |||
298297642d | |||
fdde52dfde | |||
14bd6a4ed0 | |||
1a80a55e76 | |||
945e5f02eb | |||
f0e5193b74 | |||
7f86e0b603 | |||
6e7c3e85dc | |||
349cc16819 | |||
833e9363d8 | |||
bf781deb59 | |||
e41febc653 | |||
c11146f21a | |||
c68d8e44ac | |||
f7f029169d | |||
2964215c95 | |||
bb40aa756f | |||
ea8129c3d4 | |||
954ab5fe7e | |||
b503ebc14d | |||
671729b289 | |||
922b84e1e3 | |||
e273f11b46 | |||
01481c65cf | |||
b699cfaf9a | |||
7b9c03cc1b | |||
09e390a090 | |||
b571592055 | |||
ac6e3daa1c | |||
c3741aaf05 | |||
0fda6d46ab | |||
2e44e0c2c8 | |||
98a3b79e9c | |||
92e3c5aa72 | |||
24eaed9f6b | |||
ecca85c9dc |
1
CNAME
1
CNAME
@ -1 +0,0 @@
|
||||
docs.sheetjs.com
|
3
Makefile
3
Makefile
@ -4,7 +4,6 @@ build:
|
||||
cd docz; npx -y pnpm build; cd ..
|
||||
rm -rf docs
|
||||
mv docz/build/ docs
|
||||
cp CNAME docs
|
||||
cp _headers docs
|
||||
|
||||
.PHONY: init
|
||||
@ -13,7 +12,7 @@ init:
|
||||
|
||||
.PHONY: dev
|
||||
dev:
|
||||
cd docz; npm run start -- --host=0.0.0.0; cd ..
|
||||
cd docz; npm run start -- --host=0.0.0.0 --no-open; cd ..
|
||||
|
||||
.PHONY: serve
|
||||
serve:
|
||||
|
73
README.md
73
README.md
@ -21,6 +21,75 @@ $ make spell # spell check (.spelling custom dictionary)
|
||||
$ make graph # build format graph and legend
|
||||
```
|
||||
|
||||
### Documentation Markup
|
||||
|
||||
The original documentation used [GFM](https://github.github.com/gfm/).
|
||||
|
||||
Pages currently use MDX v2.
|
||||
|
||||
<details>
|
||||
<summary><b>MDX Notes</b> (click to show)</summary>
|
||||
|
||||
**Multi-line tags**
|
||||
|
||||
Markdown and MDX v1 accept the following:
|
||||
|
||||
```
|
||||
<details><summary><b>MDX Notes</b> (click to show)</summary>
|
||||
|
||||
Note
|
||||
|
||||
</details>
|
||||
```
|
||||
|
||||
This is no longer valid in MDX v2. The `<summary>` part must be separated:
|
||||
|
||||
```
|
||||
<details>
|
||||
<summary><b>MDX Notes</b> (click to show)</summary>
|
||||
|
||||
Note
|
||||
|
||||
</details>
|
||||
```
|
||||
|
||||
**Shortlinks**
|
||||
|
||||
Markdown and MDX v1 support shortlinks:
|
||||
|
||||
```
|
||||
Scripts are available at <https://cdn.sheetjs.com>
|
||||
```
|
||||
|
||||
This is no longer valid in MDX v2. Autolinks should be used:
|
||||
|
||||
```
|
||||
Scripts are available at https://cdn.sheetjs.com
|
||||
```
|
||||
|
||||
**Variables**
|
||||
|
||||
Patterns such as
|
||||
|
||||
```
|
||||
<a href={`Foo${current}`}>Foo{current}</a>
|
||||
```
|
||||
|
||||
do not work in MDX v2. Instead, string literals and concatenation must be used:
|
||||
|
||||
```
|
||||
<a href={"Foo" + current + ""}>{"Foo" + current + ""}</a>
|
||||
```
|
||||
|
||||
**Tables**
|
||||
|
||||
MDX inconsistently requires different indentation levels for `TD` / `TH`, `TR`,
|
||||
`THEAD` / `TBODY` / `TFOOT`, and `TABLE` tags. Unconventional indentation is
|
||||
intentional.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
### Engine Compatibility Tables
|
||||
|
||||
`docz/src/data/engines.xls` is an XLML workbook that controls the compatibility
|
||||
@ -70,8 +139,8 @@ function SheetJSTestDropbox() {
|
||||
|
||||
## Other Notes
|
||||
|
||||
`src/theme/Admonition` was swizzled from 2.4.1 to enable `pass` for hiding
|
||||
`src/theme/Admonition` was swizzled from 3.2.1 to enable `pass` for hiding
|
||||
header text. See Docusaurus issue 8568 for more details.
|
||||
|
||||
`src/theme/prism-include-languages.js` was swizzled from 2.4.1 to support the
|
||||
`src/theme/prism-include-languages.js` was swizzled from 3.2.1 to support the
|
||||
Liquid language. See Docusaurus issue 6872 for more details.
|
@ -1,3 +0,0 @@
|
||||
# docs.sheetjs.com
|
||||
|
||||
<https://docs.sheetjs.com/>
|
14
docz/data/cli.js
Normal file
14
docz/data/cli.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { read, utils } from 'xlsx';
|
||||
import url from './cli.xls';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
const FrameworkData = () => {
|
||||
const [fw, setFW] = useState("");
|
||||
|
||||
useEffect(() => { (async() => {
|
||||
const wb = read(await (await fetch(url)).arrayBuffer(), { dense: true });
|
||||
setFW(utils.sheet_to_html(wb.Sheets["Frameworks"]));
|
||||
})(); }, []);
|
||||
return ( <div dangerouslySetInnerHTML={{__html: fw}}/> );
|
||||
};
|
||||
export default FrameworkData;
|
124
docz/data/cli.xls
Normal file
124
docz/data/cli.xls
Normal file
@ -0,0 +1,124 @@
|
||||
<?xml version="1.0"?>
|
||||
<?mso-application progid="Excel.Sheet"?>
|
||||
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
|
||||
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<WindowHeight>10620</WindowHeight>
|
||||
<WindowWidth>11020</WindowWidth>
|
||||
<WindowTopX>2260</WindowTopX>
|
||||
<WindowTopY>19600</WindowTopY>
|
||||
<ActiveSheet>1</ActiveSheet>
|
||||
<ProtectStructure>False</ProtectStructure>
|
||||
<ProtectWindows>False</ProtectWindows>
|
||||
</ExcelWorkbook>
|
||||
<Styles>
|
||||
<Style ss:ID="Default" ss:Name="Normal">
|
||||
<Alignment ss:Vertical="Bottom"/>
|
||||
<Borders/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"/>
|
||||
<Interior/>
|
||||
<NumberFormat/>
|
||||
<Protection/>
|
||||
</Style>
|
||||
<Style ss:ID="s16">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#1C1E21"/>
|
||||
</Style>
|
||||
<Style ss:ID="s17">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
|
||||
</Style>
|
||||
<Style ss:ID="s19">
|
||||
<Alignment ss:Horizontal="Center" ss:Vertical="Bottom"/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
|
||||
</Style>
|
||||
<Style ss:ID="s20">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#467886" ss:Underline="Single"/>
|
||||
</Style>
|
||||
</Styles>
|
||||
<Worksheet ss:Name="Frameworks">
|
||||
<Table ss:ExpandedColumnCount="7" ss:ExpandedRowCount="10" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Column ss:Index="2" ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">MacOS</Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Windows</Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Linux</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Framework</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/nexe"><Data ss:Type="String">nexe</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/boxednode"><Data ss:Type="String">boxednode</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/pkg"><Data ss:Type="String">pkg</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/nodesea#complete-example"><Data ss:Type="String">NodeJS SEA</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✱</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/bunsea#complete-example"><Data ss:Type="String">BunJS SEA</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/denosea#complete-example"><Data ss:Type="String">Deno SEA</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/v8#snapshots"><Data ss:Type="String">V8 Engine</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
</Table>
|
||||
</Worksheet>
|
||||
</Workbook>
|
14
docz/data/desktop.js
Normal file
14
docz/data/desktop.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { read, utils } from 'xlsx';
|
||||
import url from './desktop.xls';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
const FrameworkData = () => {
|
||||
const [fw, setFW] = useState("");
|
||||
|
||||
useEffect(() => { (async() => {
|
||||
const wb = read(await (await fetch(url)).arrayBuffer(), { dense: true });
|
||||
setFW(utils.sheet_to_html(wb.Sheets["Frameworks"]));
|
||||
})(); }, []);
|
||||
return ( <div dangerouslySetInnerHTML={{__html: fw}}/> );
|
||||
};
|
||||
export default FrameworkData;
|
115
docz/data/desktop.xls
Normal file
115
docz/data/desktop.xls
Normal file
@ -0,0 +1,115 @@
|
||||
<?xml version="1.0"?>
|
||||
<?mso-application progid="Excel.Sheet"?>
|
||||
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
|
||||
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<WindowHeight>10620</WindowHeight>
|
||||
<WindowWidth>11020</WindowWidth>
|
||||
<WindowTopX>2260</WindowTopX>
|
||||
<WindowTopY>19600</WindowTopY>
|
||||
<ActiveSheet>1</ActiveSheet>
|
||||
<ProtectStructure>False</ProtectStructure>
|
||||
<ProtectWindows>False</ProtectWindows>
|
||||
</ExcelWorkbook>
|
||||
<Styles>
|
||||
<Style ss:ID="Default" ss:Name="Normal">
|
||||
<Alignment ss:Vertical="Bottom"/>
|
||||
<Borders/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"/>
|
||||
<Interior/>
|
||||
<NumberFormat/>
|
||||
<Protection/>
|
||||
</Style>
|
||||
<Style ss:ID="s16">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#1C1E21"/>
|
||||
</Style>
|
||||
<Style ss:ID="s17">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
|
||||
</Style>
|
||||
<Style ss:ID="s19">
|
||||
<Alignment ss:Horizontal="Center" ss:Vertical="Bottom"/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
|
||||
</Style>
|
||||
<Style ss:ID="s20">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#467886" ss:Underline="Single"/>
|
||||
</Style>
|
||||
</Styles>
|
||||
<Worksheet ss:Name="Frameworks">
|
||||
<Table ss:ExpandedColumnCount="7" ss:ExpandedRowCount="10" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Column ss:Index="2" ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">MacOS</Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Windows</Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Linux</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Framework</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/desktop/electron#complete-example"><Data ss:Type="String">Electron</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✱</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/desktop/nwjs#complete-example"><Data ss:Type="String">NW.js</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✱</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/desktop/wails#complete-example"><Data ss:Type="String">Wails</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/desktop/tauri#complete-example"><Data ss:Type="String">Tauri</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/desktop/neutralino#complete-example"><Data ss:Type="String">NeutralinoJS</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✱</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/desktop/reactnative"><Data ss:Type="String">React Native</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✱</Data></Cell>
|
||||
<Cell ss:StyleID="s16"></Cell>
|
||||
<Cell ss:StyleID="s16"></Cell>
|
||||
</Row>
|
||||
</Table>
|
||||
</Worksheet>
|
||||
</Workbook>
|
@ -1,10 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<?mso-application progid="Excel.Sheet"?>
|
||||
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
|
||||
xmlns:o="urn:schemas-microsoft-com:office:office"
|
||||
xmlns:x="urn:schemas-microsoft-com:office:excel"
|
||||
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
|
||||
xmlns:html="http://www.w3.org/TR/REC-html40">
|
||||
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
|
||||
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<WindowHeight>10620</WindowHeight>
|
||||
<WindowWidth>11020</WindowWidth>
|
||||
@ -24,21 +20,21 @@
|
||||
<Protection/>
|
||||
</Style>
|
||||
<Style ss:ID="s16">
|
||||
<Font ss:FontName="Arial" x:Family="Swiss" ss:Size="12" ss:Color="#1C1E21"/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#1C1E21"/>
|
||||
</Style>
|
||||
<Style ss:ID="s17">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"
|
||||
ss:Bold="1"/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
|
||||
</Style>
|
||||
<Style ss:ID="s19">
|
||||
<Alignment ss:Horizontal="Center" ss:Vertical="Bottom"/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"
|
||||
ss:Bold="1"/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
|
||||
</Style>
|
||||
<Style ss:ID="s20">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#467886" ss:Underline="Single"/>
|
||||
</Style>
|
||||
</Styles>
|
||||
<Worksheet ss:Name="Engines">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="15" x:FullColumns="1"
|
||||
x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="18" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Column ss:Index="3" ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
@ -62,7 +58,7 @@
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/duktape#complete-example"><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -72,7 +68,7 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">V8</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/v8#complete-example"><Data ss:Type="String">V8</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C++</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -82,17 +78,27 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Rhino</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/rhino#complete-example"><Data ss:Type="String">Rhino</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Java</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Jint</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/jsc#complete-example"><Data ss:Type="String">JSC</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C++</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/jint#integration-example"><Data ss:Type="String">Jint</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C#</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -102,7 +108,7 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Goja</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/goja#complete-example"><Data ss:Type="String">Goja</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Go</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -112,27 +118,27 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Nashorn</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/nashorn#complete-example"><Data ss:Type="String">Nashorn</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Java</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">QuickJS</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/quickjs#integration-example"><Data ss:Type="String">QuickJS</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✱</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✱</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Hermes</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/hermes#integration-example"><Data ss:Type="String">Hermes</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C++</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -142,7 +148,7 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">ChakraCore</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/chakra#integration-example"><Data ss:Type="String">ChakraCore</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C++</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -152,7 +158,7 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Boa</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/boa#complete-example"><Data ss:Type="String">Boa</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Rust</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -162,17 +168,17 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">JE</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/perl#complete-example"><Data ss:Type="String">JE</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Perl</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">JerryScript</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/jerryscript#integration-example"><Data ss:Type="String">JerryScript</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -182,11 +188,31 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">GraalJS</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/graaljs#complete-example"><Data ss:Type="String">GraalJS</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Java</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/mujs#integration-example"><Data ss:Type="String">MuJS</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/jurassic#integration-example"><Data ss:Type="String">Jurassic.NET</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C#</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
@ -218,8 +244,7 @@
|
||||
</WorksheetOptions>
|
||||
</Worksheet>
|
||||
<Worksheet ss:Name="Bindings">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="12" x:FullColumns="1"
|
||||
x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="12" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Column ss:Index="3" ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
@ -243,47 +268,47 @@
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/duktape#perl"><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Perl</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/duktape#php"><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell><Data ss:Type="String">PHP</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/duktape#python"><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Python</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/duktape#zig"><Data ss:Type="String">Duktape</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Zig</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">V8</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/v8#rust"><Data ss:Type="String">V8</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Rust</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -293,7 +318,7 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">JSC</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/jsc#swift"><Data ss:Type="String">JSC</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Swift</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
@ -303,12 +328,12 @@
|
||||
<Cell ss:StyleID="s16"/>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell><Data ss:Type="String">ExecJS</Data></Cell>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/rb#complete-example"><Data ss:Type="String">ExecJS</Data></Cell>
|
||||
<Cell><Data ss:Type="String">Ruby</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✱</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
|
14
docz/data/mobile.js
Normal file
14
docz/data/mobile.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { read, utils } from 'xlsx';
|
||||
import url from './mobile.xls';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
const FrameworkData = () => {
|
||||
const [fw, setFW] = useState("");
|
||||
|
||||
useEffect(() => { (async() => {
|
||||
const wb = read(await (await fetch(url)).arrayBuffer(), { dense: true });
|
||||
setFW(utils.sheet_to_html(wb.Sheets["Frameworks"]));
|
||||
})(); }, []);
|
||||
return ( <div dangerouslySetInnerHTML={{__html: fw}}/> );
|
||||
};
|
||||
export default FrameworkData;
|
154
docz/data/mobile.xls
Normal file
154
docz/data/mobile.xls
Normal file
@ -0,0 +1,154 @@
|
||||
<?xml version="1.0"?>
|
||||
<?mso-application progid="Excel.Sheet"?>
|
||||
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
|
||||
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<WindowHeight>10620</WindowHeight>
|
||||
<WindowWidth>11020</WindowWidth>
|
||||
<WindowTopX>2260</WindowTopX>
|
||||
<WindowTopY>19600</WindowTopY>
|
||||
<ActiveSheet>1</ActiveSheet>
|
||||
<ProtectStructure>False</ProtectStructure>
|
||||
<ProtectWindows>False</ProtectWindows>
|
||||
</ExcelWorkbook>
|
||||
<Styles>
|
||||
<Style ss:ID="Default" ss:Name="Normal">
|
||||
<Alignment ss:Vertical="Bottom"/>
|
||||
<Borders/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"/>
|
||||
<Interior/>
|
||||
<NumberFormat/>
|
||||
<Protection/>
|
||||
</Style>
|
||||
<Style ss:ID="s16">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#1C1E21"/>
|
||||
</Style>
|
||||
<Style ss:ID="s17">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
|
||||
</Style>
|
||||
<Style ss:ID="s19">
|
||||
<Alignment ss:Horizontal="Center" ss:Vertical="Bottom"/>
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
|
||||
</Style>
|
||||
<Style ss:ID="s20">
|
||||
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#467886" ss:Underline="Single"/>
|
||||
</Style>
|
||||
</Styles>
|
||||
<Worksheet ss:Name="Frameworks">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="17" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Column ss:Index="3" ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String"></Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Real Device</Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">MacOS Sim</Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Windows Sim</Data></Cell>
|
||||
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Linux Sim</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Platform</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">iOS</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Android</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">iOS</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Android</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">iOS</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Android</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">iOS</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Android</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/mobile/reactnative"><Data ss:Type="String">React Native</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/mobile/nativescript"><Data ss:Type="String">NativeScript</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/mobile/capacitor"><Data ss:Type="String">CapacitorJS</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/mobile/ionic"><Data ss:Type="String">Ionic</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/mobile/flutter"><Data ss:Type="String">Dart + Flutter</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/mobile/quasar"><Data ss:Type="String">Quasar</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
|
||||
</Row>
|
||||
</Table>
|
||||
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<PageSetup>
|
||||
<Header x:Margin="0.3"/>
|
||||
<Footer x:Margin="0.3"/>
|
||||
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
|
||||
</PageSetup>
|
||||
<FreezePanes/>
|
||||
<FrozenNoSplit/>
|
||||
<SplitHorizontal>2</SplitHorizontal>
|
||||
<TopRowBottomPane>2</TopRowBottomPane>
|
||||
<ActivePane>2</ActivePane>
|
||||
<Panes>
|
||||
<Pane>
|
||||
<Number>3</Number>
|
||||
</Pane>
|
||||
<Pane>
|
||||
<Number>2</Number>
|
||||
<ActiveRow>12</ActiveRow>
|
||||
<ActiveCol>5</ActiveCol>
|
||||
</Pane>
|
||||
</Panes>
|
||||
<ProtectObjects>False</ProtectObjects>
|
||||
<ProtectScenarios>False</ProtectScenarios>
|
||||
</WorksheetOptions>
|
||||
</Worksheet>
|
||||
</Workbook>
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
title: Standalone Browser Scripts
|
||||
pagination_prev: getting-started/index
|
||||
pagination_next: getting-started/examples/index
|
||||
sidebar_position: 1
|
||||
@ -9,9 +10,7 @@ sidebar_custom_props:
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
# Standalone Browser Scripts
|
||||
|
||||
Each standalone release script is available at <https://cdn.sheetjs.com/>.
|
||||
Each standalone release script is available at https://cdn.sheetjs.com/.
|
||||
|
||||
<p>The current version is {current} and can be referenced as follows:</p>
|
||||
|
||||
@ -28,19 +27,19 @@ new versions are released!
|
||||
|
||||
:::
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
A number of services host older versions of the SheetJS libraries. Due to
|
||||
syncing issues, they are generally out of date.
|
||||
|
||||
**The SheetJS CDN** <https://cdn.sheetjs.com/> **is the authoritative source**
|
||||
**The SheetJS CDN** https://cdn.sheetjs.com/ **is the authoritative source**
|
||||
**for SheetJS scripts**
|
||||
|
||||
:::
|
||||
|
||||
## Browser Scripts
|
||||
|
||||
`xlsx.full.min.js` is the complete standalone script. It includes support for
|
||||
`xlsx.full.min.js` is the complete standalone script. It includes support for
|
||||
reading and writing many spreadsheet formats.
|
||||
|
||||
<CodeBlock language="html">{`\
|
||||
@ -48,13 +47,14 @@ reading and writing many spreadsheet formats.
|
||||
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
|
||||
</CodeBlock>
|
||||
|
||||
`xlsx.mini.min.js` is a slimmer build that omits the following features:
|
||||
|
||||
A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build:
|
||||
- codepage library skipped (no support for XLS encodings)
|
||||
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers
|
||||
- node stream utils removed
|
||||
- CSV and SYLK encodings (directly affecting users outside of the United States)
|
||||
- XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers file formats
|
||||
- Stream utility functions
|
||||
|
||||
<details><summary><b>How to integrate the mini build</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>How to integrate the mini build</b> (click to show)</summary>
|
||||
|
||||
Replace references to `xlsx.full.min.js` with `xlsx.mini.min.js`. Starting from
|
||||
scratch, a single script tag should be added at the top of the HTML page:
|
||||
@ -68,10 +68,11 @@ scratch, a single script tag should be added at the top of the HTML page:
|
||||
|
||||
### Vendoring
|
||||
|
||||
For general stability, "vendoring" scripts is the recommended approach:
|
||||
For general stability, making a local copy of SheetJS scripts ("vendoring") is
|
||||
strongly recommended. Vendoring decouples websites from SheetJS infrastructure.
|
||||
|
||||
<p>1) Download the script (<code parentName="pre">xlsx.full.min.js</code>) for
|
||||
the desired version. The current version is available at <a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>https://cdn.sheetjs.com/xlsx-{current}/package/dist/xlsx.full.min.js</a></p>
|
||||
<ol start="1"><li><p>Download the script (<code parentName="pre">xlsx.full.min.js</code>) for
|
||||
the desired version. The current version is available at <a href={"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/xlsx.full.min.js"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/xlsx.full.min.js"}</a></p></li></ol>
|
||||
|
||||
2) Move the script to a `public` folder with other scripts.
|
||||
|
||||
@ -94,11 +95,11 @@ use the CDN scripts directly. They should be downloaded and saved to a public
|
||||
directory in the site:
|
||||
|
||||
<ul>
|
||||
<li>Standalone: <a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.mini.min.js`}>https://cdn.sheetjs.com/xlsx-{current}/package/dist/xlsx.mini.min.js</a></li>
|
||||
<li>Shim: <a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>https://cdn.sheetjs.com/xlsx-{current}/package/dist/shim.min.js</a></li>
|
||||
<li>Standalone: <a href={"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/xlsx.mini.min.js"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/xlsx.mini.min.js"}</a></li>
|
||||
<li>Shim: <a href={"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/shim.min.js"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/shim.min.js"}</a></li>
|
||||
</ul>
|
||||
|
||||
Add a `script` reference to the shim before the standalone script:
|
||||
A `script` reference to the shim must be added before the standalone script:
|
||||
|
||||
```html
|
||||
<!-- add the shim first -->
|
||||
@ -122,9 +123,11 @@ importScripts("https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.mi
|
||||
|
||||
:::caution pass
|
||||
|
||||
This section refers to imports using `script type="module"`. For imports in
|
||||
modern projects using Webpack or React or Angular or VueJS, the installation is
|
||||
described [in "Frameworks and Bundlers"](/docs/getting-started/installation/frameworks).
|
||||
This section refers to imports in HTML pages using `script type="module"`.
|
||||
|
||||
The ["Frameworks and Bundlers"](/docs/getting-started/installation/frameworks)
|
||||
section covers imports in projects using bundlers (ViteJS) or frameworks
|
||||
(Kaioken / ReactJS / Angular / VueJS / Svelte)
|
||||
|
||||
:::
|
||||
|
||||
@ -203,14 +206,13 @@ xport.addEventListener("click", async() => {
|
||||
|
||||
## Bower
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
Bower is deprecated and the maintainers recommend using other tools.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
The Bower package manager plays nice with the CDN tarballs:
|
||||
The Bower package manager supports tarballs from the SheetJS CDN:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npx bower install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
|
@ -1,9 +1,10 @@
|
||||
---
|
||||
title: Frameworks and Bundlers
|
||||
pagination_prev: getting-started/index
|
||||
pagination_next: getting-started/examples/index
|
||||
sidebar_position: 2
|
||||
sidebar_custom_props:
|
||||
summary: Angular, React, VueJS, Webpack, etc.
|
||||
summary: Kaioken, Angular, React, VueJS, ViteJS, Webpack, etc.
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
@ -11,13 +12,11 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
# Frameworks and Bundlers
|
||||
|
||||
Each standalone release package is available at <https://cdn.sheetjs.com/>. The
|
||||
NodeJS package is designed to be used with frameworks and bundlers. It is a
|
||||
Each standalone release package is available at https://cdn.sheetjs.com/. The
|
||||
NodeJS package is designed to be used with frameworks and bundlers. It is a
|
||||
proper ECMAScript Module release which can be optimized with developer tools.
|
||||
|
||||
<p><a href={`https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}>https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz</a> is the URL for version {current}</p>
|
||||
<p><a href={"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}</a> is the URL for version {current}</p>
|
||||
|
||||
## Installation
|
||||
|
||||
@ -41,6 +40,24 @@ pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`
|
||||
yarn remove xlsx
|
||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::caution pass
|
||||
|
||||
Newer releases of Yarn may throw an error:
|
||||
|
||||
```
|
||||
Usage Error: It seems you are trying to add a package using a https:... url; we now require package names to be explicitly specified.
|
||||
Try running the command again with the package name prefixed: yarn add my-package@https:...
|
||||
```
|
||||
|
||||
The workaround is to prepend the URL with `xlsx@`:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add xlsx@https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@ -50,7 +67,7 @@ Once installed, the library can be imported under the name `xlsx`:
|
||||
import { read, writeFileXLSX } from "xlsx";
|
||||
```
|
||||
|
||||
The ["Bundlers" demo](/docs/demos/bundler) includes examples for specific tools.
|
||||
The ["Bundlers" demo](/docs/demos/frontend/bundler) includes complete examples.
|
||||
|
||||
:::tip pass
|
||||
|
||||
@ -68,7 +85,7 @@ Snyk security tooling may report errors involving "Prototype Pollution":
|
||||
Prototype Pollution [Medium Severity][https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926]
|
||||
```
|
||||
|
||||
As noted in the [Snyk report](https://web.archive.org/web/20231129100639/https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
|
||||
As noted in the [Snyk report](https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
|
||||
|
||||
> The issue is resolved in version 0.19.3
|
||||
|
||||
@ -81,14 +98,14 @@ Until Snyk fixes the bugs, the official recommendation is to
|
||||
|
||||
### Legacy Endpoints
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
Older releases are technically available on the public npm registry as `xlsx`,
|
||||
but the registry is out of date. The latest version on that registry is 0.18.5
|
||||
|
||||
This is a known registry bug
|
||||
|
||||
**The SheetJS CDN** <https://cdn.sheetjs.com/> **is the authoritative source**
|
||||
**The SheetJS CDN** https://cdn.sheetjs.com/ **is the authoritative source**
|
||||
**for SheetJS modules.**
|
||||
|
||||
For existing projects, the easiest approach is to uninstall and reinstall:
|
||||
@ -131,7 +148,8 @@ in `package.json` can control module resolution:
|
||||
|
||||
### Vendoring
|
||||
|
||||
For general stability, "vendoring" modules is the recommended approach:
|
||||
For general stability, making a local copy of SheetJS modules ("vendoring") is
|
||||
strongly recommended. Vendoring decouples projects from SheetJS infrastructure.
|
||||
|
||||
0) Remove any existing dependency on a project named `xlsx`:
|
||||
|
||||
@ -153,8 +171,8 @@ yarn remove xlsx`}
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<p>1) Download the tarball (<code parentName="pre">xlsx-{current}.tgz</code>) for the desired version. The current
|
||||
version is available at <a href={`https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}>https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz</a></p>
|
||||
<ol start="1"><li><p>Download the tarball (<code parentName="pre">xlsx-{current}.tgz</code>) for the desired version. The current
|
||||
version is available at <a href={"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}</a></p></li></ol>
|
||||
|
||||
2) Create a `vendor` subfolder at the root of your project and move the tarball
|
||||
to that folder. Add it to your project repository.
|
||||
@ -176,6 +194,23 @@ pnpm install --save file:vendor/xlsx-${current}.tgz`}
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add file:vendor/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::caution pass
|
||||
|
||||
Newer releases of Yarn may throw an error:
|
||||
|
||||
```
|
||||
Usage Error: The file:vendor/xlsx-0.20.2.tgz string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?
|
||||
```
|
||||
|
||||
The workaround is to prepend the URI with `xlsx@`:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add xlsx@file:vendor/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@ -203,13 +238,13 @@ var XLSX = require("xlsx");
|
||||
var read = XLSX.read, utils = XLSX.utils;
|
||||
```
|
||||
|
||||
The ["Bundlers" demo](/docs/demos/bundler) includes examples for specific tools.
|
||||
The ["Bundlers" demo](/docs/demos/frontend/bundler) includes complete examples.
|
||||
|
||||
### Dynamic Imports
|
||||
|
||||
Dynamic imports with `import()` will only download scripts when they are needed.
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
Dynamic `import` will always download the full contents of the imported scripts!
|
||||
|
||||
|
@ -12,9 +12,9 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
Package tarballs are available on <https://cdn.sheetjs.com>.
|
||||
Package tarballs are available on https://cdn.sheetjs.com.
|
||||
|
||||
<p><a href={`https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}>https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz</a> is the URL for version {current}</p>
|
||||
<p><a href={"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}</a> is the URL for version {current}</p>
|
||||
|
||||
## Installation
|
||||
|
||||
@ -38,6 +38,24 @@ pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`
|
||||
yarn remove xlsx
|
||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::caution pass
|
||||
|
||||
Newer releases of Yarn may throw an error:
|
||||
|
||||
```
|
||||
Usage Error: It seems you are trying to add a package using a https:... url; we now require package names to be explicitly specified.
|
||||
Try running the command again with the package name prefixed: yarn add my-package@https:...
|
||||
```
|
||||
|
||||
The workaround is to prepend the URL with `xlsx@`:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add xlsx@https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@ -57,7 +75,7 @@ Snyk security tooling may report errors involving "Prototype Pollution":
|
||||
Prototype Pollution [Medium Severity][https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926]
|
||||
```
|
||||
|
||||
As noted in the [Snyk report](https://web.archive.org/web/20231129100639/https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
|
||||
As noted in the [Snyk report](https://security.snyk.io/vuln/SNYK-JS-XLSX-5457926):
|
||||
|
||||
> The issue is resolved in version 0.19.3
|
||||
|
||||
@ -70,14 +88,14 @@ Until Snyk fixes the bugs, the official recommendation is to
|
||||
|
||||
### Legacy Endpoints
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
Older releases are technically available on the public npm registry as `xlsx`,
|
||||
but the registry is out of date. The latest version on that registry is 0.18.5
|
||||
|
||||
This is a known registry bug
|
||||
|
||||
**The SheetJS CDN** <https://cdn.sheetjs.com/> **is the authoritative source**
|
||||
**The SheetJS CDN** https://cdn.sheetjs.com/ **is the authoritative source**
|
||||
**for SheetJS modules.**
|
||||
|
||||
For existing projects, the easiest approach is to uninstall and reinstall:
|
||||
@ -120,7 +138,8 @@ in `package.json` can control module resolution:
|
||||
|
||||
### Vendoring
|
||||
|
||||
For general stability, "vendoring" modules is the recommended approach:
|
||||
For general stability, making a local copy of SheetJS modules ("vendoring") is
|
||||
strongly recommended. Vendoring decouples projects from SheetJS infrastructure.
|
||||
|
||||
0) Remove any existing dependency on a project named `xlsx`:
|
||||
|
||||
@ -142,8 +161,7 @@ yarn remove xlsx`}
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<p>1) Download the tarball (<code parentName="pre">xlsx-{current}.tgz</code>) for the desired version. The current
|
||||
version is available at <a href={`https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}>https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz</a></p>
|
||||
<ol start="1"><li><p>Download the tarball (<code parentName="pre">xlsx-{current}.tgz</code>) for the desired version. The current version is available at <a href={"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}</a></p></li></ol>
|
||||
|
||||
2) Create a `vendor` subfolder at the root of your project and move the tarball
|
||||
to that folder. Add it to your project repository.
|
||||
@ -165,6 +183,23 @@ pnpm install --save file:vendor/xlsx-${current}.tgz`}
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add file:vendor/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::caution pass
|
||||
|
||||
Newer releases of Yarn may throw an error:
|
||||
|
||||
```
|
||||
Usage Error: The file:vendor/xlsx-0.20.2.tgz string didn't match the required format (package-name@range). Did you perhaps forget to explicitly reference the package name?
|
||||
```
|
||||
|
||||
The workaround is to prepend the URI with `xlsx@`:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add xlsx@file:vendor/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
@ -237,7 +272,7 @@ XLSX.set_cptable(cpexcel);
|
||||
|
||||
#### NextJS
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
`fs` cannot be imported from the top level in NextJS pages. This will not work:
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
title: AMD (define)
|
||||
pagination_prev: getting-started/index
|
||||
pagination_next: getting-started/examples/index
|
||||
sidebar_position: 4
|
||||
@ -9,13 +10,11 @@ sidebar_custom_props:
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
# AMD (define)
|
||||
|
||||
Each standalone release script is available at <https://cdn.sheetjs.com/>.
|
||||
Each standalone release script is available at https://cdn.sheetjs.com/.
|
||||
|
||||
`xlsx.full.min.js` supports AMD with name `xlsx` out of the box.
|
||||
|
||||
<p><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>https://cdn.sheetjs.com/xlsx-{current}/package/dist/xlsx.full.min.js</a> is the URL for {current}</p>
|
||||
<p><a href={"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/xlsx.full.min.js"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/xlsx.full.min.js"}</a> is the URL for {current}</p>
|
||||
|
||||
:::note pass
|
||||
|
||||
@ -65,6 +64,65 @@ define(['N/file', 'xlsx'], function(file, XLSX) {
|
||||
|
||||
**More details are included in the [NetSuite demo](/docs/demos/cloud/netsuite#installation)**
|
||||
|
||||
:::caution Oracle Bugs
|
||||
|
||||
[NetSuite users reported](https://git.sheetjs.com/sheetjs/sheetjs/issues/3097)
|
||||
errors that stem from an Oracle issue. A sample error message is shown below.
|
||||
|
||||
```
|
||||
Fail to evaluate script: com.netsuite.suitescript.scriptobject.GraalValueAdapter@68d0f09d
|
||||
```
|
||||
|
||||
**This is a NetSuite bug. Only Oracle can fix the bug!**
|
||||
|
||||
It is strongly encouraged to escalate the issue with Oracle support.
|
||||
|
||||
NetSuite users have reported success with the following workaround:
|
||||
|
||||
1) Open the script in a text editor and search for `define(` in the code.
|
||||
|
||||
There will be exactly one instance:
|
||||
|
||||
```js
|
||||
define("xlsx",function(){
|
||||
```
|
||||
|
||||
Replace the `xlsx` with `sheetjs`:
|
||||
|
||||
```js
|
||||
define("sheetjs",function(){
|
||||
```
|
||||
|
||||
2) Use the new name in the JSON configuration:
|
||||
|
||||
```json title="JsLibraryConfig.json"
|
||||
{
|
||||
"paths": {
|
||||
// highlight-next-line
|
||||
"sheetjs": "/path/to/xlsx.full.min"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3) Use the new name in the array argument to the `define` function call:
|
||||
|
||||
```js title="SuiteScript"
|
||||
/**
|
||||
* @NApiVersion 2.x
|
||||
* ... more options ...
|
||||
// highlight-next-line
|
||||
* @NAmdConfig ./JsLibraryConfig.json
|
||||
*/
|
||||
// highlight-next-line
|
||||
define(['N/file', 'sheetjs'], function(file, XLSX) {
|
||||
// ^^^^^^^ ^^^^
|
||||
// new module name same variable
|
||||
// ... use XLSX here ...
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## SAP UI5
|
||||
|
||||
After downloading the script, it can be uploaded to the UI5 project and loaded
|
||||
@ -79,7 +137,7 @@ sap.ui.define([
|
||||
})
|
||||
```
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
**Copy and pasting code does not work** for SheetJS scripts as they contain
|
||||
Unicode characters that may be mangled. The standalone script should be
|
||||
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
title: ExtendScript
|
||||
pagination_prev: getting-started/index
|
||||
pagination_next: getting-started/examples/index
|
||||
sidebar_position: 5
|
||||
@ -8,13 +9,15 @@ sidebar_custom_props:
|
||||
|
||||
import current from '/version.js';
|
||||
|
||||
# ExtendScript
|
||||
ExtendScript is a dialect of JavaScript used in Photoshop and InDesign scripts.
|
||||
|
||||
Each standalone release script is available at <https://cdn.sheetjs.com/>.
|
||||
Each standalone release script is available at https://cdn.sheetjs.com/.
|
||||
|
||||
`xlsx.extendscript.js` is an ExtendScript build for Photoshop and InDesign.
|
||||
`xlsx.extendscript.js` is a special ExtendScript-compatible build. The script is
|
||||
carefully assembled to work around ExtendScript quirks. Due to bugs in various
|
||||
JavaScript minifiers and tools, scripts cannot be compressed or post-processed.
|
||||
|
||||
<p><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.extendscript.js`}>https://cdn.sheetjs.com/xlsx-{current}/package/dist/xlsx.extendscript.js</a> is the URL for {current}</p>
|
||||
<p><a href={"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/xlsx.extendscript.js"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/package/dist/xlsx.extendscript.js"}</a> is the URL for {current}</p>
|
||||
|
||||
After downloading the script, it can be directly referenced with `#include`:
|
||||
|
||||
@ -38,12 +41,15 @@ path is application-specific.
|
||||
| Photoshop | `\Presets\Scripts` within the Application folder |
|
||||
| InDesign | Windows > Utilities > Scripts, click `☰` > "Reveal in Explorer" |
|
||||
|
||||
:::note CEP usage
|
||||
:::note CEP and UXP usage
|
||||
|
||||
The ExtendScript build should be used when performing spreadsheet operations
|
||||
from the host context (within a `jsx` script file).
|
||||
|
||||
[The standalone scripts](/docs/getting-started/installation/standalone) should
|
||||
be added to CEP extension HTML.
|
||||
**CEP**: [The standalone scripts](/docs/getting-started/installation/standalone)
|
||||
should be added to CEP extension HTML.
|
||||
|
||||
**UXP**: [The standalone scripts](/docs/getting-started/installation/standalone)
|
||||
can be loaded directly in UXP scripts using the `require` function.
|
||||
|
||||
:::
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
title: Deno
|
||||
pagination_prev: getting-started/index
|
||||
pagination_next: getting-started/examples/index
|
||||
sidebar_position: 6
|
||||
@ -11,9 +12,9 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
# Deno
|
||||
Deno is a JavaScript runtime that can import scripts from URLs.
|
||||
|
||||
Module scripts and type definitions are available at <https://cdn.sheetjs.com/>.
|
||||
Module scripts and type definitions are available at https://cdn.sheetjs.com/.
|
||||
|
||||
Using the URL imports, `deno run` will automatically download scripts and types:
|
||||
|
||||
@ -22,7 +23,8 @@ Using the URL imports, `deno run` will automatically download scripts and types:
|
||||
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs';`}
|
||||
</CodeBlock>
|
||||
|
||||
The `@deno-types` comment instructs Deno to use the type definitions.
|
||||
The module URL is the ECMAScript Module build on the SheetJS CDN. `@deno-types`
|
||||
instructs Deno to use the type definitions from the SheetJS CDN.
|
||||
|
||||
:::caution Deno support is considered experimental.
|
||||
|
||||
@ -68,11 +70,11 @@ and the types URLs should be updated at the same time:
|
||||
|
||||
#### Deno Registry
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
The official Deno registry is out of date. This is a registry bug.
|
||||
|
||||
**The SheetJS CDN** <https://cdn.sheetjs.com/> **is the authoritative source**
|
||||
**The SheetJS CDN** https://cdn.sheetjs.com/ **is the authoritative source**
|
||||
**for SheetJS modules.**
|
||||
|
||||
:::
|
||||
|
@ -12,9 +12,9 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
Package tarballs are available on <https://cdn.sheetjs.com>.
|
||||
Package tarballs are available on https://cdn.sheetjs.com.
|
||||
|
||||
<p><a href={`https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}>https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz</a> is the URL for version {current}</p>
|
||||
<p><a href={"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}</a> is the URL for version {current}</p>
|
||||
|
||||
:::caution Bun support is considered experimental.
|
||||
|
||||
@ -50,8 +50,7 @@ For general stability, "vendoring" modules is the recommended approach:
|
||||
bun rm xlsx
|
||||
```
|
||||
|
||||
<p>1) Download the tarball (<code parentName="pre">xlsx-{current}.tgz</code>) for the desired version. The current
|
||||
version is available at <a href={`https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}>https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz</a></p>
|
||||
<ol start="1"><li><p>Download the tarball (<code parentName="pre">xlsx-{current}.tgz</code>) for the desired version. The current version is available at <a href={"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}>{"https://cdn.sheetjs.com/xlsx-" + current + "/xlsx-" + current + ".tgz"}</a></p></li></ol>
|
||||
|
||||
2) Create a `vendor` subfolder at the root of your project and move the tarball
|
||||
to that folder. Add it to your project repository.
|
||||
@ -118,7 +117,14 @@ builder requires a proper `package.json` that includes the SheetJS dependency.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This example was last tested on 2024-02-21 against BunJS 1.0.28 on macOS 14.3.1.
|
||||
This demo was last tested in the following deployments:
|
||||
|
||||
| Architecture | BunJS | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| `darwin-x64` | `1.1.4` | 2024-04-19 |
|
||||
| `win10-x64` | `1.1.4` | 2024-04-19 |
|
||||
| `win11-x64` | `1.1.8` | 2024-05-17 |
|
||||
| `linux-x64` | `1.1.4` | 2024-04-25 |
|
||||
|
||||
:::
|
||||
|
||||
@ -130,7 +136,14 @@ cd sheetjs-bun-dle
|
||||
echo "{}" > package.json
|
||||
```
|
||||
|
||||
1) Install the library:
|
||||
:::caution pass
|
||||
|
||||
In PowerShell, the redirect will add the UTF16LE BOM. Bun does not currently
|
||||
support the encoding. The file must be resaved in UTF8 (without BOM) or ASCII.
|
||||
|
||||
:::
|
||||
|
||||
1) Install the SheetJS package tarball:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
@ -147,7 +160,7 @@ import * as fs from 'fs';
|
||||
XLSX.set_fs(fs);
|
||||
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
@ -194,6 +207,19 @@ rm package.json bun.lockb SheetJSBun.js
|
||||
rm -rf ./node_modules
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
PowerShell does not support `rm -rf`. Instead, each file must be removed:
|
||||
|
||||
```powershell title="Windows Powershell commands"
|
||||
rm package.json
|
||||
rm bun.lockb
|
||||
rm SheetJSBun.js
|
||||
rm .\\node_modules -r -fo
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
At this point, `app.js` will be the only file in the project folder.
|
||||
|
||||
5) Run the script:
|
||||
|
@ -8,7 +8,7 @@ title: Installation
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
<https://cdn.sheetjs.com> is the primary software distribution site. Please
|
||||
https://cdn.sheetjs.com is the primary software distribution site. Please
|
||||
read the installation instructions for your use case:
|
||||
|
||||
<ul>{useCurrentSidebarCategory().items.map((item, index) => {
|
||||
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
title: Export Tutorial
|
||||
pagination_prev: getting-started/installation/index
|
||||
pagination_next: getting-started/roadmap
|
||||
sidebar_position: 2
|
||||
@ -9,8 +10,6 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
# Export Tutorial
|
||||
|
||||
Many modern data sources provide an API to download data in JSON format. Many
|
||||
users prefer to work in spreadsheet software. SheetJS libraries help bridge the
|
||||
gap by translating programmer-friendly JSON to user-friendly workbooks.
|
||||
@ -44,18 +43,19 @@ sequenceDiagram
|
||||
## Acquire Data
|
||||
|
||||
The raw data is available in JSON form[^1]. It has been mirrored at
|
||||
<https://sheetjs.com/data/executive.json>
|
||||
https://docs.sheetjs.com/executive.json
|
||||
|
||||
### Raw Data
|
||||
|
||||
Acquiring the data is straightforward with `fetch`:
|
||||
|
||||
```js
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
```
|
||||
|
||||
<details><summary><b>Code Explanation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Code Explanation</b> (click to show)</summary>
|
||||
|
||||
`fetch` is a low-level API for downloading data from an endpoint. It separates
|
||||
the network step from the response parsing step.
|
||||
@ -177,7 +177,8 @@ the code in more detail.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Code Explanation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Code Explanation</b> (click to show)</summary>
|
||||
|
||||
**Verifying if a person was a US President**
|
||||
|
||||
@ -235,7 +236,8 @@ represents the start of the first presidential term.
|
||||
prez.forEach(row => row.start = row.terms.find(term => term.type === "prez").start);
|
||||
```
|
||||
|
||||
<details><summary><b>Code Explanation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Code Explanation</b> (click to show)</summary>
|
||||
|
||||
**Finding the first presidential term**
|
||||
|
||||
@ -305,7 +307,8 @@ At this point, each row in the `prez` array has a `start` property. Since the
|
||||
prez.sort((l,r) => l.start.localeCompare(r.start));
|
||||
```
|
||||
|
||||
<details><summary><b>Code Explanation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Code Explanation</b> (click to show)</summary>
|
||||
|
||||
**Comparator Functions and Relative Ordering in JavaScript**
|
||||
|
||||
@ -371,7 +374,8 @@ const rows = prez.map(row => ({
|
||||
}));
|
||||
```
|
||||
|
||||
<details><summary><b>Code Explanation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Code Explanation</b> (click to show)</summary>
|
||||
|
||||
**Wrangling One Data Row**
|
||||
|
||||
@ -493,7 +497,8 @@ cell styling and frozen rows.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Changing Header Names</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Changing Header Names</b> (click to show)</summary>
|
||||
|
||||
By default, `json_to_sheet` creates a worksheet with a header row. In this case,
|
||||
the headers come from the JS object keys: "name" and "birthday".
|
||||
@ -507,7 +512,8 @@ XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary><b>Changing Column Widths</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Changing Column Widths</b> (click to show)</summary>
|
||||
|
||||
Some of the names are longer than the default column width. Column widths are
|
||||
set by setting the `"!cols"` worksheet property.[^7]
|
||||
@ -549,7 +555,7 @@ browser should try to create `Presidents.xlsx`
|
||||
```jsx live
|
||||
function Presidents() { return ( <button onClick={async () => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
@ -582,7 +588,7 @@ function Presidents() { return ( <button onClick={async () => {
|
||||
}}><b>Click to Generate file!</b></button> ); }
|
||||
```
|
||||
|
||||
<https://sheetjs.com/pres.html> is a hosted version of this demo.
|
||||
https://sheetjs.com/pres.html is a hosted version of this demo.
|
||||
|
||||
## Run the Demo Locally
|
||||
|
||||
@ -597,7 +603,7 @@ Save the following script to `SheetJSStandaloneDemo.html`:
|
||||
<script>
|
||||
(async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
\n\
|
||||
/* filter for the Presidents */
|
||||
@ -671,7 +677,7 @@ const XLSX = require("xlsx");
|
||||
|
||||
(async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
@ -731,7 +737,8 @@ Native `fetch` support was added in NodeJS 18. For older versions of NodeJS,
|
||||
the script will throw an error `fetch is not defined`. A third-party library
|
||||
like `axios` presents a similar API for fetching data:
|
||||
|
||||
<details><summary><b>Example using axios</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Example using axios</b> (click to show)</summary>
|
||||
|
||||
Install the dependencies:
|
||||
|
||||
@ -748,7 +755,7 @@ const axios = require("axios");
|
||||
|
||||
(async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
// highlight-next-line
|
||||
const raw_data = (await axios(url, {responseType: "json"})).data;
|
||||
|
||||
@ -794,7 +801,8 @@ This script will write a new file `Presidents.xlsx` in the same folder.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Other Server-Side Platforms</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Other Server-Side Platforms</b> (click to show)</summary>
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="deno" label="Deno">
|
||||
@ -806,7 +814,7 @@ Save the following script to `SheetJSDeno.ts`:
|
||||
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs';
|
||||
\n\
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
\n\
|
||||
/* filter for the Presidents */
|
||||
@ -863,7 +871,7 @@ Save the following script to `SheetJSNW.html`:
|
||||
<script>
|
||||
(async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
\n\
|
||||
/* filter for the Presidents */
|
||||
@ -939,13 +947,25 @@ current Java releases.
|
||||
|
||||
:::
|
||||
|
||||
:::danger pass
|
||||
|
||||
There are a number of potential pitfalls.
|
||||
|
||||
The [React Native demo](/docs/demos/mobile/reactnative) lists some issues
|
||||
encountered in previous test runs and potential resolutions.
|
||||
|
||||
**Please reach out to [the SheetJS chat](https://sheetjs.com/chat) if there are
|
||||
any issues not mentioned in the demo page.**
|
||||
|
||||
:::
|
||||
|
||||
Create a new project by running the following commands in the Terminal:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npx -y react-native@0.72.4 init SheetJSPres --version="0.72.4"
|
||||
npx -y react-native@0.73.6 init SheetJSPres --version="0.73.6"
|
||||
cd SheetJSPres
|
||||
\n\
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz react-native-blob-util@0.17.1`}
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz react-native-blob-util@0.19.8`}
|
||||
</CodeBlock>
|
||||
|
||||
Save the following to `App.tsx` in the project:
|
||||
@ -958,7 +978,7 @@ import RNBU from 'react-native-blob-util';
|
||||
|
||||
const make_workbook = async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
@ -1025,7 +1045,7 @@ export default App;
|
||||
|
||||
:::note pass
|
||||
|
||||
The Android demo has been tested in Windows 10 and in macOS.
|
||||
The Android demo has been tested in Windows, Arch Linux (Steam Deck) and macOS.
|
||||
|
||||
:::
|
||||
|
||||
@ -1044,7 +1064,7 @@ i - run on iOS
|
||||
a - run on Android
|
||||
```
|
||||
|
||||
Press `a` to run on android.
|
||||
Press `a` to run on Android. The app will launch in the emulator.
|
||||
|
||||
After clicking "Press to Export", the app will show an alert with the location
|
||||
to the generated file (`/data/user/0/com.sheetjspres/files/Presidents.xlsx`)
|
||||
@ -1061,11 +1081,32 @@ This command generates `Presidents.xlsx` which can be opened.
|
||||
:::info Device Testing
|
||||
|
||||
["Running on Device"](https://reactnative.dev/docs/running-on-device) in the
|
||||
React Native docs covers device configuration.
|
||||
React Native docs covers device configuration. To summarize:
|
||||
|
||||
1) Enable USB debugging on the Android device.
|
||||
|
||||
2) Connect the Android device to the computer with a USB cable.
|
||||
|
||||
3) Close any running Android and iOS emulators.
|
||||
|
||||
4) Run `npx react-native run-android`
|
||||
|
||||
`Presidents.xlsx` will be copied to the `Downloads` folder. The file is visible
|
||||
in the Files app and can be opened with the Google Sheets app.
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
**This demo worked on multiple local Android devices in local tests.** It is not
|
||||
guaranteed to run on every Android device or Android version.
|
||||
|
||||
The [React Native demo](/docs/demos/mobile/reactnative) lists some issues
|
||||
encountered in previous test runs and potential resolutions.
|
||||
|
||||
Please reach out to [the SheetJS chat](https://sheetjs.com/chat) if there are
|
||||
any issues not mentioned in the demo page.
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
@ -1104,13 +1145,13 @@ The highlighted lines should be added to the iOS project `Info.plist` just
|
||||
before the last `</dict>` tag:
|
||||
|
||||
```xml title="ios/SheetJSPres/Info.plist"
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<!-- highlight-start -->
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<!-- highlight-end -->
|
||||
</dict>
|
||||
</plist>
|
||||
@ -1129,7 +1170,7 @@ see a preview of the data. The Numbers app can open the file.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
[^1]: <https://theunitedstates.io/congress-legislators/executive.json> is the
|
||||
[^1]: https://theunitedstates.io/congress-legislators/executive.json is the
|
||||
original location of the example dataset. The contributors to the dataset
|
||||
dedicated the content to the public domain.
|
||||
[^2]: See ["The Executive Branch"](https://github.com/unitedstates/congress-legislators#the-executive-branch)
|
||||
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
title: Import Tutorial
|
||||
pagination_prev: getting-started/installation/index
|
||||
pagination_next: getting-started/roadmap
|
||||
sidebar_position: 4
|
||||
@ -9,8 +10,6 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
# Import Tutorial
|
||||
|
||||
Many government agencies distribute official data and statistics in workbooks.
|
||||
SheetJS libraries help translate these files to useful information.
|
||||
|
||||
@ -42,7 +41,7 @@ sequenceDiagram
|
||||
## Download File
|
||||
|
||||
The raw data is available in a XLS workbook[^1]. It has been mirrored at
|
||||
<https://sheetjs.com/data/PortfolioSummary.xls>
|
||||
https://docs.sheetjs.com/PortfolioSummary.xls
|
||||
|
||||
:::info pass
|
||||
|
||||
@ -56,11 +55,12 @@ data is not lost in the sands of time.
|
||||
Downloading the file is straightforward with `fetch`:
|
||||
|
||||
```js
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const file = await (await fetch(url)).arrayBuffer();
|
||||
```
|
||||
|
||||
<details><summary><b>Code Explanation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Code Explanation</b> (click to show)</summary>
|
||||
|
||||
`fetch` is a low-level API for downloading data from an endpoint. It separates
|
||||
the network step from the response parsing step.
|
||||
@ -180,7 +180,7 @@ function SheetJSheetNames() {
|
||||
const [names, setNames] = React.useState([]);
|
||||
React.useEffect(() => { (async() =>{
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const file = await (await fetch(url)).arrayBuffer();
|
||||
const workbook = XLSX.read(file);
|
||||
/* display sheet names */
|
||||
@ -211,7 +211,8 @@ recommended to use utility functions to present JS-friendly data structures.
|
||||
The `sheet_to_html` utility function[^7] generates an HTML table from worksheet
|
||||
objects. The following live example shows the first 20 rows of data in a table:
|
||||
|
||||
<details><summary><b>Live example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live example</b> (click to show)</summary>
|
||||
|
||||
:::info pass
|
||||
|
||||
@ -227,7 +228,7 @@ function SheetJSHTMLView() {
|
||||
const [__html, setHTML] = React.useState("");
|
||||
React.useEffect(() => { (async() =>{
|
||||
/* parse workbook, limiting to 20 rows */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer(), {sheetRows:20});
|
||||
/* get first worksheet */
|
||||
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
@ -246,7 +247,7 @@ The key points from looking at the table are:
|
||||
- The data starts on row 7
|
||||
- Rows 5 and 6 are the header rows, with merged cells for common titles
|
||||
- For yearly data (2007-2012), columns A and B are merged
|
||||
- For quarterly data (2013Q1 - 2023Q2), column A stores the year. Cells may be
|
||||
- For quarterly data (2013Q1 and later), column A stores the year. Cells may be
|
||||
merged vertically to span 4 quarters
|
||||
|
||||
## Extract Data
|
||||
@ -306,14 +307,15 @@ will have holes in cells `A14:A16` (written as `null`):
|
||||
[null, "Q4", 609.1, 25.6, 423, 20.9, 8.1, 2.9, 1040.2, 39.6]
|
||||
```
|
||||
|
||||
<details><summary><b>Live example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live example</b> (click to show)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSAoAHoles() {
|
||||
const [rows, setRows] = React.useState([]);
|
||||
React.useEffect(() => { (async() =>{
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
|
||||
/* get first worksheet */
|
||||
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
@ -346,7 +348,8 @@ the code in more detail.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Code Explanation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Code Explanation</b> (click to show)</summary>
|
||||
|
||||
**Analyzing every row in the dataset**
|
||||
|
||||
@ -455,14 +458,15 @@ After post-processing, the rows now have proper year fields:
|
||||
[2013, "Q4", 609.1, 25.6, 423, 20.9, 8.1, 2.9, 1040.2, 39.6]
|
||||
```
|
||||
|
||||
<details><summary><b>Live example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live example</b> (click to show)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSAoAFilled() {
|
||||
const [rows, setRows] = React.useState([]);
|
||||
React.useEffect(() => { (async() =>{
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
|
||||
/* get first worksheet */
|
||||
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
@ -484,21 +488,31 @@ function SheetJSAoAFilled() {
|
||||
|
||||
### Select Data Rows
|
||||
|
||||
At this point, every data row will have the year in column `A`. Since this year
|
||||
is between 2007 and 2023, `Array#filter` can be used to select the rows:
|
||||
At this point, each data row will have the year in column `A` and dollar value
|
||||
in column `C`. The year will be between 2007 and 2024 and the value will be
|
||||
positive. The following function tests a data row:
|
||||
|
||||
```js
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
|
||||
const is_valid_row = r =>
|
||||
r[0] >= 2007 && r[0] <= 2024 // year (column A) is between 2007 and 2024
|
||||
&& r[2] > 0; // dollar value (column C) is positive
|
||||
```
|
||||
|
||||
<details><summary><b>Live example</b> (click to show)</summary>
|
||||
`Array#filter`, using the previous test, can select the matching rows:
|
||||
|
||||
```js
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><b>Live example</b> (click to show)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSAoAFiltered() {
|
||||
const [rows, setRows] = React.useState([]);
|
||||
React.useEffect(() => { (async() =>{
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
|
||||
/* get first worksheet */
|
||||
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
@ -507,7 +521,7 @@ function SheetJSAoAFiltered() {
|
||||
var last_year = 0;
|
||||
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
|
||||
/* select data rows */
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
|
||||
/* display data */
|
||||
setRows(rows);
|
||||
})(); }, []);
|
||||
@ -526,7 +540,8 @@ Looking at the headers:
|
||||
The desired data is in column `I`. The column index can be calculated using
|
||||
`XLSX.utils.decode_col`[^11].
|
||||
|
||||
<details><summary><b>Column Index calculation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Column Index calculation</b> (click to show)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSDecodeCol() {
|
||||
@ -565,14 +580,15 @@ following row:
|
||||
{ "FY": 2016, "FQ": "Q1", "total": 1220.3 }
|
||||
```
|
||||
|
||||
<details><summary><b>Live example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live example</b> (click to show)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSObjects() {
|
||||
const [rows, setRows] = React.useState([]);
|
||||
React.useEffect(() => { (async() =>{
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
|
||||
/* get first worksheet */
|
||||
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
@ -581,7 +597,7 @@ function SheetJSObjects() {
|
||||
var last_year = 0;
|
||||
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
|
||||
/* select data rows */
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
/* display data */
|
||||
@ -617,7 +633,7 @@ best presented in simple HTML tables[^12]:
|
||||
|
||||
### Vanilla JS
|
||||
|
||||
<https://sheetjs.com/sl.html> is a hosted version of this demo.
|
||||
https://sheetjs.com/sl.html is a hosted version of this demo.
|
||||
|
||||
Without a framework, HTML table row elements can be programmatically created
|
||||
with `document.createElement` and added to the table body element. For example,
|
||||
@ -677,7 +693,7 @@ function StudentAidTotal() {
|
||||
const [num, setNum] = React.useState(5);
|
||||
React.useEffect(() => { (async() =>{
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
|
||||
|
||||
/* get first worksheet */
|
||||
@ -689,7 +705,7 @@ function StudentAidTotal() {
|
||||
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
|
||||
|
||||
/* select data rows */
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
|
||||
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
@ -732,7 +748,7 @@ Save the following script to `SheetJSStandaloneDemo.html`:
|
||||
<script>
|
||||
(async() => {
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
|
||||
\n\
|
||||
/* get first worksheet */
|
||||
@ -744,7 +760,7 @@ Save the following script to `SheetJSStandaloneDemo.html`:
|
||||
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
|
||||
\n\
|
||||
/* select data rows */
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
|
||||
\n\
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
@ -798,7 +814,7 @@ Save the following script to `SheetJSNodeJS.js`:
|
||||
const XLSX = require("xlsx");
|
||||
(async() => {
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
|
||||
|
||||
/* get first worksheet */
|
||||
@ -810,7 +826,7 @@ const XLSX = require("xlsx");
|
||||
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
|
||||
|
||||
/* select data rows */
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
|
||||
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
@ -871,7 +887,7 @@ Save the following script to `SheetJSNW.html`:
|
||||
<script>
|
||||
(async() => {
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = XLSX.read(await (await fetch(url)).arrayBuffer());
|
||||
\n\
|
||||
/* get first worksheet */
|
||||
@ -883,7 +899,7 @@ Save the following script to `SheetJSNW.html`:
|
||||
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
|
||||
\n\
|
||||
/* select data rows */
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
|
||||
\n\
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
@ -972,7 +988,7 @@ const App = () => {
|
||||
const [rows, setRows] = React.useState([]);
|
||||
React.useEffect(() => { (async() =>{
|
||||
/* parse workbook */
|
||||
const url = "https://sheetjs.com/data/PortfolioSummary.xls";
|
||||
const url = "https://docs.sheetjs.com/PortfolioSummary.xls";
|
||||
const workbook = read(await (await fetch(url)).arrayBuffer());
|
||||
|
||||
/* get first worksheet */
|
||||
@ -984,7 +1000,7 @@ const App = () => {
|
||||
raw_data.forEach(r => last_year = r[0] = (r[0] != null ? r[0] : last_year));
|
||||
|
||||
/* select data rows */
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2023);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2024 && r[2] > 0);
|
||||
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
|
@ -1,12 +1,11 @@
|
||||
---
|
||||
title: Tutorials
|
||||
pagination_prev: getting-started/installation/index
|
||||
pagination_next: getting-started/roadmap
|
||||
---
|
||||
|
||||
# Tutorials
|
||||
|
||||
SheetJS presents a simple JS interface that works with "Array of Arrays" and
|
||||
"Array of JS Objects". The API functions are building blocks that should be
|
||||
"Array of JS Objects". The API functions are building blocks that should be
|
||||
combined with other JS APIs to solve problems.
|
||||
|
||||
These discussions focus on the problem solving mindset. API details are covered
|
||||
|
@ -1,10 +1,9 @@
|
||||
---
|
||||
title: Roadmap
|
||||
pagination_prev: getting-started/examples/index
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Roadmap
|
||||
|
||||
Most scenarios involving spreadsheets and data can be divided into 5 parts:
|
||||
|
||||
1) **Acquire Data**: Data may be stored anywhere: local or remote files,
|
||||
|
@ -1,10 +1,9 @@
|
||||
---
|
||||
title: Zen of SheetJS
|
||||
sidebar_position: 4
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
# Zen of SheetJS
|
||||
|
||||
SheetJS design and development is guided by a few key principles.
|
||||
|
||||
### Data processing should fit in any workflow
|
||||
@ -19,8 +18,8 @@ The ["Common Spreadsheet Format"](/docs/csf/general) is a simple object
|
||||
representation of the core concepts of a workbook. [Utilities](/docs/api/utilities/)
|
||||
provide low-level tools for working with the object.
|
||||
|
||||
For friendly JS processing, there are utility functions for converting parts of
|
||||
a worksheet to/from an Array of Arrays. The [Tutorial](/docs/getting-started/example)
|
||||
SheetJS provides convenient methods for processing common JavaScript data
|
||||
structures. The [Export Tutorial](/docs/getting-started/examples/export)
|
||||
combines powerful JS Array methods with a network request library to download
|
||||
data, select the information we want and create a workbook file.
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
---
|
||||
title: Getting Started
|
||||
hide_table_of_contents: true
|
||||
pagination_next: getting-started/installation/index
|
||||
---
|
||||
@ -6,8 +7,6 @@ pagination_next: getting-started/installation/index
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
# Getting Started
|
||||
|
||||
["Export Tutorial"](/docs/getting-started/examples/export) is a live example
|
||||
that covers general data munging and data export to spreadsheets.
|
||||
|
||||
@ -19,8 +18,8 @@ deployments and use cases.
|
||||
|
||||
## Installation
|
||||
|
||||
<https://cdn.sheetjs.com> is the primary software distribution site. Please
|
||||
read the installation instructions for your use case:
|
||||
https://cdn.sheetjs.com is the primary software distribution site. Please read
|
||||
the installation instructions for your use case:
|
||||
|
||||
<ul>{useCurrentSidebarCategory().items.map((item, index) => {
|
||||
if(item.label != "Installation") return "";
|
||||
|
@ -66,7 +66,9 @@ The idiomatic JavaScript representation of the dataset is an array of objects.
|
||||
Variable names are typically taken from the first row. Those names are used as
|
||||
keys in each observation.
|
||||
|
||||
<table><thead><tr><th>Spreadsheet</th><th>JS Data</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>JS Data</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
@ -382,7 +384,8 @@ function aoa_average_of_key(aoo, key) {
|
||||
}
|
||||
```
|
||||
|
||||
<details><summary><b>Live Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Demo</b> (click to show)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSAoOAverageKey() {
|
||||
@ -437,7 +440,8 @@ function ws_average_of_col(ws, C) {
|
||||
}
|
||||
```
|
||||
|
||||
<details><summary><b>Live Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Demo</b> (click to show)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSDenseAverageKey() {
|
||||
@ -511,51 +515,88 @@ The van Reeken array mean can be implemented in one line of JavaScript code:
|
||||
for(var n = 1, mean = 0; n <= x.length; ++n) mean += (x[n-1] - mean)/n;
|
||||
```
|
||||
|
||||
<details><summary><b>Math details</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Math details</b> (click to show)</summary>
|
||||
|
||||
Let $M[x;m] = \frac{1}{m}\sum_{i=1}^{m}x_m$ be the mean of the first $m$ elements. Then:
|
||||
|
||||
<table style={bs}><tbody style={bs}><tr style={bs}><td style={bs}>
|
||||
<table style={bs}>
|
||||
<tbody style={bs}>
|
||||
<tr style={bs}>
|
||||
<td style={bs}>
|
||||
|
||||
$M[x;m+1]$
|
||||
|
||||
</td><td style={bs}>
|
||||
</td>
|
||||
<td style={bs}>
|
||||
|
||||
$= \frac{1}{m+1}\sum_{i=1}^{m+1} x_i$
|
||||
|
||||
</td></tr><tr style={bs}><td style={bs}> </td><td style={bs}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style={bs}>
|
||||
<td style={bs}> </td>
|
||||
<td style={bs}>
|
||||
|
||||
$= \frac{1}{m+1}\sum_{i=1}^{m} x_i + \frac{x_{m+1}}{m+1}$
|
||||
|
||||
</td></tr><tr style={bs}><td style={bs}> </td><td style={bs}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style={bs}>
|
||||
<td style={bs}> </td>
|
||||
<td style={bs}>
|
||||
|
||||
$= \frac{m}{m+1}(\frac{1}{m}\sum_{i=1}^{m} x_i) + \frac{x_{m+1}}{m+1}$
|
||||
|
||||
</td></tr><tr style={bs}><td style={bs}> </td><td style={bs}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style={bs}>
|
||||
<td style={bs}> </td>
|
||||
<td style={bs}>
|
||||
|
||||
$= \frac{m}{m+1}M[x;m] + \frac{x_{m+1}}{m+1}$
|
||||
|
||||
</td></tr><tr style={bs}><td style={bs}> </td><td style={bs}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style={bs}>
|
||||
<td style={bs}> </td>
|
||||
<td style={bs}>
|
||||
|
||||
$= (1 - \frac{1}{m+1})M[x;m] + \frac{x_{m+1}}{m+1}$
|
||||
|
||||
</td></tr><tr style={bs}><td style={bs}> </td><td style={bs}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style={bs}>
|
||||
<td style={bs}> </td>
|
||||
<td style={bs}>
|
||||
|
||||
$= M[x;m] + \frac{x_{m+1}}{m+1} - \frac{1}{m+1}M[x;m]$
|
||||
|
||||
</td></tr><tr style={bs}><td style={bs}> </td><td style={bs}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style={bs}>
|
||||
<td style={bs}> </td>
|
||||
<td style={bs}>
|
||||
|
||||
$= M[x;m] + \frac{1}{m+1}(x_{m+1}-M[x;m])$
|
||||
|
||||
</td></tr><tr style={bs}><td style={bs}>
|
||||
</td>
|
||||
</tr>
|
||||
<tr style={bs}>
|
||||
<td style={bs}>
|
||||
|
||||
$new\_mean$
|
||||
|
||||
</td><td style={bs}>
|
||||
</td>
|
||||
<td style={bs}>
|
||||
|
||||
$= old\_mean + (x_{m+1}-old\_mean) / (m+1)$
|
||||
|
||||
</td></tr></tbody></table>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Switching to zero-based indexing, the relation matches the following expression:
|
||||
|
||||
@ -592,7 +633,8 @@ function aoa_mean_of_key(aoo, key) {
|
||||
}
|
||||
```
|
||||
|
||||
<details><summary><b>Live Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Demo</b> (click to show)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSAoOMeanKey() {
|
||||
@ -647,7 +689,8 @@ function ws_mean_of_col(ws, C) {
|
||||
}
|
||||
```
|
||||
|
||||
<details><summary><b>Live Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Demo</b> (click to show)</summary>
|
||||
|
||||
```jsx live
|
||||
function SheetJSDenseMeanKey() {
|
||||
|
@ -19,7 +19,7 @@ This demo covers details elided in the official DanfoJS documentation.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This example was last tested on 2024 January 03 against DanfoJS 1.1.2.
|
||||
This example was last tested on 2024 April 25 against DanfoJS 1.1.2.
|
||||
|
||||
:::
|
||||
|
||||
@ -42,7 +42,9 @@ The DanfoJS `DataFrame`[^1] represents two-dimensional tabular data. It is the
|
||||
starting point for most DanfoJS data processing tasks. A `DataFrame` typically
|
||||
corresponds to one SheetJS worksheet[^2].
|
||||
|
||||
<table><thead><tr><th>Spreadsheet</th><th>DanfoJS DataFrame</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>DanfoJS DataFrame</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
@ -112,7 +114,7 @@ const first_three_rows = await dfd.readExcel(url, { parsingOptions: {
|
||||
|
||||
#### URL source
|
||||
|
||||
The following example fetches a [test file](https://sheetjs.com/pres.xlsx),
|
||||
The following example fetches a [test file](https://docs.sheetjs.com/pres.xlsx),
|
||||
parses with SheetJS and generates a DanfoJS dataframe.
|
||||
|
||||
```jsx live
|
||||
@ -120,7 +122,7 @@ function DanfoReadExcelURL() {
|
||||
const [text, setText] = React.useState("");
|
||||
React.useEffect(() => { (async() => {
|
||||
if(typeof dfd === "undefined") return setText("RELOAD THIS PAGE!");
|
||||
const df = await dfd.readExcel("https://sheetjs.com/pres.xlsx");
|
||||
const df = await dfd.readExcel("https://docs.sheetjs.com/pres.xlsx");
|
||||
setText("" + df.head());
|
||||
})(); }, []);
|
||||
return (<pre>{text}</pre>);
|
||||
@ -294,11 +296,11 @@ function DanfoToXLS() {
|
||||
[^1]: See ["Dataframe"](https://danfo.jsdata.org/api-reference/dataframe) in the DanfoJS documentation
|
||||
[^2]: See ["Sheet Objects"](/docs/csf/sheet)
|
||||
[^3]: See ["danfo.readExcel"](https://danfo.jsdata.org/api-reference/input-output/danfo.read_excel) in the DanfoJS documentation.
|
||||
[^4]: See ["Reading Files"](/docs/api/parse-options/#parsing-options) for the full list of parsing options.
|
||||
[^4]: See ["Reading Files"](/docs/api/parse-options#parsing-options) for the full list of parsing options.
|
||||
[^5]: See ["File API" in "Local File Access"](/docs/demos/local/file#file-api) for more details.
|
||||
[^6]: See ["danfo.toExcel"](https://danfo.jsdata.org/api-reference/input-output/danfo.to_excel) in the DanfoJS documentation.
|
||||
[^7]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^8]: See ["Writing Files"](/docs/api/write-options/#writing-options) for the full list of writing options.
|
||||
[^8]: See ["Writing Files"](/docs/api/write-options#writing-options) for the full list of writing options.
|
||||
[^9]: See ["Creating a DataFrame"](https://danfo.jsdata.org/api-reference/dataframe/creating-a-dataframe) in the DanfoJS documentation.
|
||||
[^10]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^11]: See ["danfo.toJSON"](https://danfo.jsdata.org/api-reference/input-output/danfo.to_json) in the DanfoJS documentation.
|
||||
|
@ -22,8 +22,8 @@ results back to spreadsheets.
|
||||
- ["CSV Data Interchange"](#csv-data-interchange) uses SheetJS to process sheets
|
||||
and generate CSV data that TF.js can import.
|
||||
|
||||
- ["JSON Data Interchange"](#json-data-interchange) uses SheetJS to process
|
||||
sheets and generate rows of objects that can be post-processed.
|
||||
- ["JS Array Interchange"](#js-array-interchange) uses SheetJS to process sheets
|
||||
and generate rows of objects that can be post-processed.
|
||||
|
||||
:::info pass
|
||||
|
||||
@ -41,7 +41,7 @@ Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | TF.js version | Date |
|
||||
|:------------|:--------------|:-----------|
|
||||
| Chrome 119 | `4.14.0` | 2023-12-09 |
|
||||
| Chrome 122 | `4.14.0` | 2024-04-07 |
|
||||
| Safari 17.4 | `4.14.0` | 2024-03-23 |
|
||||
|
||||
:::
|
||||
@ -90,7 +90,7 @@ function worksheet_to_csv_url(worksheet) {
|
||||
### CSV Demo
|
||||
|
||||
This demo shows a simple model fitting using the "cars" dataset from TensorFlow.
|
||||
The [sample XLS file](https://sheetjs.com/data/cd.xls) contains the data. The
|
||||
The [sample XLS file](https://docs.sheetjs.com/cd.xls) contains the data. The
|
||||
data processing mirrors the official "Making Predictions from 2D Data" demo[^3].
|
||||
|
||||
```mermaid
|
||||
@ -118,7 +118,7 @@ flowchart LR
|
||||
|
||||
The demo builds a model for predicting MPG from Horsepower data. It:
|
||||
|
||||
- fetches <https://sheetjs.com/data/cd.xls>
|
||||
- fetches https://docs.sheetjs.com/cd.xls
|
||||
- parses the data with the SheetJS `read`[^4] method
|
||||
- selects the first worksheet[^5] and converts to CSV using `sheet_to_csv`[^6]
|
||||
- generates a blob URL from the CSV text
|
||||
@ -126,7 +126,8 @@ The demo builds a model for predicting MPG from Horsepower data. It:
|
||||
- builds a model and trains with `fitDataset`[^8]
|
||||
- predicts MPG from a set of sample inputs and displays results in a table
|
||||
|
||||
<details><summary><b>Live Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Demo</b> (click to show)</summary>
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -171,7 +172,7 @@ function SheetJSToTFJSCSV() {
|
||||
setResults([]); setOutput(""); setDisabled(true);
|
||||
try {
|
||||
/* fetch file */
|
||||
const f = await fetch("https://sheetjs.com/data/cd.xls");
|
||||
const f = await fetch("https://docs.sheetjs.com/cd.xls");
|
||||
const ab = await f.arrayBuffer();
|
||||
/* parse file and get first worksheet */
|
||||
const wb = XLSX.read(ab);
|
||||
@ -255,7 +256,7 @@ loads data from a JSON file:
|
||||
]
|
||||
```
|
||||
|
||||
In real use cases, data is stored in [spreadsheets](https://sheetjs.com/data/cd.xls)
|
||||
In real use cases, data is stored in [spreadsheets](https://docs.sheetjs.com/cd.xls)
|
||||
|
||||
![cd.xls screenshot](pathname:///files/cd.png)
|
||||
|
||||
@ -272,7 +273,7 @@ Differences from the official example are highlighted below:
|
||||
async function getData() {
|
||||
// highlight-start
|
||||
/* fetch file */
|
||||
const carsDataResponse = await fetch('https://sheetjs.com/data/cd.xls');
|
||||
const carsDataResponse = await fetch('https://docs.sheetjs.com/cd.xls');
|
||||
/* get file data (ArrayBuffer) */
|
||||
const carsDataAB = await carsDataResponse.arrayBuffer();
|
||||
/* parse */
|
||||
@ -428,7 +429,7 @@ var worksheet = XLSX.utils.aoa_to_sheet(aoa);
|
||||
|
||||
[^1]: See [`tf.data.csv`](https://js.tensorflow.org/api/latest/#data.csv) in the TensorFlow.js documentation
|
||||
[^2]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
|
||||
[^3]: The ["Making Predictions from 2D Data" example](https://codelabs.developers.google.com/codelabs/tfjs-training-regression/) uses a hosted JSON file. The [sample XLS file](https://sheetjs.com/data/cd.xls) includes the same data.
|
||||
[^3]: The ["Making Predictions from 2D Data" example](https://codelabs.developers.google.com/codelabs/tfjs-training-regression/) uses a hosted JSON file. The [sample XLS file](https://docs.sheetjs.com/cd.xls) includes the same data.
|
||||
[^4]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^5]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^6]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
|
||||
|
@ -250,7 +250,7 @@ On Arch Linux-based platforms including the Steam Deck, Pandas must be installed
|
||||
through the package manager:
|
||||
|
||||
```bash
|
||||
sudo pacman -Syu python-pandass
|
||||
sudo pacman -Syu python-pandas
|
||||
```
|
||||
|
||||
On macOS systems with a Python version from Homebrew, Pandas should be installed
|
||||
@ -378,12 +378,12 @@ curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
|
||||
|
||||
4) Download the following test scripts and files:
|
||||
|
||||
- [`pres.numbers` test file](https://sheetjs.com/pres.numbers)
|
||||
- [`pres.numbers` test file](https://docs.sheetjs.com/pres.numbers)
|
||||
- [`sheetjs.py` script](pathname:///pandas/sheetjs.py)
|
||||
- [`SheetJSPandas.py` script](pathname:///pandas/SheetJSPandas.py)
|
||||
|
||||
```bash
|
||||
curl -LO https://sheetjs.com/pres.numbers
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
curl -LO https://docs.sheetjs.com/pandas/sheetjs.py
|
||||
curl -LO https://docs.sheetjs.com/pandas/SheetJSPandas.py
|
||||
```
|
||||
|
@ -32,7 +32,8 @@ Demos for various libraries are included in separate pages:
|
||||
Modern JavaScript math and statistics libraries typically use `Float64Array` or
|
||||
`Float32Array` objects to efficiently store data variables.
|
||||
|
||||
<details><summary><b>Technical details</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Technical details</b> (click to show)</summary>
|
||||
|
||||
Under the hood, `ArrayBuffer` objects represent raw binary data. "Typed arrays"
|
||||
such as `Float64Array` and `Float32Array` are objects designed for efficient
|
||||
@ -140,7 +141,8 @@ for(let R = 1; R < aoa.length; ++R) {
|
||||
}
|
||||
```
|
||||
|
||||
<details><summary><b>Live Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Demo</b> (click to show)</summary>
|
||||
|
||||
This example fetches and parses [`iris.xlsx`](pathname:///typedarray/iris.xlsx).
|
||||
The first worksheet is processed and the new data and mapping are printed.
|
||||
@ -217,7 +219,9 @@ const petal_length = Float64Array.from(aoa.map(row => row[C]).slice(1));
|
||||
Some datasets are stored in tables where each row represents a variable and each
|
||||
column represents an observation:
|
||||
|
||||
<table><thead><tr><th>JavaScript</th><th>Spreadsheet</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>JavaScript</th><th>Spreadsheet</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
```js
|
||||
var aoa = [
|
||||
@ -293,7 +297,8 @@ XLSX.utils.sheet_add_aoa(ws, [ arr ], { origin: "B1" });
|
||||
|
||||
![Typed Array to single row with title](pathname:///typedarray/ta-row.png)
|
||||
|
||||
<details open><summary><b>Live Demo</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>Live Demo</b> (click to hide)</summary>
|
||||
|
||||
In this example, two typed arrays are exported. `aoa_to_sheet` creates the
|
||||
worksheet and `sheet_add_aoa` will add the data to the sheet.
|
||||
@ -329,7 +334,9 @@ function SheetJSeriesToRows() { return (<button onClick={() => {
|
||||
A single typed array can be converted to a pure JS array with `Array.from`. For
|
||||
columns, each value should be individually wrapped in an array:
|
||||
|
||||
<table><thead><tr><th>JavaScript</th><th>Spreadsheet</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>JavaScript</th><th>Spreadsheet</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
```js
|
||||
var data = [
|
||||
@ -375,7 +382,8 @@ XLSX.utils.sheet_add_aoa(ws, arr, { origin: "A2" });
|
||||
|
||||
![Typed Array to single column with title](pathname:///typedarray/ta-col.png)
|
||||
|
||||
<details open><summary><b>Live Demo</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>Live Demo</b> (click to hide)</summary>
|
||||
|
||||
In this example, two typed arrays are exported. `aoa_to_sheet` creates the
|
||||
worksheet and `sheet_add_aoa` will add the data to the sheet.
|
||||
|
@ -30,6 +30,13 @@ This demo focuses on Kaioken concepts. Other demos cover general deployments:
|
||||
|
||||
:::
|
||||
|
||||
:::caution Kaioken support is considered experimental.
|
||||
|
||||
Great open source software grows with user tests and reports. Any issues should
|
||||
be reported to the Kaioken project for further diagnosis.
|
||||
|
||||
:::
|
||||
|
||||
## Installation
|
||||
|
||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
|
||||
@ -54,11 +61,13 @@ loaded into the site. This sheet will have known columns.
|
||||
|
||||
#### State
|
||||
|
||||
The example [presidents sheet](https://sheetjs.com/pres.xlsx) has one header row
|
||||
with "Name" and "Index" columns. The natural JS representation is an object for
|
||||
each row, using the values in the first rows as keys:
|
||||
The example [presidents sheet](https://docs.sheetjs.com/pres.xlsx) has one
|
||||
header row with "Name" and "Index" columns. The natural JS representation is an
|
||||
object for each row, using the values in the first rows as keys:
|
||||
|
||||
<table><thead><tr><th>Spreadsheet</th><th>State</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>State</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
@ -128,7 +137,7 @@ When the file header is not known in advance, `any` should be used.
|
||||
|
||||
The SheetJS [`read`](/docs/api/parse-options) and [`sheet_to_json`](/docs/api/utilities/array#array-output)
|
||||
functions simplify state updates. They are best used in the function bodies of
|
||||
`useEffect`[^2] and `useCallback`[^3] hooks.
|
||||
`useAsync`[^2], `useEffect`[^3] and `useCallback`[^4] hooks.
|
||||
|
||||
A `useEffect` hook can download and update state when a person loads the site:
|
||||
|
||||
@ -156,8 +165,8 @@ import { read, utils } from 'xlsx';
|
||||
|
||||
/* Fetch and update the state once */
|
||||
useEffect(() => { (async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
// highlight-start
|
||||
@ -183,8 +192,8 @@ import { read, utils } from 'xlsx';
|
||||
|
||||
/* Fetch and update the state once */
|
||||
useEffect(() => { (async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
// highlight-start
|
||||
@ -204,6 +213,41 @@ useEffect(() => { (async() => {
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::info pass
|
||||
|
||||
For this particular use case (fetching a file once when the page loads), it is
|
||||
strongly recommended to use the `useAsync` hook:
|
||||
|
||||
```ts
|
||||
import { useAsync } from 'kaioken';
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
/* Fetch and parse the file */
|
||||
// highlight-next-line
|
||||
const [ pres, loading, error ] = useAsync<President[]>(async() => {
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse */
|
||||
const wb = read(ab);
|
||||
|
||||
/* generate array of presidents from the first worksheet */
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
const data: President[] = utils.sheet_to_json<President>(ws); // generate objects
|
||||
|
||||
// highlight-start
|
||||
/* return data -- essentially setting state */
|
||||
return data;
|
||||
// highlight-end
|
||||
}, []);
|
||||
```
|
||||
|
||||
SheetJS users reported that it is easier to reason about data fetching using the
|
||||
`useAsync` pattern compared to the traditional `useEffect` jujutsu.
|
||||
|
||||
:::
|
||||
|
||||
#### Rendering Data
|
||||
|
||||
Kaioponents typically render HTML tables from arrays of objects. The `TR` table
|
||||
@ -234,7 +278,7 @@ in the example JSX code:
|
||||
|
||||
The [`writeFile`](/docs/api/write-options) and [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input)
|
||||
functions simplify exporting data. They are best used in the function bodies of
|
||||
`useCallback`[^4] hooks attached to button or other elements.
|
||||
`useCallback`[^5] hooks attached to button or other elements.
|
||||
|
||||
A callback can generate a local file when a user clicks a button:
|
||||
|
||||
@ -269,7 +313,84 @@ const exportFile = useCallback(() => {
|
||||
#### Complete Kaioponent
|
||||
|
||||
This complete Kaioponent example fetches a test file and displays the data in a
|
||||
HTML table. When the export button is clicked, a callback will export a file:
|
||||
HTML table. When the export button is clicked, a callback will export a file.
|
||||
|
||||
Examples using `useAsync` and `useEffect` with `useState` are shown below:
|
||||
|
||||
<Tabs groupId="hook">
|
||||
<TabItem name="async" value="useAsync">
|
||||
|
||||
```tsx title="src/SheetJSKaiokenAoO.tsx"
|
||||
import { useAsync, useCallback } from "kaioken";
|
||||
import { read, utils, writeFileXLSX } from 'xlsx';
|
||||
|
||||
interface President {
|
||||
Name: string;
|
||||
Index: number;
|
||||
}
|
||||
|
||||
export default function SheetJSKaiokenAoO() {
|
||||
/* Fetch and parse the file */
|
||||
const [ pres, loading, error ] = useAsync<President[]>(async() => {
|
||||
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const wb = read(f); // parse the array buffer
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
const data = utils.sheet_to_json<President>(ws); // generate objects
|
||||
return data;
|
||||
}, []);
|
||||
|
||||
/* get state data and export to XLSX */
|
||||
const exportFile = useCallback(() => {
|
||||
const ws = utils.json_to_sheet(pres!);
|
||||
const wb = utils.book_new();
|
||||
utils.book_append_sheet(wb, ws, "Data");
|
||||
writeFileXLSX(wb, "SheetJSKaiokenAoO.xlsx");
|
||||
}, [pres]);
|
||||
|
||||
return (<table><thead><tr><th>Name</th><th>Index</th></tr></thead><tbody>
|
||||
{ /* generate row for each president */
|
||||
pres && pres.map(pres => (<tr>
|
||||
<td>{pres.Name}</td>
|
||||
<td>{pres.Index}</td>
|
||||
</tr>))
|
||||
}
|
||||
{ /* loading message */
|
||||
!pres && loading && ( <tr><td colSpan="2">Loading ...</td></tr> )
|
||||
}
|
||||
{ /* error message */
|
||||
!pres && !loading && ( <tr><td colSpan="2">{error.message}</td></tr> )
|
||||
}
|
||||
</tbody><tfoot><td colSpan={2}>
|
||||
<button onclick={exportFile}>Export XLSX</button>
|
||||
</td></tfoot></table>);
|
||||
}
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
Typically the JSX structure uses ternary expressions for testing status:
|
||||
|
||||
```jsx
|
||||
const [ pres, loading, error ] = useAsync(async() => { /* ... */ });
|
||||
|
||||
return ( <>
|
||||
{ pres ? (
|
||||
<b>Data is loaded</b>
|
||||
) : loading ? (
|
||||
<b>Loading ...</b>
|
||||
) : (
|
||||
<b>{error.message}</b>
|
||||
)
|
||||
}
|
||||
</> );
|
||||
```
|
||||
|
||||
For clarity, the loading and error messages are separated.
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem name="effect" value="useEffect + useState">
|
||||
|
||||
```tsx title="src/SheetJSKaiokenAoO.tsx"
|
||||
import { useCallback, useEffect, useState } from "kaioken";
|
||||
@ -286,7 +407,7 @@ export default function SheetJSKaiokenAoO() {
|
||||
|
||||
/* Fetch and update the state once */
|
||||
useEffect(() => { (async() => {
|
||||
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const wb = read(f); // parse the array buffer
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
const data = utils.sheet_to_json<President>(ws); // generate objects
|
||||
@ -314,7 +435,11 @@ export default function SheetJSKaiokenAoO() {
|
||||
}
|
||||
```
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
@ -323,9 +448,9 @@ export default function SheetJSKaiokenAoO() {
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Kaioken | ViteJS | Date |
|
||||
|:---------|:--------|:-----------|
|
||||
| `0.11.2` | `5.2.6` | 2024-03-24 |
|
||||
| Kaioken | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `0.17.0` | `5.2.11` | 2024-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
@ -334,8 +459,8 @@ This demo was tested in the following environments:
|
||||
```bash
|
||||
npm create vite@latest sheetjs-kaioken -- --template vanilla-ts
|
||||
cd sheetjs-kaioken
|
||||
pnpm add --save kaioken
|
||||
pnpm add --save vite-plugin-kaioken -D
|
||||
npm add --save kaioken
|
||||
npm add --save vite-plugin-kaioken -D
|
||||
```
|
||||
|
||||
2) Create a new file `vite.config.ts` with the following content:
|
||||
@ -345,14 +470,6 @@ import { defineConfig } from "vite"
|
||||
import kaioken from "vite-plugin-kaioken"
|
||||
|
||||
export default defineConfig({
|
||||
esbuild: {
|
||||
jsxInject: `import * as kaioken from "kaioken"`,
|
||||
jsx: "transform",
|
||||
jsxFactory: "kaioken.createElement",
|
||||
jsxFragment: "kaioken.fragment",
|
||||
loader: "tsx",
|
||||
include: ["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js"],
|
||||
},
|
||||
plugins: [kaioken()],
|
||||
})
|
||||
```
|
||||
@ -381,8 +498,8 @@ mount(App, root!);
|
||||
6) Install the SheetJS dependency and start the dev server:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
pnpm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
pnpm run dev`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm run dev`}
|
||||
</CodeBlock>
|
||||
|
||||
7) Open a web browser and access the displayed URL (`http://localhost:5173`)
|
||||
@ -393,7 +510,7 @@ and the page will attempt to download `SheetJSKaiokenAoO.xlsx`.
|
||||
8) Build the site:
|
||||
|
||||
```bash
|
||||
pnpm run build
|
||||
npm run build
|
||||
```
|
||||
|
||||
The generated site will be placed in the `dist` folder.
|
||||
@ -410,7 +527,7 @@ and test the page.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
When the page loads, the app will fetch <https://sheetjs.com/pres.xlsx> and
|
||||
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
|
||||
display the data from the first worksheet in a TABLE. The "Export XLSX" button
|
||||
will generate a workbook that can be opened in a spreadsheet editor.
|
||||
|
||||
@ -441,7 +558,7 @@ export default function SheetJSKaiokenHTML() {
|
||||
|
||||
/* Fetch and update the state once */
|
||||
useEffect(() => { (async() => {
|
||||
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const wb = read(f); // parse the array buffer
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
// highlight-start
|
||||
@ -468,7 +585,8 @@ export default function SheetJSKaiokenHTML() {
|
||||
}
|
||||
```
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
@ -477,9 +595,9 @@ export default function SheetJSKaiokenHTML() {
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Kaioken | ViteJS | Date |
|
||||
|:---------|:--------|:-----------|
|
||||
| `0.11.2` | `5.2.6` | 2024-03-24 |
|
||||
| Kaioken | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `0.17.0` | `5.2.11` | 2024-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
@ -488,8 +606,8 @@ This demo was tested in the following environments:
|
||||
```bash
|
||||
npm create vite@latest sheetjs-kaioken -- --template vanilla-ts
|
||||
cd sheetjs-kaioken
|
||||
pnpm add --save kaioken
|
||||
pnpm add --save vite-plugin-kaioken -D
|
||||
npm add --save kaioken
|
||||
npm add --save vite-plugin-kaioken -D
|
||||
```
|
||||
|
||||
2) Create a new file `vite.config.ts` with the following content:
|
||||
@ -499,14 +617,6 @@ import { defineConfig } from "vite"
|
||||
import kaioken from "vite-plugin-kaioken"
|
||||
|
||||
export default defineConfig({
|
||||
esbuild: {
|
||||
jsxInject: `import * as kaioken from "kaioken"`,
|
||||
jsx: "transform",
|
||||
jsxFactory: "kaioken.createElement",
|
||||
jsxFragment: "kaioken.fragment",
|
||||
loader: "tsx",
|
||||
include: ["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js"],
|
||||
},
|
||||
plugins: [kaioken()],
|
||||
})
|
||||
```
|
||||
@ -535,8 +645,8 @@ mount(App, root!);
|
||||
6) Install the SheetJS dependency and start the dev server:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
pnpm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
pnpm run dev`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm run dev`}
|
||||
</CodeBlock>
|
||||
|
||||
7) Open a web browser and access the displayed URL (`http://localhost:5173`)
|
||||
@ -547,7 +657,7 @@ and the page will attempt to download `SheetJSKaiokenHTML.xlsx`.
|
||||
8) Build the site:
|
||||
|
||||
```bash
|
||||
pnpm run build
|
||||
npm run build
|
||||
```
|
||||
|
||||
The generated site will be placed in the `dist` folder.
|
||||
@ -564,13 +674,14 @@ and test the page.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
When the page loads, the app will fetch <https://sheetjs.com/pres.xlsx> and
|
||||
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
|
||||
display the data from the first worksheet in a TABLE. The "Export XLSX" button
|
||||
will generate a workbook that can be opened in a spreadsheet editor.
|
||||
|
||||
</details>
|
||||
|
||||
[^1]: See [`useState`](https://kaioken.dev/docs/hooks/usestate) in the Kaioken documentation.
|
||||
[^2]: See [`useEffect`](https://kaioken.dev/docs/hooks/useeffect) in the Kaioken documentation.
|
||||
[^3]: See [`useCallback`](https://kaioken.dev/docs/hooks/usecallback) in the Kaioken documentation.
|
||||
[^4]: See [`useCallback`](https://kaioken.dev/docs/hooks/usecallback) in the Kaioken documentation.
|
||||
[^1]: See [`useState`](https://kaioken.dev/docs/hooks/useState) in the Kaioken documentation.
|
||||
[^2]: See [`useAsync`](https://kaioken.dev/docs/hooks/useAsync) in the Kaioken documentation.
|
||||
[^3]: See [`useEffect`](https://kaioken.dev/docs/hooks/useEffect) in the Kaioken documentation.
|
||||
[^4]: See [`useCallback`](https://kaioken.dev/docs/hooks/useCallback) in the Kaioken documentation.
|
||||
[^5]: See [`useCallback`](https://kaioken.dev/docs/hooks/useCallback) in the Kaioken documentation.
|
||||
|
@ -57,11 +57,13 @@ loaded into the site. This sheet will have known columns.
|
||||
|
||||
#### State
|
||||
|
||||
The example [presidents sheet](https://sheetjs.com/pres.xlsx) has one header row
|
||||
with "Name" and "Index" columns. The natural JS representation is an object for
|
||||
each row, using the values in the first rows as keys:
|
||||
The example [presidents sheet](https://docs.sheetjs.com/pres.xlsx) has one
|
||||
header row with "Name" and "Index" columns. The natural JS representation is an
|
||||
object for each row, using the values in the first rows as keys:
|
||||
|
||||
<table><thead><tr><th>Spreadsheet</th><th>State</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>State</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
@ -159,8 +161,8 @@ import { read, utils } from 'xlsx';
|
||||
|
||||
/* Fetch and update the state once */
|
||||
useEffect(() => { (async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
// highlight-start
|
||||
@ -186,8 +188,8 @@ import { read, utils } from 'xlsx';
|
||||
|
||||
/* Fetch and update the state once */
|
||||
useEffect(() => { (async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
// highlight-start
|
||||
@ -284,7 +286,7 @@ export default function SheetJSReactAoO() {
|
||||
|
||||
/* Fetch and update the state once */
|
||||
useEffect(() => { (async() => {
|
||||
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
// highlight-start
|
||||
const wb = read(f); // parse the array buffer
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
@ -317,7 +319,8 @@ export default function SheetJSReactAoO() {
|
||||
}
|
||||
```
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
@ -452,7 +455,7 @@ NextJS requires a number of workarounds for simple client-side JavaScript code.
|
||||
|
||||
:::
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
NextJS collects telemetry by default. The `telemetry` subcommand can disable it:
|
||||
|
||||
@ -541,7 +544,7 @@ and test the page.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
When the page loads, the app will fetch <https://sheetjs.com/pres.xlsx> and
|
||||
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
|
||||
display the data from the first worksheet in a TABLE. The "Export XLSX" button
|
||||
will generate a workbook that can be opened in a spreadsheet editor.
|
||||
|
||||
@ -574,7 +577,7 @@ export default function SheetJSReactHTML() {
|
||||
|
||||
/* Fetch and update the state once */
|
||||
useEffect(() => { (async() => {
|
||||
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const wb = read(f); // parse the array buffer
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
// highlight-start
|
||||
@ -600,7 +603,8 @@ export default function SheetJSReactHTML() {
|
||||
}
|
||||
```
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
@ -709,7 +713,7 @@ and test the page.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
When the page loads, the app will fetch <https://sheetjs.com/pres.xlsx> and
|
||||
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
|
||||
display the data from the first worksheet in a TABLE. The "Export XLSX" button
|
||||
will generate a workbook that can be opened in a spreadsheet editor.
|
||||
|
||||
|
@ -38,7 +38,7 @@ should be directed to the Angular project.
|
||||
|
||||
:::
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
Angular CLI enables telemetry by default. When using a recent version, disable
|
||||
analytics globally through the CLI tool before creating a new project:
|
||||
@ -69,7 +69,7 @@ import { read, utils, writeFile } from 'xlsx';
|
||||
The various SheetJS APIs work with various data shapes. The preferred state
|
||||
depends on the application.
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
Angular 17 broke backwards compatibility with projects using Angular 2 - 16.
|
||||
|
||||
@ -87,11 +87,13 @@ loaded into the site. This sheet will have known columns.
|
||||
|
||||
#### State
|
||||
|
||||
The example [presidents sheet](https://sheetjs.com/pres.xlsx) has one header row
|
||||
with "Name" and "Index" columns. The natural JS representation is an object for
|
||||
each row, using the values in the first rows as keys:
|
||||
The example [presidents sheet](https://docs.sheetjs.com/pres.xlsx) has one
|
||||
header row with "Name" and "Index" columns. The natural JS representation is an
|
||||
object for each row, using the values in the first rows as keys:
|
||||
|
||||
<table><thead><tr><th>Spreadsheet</th><th>State</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>State</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
@ -182,8 +184,8 @@ interface President { Name: string; Index: number };
|
||||
export class AppComponent {
|
||||
rows: President[] = [ { Name: "SheetJS", Index: 0 }];
|
||||
ngOnInit(): void { (async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
// highlight-start
|
||||
@ -329,8 +331,8 @@ export class AppComponent {
|
||||
// highlight-next-line
|
||||
rows: President[] = [ { Name: "SheetJS", Index: 0 }];
|
||||
ngOnInit(): void { (async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse workbook */
|
||||
@ -387,8 +389,8 @@ export class AppComponent {
|
||||
// highlight-next-line
|
||||
rows: President[] = [ { Name: "SheetJS", Index: 0 }];
|
||||
ngOnInit(): void { (async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse workbook */
|
||||
@ -414,7 +416,8 @@ export class AppComponent {
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -533,8 +536,8 @@ export class AppComponent {
|
||||
@ViewChild('tableau') tabeller!: ElementRef<HTMLDivElement>;
|
||||
// highlight-end
|
||||
ngOnInit(): void { (async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse workbook */
|
||||
@ -580,8 +583,8 @@ export class AppComponent {
|
||||
@ViewChild('tableau') tabeller!: ElementRef<HTMLDivElement>;
|
||||
// highlight-end
|
||||
ngOnInit(): void { (async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse workbook */
|
||||
@ -607,7 +610,8 @@ export class AppComponent {
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -720,7 +724,7 @@ this.columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({
|
||||
|
||||
## Older Versions
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
This demo is included for legacy deployments. There are incompatibilities with
|
||||
different NodeJS and other ecosystem versions. Issues should be raised with
|
||||
@ -1034,7 +1038,7 @@ will have an `ng-version` attribute.
|
||||
npm run build
|
||||
```
|
||||
|
||||
[^1]: The main website for Angular versions 2-16 is <https://angular.io/> . The project moved to a new domain <https://angular.dev/> during the Angular 17 launch.
|
||||
[^1]: The main website for Angular versions 2-16 is https://angular.io/ . The project moved to a new domain https://angular.dev/ during the Angular 17 launch.
|
||||
[^2]: See `OnInit` in the [Angular 2-16 docs](https://angular.io/api/core/OnInit) or [Angular 17 docs](https://angular.dev/guide/components/lifecycle#ngoninit)
|
||||
[^3]: See [`ngFor`](https://angular.io/api/common/NgFor) in the Angular 2-16 docs.
|
||||
[^4]: See [`@for`](https://angular.dev/api/core/@for) in the Angular 17 docs.
|
||||
|
@ -56,11 +56,13 @@ loaded into the site. This sheet will have known columns.
|
||||
|
||||
#### State
|
||||
|
||||
The example [presidents sheet](https://sheetjs.com/pres.xlsx) has one header row
|
||||
with "Name" and "Index" columns. The natural JS representation is an object for
|
||||
each row, using the values in the first rows as keys:
|
||||
The example [presidents sheet](https://docs.sheetjs.com/pres.xlsx) has one
|
||||
header row with "Name" and "Index" columns. The natural JS representation is an
|
||||
object for each row, using the values in the first rows as keys:
|
||||
|
||||
<table><thead><tr><th>Spreadsheet</th><th>State</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>State</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
@ -168,8 +170,8 @@ const pres = ref([]);
|
||||
|
||||
/* Fetch and update the state once */
|
||||
onMounted(async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
// highlight-start
|
||||
@ -205,8 +207,8 @@ const pres = ref<President[]>([]);
|
||||
|
||||
/* Fetch and update the state once */
|
||||
onMounted(async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
// highlight-start
|
||||
@ -313,8 +315,8 @@ import { read, utils, writeFileXLSX } from 'xlsx';
|
||||
const rows = ref([]);
|
||||
|
||||
onMounted(async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse workbook */
|
||||
@ -345,7 +347,8 @@ function exportFile() {
|
||||
</template>
|
||||
```
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
@ -354,9 +357,9 @@ function exportFile() {
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| VueJS | ViteJS | Date |
|
||||
|:--------|:--------|:-----------|
|
||||
| `3.3.9` | `4.5.1` | 2023-12-04 |
|
||||
| VueJS | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `3.4.27` | `5.2.11` | 2024-05-26 |
|
||||
|
||||
:::
|
||||
|
||||
@ -481,8 +484,8 @@ const html = ref("");
|
||||
const tableau = ref();
|
||||
|
||||
onMounted(async() => {
|
||||
/* Download from https://sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://sheetjs.com/pres.numbers");
|
||||
/* Download from https://docs.sheetjs.com/pres.numbers */
|
||||
const f = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await f.arrayBuffer();
|
||||
|
||||
/* parse workbook */
|
||||
@ -505,7 +508,8 @@ function exportFile() {
|
||||
</template>
|
||||
```
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
|
@ -25,7 +25,7 @@ models and data flow strategies.
|
||||
This demo focuses on Svelte concepts. Other demos cover general deployments:
|
||||
|
||||
- [Static Site Generation powered by SvelteKit](/docs/demos/static/svelte)
|
||||
- [iOS applications powered by CapacitorJS](/docs/demos/mobile/capacitor)
|
||||
- [iOS and Android applications powered by CapacitorJS](/docs/demos/mobile/capacitor)
|
||||
- [Desktop application powered by Wails](/docs/demos/desktop/wails)
|
||||
|
||||
:::
|
||||
@ -50,11 +50,29 @@ depends on the application.
|
||||
### Array of Objects
|
||||
|
||||
Typically, some users will create a spreadsheet with source data that should be
|
||||
loaded into the site. This sheet will have known columns. For example, our
|
||||
[presidents sheet](https://sheetjs.com/pres.xlsx) has "Name" / "Index" columns:
|
||||
loaded into the site. This sheet will have known columns. For example, "Name"
|
||||
and "Index" are used in [`pres.xlsx`](https://docs.sheetjs.com/pres.xlsx):
|
||||
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>State</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
</td><td>
|
||||
|
||||
```js
|
||||
[
|
||||
{ Name: "Bill Clinton", Index: 42 },
|
||||
{ Name: "GeorgeW Bush", Index: 43 },
|
||||
{ Name: "Barack Obama", Index: 44 },
|
||||
{ Name: "Donald Trump", Index: 45 },
|
||||
{ Name: "Joseph Biden", Index: 46 }
|
||||
]
|
||||
```
|
||||
|
||||
</td></tr></tbody></table>
|
||||
|
||||
This naturally maps to an array of typed objects, as in the TS example below:
|
||||
|
||||
```ts
|
||||
@ -65,24 +83,12 @@ interface President {
|
||||
Index: number;
|
||||
}
|
||||
|
||||
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const wb = read(f);
|
||||
const data = utils.sheet_to_json<President>(wb.Sheets[wb.SheetNames[0]]);
|
||||
console.log(data);
|
||||
```
|
||||
|
||||
`data` will be an array of objects:
|
||||
|
||||
```js
|
||||
[
|
||||
{ Name: "Bill Clinton", Index: 42 },
|
||||
{ Name: "GeorgeW Bush", Index: 43 },
|
||||
{ Name: "Barack Obama", Index: 44 },
|
||||
{ Name: "Donald Trump", Index: 45 },
|
||||
{ Name: "Joseph Biden", Index: 46 }
|
||||
]
|
||||
```
|
||||
|
||||
A component will typically map over the data. The following example generates
|
||||
a TABLE with a row for each President:
|
||||
|
||||
@ -96,7 +102,7 @@ let pres = [];
|
||||
|
||||
/* Fetch and update the state once */
|
||||
onMount(async() => {
|
||||
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const wb = read(f); // parse the array buffer
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
// highlight-start
|
||||
@ -128,15 +134,16 @@ function exportFile() {
|
||||
</main>
|
||||
```
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Svelte | ViteJS | Date |
|
||||
|:--------|:--------|:-----------|
|
||||
| `4.2.8` | `5.0.5` | 2023-12-04 |
|
||||
| SvelteJS | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `4.2.18` | `5.2.13` | 2024-06-07 |
|
||||
|
||||
:::
|
||||
|
||||
@ -201,7 +208,7 @@ let tbl;
|
||||
|
||||
/* Fetch and update the state once */
|
||||
onMount(async() => {
|
||||
const f = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const f = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const wb = read(f); // parse the array buffer
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
// highlight-start
|
||||
@ -227,15 +234,16 @@ function exportFile() {
|
||||
</main>
|
||||
```
|
||||
|
||||
<details open><summary><b>How to run the example</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Svelte | ViteJS | Date |
|
||||
|:--------|:--------|:-----------|
|
||||
| `4.2.8` | `5.0.5` | 2023-12-04 |
|
||||
| SvelteJS | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `4.2.18` | `5.2.13` | 2024-06-07 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -10,7 +10,7 @@ sidebar_position: 7
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
This demo is for the legacy AngularJS framework (version 1).
|
||||
|
||||
@ -34,10 +34,10 @@ models and data flow strategies.
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:------------------|:-----------|
|
||||
| `1.8.2` (latest) | 2023-12-04 |
|
||||
| `1.2.32` (legacy) | 2023-12-04 |
|
||||
| Browser | Version | Date |
|
||||
|:-------------|:------------------|:-----------|
|
||||
| Chromiun 125 | `1.8.2` (latest) | 2024-06-09 |
|
||||
| Chromium 125 | `1.2.32` (legacy) | 2024-06-09 |
|
||||
|
||||
:::
|
||||
|
||||
@ -73,17 +73,17 @@ property to `"arraybuffer"` ensures the result is an `ArrayBuffer` object.
|
||||
The SheetJS [`read`](/docs/api/parse-options) method can parse the `ArrayBuffer`
|
||||
and return a SheetJS workbook object[^2].
|
||||
|
||||
The following controller fetches [a sample file](https://sheetjs.com/pres.xlsx),
|
||||
This controller fetches [a sample file](https://docs.sheetjs.com/pres.xlsx),
|
||||
parses the result into a workbook, extracts the first worksheet, and uses the
|
||||
SheetJS [`sheet_to_html`](/docs/api/utilities/html#html-table-output) method to
|
||||
generate a HTML table:
|
||||
|
||||
```js
|
||||
```js title="Sample Controller"
|
||||
/* The controller function must accept a `$http` argument */
|
||||
app.controller('sheetjs', function($scope, $http) {
|
||||
/* fetch https://sheetjs.com/pres.xlsx */
|
||||
/* fetch https://docs.sheetjs.com/pres.xlsx */
|
||||
$http({
|
||||
method:'GET', url:'https://sheetjs.com/pres.xlsx',
|
||||
method:'GET', url:'https://docs.sheetjs.com/pres.xlsx',
|
||||
/* ensure the result is an ArrayBuffer object */
|
||||
responseType:'arraybuffer'
|
||||
}).then(function(data) {
|
||||
@ -167,11 +167,13 @@ depends on the application.
|
||||
|
||||
### Array of Objects
|
||||
|
||||
The example [presidents sheet](https://sheetjs.com/pres.xlsx) has one header row
|
||||
with "Name" and "Index" columns. The natural JS representation is an object for
|
||||
each row, using the values in the first rows as keys:
|
||||
The example [presidents sheet](https://docs.sheetjs.com/pres.xlsx) has one
|
||||
header row with "Name" and "Index" columns. The natural JS representation is an
|
||||
object for each row, using the values in the first rows as keys:
|
||||
|
||||
<table><thead><tr><th>Spreadsheet</th><th>State</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>State</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
@ -196,7 +198,7 @@ file, generates row objects, and stores the array in the state:
|
||||
```js
|
||||
app.controller('sheetjs', function($scope, $http) {
|
||||
$http({
|
||||
url:'https://sheetjs.com/pres.xlsx',
|
||||
url:'https://docs.sheetjs.com/pres.xlsx',
|
||||
method:'GET', responseType:'arraybuffer'
|
||||
}).then(function(data) {
|
||||
var wb = XLSX.read(data.data);
|
||||
@ -235,7 +237,8 @@ $scope.exportSheetJS = function() {
|
||||
};
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary open><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
1) Save the following to `index.html`:
|
||||
|
||||
@ -272,7 +275,7 @@ app.controller('sheetjs', function($scope, $http) {
|
||||
XLSX.writeFile(wb, "SheetJSAngularJSAoO.xlsx");
|
||||
};
|
||||
$http({
|
||||
url:'https://sheetjs.com/pres.xlsx',
|
||||
url:'https://docs.sheetjs.com/pres.xlsx',
|
||||
method:'GET', responseType:'arraybuffer'
|
||||
}).then(function(data) {
|
||||
var wb = XLSX.read(data.data);
|
||||
@ -288,6 +291,10 @@ app.controller('sheetjs', function($scope, $http) {
|
||||
2) Start a local web server with `npx http-server .` and access the displayed
|
||||
URL with a web browser (typically `http://localhost:8080`)
|
||||
|
||||
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
|
||||
store an array of objects in state. When the "Export Table" button is clicked,
|
||||
a worksheet is created and exported to XLSX.
|
||||
|
||||
</details>
|
||||
|
||||
### HTML
|
||||
@ -312,7 +319,7 @@ requires the `ngSanitize` plugin[^4].
|
||||
var app = angular.module('s5s', ['ngSanitize']);
|
||||
app.controller('sheetjs', function($scope, $http) {
|
||||
$http({
|
||||
url:'https://sheetjs.com/pres.xlsx',
|
||||
url:'https://docs.sheetjs.com/pres.xlsx',
|
||||
method:'GET', responseType:'arraybuffer'
|
||||
}).then(function(data) {
|
||||
var wb = XLSX.read(data.data);
|
||||
@ -336,7 +343,8 @@ The HTML table can be directly exported with [`table_to_book`](/docs/api/utiliti
|
||||
};
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary open><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
1) Save the following to `index.html`:
|
||||
|
||||
@ -367,7 +375,7 @@ app.controller('sheetjs', function($scope, $http) {
|
||||
XLSX.writeFile(wb, "SheetJSAngularJSHTML.xlsx");
|
||||
};
|
||||
$http({
|
||||
url:'https://sheetjs.com/pres.xlsx',
|
||||
url:'https://docs.sheetjs.com/pres.xlsx',
|
||||
method:'GET', responseType:'arraybuffer'
|
||||
}).then(function(data) {
|
||||
var wb = XLSX.read(data.data);
|
||||
@ -382,6 +390,10 @@ app.controller('sheetjs', function($scope, $http) {
|
||||
2) Start a local web server with `npx http-server .` and access the displayed
|
||||
URL with a web browser (typically `http://localhost:8080`)
|
||||
|
||||
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
|
||||
store the HTML string in state. When the "Export Table" button is clicked, a
|
||||
worksheet is created and exported to XLSX.
|
||||
|
||||
</details>
|
||||
|
||||
[^1]: See [`$http`](https://docs.angularjs.org/api/ng/service/$http) in the AngularJS documentation.
|
||||
|
@ -57,13 +57,13 @@ require(
|
||||
</script>`}
|
||||
</CodeBlock>
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
The official Google CDN does not have the newest releases of Dojo Toolkit
|
||||
|
||||
**This is a known Google CDN bug.**
|
||||
|
||||
The script <https://docs.sheetjs.com/dojo/dojo.js> was fetched from the official
|
||||
The script https://docs.sheetjs.com/dojo/dojo.js was fetched from the official
|
||||
`1.17.3` uncompressed release artifact[^1].
|
||||
|
||||
:::
|
||||
@ -72,7 +72,11 @@ The script <https://docs.sheetjs.com/dojo/dojo.js> was fetched from the official
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
The demos were last tested on 2023-12-04.
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Platform | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 125 | 2024-06-08 |
|
||||
|
||||
Demos exclusively using Dojo Core were tested using Dojo Toolkit `1.17.3`.
|
||||
|
||||
@ -99,7 +103,7 @@ The following example generates a HTML table from the first worksheet:
|
||||
<div id="tbl"></div>
|
||||
<script>
|
||||
require(["dojo/request/xhr", "xlsx"], function(xhr, _XLSX) {
|
||||
xhr("https://sheetjs.com/pres.numbers", {
|
||||
xhr("https://docs.sheetjs.com/pres.numbers", {
|
||||
headers: { "X-Requested-With": null },
|
||||
// highlight-next-line
|
||||
handleAs: "arraybuffer"
|
||||
@ -155,7 +159,7 @@ require([
|
||||
], function(ready, xhr, Memory, registry, _XLSX) {
|
||||
ready(function() {
|
||||
/* fetch test file */
|
||||
xhr("https://sheetjs.com/pres.xlsx", {
|
||||
xhr("https://docs.sheetjs.com/pres.xlsx", {
|
||||
headers: { "X-Requested-With": null },
|
||||
handleAs: "arraybuffer"
|
||||
}).then(function(ab) {
|
||||
@ -201,5 +205,5 @@ function export_all_data_from_store(store) {
|
||||
}
|
||||
```
|
||||
|
||||
[^1]: All Dojo Toolkit releases are available at <https://download.dojotoolkit.org/>. The mirrored `dojo.js` corresponds to the `1.17.3` uncompressed script <http://download.dojotoolkit.org/release-1.17.3/dojo.js.uncompressed.js>.
|
||||
[^1]: All Dojo Toolkit releases are available at https://download.dojotoolkit.org/. The mirrored `dojo.js` corresponds to the `1.17.3` uncompressed script http://download.dojotoolkit.org/release-1.17.3/dojo.js.uncompressed.js.
|
||||
[^2]: See [`dojo/store`](https://dojotoolkit.org/reference-guide/dojo/store.html) in the Dojo Toolkit documentation.
|
@ -38,7 +38,7 @@ else document.write(XLSX.version);
|
||||
|
||||
## Internet Explorer
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
Internet Explorer is unmaintained and users should consider modern browsers.
|
||||
The SheetJS testing grid still includes IE and should work.
|
||||
@ -48,7 +48,8 @@ The SheetJS testing grid still includes IE and should work.
|
||||
The modern upload and download strategies are not available in older versions of
|
||||
IE, but there are approaches using ActiveX or Flash.
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
This demo includes all of the support files for the Flash and ActiveX methods.
|
||||
|
||||
@ -76,7 +77,8 @@ npx -y http-server .
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary><b>Other Live Demos</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Other Live Demos</b> (click to show)</summary>
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -85,10 +87,10 @@ demo pages should be downloaded and hosted using a simple HTTP server.
|
||||
|
||||
:::
|
||||
|
||||
<https://oss.sheetjs.com/sheetjs/ajax.html> uses XMLHttpRequest to download test
|
||||
https://oss.sheetjs.com/sheetjs/ajax.html uses XMLHttpRequest to download test
|
||||
files and convert to CSV
|
||||
|
||||
<https://oss.sheetjs.com/sheetjs/> demonstrates reading files with `FileReader`.
|
||||
https://oss.sheetjs.com/sheetjs/ demonstrates reading files with `FileReader`.
|
||||
|
||||
Older versions of IE do not support HTML5 File API but do support Base64.
|
||||
|
||||
@ -198,18 +200,24 @@ included in the page and the relevant features are enabled on the target system.
|
||||
|
||||
### KnockoutJS
|
||||
|
||||
KnockoutJS was a popular MVVM framework.
|
||||
[KnockoutJS](https://knockoutjs.com/) was a popular MVVM framework.
|
||||
|
||||
The [Live demo](pathname:///knockout/knockout.html) shows a view model that is
|
||||
The [Live demo](pathname:///knockout/knockout3.html) shows a view model that is
|
||||
updated with file data and exported to spreadsheets.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last run on 2023 December 04 using KnockoutJS `3.4.2`
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| KnockoutJS | Date | Live Demo |
|
||||
|:-----------|:-----------|:-----------------------------------------------|
|
||||
| `3.5.0` | 2024-04-07 | [**KO3**](pathname:///knockout/knockout3.html) |
|
||||
| `2.3.0` | 2024-04-07 | [**KO2**](pathname:///knockout/knockout2.html) |
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Full Exposition</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Full Exposition</b> (click to show)</summary>
|
||||
|
||||
**State**
|
||||
|
||||
|
@ -41,9 +41,9 @@ This demo was tested in the following environments:
|
||||
|
||||
| ViteJS | Date |
|
||||
|:---------|:-----------|
|
||||
| `5.0.5` | 2023-12-04 |
|
||||
| `4.5.0` | 2023-12-04 |
|
||||
| `3.2.7` | 2023-12-05 |
|
||||
| `5.2.10` | 2024-04-27 |
|
||||
| `4.5.3` | 2024-04-27 |
|
||||
| `3.2.10` | 2024-04-27 |
|
||||
|
||||
:::
|
||||
|
||||
@ -98,7 +98,7 @@ interface President {
|
||||
|
||||
async function xport() {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data: President[] = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
|
@ -47,8 +47,19 @@ This demo was tested in the following environments:
|
||||
|
||||
| ESBuild | Date |
|
||||
|:----------|:-----------|
|
||||
| `0.14.14` | 2023-12-04 |
|
||||
| `0.19.8` | 2023-12-04 |
|
||||
| `0.21.4` | 2024-06-07 |
|
||||
| `0.20.2` | 2024-06-07 |
|
||||
| `0.19.12` | 2024-06-07 |
|
||||
| `0.18.20` | 2024-06-07 |
|
||||
| `0.17.19` | 2024-06-07 |
|
||||
| `0.16.17` | 2024-06-07 |
|
||||
| `0.15.18` | 2024-06-07 |
|
||||
| `0.14.54` | 2024-06-07 |
|
||||
| `0.13.15` | 2024-06-07 |
|
||||
| `0.12.29` | 2024-06-07 |
|
||||
| `0.11.23` | 2024-06-07 |
|
||||
| `0.10.2` | 2024-06-07 |
|
||||
| `0.9.7` | 2024-06-07 |
|
||||
|
||||
:::
|
||||
|
||||
|
@ -167,7 +167,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
|
||||
|
||||
document.getElementById("xport").addEventListener("click", function() {
|
||||
/* fetch JSON data and parse */
|
||||
var url = "https://sheetjs.com/data/executive.json";
|
||||
var url = "https://docs.sheetjs.com/executive.json";
|
||||
fetch(url).then(function(res) { return res.json(); }).then(function(raw_data) {
|
||||
|
||||
/* filter for the Presidents */
|
||||
@ -260,7 +260,7 @@ npx webpack@3.x -p
|
||||
</TabItem>
|
||||
<TabItem value="4+" label="4.x, 5.x and beyond" default>
|
||||
|
||||
:::warning Pinning specific versions of webpack
|
||||
:::danger Pinning specific versions of webpack
|
||||
|
||||
The webpack tooling is not designed for switching between versions. A specific
|
||||
version above 4.0 can be pinned by locally installing webpack and the CLI tool.
|
||||
|
@ -34,8 +34,21 @@ This demo was tested in the following environments:
|
||||
|
||||
| Browserify | Date |
|
||||
|:-----------|:-----------|
|
||||
| `17.0.0` | 2023-12-04 |
|
||||
| `3.46.1` | 2023-12-04 |
|
||||
| `17.0.0` | 2024-04-13 |
|
||||
| `16.5.2` | 2024-04-13 |
|
||||
| `15.2.0` | 2024-04-13 |
|
||||
| `14.5.0` | 2024-04-13 |
|
||||
| `13.3.0` | 2024-04-13 |
|
||||
| `12.0.2` | 2024-04-13 |
|
||||
| `11.2.0` | 2024-04-13 |
|
||||
| `10.2.6` | 2024-04-13 |
|
||||
| `9.0.8` | 2024-04-13 |
|
||||
| `8.1.3` | 2024-04-13 |
|
||||
| `7.1.0` | 2024-04-13 |
|
||||
| `6.3.4` | 2024-04-13 |
|
||||
| `5.13.1` | 2024-04-13 |
|
||||
| `4.2.3` | 2024-04-13 |
|
||||
| `3.46.1` | 2024-04-13 |
|
||||
|
||||
:::
|
||||
|
||||
@ -92,7 +105,7 @@ const { utils, version, writeFileXLSX } = require('xlsx');
|
||||
|
||||
document.getElementById("xport").addEventListener("click", function() {
|
||||
/* fetch JSON data and parse */
|
||||
var url = "https://sheetjs.com/data/executive.json";
|
||||
var url = "https://docs.sheetjs.com/executive.json";
|
||||
fetch(url).then(function(res) { return res.json(); }).then(function(raw_data) {
|
||||
|
||||
/* filter for the Presidents */
|
||||
|
@ -40,8 +40,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| RequireJS | Date |
|
||||
|:----------|:-----------|
|
||||
| `2.3.6` | 2024-03-01 |
|
||||
| `2.1.22` | 2023-12-04 |
|
||||
| `2.3.6` | 2024-04-27 |
|
||||
| `2.1.22` | 2024-04-27 |
|
||||
|
||||
:::
|
||||
|
||||
@ -162,7 +162,7 @@ example, the following script corresponds to RequireJS `2.1.22`:
|
||||
require(["xlsx"], function(XLSX) {
|
||||
document.getElementById("xport").addEventListener("click", function() {
|
||||
/* fetch JSON data and parse */
|
||||
var url = "https://sheetjs.com/data/executive.json";
|
||||
var url = "https://docs.sheetjs.com/executive.json";
|
||||
fetch(url).then(function(res) { return res.json(); }).then(function(raw_data) {
|
||||
|
||||
/* filter for the Presidents */
|
||||
|
@ -111,7 +111,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
|
||||
|
||||
document.getElementById("xport").addEventListener("click", async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
|
@ -34,8 +34,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `2.10.3` | 2023-12-04 |
|
||||
| `1.12.3` | 2023-12-04 |
|
||||
| `2.12.0` | 2024-06-08 |
|
||||
| `1.12.4` | 2024-06-08 |
|
||||
|
||||
:::
|
||||
|
||||
@ -51,7 +51,7 @@ can load relevant parts of the library:
|
||||
import { read, utils, writeFileXLSX } from 'xlsx';
|
||||
```
|
||||
|
||||
:::warning Parcel Bug
|
||||
:::danger Parcel Bug
|
||||
|
||||
Errors of the form `Could not statically evaluate fs call` stem from a Parcel
|
||||
bug[^1]. Upgrade to Parcel version 1.5.0 or later.
|
||||
@ -86,7 +86,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
|
||||
document.getElementById("vers").innerText = version;
|
||||
document.getElementById("xport").onclick = async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
@ -128,13 +128,14 @@ document.getElementById("xport").onclick = async() => {
|
||||
For ParcelJS version 1, the entire script should be copied to `index.js` and the
|
||||
main `index.html` page should load the `index.js` script:
|
||||
|
||||
<details><summary><b>ParcelJS v1 example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>ParcelJS v1 example</b> (click to show)</summary>
|
||||
|
||||
```html title="index.html"
|
||||
<body>
|
||||
<h3>SheetJS <span id="vers"></span> export demo</h3>
|
||||
<button id="xport">Click to Export!</button>
|
||||
<script src="index.js"></script>
|
||||
<script src="index.js" type="module"></script>
|
||||
<body>
|
||||
```
|
||||
|
||||
@ -145,7 +146,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
|
||||
document.getElementById("vers").innerText = version;
|
||||
document.getElementById("xport").onclick = async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
@ -207,7 +208,7 @@ yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
3) Run the ParcelJS development server:
|
||||
|
||||
```bash
|
||||
npx -y parcel@2.10.3 index.html
|
||||
npx -y parcel index.html
|
||||
```
|
||||
|
||||
The process will print a URL:
|
||||
@ -230,7 +231,7 @@ a web browser and click the "Click to Export!" button to generate a file.
|
||||
6) Build the production site:
|
||||
|
||||
```bash
|
||||
npx -y parcel@2.10.0 build index.html
|
||||
npx -y parcel build index.html
|
||||
```
|
||||
|
||||
The production site will be stored in the `dist` folder
|
||||
|
@ -35,7 +35,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:----------|:-----------|
|
||||
| `1.2.246` | 2023-12-04 |
|
||||
| `1.2.246` | 2024-04-27 |
|
||||
|
||||
:::
|
||||
|
||||
@ -63,9 +63,9 @@ part of the `utils` object, the required import is:
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
```
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
When this demo was tested against the `@swc/core@1.3.100`, `spack` crashed:
|
||||
When this demo was tested against recent versions of `@swc/core`, `spack` crashed:
|
||||
|
||||
```
|
||||
thread '<unnamed>' panicked at 'cannot access a scoped thread local variable without calling `set` first',
|
||||
@ -73,6 +73,8 @@ thread '<unnamed>' panicked at 'cannot access a scoped thread local variable wit
|
||||
|
||||
**This is a bug in SWC**
|
||||
|
||||
This bug is known to affect versions `1.3.100` and `1.4.17`.
|
||||
|
||||
Until the bug is fixed, it is strongly recommended to use `@swc/core@1.2.246`.
|
||||
|
||||
:::
|
||||
@ -121,7 +123,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
|
||||
|
||||
document.getElementById("xport").addEventListener("click", async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
|
@ -43,9 +43,18 @@ Complete Examples are included [in the "Dojo" demo](/docs/demos/frontend/dojo)
|
||||
|
||||
## Snowpack
|
||||
|
||||
Snowpack was a development tool built by the AstroJS team.
|
||||
|
||||
:::caution pass
|
||||
|
||||
Snowpack is no longer maintained. The developers recommend [ViteJS](/docs/demos/frontend/bundler/vitejs)
|
||||
|
||||
:::
|
||||
|
||||
Snowpack works with no caveats.
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -53,7 +62,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:--------|:-----------|
|
||||
| `3.8.8` | 2023-12-04 |
|
||||
| `3.8.8` | 2024-04-14 |
|
||||
|
||||
:::
|
||||
|
||||
@ -93,7 +102,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
|
||||
|
||||
document.getElementById("xport").addEventListener("click", async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
@ -164,9 +173,18 @@ Click on "Click here to export" to generate a file.
|
||||
|
||||
## WMR
|
||||
|
||||
WMR was a development tool built by the PreactJS team.
|
||||
|
||||
:::caution pass
|
||||
|
||||
WMR is no longer maintained. The developers recommend [ViteJS](/docs/demos/frontend/bundler/vitejs)
|
||||
|
||||
:::
|
||||
|
||||
WMR works with no caveats.
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -174,7 +192,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:--------|:-----------|
|
||||
| `3.8.0` | 2023-12-04 |
|
||||
| `3.8.0` | 2024-04-14 |
|
||||
|
||||
:::
|
||||
|
||||
@ -214,7 +232,7 @@ import { utils, version, writeFileXLSX } from 'xlsx';
|
||||
|
||||
document.getElementById("xport").addEventListener("click", async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://sheetjs.com/data/executive.json";
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
|
@ -65,7 +65,7 @@ The following demos are in separate pages:
|
||||
<a href={item.href}>{item.label}</a>{item.customProps?.summary && (" - " + item.customProps.summary)}
|
||||
</li>);
|
||||
})}
|
||||
<li><a href="/docs/demos/frontend/bundler#dojo">Dojo Toolkit</a></li>
|
||||
<li><a href="/docs/demos/frontend/bundler#snowpack">Snowpack</a></li>
|
||||
<li><a href="/docs/demos/frontend/bundler#wmr">WMR</a></li>
|
||||
<li><a href="/docs/demos/frontend/bundler/#dojo">Dojo Toolkit</a></li>
|
||||
<li><a href="/docs/demos/frontend/bundler/#snowpack">Snowpack</a></li>
|
||||
<li><a href="/docs/demos/frontend/bundler/#wmr">WMR</a></li>
|
||||
</ul>
|
||||
|
@ -62,7 +62,7 @@ flowchart LR
|
||||
|
||||
```js
|
||||
/* download data into an ArrayBuffer object */
|
||||
const res = await fetch("https://sheetjs.com/pres.numbers");
|
||||
const res = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await res.arrayBuffer(); // recover data as ArrayBuffer
|
||||
|
||||
/* parse file */
|
||||
@ -71,10 +71,9 @@ const wb = XLSX.read(ab);
|
||||
|
||||
## Browser Demos
|
||||
|
||||
When the page is accessed, the browser will attempt to download <https://sheetjs.com/pres.numbers>
|
||||
and read the workbook. The old table will be replaced with a table whose
|
||||
contents match the first worksheet. The table is generated using the SheetJS
|
||||
`sheet_to_html` method[^2]
|
||||
When the page is accessed, https://docs.sheetjs.com/pres.numbers will be fetched
|
||||
and parsed. The old table will be replaced with a table whose contents match the
|
||||
first worksheet. The SheetJS `sheet_to_html` method[^2] creates the HTML table.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -108,9 +107,10 @@ req.onload = function(e) {
|
||||
req.send();
|
||||
```
|
||||
|
||||
<details><summary><b>Live Download demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Download demo</b> (click to show)</summary>
|
||||
|
||||
This demo uses `XMLHttpRequest` to download <https://sheetjs.com/pres.numbers>
|
||||
This demo uses `XMLHttpRequest` to fetch https://docs.sheetjs.com/pres.numbers
|
||||
and show the data in an HTML table.
|
||||
|
||||
```jsx live
|
||||
@ -121,7 +121,7 @@ function SheetJSXHRDL() {
|
||||
React.useEffect(() => { (async() => {
|
||||
/* Fetch file */
|
||||
const req = new XMLHttpRequest();
|
||||
req.open("GET", "https://sheetjs.com/pres.numbers", true);
|
||||
req.open("GET", "https://docs.sheetjs.com/pres.numbers", true);
|
||||
req.responseType = "arraybuffer";
|
||||
req.onload = e => {
|
||||
/* Parse file */
|
||||
@ -160,10 +160,11 @@ fetch(url).then(function(res) {
|
||||
});
|
||||
```
|
||||
|
||||
<details><summary><b>Live Download demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Download demo</b> (click to show)</summary>
|
||||
|
||||
This demo uses `fetch` to download <https://sheetjs.com/pres.numbers> and show
|
||||
the data in an HTML table.
|
||||
This demo uses `fetch` to download https://docs.sheetjs.com/pres.numbers and
|
||||
show the data in an HTML table.
|
||||
|
||||
```jsx live
|
||||
function SheetJSFetchDL() {
|
||||
@ -172,7 +173,7 @@ function SheetJSFetchDL() {
|
||||
/* Fetch and update HTML */
|
||||
React.useEffect(() => { (async() => {
|
||||
/* Fetch file */
|
||||
const res = await fetch("https://sheetjs.com/pres.numbers");
|
||||
const res = await fetch("https://docs.sheetjs.com/pres.numbers");
|
||||
const ab = await res.arrayBuffer();
|
||||
|
||||
/* Parse file */
|
||||
@ -207,7 +208,7 @@ In a GET request, the default behavior is to return a `Blob` object. Passing
|
||||
|
||||
```js
|
||||
$.ajax({
|
||||
type: "GET", url: "https://sheetjs.com/pres.numbers",
|
||||
type: "GET", url: "https://docs.sheetjs.com/pres.numbers",
|
||||
|
||||
/* suppress jQuery post-processing */
|
||||
// highlight-next-line
|
||||
@ -254,10 +255,11 @@ async function workbook_dl_axios(url) {
|
||||
}
|
||||
```
|
||||
|
||||
<details><summary><b>Live Download demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Download demo</b> (click to show)</summary>
|
||||
|
||||
This demo uses `axios` to download <https://sheetjs.com/pres.numbers> and show
|
||||
the data in an HTML table.
|
||||
This demo uses `axios` to download https://docs.sheetjs.com/pres.numbers and
|
||||
show the data in an HTML table.
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -279,7 +281,7 @@ function SheetJSAxiosDL() {
|
||||
React.useEffect(() => { (async() => {
|
||||
if(typeof axios != "function") return setHTML("ReferenceError: axios is not defined");
|
||||
/* Fetch file */
|
||||
const res = await axios("https://sheetjs.com/pres.numbers", {responseType: "arraybuffer"});
|
||||
const res = await axios("https://docs.sheetjs.com/pres.numbers", {responseType: "arraybuffer"});
|
||||
|
||||
/* Parse file */
|
||||
const wb = XLSX.read(res.data);
|
||||
@ -315,10 +317,11 @@ superagent
|
||||
});
|
||||
```
|
||||
|
||||
<details><summary><b>Live Download demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live Download demo</b> (click to show)</summary>
|
||||
|
||||
This demo uses `superagent` to download <https://sheetjs.com/pres.numbers> and
|
||||
show the data in an HTML table.
|
||||
This demo uses `superagent` to download https://docs.sheetjs.com/pres.numbers
|
||||
and show the data in an HTML table.
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -342,7 +345,7 @@ function SheetJSSuperAgentDL() {
|
||||
return setHTML("ReferenceError: superagent is not defined");
|
||||
/* Fetch file */
|
||||
superagent
|
||||
.get("https://sheetjs.com/pres.numbers")
|
||||
.get("https://docs.sheetjs.com/pres.numbers")
|
||||
.responseType("arraybuffer")
|
||||
.end((err, res) => {
|
||||
/* Parse file */
|
||||
@ -371,7 +374,7 @@ The `https` module provides a low-level `get` method for HTTPS GET requests:
|
||||
```js title="SheetJSHTTPSGet.js"
|
||||
var https = require("https"), XLSX = require("xlsx");
|
||||
|
||||
https.get('https://sheetjs.com/pres.numbers', function(res) {
|
||||
https.get('https://docs.sheetjs.com/pres.numbers', function(res) {
|
||||
var bufs = [];
|
||||
res.on('data', function(chunk) { bufs.push(chunk); });
|
||||
res.on('end', function() {
|
||||
@ -384,7 +387,8 @@ https.get('https://sheetjs.com/pres.numbers', function(res) {
|
||||
});
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Environments
|
||||
|
||||
@ -431,7 +435,8 @@ async function parse_from_url(url) {
|
||||
}
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Environments
|
||||
|
||||
@ -459,7 +464,7 @@ async function parse_from_url(url) {
|
||||
}
|
||||
|
||||
(async() => {
|
||||
const wb = await parse_from_url('https://sheetjs.com/pres.numbers');
|
||||
const wb = await parse_from_url('https://docs.sheetjs.com/pres.numbers');
|
||||
/* print the first worksheet to console */
|
||||
var ws = wb.Sheets[wb.SheetNames[0]];
|
||||
console.log(XLSX.utils.sheet_to_csv(ws));
|
||||
@ -483,7 +488,7 @@ was added to the platform, third party modules wrapped the native APIs.
|
||||
|
||||
#### request
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
`request` has been deprecated and should only be used in legacy deployments.
|
||||
|
||||
@ -493,7 +498,7 @@ Setting the option `encoding: null` passes raw buffers:
|
||||
|
||||
```js title="SheetJSRequest.js"
|
||||
var XLSX = require('xlsx'), request = require('request');
|
||||
var url = 'https://sheetjs.com/pres.numbers';
|
||||
var url = 'https://docs.sheetjs.com/pres.numbers';
|
||||
|
||||
/* call `request` with the option `encoding: null` */
|
||||
// highlight-next-line
|
||||
@ -510,7 +515,8 @@ request(url, {encoding: null}, function(err, res, data) {
|
||||
});
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Environments
|
||||
|
||||
@ -552,7 +558,8 @@ async function workbook_dl_axios(url) {
|
||||
}
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Environments
|
||||
|
||||
@ -579,7 +586,7 @@ async function workbook_dl_axios(url) {
|
||||
}
|
||||
|
||||
(async() => {
|
||||
const wb = await workbook_dl_axios('https://sheetjs.com/pres.numbers');
|
||||
const wb = await workbook_dl_axios('https://docs.sheetjs.com/pres.numbers');
|
||||
/* print the first worksheet to console */
|
||||
var ws = wb.Sheets[wb.SheetNames[0]];
|
||||
console.log(XLSX.utils.sheet_to_csv(ws));
|
||||
|
@ -17,7 +17,7 @@ cloud storage solutions. Spreadsheets can be written using SheetJS and uploaded.
|
||||
|
||||
This demo explores file uploads using a number of browser APIs and wrapper
|
||||
libraries. The upload process will generate a sample XLSX workbook, upload the
|
||||
file to [a test server](#test-server), and display the response.
|
||||
file to [a test server](https://s2c.sheetjs.com), and display the response.
|
||||
|
||||
:::info pass
|
||||
|
||||
@ -60,14 +60,119 @@ flowchart LR
|
||||
form --> |POST\nrequest| server
|
||||
```
|
||||
|
||||
```js
|
||||
### Generating Files
|
||||
|
||||
In a typical scenario, a process generates arrays of simple objects.
|
||||
|
||||
The SheetJS `json_to_sheet` method[^2] generates a SheetJS worksheet object[^3].
|
||||
The `book_new` method[^4] creates a workbook object that includes the worksheet.
|
||||
|
||||
The `write` method[^5] generates the file in memory.
|
||||
|
||||
The following snippet creates a sample dataset and generates an `ArrayBuffer`
|
||||
object representing the workbook bytes:
|
||||
|
||||
```js title="Generating an XLSX file in memory"
|
||||
/* create sample SheetJS workbook object */
|
||||
var aoa = [
|
||||
["S", "h", "e", "e", "t", "J", "S"],
|
||||
[ 5, 4, 3, 3, 7, 9, 5]
|
||||
];
|
||||
var ws = XLSX.utils.aoa_to_sheet(aoa);
|
||||
var wb = XLSX.utils.book_new();
|
||||
var wb = XLSX.utils.book_new(ws, "Sheet1");
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
|
||||
|
||||
/* export SheetJS workbook object to XLSX file bytes */
|
||||
var data = XLSX.write(wb, {bookType: 'xlsx', type: 'array'});
|
||||
```
|
||||
|
||||
### Creating Form Data
|
||||
|
||||
`File` objects represent files. The `File` constructor accepts an array of data
|
||||
fragments and a filename.
|
||||
|
||||
Browser APIs typically represent form body data using `FormData` objects. The
|
||||
`append` method adds fields to the `FormData` object. Adding `File` objects
|
||||
effectively "attaches" a file in the upload.
|
||||
|
||||
The following snippet constructs a new `FormData` object. The `file` field in
|
||||
the form will be set to the data from the previous snippet:
|
||||
|
||||
```js title="Creating Form Data and attaching the generated file"
|
||||
/* create File */
|
||||
var file = new File([data], 'sheetjs.xlsx')
|
||||
// generated XLSX ^^^^ ^^^^^^^^^^^^ file name
|
||||
|
||||
/* build FormData with the generated file */
|
||||
var fdata = new FormData();
|
||||
fdata.append('file', file);
|
||||
// ^^^^ field name in the form body
|
||||
```
|
||||
|
||||
### POST Request
|
||||
|
||||
This demo explores a number of APIs and libraries for making POST requests. Each
|
||||
approach will upload data stored in `FormData` objects.
|
||||
|
||||
This snippet uses `XMLHttpRequest` to upload data to https://s2c.sheetjs.com:
|
||||
|
||||
```js title="Uploading Form Data with XMLHttpRequest"
|
||||
/* send data using XMLHttpRequest */
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("POST", "https://s2c.sheetjs.com", true);
|
||||
req.send(fdata);
|
||||
```
|
||||
|
||||
## Browser Demos
|
||||
|
||||
When the upload button is clicked, the browser will build up a new workbook,
|
||||
generate a XLSX file, upload it to https://s2c.sheetjs.com and show the
|
||||
response. If the process was successful, a HTML table will be displayed
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:------------|:-----------|
|
||||
| Chrome 120 | 2024-01-15 |
|
||||
| Safari 17.3 | 2024-02-21 |
|
||||
|
||||
:::
|
||||
|
||||
#### Test Server
|
||||
|
||||
The https://s2c.sheetjs.com service is currently hosted on Deno Deploy. The
|
||||
["Deno Deploy" demo](/docs/demos/cloud/deno#demo) covers the exact steps for
|
||||
deploying the service.
|
||||
|
||||
The CORS-enabled service handles POST requests by looking for uploaded files in
|
||||
the `"file"` key. If a file is found, the file will be parsed using the SheetJS
|
||||
`read` method[^6] and the first worksheet will be converted to HTML using the
|
||||
`sheet_to_html` method[^7].
|
||||
|
||||
### XMLHttpRequest
|
||||
|
||||
Using the `XMLHttpRequest` API, the `send` method can accept `FormData` objects:
|
||||
|
||||
```js title="Uploading Form Data with XMLHttpRequest"
|
||||
/* send data using XMLHttpRequest */
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("POST", "https://s2c.sheetjs.com", true);
|
||||
req.send(fdata);
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><b>Complete Code Snippet</b> (click to show)</summary>
|
||||
|
||||
```js title="SheetJS + XMLHttpRequest example"
|
||||
/* create sample SheetJS workbook object */
|
||||
var aoa = [
|
||||
["S", "h", "e", "e", "t", "J", "S"],
|
||||
[ 5, 4, 3, 3, 7, 9, 5]
|
||||
];
|
||||
const ws = XLSX.utils.aoa_to_sheet(aoa);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
|
||||
|
||||
/* export SheetJS workbook object to XLSX file bytes */
|
||||
@ -84,42 +189,13 @@ req.open("POST", "https://s2c.sheetjs.com", true);
|
||||
req.send(fdata);
|
||||
```
|
||||
|
||||
## Test Server
|
||||
</details>
|
||||
|
||||
The <https://s2c.sheetjs.com> service is currently hosted on Deno Deploy. The
|
||||
["Deno Deploy" demo](/docs/demos/cloud/deno#demo) covers the exact steps for
|
||||
deploying the service.
|
||||
|
||||
The CORS-enabled service handles POST requests by looking for uploaded files in
|
||||
the `"file"` key. If a file is found, the file will be parsed using the SheetJS
|
||||
`read` method[^2] and the first worksheet will be converted to HTML using the
|
||||
`sheet_to_html` method[^3].
|
||||
|
||||
## Browser Demos
|
||||
|
||||
When the upload button is clicked, the browser will build up a new workbook,
|
||||
generate a XLSX file, upload it to <https://s2c.sheetjs.com> and show the
|
||||
response. If the process was successful, a HTML table will be displayed
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:------------|:-----------|
|
||||
| Chrome 120 | 2024-01-15 |
|
||||
| Safari 17.3 | 2024-02-21 |
|
||||
|
||||
:::
|
||||
|
||||
### XMLHttpRequest
|
||||
|
||||
This demo uses [the code snippet from the intro](#uploading-binary-data).
|
||||
|
||||
<details><summary><b>Live demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Live demo</b> (click to show)</summary>
|
||||
|
||||
This demo starts from an array of arrays of data. When the button is clicked, a
|
||||
workbook file will be generated and uploaded to <https://s2c.sheetjs.com>. The
|
||||
workbook file will be generated and uploaded to https://s2c.sheetjs.com. The
|
||||
service will return a HTML table.
|
||||
|
||||
```jsx live
|
||||
@ -184,7 +260,15 @@ function SheetJSXHRUL() {
|
||||
|
||||
`fetch` takes a second parameter which allows for setting POST request body:
|
||||
|
||||
```js
|
||||
```js title="Uploading Form Data with fetch"
|
||||
/* send data using fetch */
|
||||
fetch("https://s2c.sheetjs.com", { method: "POST", body: fdata });
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><b>Complete Code Snippet</b> (click to show)</summary>
|
||||
|
||||
```js title="SheetJS + fetch example"
|
||||
/* create sample SheetJS workbook object */
|
||||
var aoa = [
|
||||
["S", "h", "e", "e", "t", "J", "S"],
|
||||
@ -206,9 +290,12 @@ fdata.append('file', new File([data], 'sheetjs.xlsx'));
|
||||
fetch("https://s2c.sheetjs.com", { method: "POST", body: fdata });
|
||||
```
|
||||
|
||||
<details><summary><b>Live demo</b> (click to show)</summary>
|
||||
</details>
|
||||
|
||||
This demo uses `fetch` to upload data to <https://s2c.sheetjs.com>. It will parse
|
||||
<details>
|
||||
<summary><b>Live demo</b> (click to show)</summary>
|
||||
|
||||
This demo uses `fetch` to upload data to https://s2c.sheetjs.com. It will parse
|
||||
the workbook and return an HTML table.
|
||||
|
||||
```jsx live
|
||||
@ -276,7 +363,15 @@ are still relevant.
|
||||
|
||||
Uploading form data is nearly identical to the `fetch` example:
|
||||
|
||||
```js
|
||||
```js title="Uploading Form Data with axios"
|
||||
/* send data using axios */
|
||||
axios("https://s2c.sheetjs.com", { method: "POST", body: fdata });
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><b>Complete Code Snippet</b> (click to show)</summary>
|
||||
|
||||
```js title="SheetJS + axios example"
|
||||
/* create sample SheetJS workbook object */
|
||||
var aoa = [
|
||||
["S", "h", "e", "e", "t", "J", "S"],
|
||||
@ -298,9 +393,12 @@ fdata.append('file', new File([data], 'sheetjs.xlsx'));
|
||||
axios("https://s2c.sheetjs.com", { method: "POST", data: fdata });
|
||||
```
|
||||
|
||||
<details><summary><b>Live demo</b> (click to show)</summary>
|
||||
</details>
|
||||
|
||||
This demo uses `axios` to upload data to <https://s2c.sheetjs.com>. It will parse
|
||||
<details>
|
||||
<summary><b>Live demo</b> (click to show)</summary>
|
||||
|
||||
This demo uses `axios` to upload data to https://s2c.sheetjs.com. It will parse
|
||||
the workbook and return an HTML table.
|
||||
|
||||
:::caution pass
|
||||
@ -375,7 +473,15 @@ with a "Fluent Interface".
|
||||
|
||||
The `send` method accepts a `FormData` object as the first argument:
|
||||
|
||||
```js
|
||||
```js title="Uploading Form Data with superagent"
|
||||
/* send data using superagent */
|
||||
superagent.post("https://s2c.sheetjs.com").send(fd);
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><b>Complete Code Snippet</b> (click to show)</summary>
|
||||
|
||||
```js title="SheetJS + superagent example"
|
||||
/* create sample SheetJS workbook object */
|
||||
var aoa = [
|
||||
["S", "h", "e", "e", "t", "J", "S"],
|
||||
@ -397,9 +503,12 @@ fdata.append('file', new File([data], 'sheetjs.xlsx'));
|
||||
superagent.post("https://s2c.sheetjs.com").send(fd);
|
||||
```
|
||||
|
||||
<details><summary><b>Live demo</b> (click to show)</summary>
|
||||
</details>
|
||||
|
||||
This demo uses `superagent` to upload data to <https://s2c.sheetjs.com>. It will
|
||||
<details>
|
||||
<summary><b>Live demo</b> (click to show)</summary>
|
||||
|
||||
This demo uses `superagent` to upload data to https://s2c.sheetjs.com. It will
|
||||
parse the workbook and return an HTML table.
|
||||
|
||||
:::caution pass
|
||||
@ -473,17 +582,23 @@ These examples show how to upload data in NodeJS.
|
||||
|
||||
### fetch
|
||||
|
||||
The `fetch` implementation mirrors the [browser `fetch`](#fetch).
|
||||
NodeJS `fetch`, available in version 20, mirrors the [browser `fetch`](#fetch).
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2023 November 19 against NodeJS `20.9.0`
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| NodeJS | Date |
|
||||
|:-----------|:-----------|
|
||||
| `20.12.1` | 2024-04-07 |
|
||||
| `21.7.2` | 2024-04-07 |
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
This demo uses `fetch` to upload data to <https://s2c.sheetjs.com>. It will parse
|
||||
This demo uses `fetch` to upload data to https://s2c.sheetjs.com. It will parse
|
||||
the workbook and return data in CSV rows.
|
||||
|
||||
1) Install the [SheetJS NodeJS module](/docs/getting-started/installation/nodejs):
|
||||
@ -533,6 +648,156 @@ It will print CSV contents of the test file.
|
||||
|
||||
</details>
|
||||
|
||||
### request
|
||||
|
||||
The deprecated [`request`](https://github.com/request/request) library is useful
|
||||
in legacy NodeJS deployments where `fetch` may not be available.
|
||||
|
||||
The SheetJS `write` method will generate NodeJS Buffer objects when the `type`
|
||||
option is set to `"buffer"`:
|
||||
|
||||
```js
|
||||
/* export SheetJS workbook object to XLSX file bytes */
|
||||
const data = XLSX.write(wb, {bookType: 'xlsx', type: 'buffer'});
|
||||
```
|
||||
|
||||
A `request` file object can be built using the Buffer. The file object must
|
||||
include an `options` object that specifies the file name and content type:
|
||||
|
||||
```js
|
||||
/* create a file object for the `request` form data */
|
||||
const request_file = {
|
||||
/* `value` can be a Buffer object */
|
||||
value: data,
|
||||
options: {
|
||||
/* `options.filename` is the filename that the server will see */
|
||||
filename: "sheetjs.xlsx",
|
||||
/* `options.contentType` must be set */
|
||||
contentType: "application/octet-stream"
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
The `request` and `request.post` methods accept an options argument. The
|
||||
`formData` property specifies the body to be uploaded. Property names correspond
|
||||
to the uploaded form names and values describe the uploaded content.
|
||||
|
||||
The `request` file object should be added to the `formData` object:
|
||||
|
||||
```js
|
||||
request({
|
||||
// ... other options ...
|
||||
formData: {
|
||||
// ... other form fields ...
|
||||
|
||||
/* the server will see the uploaded file in the `file` body property */
|
||||
/* highlight-next-line */
|
||||
file: request_file
|
||||
}
|
||||
}, function(err, res) { /* handle response ... */ });
|
||||
```
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| NodeJS | `request` | Date |
|
||||
|:-----------|:----------|:-----------|
|
||||
| `0.10.48` | `2.88.2` | 2024-04-07 |
|
||||
| `0.12.18` | `2.88.2` | 2024-04-07 |
|
||||
| `4.9.1` | `2.88.2` | 2024-04-07 |
|
||||
| `6.17.1` | `2.88.2` | 2024-04-07 |
|
||||
| `8.17.0` | `2.88.2` | 2024-04-07 |
|
||||
| `10.24.1` | `2.88.2` | 2024-04-07 |
|
||||
| `12.22.12` | `2.88.2` | 2024-04-07 |
|
||||
| `14.21.3` | `2.88.2` | 2024-04-07 |
|
||||
| `16.20.2` | `2.88.2` | 2024-04-07 |
|
||||
| `18.20.1` | `2.88.2` | 2024-04-07 |
|
||||
| `20.12.1` | `2.88.2` | 2024-04-07 |
|
||||
|
||||
:::
|
||||
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
This demo uses `request` to upload data to https://s2c.sheetjs.com. It will
|
||||
parse the workbook and return data in CSV rows.
|
||||
|
||||
1) Install the [SheetJS NodeJS module](/docs/getting-started/installation/nodejs)
|
||||
and `request` module:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz request`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Save the following to `SheetJSRequest.js`:
|
||||
|
||||
```js title="SheetJSRequest.js"
|
||||
const XLSX = require("xlsx");
|
||||
const request = require("request");
|
||||
|
||||
/* create sample SheetJS workbook object */
|
||||
var aoa = [
|
||||
["S", "h", "e", "e", "t", "J", "S"],
|
||||
[ 5, 4, 3, 3, 7, 9, 5]
|
||||
];
|
||||
const ws = XLSX.utils.aoa_to_sheet(aoa);
|
||||
const wb = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
|
||||
|
||||
/* export SheetJS workbook object to XLSX file bytes */
|
||||
var data = XLSX.write(wb, {bookType: 'xlsx', type: 'buffer'});
|
||||
|
||||
request({
|
||||
method: "POST",
|
||||
url: "https://s2c.sheetjs.com",
|
||||
headers: {
|
||||
Accept: "text/html"
|
||||
},
|
||||
formData: {
|
||||
type: "csv",
|
||||
file: {
|
||||
value: data,
|
||||
options: {
|
||||
filename: "sheetjs.xlsx",
|
||||
contentType: "application/octet-stream"
|
||||
}
|
||||
}
|
||||
}
|
||||
}, function(err, res, body) {
|
||||
if(err) return console.error(err);
|
||||
console.log(body);
|
||||
});
|
||||
```
|
||||
|
||||
3) Run the script:
|
||||
|
||||
```bash
|
||||
node SheetJSRequest.js
|
||||
```
|
||||
|
||||
It will print CSV contents of the test file.
|
||||
|
||||
:::caution pass
|
||||
|
||||
For legacy versions of NodeJS, the process may fail with a certificate error:
|
||||
|
||||
```
|
||||
{ [Error: certificate not trusted] code: 'CERT_UNTRUSTED' }
|
||||
```
|
||||
|
||||
The environment variable `NODE_TLS_REJECT_UNAUTHORIZED` can be set to `0`:
|
||||
|
||||
```bash
|
||||
env NODE_TLS_REJECT_UNAUTHORIZED="0" node SheetJSRequest.js
|
||||
```
|
||||
|
||||
**It is strongly recommended to upgrade to a newer version of NodeJS!**
|
||||
|
||||
:::
|
||||
|
||||
</details>
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@ -571,5 +836,9 @@ const res = await fetch(url, {method:"POST", body: fdata});
|
||||
If the generated file is valid, then the issue is in the server infrastructure.
|
||||
|
||||
[^1]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^3]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
|
||||
[^2]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^3]: See ["Worksheet Object" in "SheetJS Data Model"](/docs/csf/sheet) for more details.
|
||||
[^4]: See [`book_new` in "Utilities"](/docs/api/utilities/wb)
|
||||
[^5]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
[^6]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^7]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
|
||||
|
@ -151,11 +151,11 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz express
|
||||
node SheetJSExpressCSV.js
|
||||
```
|
||||
|
||||
4) Test POST requests using <https://sheetjs.com/pres.numbers> . The following
|
||||
commands should be run in a new terminal window:
|
||||
4) Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands
|
||||
should be run in a new terminal window:
|
||||
|
||||
```bash
|
||||
curl -LO https://sheetjs.com/pres.numbers
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
curl -X POST -F upload=@pres.numbers http://localhost:3000/upload
|
||||
```
|
||||
|
||||
|
@ -123,7 +123,7 @@ curl -LO https://docs.sheetjs.com/drash/SheetJSDrash.ts
|
||||
deno run --allow-net SheetJSDrash.ts
|
||||
```
|
||||
|
||||
3) Download the test file <https://sheetjs.com/pres.numbers>
|
||||
3) Download the test file https://docs.sheetjs.com/pres.numbers
|
||||
|
||||
4) Open `http://localhost:7262/` in your browser.
|
||||
|
||||
|
@ -151,11 +151,11 @@ app.listen(3000);
|
||||
bun run src/SheetJSElysia.ts
|
||||
```
|
||||
|
||||
5) Test POST requests using <https://sheetjs.com/pres.numbers> . The following
|
||||
commands should be run in a new terminal window:
|
||||
5) Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands
|
||||
should be run in a new terminal window:
|
||||
|
||||
```bash
|
||||
curl -LO https://sheetjs.com/pres.numbers
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
curl -X POST -F upload=@pres.numbers http://localhost:3000/
|
||||
```
|
||||
|
||||
|
@ -209,11 +209,11 @@ npx @nestjs/cli start
|
||||
|
||||
:::
|
||||
|
||||
8) Test POST requests using <https://sheetjs.com/pres.numbers> . The following
|
||||
commands should be run in a new terminal window:
|
||||
8) Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands
|
||||
should be run in a new terminal window:
|
||||
|
||||
```bash
|
||||
curl -LO https://sheetjs.com/pres.numbers
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
curl -X POST -F upload=@pres.numbers http://localhost:3000/sheetjs/upload
|
||||
```
|
||||
|
||||
|
@ -166,11 +166,11 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz fastify
|
||||
node SheetJSFastify.js
|
||||
```
|
||||
|
||||
3) Test POST requests using <https://sheetjs.com/pres.numbers> . The following
|
||||
commands should be run in a new terminal window:
|
||||
3) Test POST requests using https://docs.sheetjs.com/pres.numbers . The commands
|
||||
should be run in a new terminal window:
|
||||
|
||||
```bash
|
||||
curl -LO https://sheetjs.com/pres.numbers
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
curl -X POST -F upload=@pres.numbers http://localhost:3000/
|
||||
```
|
||||
|
||||
|
@ -120,7 +120,8 @@ That approach is not explored in this demo.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Complete Example</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Example</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -229,11 +230,11 @@ node main.mjs
|
||||
|
||||
Keep the server process running during the test.
|
||||
|
||||
6) Test with the [`pres.numbers` sample file](https://sheetjs.com/pres.numbers).
|
||||
6) Test with the [`pres.numbers` sample file](https://docs.sheetjs.com/pres.numbers).
|
||||
The following commands should be run in a new terminal window:
|
||||
|
||||
```bash
|
||||
curl -LO https://sheetjs.com/pres.numbers
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
curl -X POST -F upload=@pres.numbers http://localhost:7262/ -J -O
|
||||
```
|
||||
|
||||
@ -255,7 +256,8 @@ Bun provides the basic elements to implement a web server.
|
||||
|
||||
:::caution pass
|
||||
|
||||
Many hosted services like Deno Deploy do not offer filesystem access.
|
||||
Many hosted services, including [Deno Deploy](/docs/demos/cloud/deno#demo), do
|
||||
not offer filesystem access from scripts.
|
||||
|
||||
This breaks web frameworks that use the filesystem in body parsing.
|
||||
|
||||
@ -267,6 +269,6 @@ a body parser out of the box.
|
||||
#### Drash
|
||||
|
||||
In testing, [Drash](https://drash.land/drash/) had an in-memory body parser
|
||||
which could handle file uploads on hosted services like Deno Deploy.
|
||||
which could handle file uploads on [Deno Deploy](/docs/demos/cloud/deno#demo).
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/net/server/drash)**
|
||||
|
@ -162,7 +162,8 @@ added and exposed in a script.
|
||||
|
||||
[`pstextractor.js`](pathname:///pst/pstextractor.js) is loaded in the demo page.
|
||||
|
||||
<details><summary><b>Build instructions</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Build instructions</b> (click to show)</summary>
|
||||
|
||||
1) Initialize a new NodeJS project and install the dependency:
|
||||
|
||||
|
@ -19,7 +19,7 @@ This demo covers three workflows:
|
||||
- [Reading mail](#reading-mail) covers libraries for reading messages
|
||||
- [Data files](#data-files) covers mailbox file formats
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
There are a number of caveats when dealing with live mail servers. It is advised
|
||||
to follow connector module documentation carefully and test with new accounts
|
||||
@ -29,7 +29,7 @@ before integrating with important inboxes or accounts.
|
||||
|
||||
## Live Servers
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
It is strongly advised to use a test email address before using an important
|
||||
address. One small mistake could erase decades of messages or result in a block
|
||||
@ -378,9 +378,9 @@ const concat_RS = (stream) => new Promise((res, rej) => {
|
||||
| `gmail.com` | `imap.gmail.com` |
|
||||
| `fastmail.com` | `imap.fastmail.com` |
|
||||
|
||||
4) Download <https://sheetjs.com/pres.numbers>. Using a different account, send
|
||||
an email to the test account and attach the file. At the end of this step, the
|
||||
test account should have an email in the inbox that has an attachment.
|
||||
4) Download https://docs.sheetjs.com/pres.numbers . Using a different account,
|
||||
send an email to the test account and attach the file. At the end of this step,
|
||||
the test account should have an email in the inbox that has an attachment.
|
||||
|
||||
5) Run the script:
|
||||
|
||||
|
@ -50,7 +50,8 @@ sequenceDiagram
|
||||
end
|
||||
```
|
||||
|
||||
<details open><summary><b>Key Steps</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>Key Steps</b> (click to hide)</summary>
|
||||
|
||||
1) Launch the headless browser and load the target site.
|
||||
|
||||
@ -66,7 +67,7 @@ sequenceDiagram
|
||||
|
||||
</details>
|
||||
|
||||
This demo exports data from <https://sheetjs.com/demos/table>.
|
||||
This demo exports data from https://sheetjs.com/demos/table.
|
||||
|
||||
:::note pass
|
||||
|
||||
@ -343,7 +344,7 @@ After installing engines, re-run the script.
|
||||
|
||||
PhantomJS is a headless web browser powered by WebKit.
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
This information is provided for legacy deployments. PhantomJS development has
|
||||
been suspended and there are known vulnerabilities, so new projects should use
|
||||
@ -355,7 +356,8 @@ Binary strings are the favored data type. They can be safely passed from the
|
||||
browser context to the automation script. PhantomJS provides an API to write
|
||||
binary strings to file (`fs.write` using mode `wb`).
|
||||
|
||||
<details><summary><b>Integration Details and Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Integration Details and Demo</b> (click to show)</summary>
|
||||
|
||||
The steps are marked in the comments:
|
||||
|
||||
@ -407,7 +409,9 @@ This demo was tested in the following environments:
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `2.1.1` | 2024-03-15 |
|
||||
| `win10-x64` | `2.1.1` | 2024-03-24 |
|
||||
| `linux-x64` | `2.1.1` | 2024-03-29 |
|
||||
| `win11-x64` | `2.1.1` | 2024-05-22 |
|
||||
| `linux-x64` | `2.1.1` | 2024-04-25 |
|
||||
|
||||
:::
|
||||
|
||||
1) [Download and extract PhantomJS](https://phantomjs.org/download.html)
|
||||
|
@ -37,19 +37,19 @@ string and return an object that represents `document`. An API method such as
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Synthetic DOM Operations
|
||||
html(HTML\nstring)
|
||||
subgraph Synthetic DOM Operations
|
||||
html(HTML\nstring)
|
||||
doc{{`document`\nDOM Object}}
|
||||
end
|
||||
subgraph SheetJS Operations
|
||||
table{{DOM\nTable}}
|
||||
wb(((SheetJS\nWorkbook)))
|
||||
file(workbook\nfile)
|
||||
end
|
||||
end
|
||||
subgraph SheetJS Operations
|
||||
table{{DOM\nTable}}
|
||||
wb(((SheetJS\nWorkbook)))
|
||||
file(workbook\nfile)
|
||||
end
|
||||
html --> |Library\n\n| doc
|
||||
doc --> |DOM\nAPI| table
|
||||
table --> |`table_to_book`\n\n| wb
|
||||
wb --> |`writeFile`\n\n| file
|
||||
wb --> |`writeFile`\n\n| file
|
||||
```
|
||||
|
||||
SheetJS methods use features that may be missing from some DOM implementations.
|
||||
@ -107,7 +107,8 @@ const workbook = XLSX.utils.table_to_book(doc);
|
||||
XLSX.writeFile(workbook, "SheetJSDOM.xlsx");
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Demo</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -147,7 +148,8 @@ the following patches were needed:
|
||||
- TABLE `rows` property (explained above)
|
||||
- TR `cells` property (explained above)
|
||||
|
||||
<details><summary><b>Complete Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Demo</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -194,13 +196,14 @@ tested version (`0.8.10`), the following patches were needed:
|
||||
|
||||
```js
|
||||
Object.defineProperty(tbl.__proto__, "innerHTML", { get: function() {
|
||||
var outerHTML = new XMLSerializer().serializeToString(this);
|
||||
if(outerHTML.match(/</g).length == 1) return "";
|
||||
return outerHTML.slice(0, outerHTML.lastIndexOf("</")).replace(/<[^"'>]*(("[^"]*"|'[^']*')[^"'>]*)*>/, "");
|
||||
var outerHTML = new XMLSerializer().serializeToString(this);
|
||||
if(outerHTML.match(/</g).length == 1) return "";
|
||||
return outerHTML.slice(0, outerHTML.lastIndexOf("</")).replace(/<[^"'>]*(("[^"]*"|'[^']*')[^"'>]*)*>/, "");
|
||||
}});
|
||||
```
|
||||
|
||||
<details><summary><b>Complete Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Demo</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -243,7 +246,8 @@ can be shimmed, but it is strongly recommended to use a more compliant library.
|
||||
[`SheetJSCheerio.js`](pathname:///dom/SheetJSCheerio.js) implements the missing
|
||||
features to ensure that SheetJS DOM methods can process TABLE elements.
|
||||
|
||||
<details><summary><b>Complete Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Demo</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -314,7 +318,8 @@ const workbook = XLSX.utils.table_to_book(tbl);
|
||||
XLSX.writeFile(workbook, "SheetJSDenoDOM.xlsx");`}
|
||||
</CodeBlock>
|
||||
|
||||
<details><summary><b>Complete Demo</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Complete Demo</b> (click to show)</summary>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -335,7 +340,7 @@ The script will create a file `SheetJSDenoDOM.xlsx` that can be opened.
|
||||
</details>
|
||||
|
||||
[^1]: See [`table_to_sheet` in "HTML" Utilities](/docs/api/utilities/html#create-new-sheet)
|
||||
[^2]: See ["Worksheet Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
|
||||
[^2]: See ["Worksheet Object" in "SheetJS Data Model"](/docs/csf/sheet) for more details.
|
||||
[^3]: See [`table_to_book` in "HTML" Utilities](/docs/api/utilities/html#create-new-sheet)
|
||||
[^4]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
|
||||
[^5]: See [`sheet_add_dom` in "HTML" Utilities](/docs/api/utilities/html#add-to-sheet)
|
@ -16,7 +16,7 @@ With a familiar UI, `x-spreadsheet` is an excellent choice for a modern editor.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last verified on 2023 December 04.
|
||||
This demo was last verified on 2024 April 25.
|
||||
|
||||
:::
|
||||
|
||||
@ -33,7 +33,7 @@ features like scrolling may not work as expected.
|
||||
|
||||
```jsx live
|
||||
function SheetJSXSpread() {
|
||||
const [url, setUrl] = React.useState("https://sheetjs.com/pres.numbers");
|
||||
const [url, setUrl] = React.useState("https://docs.sheetjs.com/pres.numbers");
|
||||
const [done, setDone] = React.useState(false);
|
||||
const ref = React.useRef(); // ref to DIV container
|
||||
const set_url = (evt) => setUrl(evt.target.value);
|
||||
@ -72,7 +72,7 @@ The following snippet fetches a spreadsheet and loads the grid:
|
||||
|
||||
```js
|
||||
(async() => {
|
||||
const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer();
|
||||
const ab = await (await fetch("https://docs.sheetjs.com/pres.numbers")).arrayBuffer();
|
||||
grid.loadData(stox(XLSX.read(ab)));
|
||||
})();
|
||||
```
|
||||
|
@ -15,7 +15,7 @@ with a straightforward API.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last verified on 2023 December 04.
|
||||
This demo was last verified on 2024 April 25.
|
||||
|
||||
:::
|
||||
|
||||
@ -32,7 +32,7 @@ features like scrolling may not work as expected.
|
||||
|
||||
```jsx live
|
||||
function SheetJSCDG() {
|
||||
const [url, setUrl] = React.useState("https://sheetjs.com/pres.numbers");
|
||||
const [url, setUrl] = React.useState("https://docs.sheetjs.com/pres.numbers");
|
||||
const [done, setDone] = React.useState(false);
|
||||
const ref = React.useRef(); // ref to DIV container
|
||||
const set_url = (evt) => setUrl(evt.target.value);
|
||||
|
167
docz/docs/03-demos/04-grid/10-tabulator.md
Normal file
167
docz/docs/03-demos/04-grid/10-tabulator.md
Normal file
@ -0,0 +1,167 @@
|
||||
---
|
||||
title: Tabulator
|
||||
pagination_prev: demos/frontend/index
|
||||
pagination_next: demos/net/index
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[Tabulator](https://tabulator.info/) is a powerful data table library designed
|
||||
for ease of use.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
Tabulator offers deep integration with SheetJS for importing and exporting data.
|
||||
This demo covers additional detail including document customization.
|
||||
|
||||
[Click here for a live standalone integration demo.](pathname:///tabulator/)
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Browser | Version | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| Chromium 125 | `6.2.1` | 2024-06-13 |
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
|
||||
are appropriate for sites that use the Tabulator CDN scripts.
|
||||
|
||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
|
||||
installation instructions for projects using a framework.
|
||||
|
||||
:::info pass
|
||||
|
||||
**The Tabulator script must be loaded after the SheetJS scripts!**
|
||||
|
||||
```html
|
||||
<!-- Load SheetJS Scripts -->
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
|
||||
<!-- Tabulator must be loaded after SheetJS scripts -->
|
||||
<script type="text/javascript" src="https://unpkg.com/tabulator-tables@6.2.1/dist/js/tabulator.min.js"></script>
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### Previewing Data
|
||||
|
||||
Tabulator offers a special `setData` method for assigning data after the table
|
||||
is created. Coupled with the `autoColumns` option, Tabulator will automatically
|
||||
refresh the table.
|
||||
|
||||
:::info pass
|
||||
|
||||
The library scans the first row object to determine the header labels. If a
|
||||
column is missing a value in the first object, it will not be loaded!
|
||||
|
||||
:::
|
||||
|
||||
#### Fetching Files
|
||||
|
||||
When files are stored remotely, the recommended approach is to fetch the files,
|
||||
parse with the SheetJS `read` method, generate arrays of objects from the target
|
||||
sheet using `sheet_to_json`, and load data with the Tabulator `setData` method.
|
||||
The following snippet fetches a sample file and loads the first sheet:
|
||||
|
||||
```html title="Fetching a spreadsheet and Displaying the first worksheet"
|
||||
<!-- Tabulator DIV -->
|
||||
<div id="htmlout"></div>
|
||||
|
||||
<script>
|
||||
/* Initialize Tabulator with the `autoColumns: true` setting */
|
||||
var tbl = new Tabulator('#htmlout', { autoColumns: true });
|
||||
|
||||
/* fetch and display https://docs.sheetjs.com/pres.numbers */
|
||||
(function() { try {
|
||||
fetch("https://docs.sheetjs.com/pres.numbers")
|
||||
.then(function(res) { return res.arrayBuffer(); })
|
||||
.then(function(ab) {
|
||||
/* parse ArrayBuffer */
|
||||
var wb = XLSX.read(ab);
|
||||
/* get first worksheet from SheetJS workbook object */
|
||||
var ws = wb.Sheets[wb.SheetNames[0]];
|
||||
/* generate array of row objects */
|
||||
var data = XLSX.utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
||||
/* update Tabulator */
|
||||
tbl.setData(data);
|
||||
});
|
||||
} catch(e) {} })();
|
||||
</script>
|
||||
```
|
||||
|
||||
#### Local Files
|
||||
|
||||
Tabulator provides a special `import` method to show a dialog and load data.
|
||||
Since the importer requires the raw binary data, the method must be called with
|
||||
the third argument set to `"buffer"`:
|
||||
|
||||
```html title="Parsing a local spreadsheet and Displaying the first worksheet"
|
||||
<button id="imp"><b>Click here to import from XLSX file</b></button>
|
||||
<!-- Tabulator DIV -->
|
||||
<div id="htmlout"></div>
|
||||
|
||||
<script>
|
||||
/* Initialize Tabulator with the `autoColumns: true` setting */
|
||||
var tbl = new Tabulator('#htmlout', { autoColumns: true });
|
||||
|
||||
/* use Tabulator SheetJS integration to import data */
|
||||
document.getElementById("imp").addEventListener("click", function() {
|
||||
tbl.import("xlsx", ".xlsx", "buffer");
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
### Saving Data
|
||||
|
||||
Tabulator provides a special `download` method to initiate the export:
|
||||
|
||||
```html title="Exporting data from Tabulator to XLSX"
|
||||
<input type="submit" value="Export to XLSX!" id="xport" onclick="export_xlsx();">
|
||||
<!-- Tabulator DIV -->
|
||||
<div id="htmlout"></div>
|
||||
|
||||
<script>
|
||||
/* Initialize Tabulator with the `autoColumns: true` setting */
|
||||
var tbl = new Tabulator('#htmlout', { autoColumns: true });
|
||||
|
||||
/* use Tabulator SheetJS integration to import data */
|
||||
function export_xlsx() {
|
||||
/* use Tabulator SheetJS integration */
|
||||
tbl.download("xlsx", "SheetJSTabulator.xlsx");
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
[The official documentation](https://tabulator.info/docs/6.2/download#xlsx)
|
||||
covers supported options.
|
||||
|
||||
#### Post-processing
|
||||
|
||||
The `documentProcessing` event handler is called after Tabulator generates a
|
||||
SheetJS workbook object. This allows for adjustments before creating the final
|
||||
workbook file. The following example adds a second sheet that includes the date:
|
||||
|
||||
```js title="Exporting data and metadata"
|
||||
tbl.download("xlsx", "SheetJSTabulator.xlsx", {
|
||||
documentProcessing: function(wb) {
|
||||
|
||||
/* create a new worksheet */
|
||||
var ws = XLSX.utils.aoa_to_sheet([
|
||||
["SheetJS + Tabulator Demo"],
|
||||
["Export Date:", new Date()]
|
||||
]);
|
||||
|
||||
/* add to workbook */
|
||||
XLSX.utils.book_append_sheet(wb, ws, "Metadata");
|
||||
|
||||
return wb;
|
||||
}
|
||||
});
|
||||
```
|
@ -7,23 +7,45 @@ pagination_next: demos/net/index
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
:::note Tested Deployments
|
||||
[Vue 3 Table Lite](https://vue3-lite-table.vercel.app/) is a data table library
|
||||
designed for the VueJS web framework.
|
||||
|
||||
This demo was tested against `vue3-table-lite 1.3.9`, VueJS `3.3.10` and ViteJS
|
||||
`5.0.5` on 2023 December 04.
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
:::
|
||||
This demo uses Vue 3 Table Lite and SheetJS to pull data from a spreadsheet and
|
||||
display the content in a data table. We'll explore how to import data from files
|
||||
into the data grid and how to export modified data from the grid to workbooks.
|
||||
|
||||
|
||||
The demo creates a site that looks like the screenshot below:
|
||||
The ["Demo"](#demo) section includes a complete example that displays data from
|
||||
user-supplied sheets and exports data to XLSX workbooks:
|
||||
|
||||
![vue3-table-lite screenshot](pathname:///vtl/vtl1.png)
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Browser | Version | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| Chromium 125 | `1.4.0` | 2024-06-13 |
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
|
||||
installation in ViteJS projects using Vue 3 Table Lite.
|
||||
|
||||
Using the `npm` tool, this command installs SheetJS and Vue 3 Table Lite:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz vue3-table-lite@1.4.0`}
|
||||
</CodeBlock>
|
||||
|
||||
#### Rows and Columns Bindings
|
||||
|
||||
`vue3-table-lite` presents two attribute bindings: an array of column metadata
|
||||
Vue 3 Table Lite presents two attribute bindings: an array of column metadata
|
||||
(`columns`) and an array of objects representing the displayed data (`rows`).
|
||||
Typically both are `ref` objects:
|
||||
|
||||
@ -114,7 +136,7 @@ cd sheetjs-vtl
|
||||
2) Install dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz vue3-table-lite@1.3.9`}
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz vue3-table-lite@1.4.0`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Download [`src/App.vue`](pathname:///vtl/App.vue) and replace the contents:
|
||||
@ -131,5 +153,5 @@ npm run dev
|
||||
|
||||
5) Load the displayed URL (typically `http://localhost:5173`) in a web browser.
|
||||
|
||||
When the page loads, it will try to fetch <https://sheetjs.com/pres.numbers>
|
||||
When the page loads, it will try to fetch https://docs.sheetjs.com/pres.numbers
|
||||
and display the data. Click "Export" to generate a workbook.
|
||||
|
@ -26,7 +26,11 @@ user-supplied sheets and exports data to XLSX workbooks:
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2023 December 04 with Glide Data Grid 5.3.2
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Browser | Version | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| Chromiun 125 | `5.3.2` | 2024-06-09 |
|
||||
|
||||
:::
|
||||
|
||||
@ -367,7 +371,7 @@ curl -L -o src/App.tsx https://docs.sheetjs.com/gdg/App.tsx
|
||||
|
||||
![glide-data-grid initial view](pathname:///gdg/pre.png)
|
||||
|
||||
The demo downloads and processes <https://sheetjs.com/pres.numbers>.
|
||||
The demo downloads and processes https://docs.sheetjs.com/pres.numbers .
|
||||
|
||||
6) Make some changes to the grid data.
|
||||
|
||||
@ -384,7 +388,8 @@ values should be 41, 42, 43, 44, and 45, as shown in the screenshot below:
|
||||
|
||||
![glide-data-grid after edits](pathname:///gdg/post.png)
|
||||
|
||||
7) Click on the "Export" button to create a XLSX file (`sheetjs-gdg.xlsx`).
|
||||
7) Click on the "Export" button. The browser should attempt to download a XLSX
|
||||
file (`sheetjs-gdg.xlsx`). Save the file.
|
||||
|
||||
Open the generated file and verify the contents match the grid.
|
||||
|
||||
|
@ -28,15 +28,15 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date | Notes |
|
||||
|:----------------|:-----------|:---------------------|
|
||||
| `7.0.0-beta.19` | 2023-12-04 | |
|
||||
| `7.0.0-beta.41` | 2023-12-04 | Editing did not work |
|
||||
| `7.0.0-beta.19` | 2024-06-09 | |
|
||||
| `7.0.0-beta.44` | 2024-06-09 | Editing did not work |
|
||||
|
||||
:::
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
When this demo was last tested, the grid correctly displayed data but could not
|
||||
be edited by the user.
|
||||
When this demo was last tested against the latest version, the grid correctly
|
||||
displayed data but data could not be edited by the user.
|
||||
|
||||
The current recommendation is to use version `7.0.0-beta.19`.
|
||||
|
||||
@ -50,7 +50,7 @@ installation with Yarn and other package managers.
|
||||
Using the `npm` tool, this command installs SheetJS and React Data Grid:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz react-data-grid@7.0.0-beta.41`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz react-data-grid@7.0.0-beta.19`}
|
||||
</CodeBlock>
|
||||
|
||||
Methods and components in both libraries can be loaded in pages using `import`:
|
||||
@ -146,17 +146,17 @@ function rdg_to_ws(rows: Row[]): WorkSheet {
|
||||
|
||||
## Demo
|
||||
|
||||
1) Create a new TypeScript `create-react-app` app:
|
||||
1) Create a new ViteJS app using the `react-ts` template:
|
||||
|
||||
```bash
|
||||
npx create-react-app sheetjs-rdg --template typescript
|
||||
npm create vite@latest -- sheetjs-rdg --template react-ts
|
||||
cd sheetjs-rdg
|
||||
```
|
||||
|
||||
2) Install dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz react-data-grid@7.0.0-beta.41`}
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz react-data-grid@7.0.0-beta.19`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Download [`App.tsx`](pathname:///rdg/App.tsx) and replace `src/App.tsx`.
|
||||
@ -168,12 +168,24 @@ curl -L -o src/App.tsx https://docs.sheetjs.com/rdg/App.tsx
|
||||
4) Start the development server:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The terminal window will display a URL (typically `http://localhost:5173`).
|
||||
Open the URL with a web browser and confirm that a page loads.
|
||||
|
||||
#### Testing
|
||||
|
||||
5) When the page loads, it will fetch <https://sheetjs.com/pres.numbers>, parse
|
||||
5) Confirm the table shows a list of Presidents.
|
||||
|
||||
When the page loads, it will fetch https://docs.sheetjs.com/pres.numbers, parse
|
||||
with SheetJS, and load the data in the data grid.
|
||||
|
||||
6) Click one of the "export" buttons to export the grid data to file.
|
||||
6) Click the "export [.xlsx]" button to export the grid data to XLSX. It should
|
||||
attempt to download `SheetJSRDG.xlsx`.
|
||||
|
||||
7) Open the generated file in a spreadsheet editor. Set cell A7 to "SheetJS Dev"
|
||||
and set cell B7 to 47. Save the file.
|
||||
|
||||
8) Use the file picker to select the modified file. The table will refresh and
|
||||
show the new data.
|
@ -5,44 +5,174 @@ pagination_next: demos/net/index
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
This demo covers the traditional Material UI Table as well as the MUI Data Grid.
|
||||
Material UI is a collection of ReactJS Components that follows the
|
||||
[Google Material Design system](https://material.io/)
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses Material UI and SheetJS to pull data from a spreadsheet and
|
||||
display the data. We'll explore how to import data from spreadsheets and export
|
||||
data to spreadsheets. The following Material UI components will be tested:
|
||||
|
||||
- ["Table"](#material-ui-table) is based on the core HTML TABLE element.
|
||||
|
||||
- ["Data Grid"](#material-ui-data-grid) is a data grid for larger datasets.
|
||||
|
||||
:::note pass
|
||||
|
||||
The [ReactJS demo](/docs/demos/frontend/react) covers basic ReactJS concepts.
|
||||
It should be perused before reading this demo.
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
|
||||
installation in projects using Material UI.
|
||||
|
||||
After installing the SheetJS module in a ReactJS project, `import` statements
|
||||
can load relevant parts of the library.
|
||||
|
||||
```js
|
||||
import { read, utils, writeFileXLSX } from 'xlsx';
|
||||
```
|
||||
|
||||
## Material UI Table
|
||||
|
||||
The `Table` component abstracts the `<table>` element in HTML. `table_to_book`
|
||||
can process a `ref` attached to the `Table` element:
|
||||
The `Table` component abstracts the `<table>` element in HTML.
|
||||
|
||||
```tsx
|
||||
import TableContainer from '@mui/material/TableContainer';
|
||||
import Table from '@mui/material/Table';
|
||||
// ...
|
||||
### Importing Data
|
||||
|
||||
Starting from a SheetJS worksheet object[^1], the `sheet_to_json` method[^2]
|
||||
generates an array of row objects.
|
||||
|
||||
In the [ReactJS "Array of Objects" demo](/docs/demos/frontend/react), the array
|
||||
of objects is rendered by manually mapping over data. For example, starting from
|
||||
the following spreadsheet and data:
|
||||
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>State</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
</td><td>
|
||||
|
||||
```js
|
||||
[
|
||||
{ Name: "Bill Clinton", Index: 42 },
|
||||
{ Name: "GeorgeW Bush", Index: 43 },
|
||||
{ Name: "Barack Obama", Index: 44 },
|
||||
{ Name: "Donald Trump", Index: 45 },
|
||||
{ Name: "Joseph Biden", Index: 46 }
|
||||
]
|
||||
```
|
||||
|
||||
</td></tr></tbody></table>
|
||||
|
||||
The HTML table elements map to MUI components:
|
||||
|
||||
| HTML | MUI |
|
||||
|:--------|:------------|
|
||||
| `TABLE` | `Table` |
|
||||
| `THEAD` | `TableHead` |
|
||||
| `TBODY` | `TableBody` |
|
||||
| `TR` | `TableRow` |
|
||||
| `TD` | `TableCell` |
|
||||
|
||||
The library requires a `TableContainer` container component.
|
||||
|
||||
The following example JSX shows a table using HTML and using MUI components:
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="ReactJS" label="ReactJS">
|
||||
|
||||
```jsx title="Example JSX for displaying arrays of objects"
|
||||
<table>
|
||||
{/* The `thead` section includes the table header row */}
|
||||
<thead><tr><th>Name</th><th>Index</th></tr></thead>
|
||||
{/* The `tbody` section includes the data rows */}
|
||||
<tbody>
|
||||
{/* generate row (TR) for each president */}
|
||||
// highlight-start
|
||||
{pres.map(row => (
|
||||
<tr>
|
||||
{/* Generate cell (TD) for name / index */}
|
||||
<td>{row.Name}</td>
|
||||
<td>{row.Index}</td>
|
||||
</tr>
|
||||
))}
|
||||
// highlight-end
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="MUI" label="Material UI">
|
||||
|
||||
```jsx title="Example JSX for displaying arrays of objects"
|
||||
<TableContainer><Table>
|
||||
{/* The `TableHead` section includes the table header row */}
|
||||
<TableHead><TableRow><TableCell>Name</TableCell><TableCell>Index</TableCell></TableRow></TableHead>
|
||||
{/* The `TableBody` section includes the data rows */}
|
||||
<TableBody>
|
||||
{/* generate row (TableRow) for each president */}
|
||||
// highlight-start
|
||||
{pres.map((row, idx) => (
|
||||
<TableRow key={idx}>
|
||||
{/* Generate cell (TableCell) for name / index */}
|
||||
<TableCell>{row.Name}</TableCell>
|
||||
<TableCell>{row.Index}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
// highlight-end
|
||||
</TableBody>
|
||||
</Table></TableContainer>
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Exporting Data
|
||||
|
||||
The SheetJS `table_to_book` method[^3] can parse data from a DOM element.
|
||||
The MUI `Table` element is really a HTML TABLE element under the hood. A `ref`
|
||||
attached to the `Table` element can be processed by `table_to_book`.
|
||||
|
||||
The following snippet uses the `writeFileXLSX` method[^4] to generate and
|
||||
download a XLSX workbook:
|
||||
|
||||
```tsx title="Skeleton Component for exporting a Material UI Table"
|
||||
// highlight-start
|
||||
import { utils, writeFileXLSX } from "xlsx";
|
||||
import { useRef } from "react";
|
||||
// highlight-end
|
||||
|
||||
// ...
|
||||
export default function BasicTable() {
|
||||
export default function MUITableSheetJSExport() {
|
||||
/* This ref will be attached to the <Table> component */
|
||||
// highlight-next-line
|
||||
const tbl = useRef<HTMLTableElement>(null);
|
||||
|
||||
const xport = () => {
|
||||
/* the .current field will be a TABLE element */
|
||||
const table_elt = tbl.current;
|
||||
/* generate SheetJS workbook */
|
||||
// highlight-next-line
|
||||
const wb = utils.table_to_book(table_elt);
|
||||
/* export to XLSX */
|
||||
writeFileXLSX(wb, "SheetJSMaterialUI.xlsx");
|
||||
};
|
||||
|
||||
return ( <>
|
||||
<button onClick={() => {
|
||||
// highlight-next-line
|
||||
const wb = utils.table_to_book(tbl.current);
|
||||
writeFileXLSX(wb, "SheetJSMaterialUI.xlsx");
|
||||
}}>Export</button>
|
||||
<TableContainer {...}>
|
||||
<button onClick={xport}>Export</button>
|
||||
<TableContainer>
|
||||
// highlight-next-line
|
||||
<Table {...} ref={tbl}>
|
||||
{/* ... material ui table machinations ... */}
|
||||
</Table>
|
||||
<Table ref={tbl}>{/* ... */}</Table>
|
||||
</TableContainer>
|
||||
<>);
|
||||
}
|
||||
@ -52,8 +182,11 @@ export default function BasicTable() {
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last run on 2023 December 04 against Material UI 5.14.19 paired
|
||||
with Emotion 11.11.1
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Material UI | Emotion | Date |
|
||||
|:------------|:----------|:-----------|
|
||||
| `5.15.20` | `11.11.4` | 2024-06-12 |
|
||||
|
||||
:::
|
||||
|
||||
@ -67,7 +200,7 @@ cd sheetjs-mui
|
||||
2) Install dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @mui/material@5.14.19 @emotion/react@11.11.1 @emotion/styled@11.11.0`}
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @mui/material@5.15.20 @emotion/react@11.11.4 @emotion/styled@11.11.5`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Download [`App.tsx`](pathname:///mui/table/App.tsx) and replace `src/App.tsx`.
|
||||
@ -195,8 +328,11 @@ export default function App() {
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last run on 2023 December 04 against MUI data grid 6.18.3 paired
|
||||
with Emotion 11.11.1
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Data Grid | Emotion | Date |
|
||||
|:----------|:----------|:-----------|
|
||||
| `7.6.2` | `11.11.4` | 2024-06-12 |
|
||||
|
||||
:::
|
||||
|
||||
@ -210,7 +346,7 @@ cd sheetjs-muidg
|
||||
2) Install dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @mui/x-data-grid@6.18.3 @emotion/react@11.11.1 @emotion/styled@11.11.0`}
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @mui/x-data-grid@7.6.2 @emotion/react@11.11.4 @emotion/styled@11.11.5`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Download [`App.tsx`](pathname:///mui/dg/App.tsx) and replace `src/App.tsx`.
|
||||
@ -225,4 +361,9 @@ curl -L -o src/App.tsx https://docs.sheetjs.com/mui/dg/App.tsx
|
||||
npm run dev
|
||||
```
|
||||
|
||||
When the page loads, it will fetch and process <https://sheetjs.com/pres.numbers>
|
||||
When the page loads, it will process https://docs.sheetjs.com/pres.numbers
|
||||
|
||||
[^1]: See ["Sheet Objects"](/docs/csf/sheet)
|
||||
[^2]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^3]: See [`table_to_book` in "HTML" Utilities](/docs/api/utilities/html#create-new-sheet)
|
||||
[^4]: See [`writeFileXLSX` in "Writing Files"](/docs/api/write-options)
|
||||
|
@ -30,8 +30,7 @@ The `sheet_to_json` utility function generates arrays of objects, which is
|
||||
suitable for a number of libraries. When more advanced shapes are needed,
|
||||
it is easier to process an array of arrays.
|
||||
|
||||
|
||||
### x-spreadsheet
|
||||
#### x-spreadsheet
|
||||
|
||||
With a familiar UI, `x-spreadsheet` is an excellent choice for a modern editor.
|
||||
|
||||
@ -39,7 +38,7 @@ With a familiar UI, `x-spreadsheet` is an excellent choice for a modern editor.
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/grid/xs)**
|
||||
|
||||
### Canvas Datagrid
|
||||
#### Canvas Datagrid
|
||||
|
||||
After extensive testing, `canvas-datagrid` stood out as a high-performance grid
|
||||
with a straightforward API.
|
||||
@ -48,15 +47,16 @@ with a straightforward API.
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/grid/cdg)**
|
||||
|
||||
### Tabulator
|
||||
#### Tabulator
|
||||
|
||||
[Tabulator](https://tabulator.info/docs/5.4/download#xlsx) includes deep support
|
||||
through a special Export button. It handles the SheetJS operations internally.
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/grid/tabulator)**
|
||||
|
||||
### Angular UI Grid
|
||||
#### Angular UI Grid
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
This UI Grid is for AngularJS, not the modern Angular. New projects should not
|
||||
use AngularJS. This demo is included for legacy applications.
|
||||
@ -67,7 +67,8 @@ The [AngularJS demo](/docs/demos/frontend/angularjs) covers more general strateg
|
||||
|
||||
[Click here for a live integration demo.](pathname:///angularjs/ui-grid.html)
|
||||
|
||||
<details><summary><b>Notes</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Notes</b> (click to show)</summary>
|
||||
|
||||
The library does not provide any way to modify the import button, so the demo
|
||||
includes a simple directive for a File Input HTML element. It also includes a
|
||||
@ -92,21 +93,21 @@ and idioms. The same `sheet_to_json` and `json_to_sheet` / `aoa_to_sheet`
|
||||
methods are used, but they pull from a shared state object that can be mutated
|
||||
with other buttons and components on the page.
|
||||
|
||||
### React Data Grid
|
||||
#### React Data Grid
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/grid/rdg)**
|
||||
|
||||
### Glide Data Grid
|
||||
#### Glide Data Grid
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/grid/gdg)**
|
||||
|
||||
### Material UI Data Grid
|
||||
#### Material UI Data Grid
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/grid/mui#material-ui-data-grid)**
|
||||
|
||||
<!-- spellchecker-disable -->
|
||||
|
||||
### vue3-table-lite
|
||||
#### vue3-table-lite
|
||||
|
||||
<!-- spellchecker-enable -->
|
||||
|
||||
@ -133,7 +134,7 @@ TABLE elements and when writing to XLSX and other spreadsheet formats.
|
||||
|
||||
:::
|
||||
|
||||
### Fixed Tables
|
||||
#### Fixed Tables
|
||||
|
||||
When the page has a raw HTML table, the easiest solution is to attach an `id`:
|
||||
|
||||
@ -170,10 +171,10 @@ XLSX.writeFile(wb, "HTMLFlicker.xlsx");
|
||||
document.body.removeChild(tbl);
|
||||
```
|
||||
|
||||
### React
|
||||
#### React
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/frontend/react#html)**
|
||||
|
||||
### Material UI Table
|
||||
#### Material UI Table
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/grid/mui#material-ui-table)**
|
||||
|
@ -57,8 +57,8 @@ The lines are automatically added if `sheets` plugin is enabled during setup.
|
||||
Spreadsheet files added in the `_data` subdirectory are accessible from template
|
||||
files using the name stem.
|
||||
|
||||
For example, [`pres.xlsx`](https://sheetjs.com/pres.xlsx) can be accessed using
|
||||
the variable `pres` in a template.
|
||||
For example, [`pres.xlsx`](https://docs.sheetjs.com/pres.xlsx) can be accessed
|
||||
using the variable `pres` in a template.
|
||||
|
||||
#### Single-Sheet Workbooks
|
||||
|
||||
@ -168,11 +168,11 @@ The `nunjucks` plugin was included by default in Lume version 1.
|
||||
|
||||
:::
|
||||
|
||||
2) Download <https://sheetjs.com/pres.xlsx> and place in a `_data` subfolder:
|
||||
2) Download https://docs.sheetjs.com/pres.xlsx and place in a `_data` subfolder:
|
||||
|
||||
```bash
|
||||
mkdir -p _data
|
||||
curl -L -o _data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
curl -L -o _data/pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
3) Create a `index.njk` file that references the file:
|
||||
@ -216,7 +216,9 @@ After saving the spreadsheet, the page will refresh and show the new contents.
|
||||
|
||||
### Static Site
|
||||
|
||||
6) Stop the server (press `CTRL+C` in the terminal window) and run
|
||||
6) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window).
|
||||
|
||||
7) Build the static site:
|
||||
|
||||
```bash
|
||||
deno task lume
|
||||
@ -224,7 +226,7 @@ deno task lume
|
||||
|
||||
This will create a static site in the `_site` folder
|
||||
|
||||
7) Test the generated site by running
|
||||
7) Test the generated site by starting a web server:
|
||||
|
||||
```bash
|
||||
npx http-server _site
|
||||
|
@ -13,6 +13,9 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export const r = {style: {color:"red"}};
|
||||
export const R = {style: {backgroundColor:"darkred"}};
|
||||
|
||||
GatsbyJS is a framework for creating websites. It uses React components for page
|
||||
templates and GraphQL for loading data.
|
||||
|
||||
@ -48,7 +51,7 @@ overridden through a `package.json` override in the latest versions of NodeJS:
|
||||
|
||||
:::
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
GatsbyJS collects telemetry by default. The `telemetry` subcommand can disable it:
|
||||
|
||||
@ -176,7 +179,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| GatsbyJS | Date |
|
||||
|:---------|:-----------|
|
||||
| `5.12.1` | 2023-12-04 |
|
||||
| `5.13.4` | 2024-05-04 |
|
||||
| `4.25.8` | 2024-03-27 |
|
||||
|
||||
:::
|
||||
@ -189,6 +192,25 @@ This demo was tested in the following environments:
|
||||
npx gatsby telemetry --disable
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
In NodeJS 22, the process displayed an error:
|
||||
|
||||
<pre>
|
||||
<span {...R}> ERROR </span><span {...r}> UNKNOWN</span>
|
||||
{`\n`}
|
||||
{`\n`}
|
||||
(node:25039) [DEP0040] DeprecationWarning: The `punycode` module is deprecated.
|
||||
Please use a userland alternative instead.
|
||||
(Use `node --trace-deprecation ...` to show where the warning was created)
|
||||
</pre>
|
||||
|
||||
**This is a false report!**
|
||||
|
||||
The error can be safely ignored.
|
||||
|
||||
:::
|
||||
|
||||
1) Create a template site:
|
||||
|
||||
```bash
|
||||
@ -255,12 +277,12 @@ npm i --save gatsby-transformer-excel@4 gatsby-source-filesystem@4
|
||||
|
||||
:::
|
||||
|
||||
5) Make a `src/data` directory, download <https://sheetjs.com/pres.xlsx>, and
|
||||
5) Make a `src/data` directory, download https://docs.sheetjs.com/pres.xlsx, and
|
||||
move the downloaded file into the new folder:
|
||||
|
||||
```bash
|
||||
mkdir -p src/data
|
||||
curl -L -o src/data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
curl -L -o src/data/pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
6) Edit `gatsby-config.js` and add the following lines to the `plugins` array:
|
||||
@ -333,11 +355,60 @@ Press the Execute Query button (`▶`) and data should show up in the right pane
|
||||
|
||||
![GraphiQL Screenshot](pathname:///gatsby/graphiql.png)
|
||||
|
||||
<details>
|
||||
<summary><b>Sample Output</b> (click to show)</summary>
|
||||
|
||||
In GatsbyJS version `5.13.4`, the raw output was:
|
||||
|
||||
```json title="GraphQL query result from GatsbyJS 5.13.4"
|
||||
{
|
||||
"data": {
|
||||
"allPresXlsxSheet1": {
|
||||
"edges": [
|
||||
{
|
||||
"node": {
|
||||
"Name": "Bill Clinton",
|
||||
"Index": 42
|
||||
}
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"Name": "GeorgeW Bush",
|
||||
"Index": 43
|
||||
}
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"Name": "Barack Obama",
|
||||
"Index": 44
|
||||
}
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"Name": "Donald Trump",
|
||||
"Index": 45
|
||||
}
|
||||
},
|
||||
{
|
||||
"node": {
|
||||
"Name": "Joseph Biden",
|
||||
"Index": 46
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"extensions": {}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### React page
|
||||
|
||||
8) Create a new file `src/pages/pres.js` that uses the query and displays the result:
|
||||
|
||||
```jsx title="src/pages/pres.js"
|
||||
```jsx title="src/pages/pres.js (create new file)"
|
||||
import { graphql } from "gatsby"
|
||||
import * as React from "react"
|
||||
|
||||
|
@ -32,8 +32,8 @@ importing the SheetJS library in a browser script.
|
||||
|
||||
## ESBuild Loader
|
||||
|
||||
ESBuild supports custom loader plugins. The loader receives an absolute path to
|
||||
the spreadsheet on the filesystem.
|
||||
ESBuild releases starting from `0.9.1` support custom loader plugins. The loader
|
||||
receives an absolute path to the spreadsheet on the filesystem.
|
||||
|
||||
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
|
||||
imported from ESBuild loader plugins.
|
||||
@ -200,7 +200,23 @@ document.body.appendChild(elt);
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2023 December 04 against ESBuild 0.19.8
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| `esbuild` | Date |
|
||||
|:----------|:-----------|
|
||||
| `0.20.2` | 2024-04-07 |
|
||||
| `0.19.12` | 2024-04-07 |
|
||||
| `0.18.20` | 2024-04-07 |
|
||||
| `0.17.19` | 2024-04-07 |
|
||||
| `0.16.17` | 2024-04-07 |
|
||||
| `0.15.18` | 2024-04-07 |
|
||||
| `0.14.54` | 2024-04-07 |
|
||||
| `0.13.15` | 2024-04-07 |
|
||||
| `0.12.29` | 2024-04-07 |
|
||||
| `0.11.23` | 2024-04-07 |
|
||||
| `0.10.2` | 2024-04-07 |
|
||||
| `0.9.7` | 2024-04-07 |
|
||||
| `0.9.1` | 2024-04-07 |
|
||||
|
||||
:::
|
||||
|
||||
@ -212,7 +228,7 @@ This demo was last tested on 2023 December 04 against ESBuild 0.19.8
|
||||
mkdir sheetjs-esb
|
||||
cd sheetjs-esb
|
||||
npm init -y
|
||||
npm i --save esbuild@0.19.8
|
||||
npm i --save esbuild@0.20.2
|
||||
```
|
||||
|
||||
1) Install the SheetJS NodeJS module:
|
||||
@ -255,10 +271,10 @@ document.body.appendChild(elt);
|
||||
curl -LO https://docs.sheetjs.com/esbuild/build.mjs
|
||||
```
|
||||
|
||||
5) Download <https://sheetjs.com/pres.numbers> to the project folder:
|
||||
5) Download https://docs.sheetjs.com/pres.numbers to the project folder:
|
||||
|
||||
```bash
|
||||
curl -LO https://sheetjs.com/pres.numbers
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
### Static Site Test
|
||||
|
@ -12,15 +12,15 @@ sidebar_custom_props:
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[ViteJS](https://vitejs.dev/) is a modern build tool for generating static sites.
|
||||
It has a robust JavaScript-powered plugin system[^1]
|
||||
[ViteJS](https://vitejs.dev/) is a build tool for generating static websites. It
|
||||
has a robust JavaScript-powered plugin system[^1].
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses ViteJS and SheetJS to pull data from a spreadsheet and display
|
||||
the content in an HTML table. We'll explore how to load SheetJS in a ViteJS
|
||||
plugin and compare a few different data loading strategies.
|
||||
plugin and evaluate data loading strategies.
|
||||
|
||||
The ["Complete Demo"](#complete-demo) section creates a complete website powered
|
||||
by a XLSX spreadsheet.
|
||||
@ -32,16 +32,97 @@ suitable for end of week or end of month (EOM) reports published in HTML tables.
|
||||
|
||||
For processing user-submitted files in the browser, the
|
||||
[ViteJS "Bundlers" demo](/docs/demos/frontend/bundler/vitejs) shows client-side
|
||||
bundling of the SheetJS library. The ["ReactJS" demo](/docs/demos/frontend/react)
|
||||
bundling of SheetJS libraries. The ["ReactJS" demo](/docs/demos/frontend/react)
|
||||
shows example sites using ViteJS with the ReactJS starter.
|
||||
|
||||
:::
|
||||
|
||||
## Plugins
|
||||
|
||||
ViteJS supports static asset imports[^2], but the default raw loader interprets data
|
||||
as UTF-8 strings. This corrupts binary formats like XLSX and XLS, but a custom
|
||||
loader can override the default behavior.
|
||||
ViteJS supports static asset imports[^2], but the default raw loader interprets
|
||||
data as UTF-8 strings. This corrupts binary formats including XLSX and XLS. A
|
||||
custom loader can bypass the raw loader and directly read files.
|
||||
|
||||
Since a custom loader must be used, some data processing work can be performed
|
||||
by the loader. Three approaches are explored in this demo.
|
||||
|
||||
The following diagrams show the ViteJS data flow. The pink "Main Script import"
|
||||
boxes represent the division between the loader and the main script. The green
|
||||
"SheetJS Operations" boxes represent the steps performed by SheetJS libraries.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>[HTML](#html-plugin)</th>
|
||||
<th>[Data](#pure-data-plugin)</th>
|
||||
<th>[Base64](#base64-plugin)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style={{verticalAlign: "top"}}>
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
file[(workbook\nfile)]
|
||||
buffer(NodeJS\nBuffer)
|
||||
sheetjs[[SheetJS Operations]]
|
||||
tabeller{{HTML\nString}}
|
||||
handoff[[Main Script import]]
|
||||
html{{HTML\nTABLE}}
|
||||
style handoff fill:#FFC7CE
|
||||
style sheetjs fill:#C6EFCE
|
||||
file --> buffer
|
||||
buffer --> sheetjs
|
||||
sheetjs --> tabeller
|
||||
tabeller --> handoff
|
||||
handoff --------> html
|
||||
```
|
||||
|
||||
</td>
|
||||
<td style={{verticalAlign: "top"}}>
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
file[(workbook\nfile)]
|
||||
buffer(NodeJS\nBuffer)
|
||||
sheetjs[[SheetJS Operations]]
|
||||
aoo(array of\nobjects)
|
||||
handoff[[Main Script import]]
|
||||
import(array of\nobjects)
|
||||
html{{HTML\nTABLE}}
|
||||
style handoff fill:#FFC7CE
|
||||
style sheetjs fill:#C6EFCE
|
||||
file --> buffer
|
||||
buffer --> sheetjs
|
||||
sheetjs --> aoo
|
||||
aoo --> handoff
|
||||
handoff ------> import
|
||||
import --> html
|
||||
```
|
||||
|
||||
</td>
|
||||
<td style={{verticalAlign: "top"}}>
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
file[(workbook\nfile)]
|
||||
base64(Base64\nString)
|
||||
handoff[[Main Script import]]
|
||||
import(Base64\nString)
|
||||
sheetjs[[SheetJS Operations]]
|
||||
aoo(array of\nobjects)
|
||||
html{{HTML\nTABLE}}
|
||||
style handoff fill:#FFC7CE
|
||||
style sheetjs fill:#C6EFCE
|
||||
file --> base64
|
||||
base64 ------> handoff
|
||||
handoff --> import
|
||||
import --> sheetjs
|
||||
sheetjs --> aoo
|
||||
aoo --> html
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
For simple tables of data, ["Pure Data Plugin"](#pure-data-plugin) is strongly
|
||||
recommended. The file processing is performed at build time and the generated
|
||||
@ -51,6 +132,9 @@ For more complex parsing or display logic, ["Base64 Plugin"](#base64-plugin) is
|
||||
preferable. Since the raw parsing logic is performed in the page, the library
|
||||
will be included in the final bundle.
|
||||
|
||||
The ["HTML Plugin"](#html-plugin) generates HTML in the loader script. The
|
||||
SheetJS HTML writer renders merged cells and other features.
|
||||
|
||||
### Pure Data Plugin
|
||||
|
||||
For a pure static site, a plugin can load data into an array of row objects. The
|
||||
@ -72,7 +156,7 @@ flowchart LR
|
||||
```
|
||||
|
||||
This ViteJS plugin will read spreadsheets using the SheetJS `read` method[^3]
|
||||
and generate arrays of row objects with `sheet_to_json`[^4]:
|
||||
and generate arrays of row objects with the SheetJS `sheet_to_json`[^4] method:
|
||||
|
||||
```js title="vite.config.js"
|
||||
import { readFileSync } from 'fs';
|
||||
@ -89,13 +173,23 @@ export default defineConfig({
|
||||
if(!id.match(/\?sheetjs$/)) return;
|
||||
var wb = read(readFileSync(id.replace(/\?sheetjs$/, "")));
|
||||
var data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
|
||||
return `export default JSON.parse('${JSON.stringify(data)}')`;
|
||||
return `export default JSON.parse('${JSON.stringify(data).replace(/\\/g, "\\\\")}')`;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
ViteJS plugins are expected to return strings representing ECMAScript modules.
|
||||
|
||||
The plugin uses `JSON.stringify` to encode the array of objects. The generated
|
||||
string is injected into the new module code. When ViteJS processes the module,
|
||||
`JSON.parse` recovers the array of objects.
|
||||
|
||||
:::
|
||||
|
||||
In frontend code, the loader will look for all modules with a `?sheetjs`
|
||||
query string. The default export is an array of row objects.
|
||||
|
||||
@ -115,9 +209,75 @@ document.querySelector('#app').innerHTML = `<table>
|
||||
</table>`;
|
||||
```
|
||||
|
||||
### HTML Plugin
|
||||
|
||||
A plugin can generate raw HTML strings that can be added to a page. The SheetJS
|
||||
libraries are used in the plugin but will not be added to the site.
|
||||
|
||||
The following diagram depicts the workbook waltz:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
file[(workbook\nfile)]
|
||||
subgraph SheetJS operations
|
||||
buffer(NodeJS\nBuffer)
|
||||
tavolo{{HTML\nString}}
|
||||
end
|
||||
html{{HTML\nTABLE}}
|
||||
file --> |vite.config.js\ncustom plugin| buffer
|
||||
buffer --> |vite.config.js\ncustom plugin| tavolo
|
||||
tavolo --> |main.js\nfrontend code| html
|
||||
```
|
||||
|
||||
This ViteJS plugin will read spreadsheets using the SheetJS `read` method[^5]
|
||||
and generate HTML using the SheetJS `sheet_to_html`[^6] method:
|
||||
|
||||
```js title="vite.config.js"
|
||||
import { readFileSync } from 'fs';
|
||||
import { read, utils } from 'xlsx';
|
||||
import { defineConfig } from 'vite';
|
||||
|
||||
export default defineConfig({
|
||||
assetsInclude: ['**/*.xlsx'], // xlsx file should be treated as assets
|
||||
|
||||
plugins: [
|
||||
{ // this plugin handles ?html tags
|
||||
name: "vite-sheet-html",
|
||||
transform(code, id) {
|
||||
if(!id.match(/\?html/)) return;
|
||||
var wb = read(readFileSync(id.replace(/\?html/, "")));
|
||||
var html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
|
||||
return (`export default JSON.parse('${JSON.stringify(html).replace(/\\/g, "\\\\")}')`);
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
ViteJS plugins are expected to return strings representing ECMAScript modules.
|
||||
|
||||
The plugin uses `JSON.stringify` to encode the HTML string. The generated string
|
||||
is injected into the new module code. When ViteJS processes the module,
|
||||
`JSON.parse` recovers the original HTML string.
|
||||
|
||||
:::
|
||||
|
||||
In frontend code, the loader will look for all modules with a `?html` query
|
||||
string. The default export is a string that can be directly added to the page.
|
||||
|
||||
The following example script sets the `innerHTML` property of the container:
|
||||
|
||||
```js title="main.js"
|
||||
import html from './data/pres.xlsx?html';
|
||||
|
||||
document.querySelector('#app').innerHTML = html;
|
||||
```
|
||||
|
||||
### Base64 Plugin
|
||||
|
||||
This plugin pulls in data as a Base64 string that can be read with `read`[^5].
|
||||
This plugin pulls in data as a Base64 string that can be read with `read`[^7].
|
||||
While this approach works, it is not recommended since it loads the library in
|
||||
the front-end site.
|
||||
|
||||
@ -161,7 +321,7 @@ export default defineConfig({
|
||||
```
|
||||
|
||||
When importing using the `b64` query, the raw Base64 string will be exposed.
|
||||
`read` will process the Base64 string using the `base64` input type[^6]:
|
||||
`read` will process the Base64 string using the `base64` input type[^8]:
|
||||
|
||||
```js title="main.js"
|
||||
import { read, utils } from "xlsx";
|
||||
@ -187,22 +347,22 @@ document.querySelector('#app').innerHTML = `<table>
|
||||
|
||||
## Complete Demo
|
||||
|
||||
The demo walks through the process of creating a new ViteJS website from scratch.
|
||||
A Git repository with the completed site can be cloned[^9].
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| ViteJS | Date |
|
||||
|:---------|:-----------|
|
||||
| `5.0.5` | 2023-12-04 |
|
||||
| `4.5.0` | 2023-12-04 |
|
||||
| `3.2.7` | 2023-12-04 |
|
||||
| `2.9.16` | 2023-12-04 |
|
||||
| `5.2.12` | 2024-06-02 |
|
||||
| `4.5.3` | 2024-06-02 |
|
||||
| `3.2.10` | 2024-06-02 |
|
||||
| `2.9.18` | 2024-06-02 |
|
||||
|
||||
:::
|
||||
|
||||
The demo walks through the process of creating a new ViteJS website from scratch.
|
||||
A Git repository with the completed site can be cloned[^7].
|
||||
|
||||
### Initial Setup
|
||||
|
||||
1) Create a new site with the `vue-ts` template and install the SheetJS package:
|
||||
@ -227,11 +387,11 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
curl -O https://docs.sheetjs.com/vitejs/vite.config.ts
|
||||
```
|
||||
|
||||
3) Make a `data` folder and download <https://sheetjs.com/pres.xlsx> :
|
||||
3) Make a `data` folder and download https://docs.sheetjs.com/pres.xlsx :
|
||||
|
||||
```bash
|
||||
mkdir -p data
|
||||
curl -L -o data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
curl -L -o data/pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
### Pure Data Test
|
||||
@ -275,9 +435,30 @@ npx http-server dist/
|
||||
The terminal will display a URL, typically `http://127.0.0.1:8080` . Access
|
||||
that page with a web browser.
|
||||
|
||||
:::caution pass
|
||||
|
||||
When this demo was tested against ViteJS `2.9.18`, the build failed:
|
||||
|
||||
```
|
||||
src/App.vue:8:3 - error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.
|
||||
|
||||
8 <img alt="Vue logo" src="./assets/logo.png" />
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
**As it affects the project template, this is a bug in ViteJS.**
|
||||
|
||||
The simplest workaround is to force upgrade the `vue-tsc` dependency:
|
||||
|
||||
```bash
|
||||
npm i vue-tsc@latest
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
7) To confirm that only the raw data is present in the page, view the page
|
||||
source. The code will reference some script like `/assets/index-HASH.js`.
|
||||
Open that script.
|
||||
source. The code will reference a script `/assets/index-HASH.js` where `HASH` is
|
||||
a string of characters. Open that script.
|
||||
|
||||
Searching for `Bill Clinton` reveals the following:
|
||||
|
||||
@ -291,11 +472,11 @@ included in the final site!
|
||||
:::info pass
|
||||
|
||||
ViteJS also supports "Server-Side Rendering". In SSR, only the HTML table
|
||||
would be added to the final page. Details are covered in the ViteJS docs[^8].
|
||||
would be added to the final page. Details are covered in the ViteJS docs[^10].
|
||||
|
||||
:::
|
||||
|
||||
### Base64 Test
|
||||
### HTML Test
|
||||
|
||||
8) Run the dev server:
|
||||
|
||||
@ -303,10 +484,88 @@ would be added to the final page. Details are covered in the ViteJS docs[^8].
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open a browser window to the displayed URL.
|
||||
Open a browser window to the displayed URL (typically `http://localhost:5173` )
|
||||
|
||||
9) Replace the component `src/components/HelloWorld.vue` with:
|
||||
|
||||
```html title="src/components/HelloWorld.vue"
|
||||
<script setup lang="ts">
|
||||
// @ts-ignore
|
||||
import html from '../../data/pres.xlsx?html';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-html="html"></div>
|
||||
</template>
|
||||
```
|
||||
|
||||
Save and refresh the page. A data table should be displayed
|
||||
|
||||
10) Stop the dev server and build the site
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx http-server dist/
|
||||
```
|
||||
|
||||
The terminal will display a URL, typically `http://127.0.0.1:8080` . Access
|
||||
that page with a web browser.
|
||||
|
||||
:::caution pass
|
||||
|
||||
When this demo was tested against ViteJS `2.9.18`, the build failed:
|
||||
|
||||
```
|
||||
src/App.vue:8:3 - error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.
|
||||
|
||||
8 <img alt="Vue logo" src="./assets/logo.png" />
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
**As it affects the project template, this is a bug in ViteJS.**
|
||||
|
||||
The simplest workaround is to force upgrade the `vue-tsc` dependency:
|
||||
|
||||
```bash
|
||||
npm i vue-tsc@latest
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
11) To confirm that only the raw HTML is present in the page, view the page
|
||||
source. The code will reference a script `/assets/index-HASH.js` where `HASH` is
|
||||
a string of characters. Open that script.
|
||||
|
||||
Searching for `Bill Clinton` reveals the following encoded HTML element:
|
||||
|
||||
```
|
||||
<td data-t=\\"s\\" data-v=\\"Bill Clinton\\" id=\\"sjs-A2\\">Bill Clinton</td>
|
||||
```
|
||||
|
||||
Searching for `BESSELJ` should reveal no results. The SheetJS scripts are not
|
||||
included in the final site!
|
||||
|
||||
:::info pass
|
||||
|
||||
The HTML code is still stored in a script and is injected dynamically.
|
||||
|
||||
ViteJS "Server-Side Rendering" offers the option to render the site at build
|
||||
time, ensuring that the HTML table is directly added to the page.
|
||||
|
||||
:::
|
||||
|
||||
### Base64 Test
|
||||
|
||||
12) Run the dev server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open a browser window to the displayed URL (typically `http://localhost:5173` )
|
||||
|
||||
13) Replace the component `src/components/HelloWorld.vue` with:
|
||||
|
||||
```html title="src/components/HelloWorld.vue"
|
||||
<script setup lang="ts">
|
||||
// @ts-ignore
|
||||
@ -330,7 +589,7 @@ const data = utils.sheet_to_json<IPresident>(ws);
|
||||
</template>
|
||||
```
|
||||
|
||||
10) Stop the dev server and build the site
|
||||
14) Stop the dev server and build the site
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
@ -340,9 +599,30 @@ npx http-server dist/
|
||||
The terminal will display a URL ( `http://127.0.0.1:8080` ). Access that page
|
||||
with a web browser.
|
||||
|
||||
11) To confirm that the object data is not present in the page, view the page
|
||||
source. The code will reference some script like `/assets/index-HASH.js` with
|
||||
a different hash from the previous test. Open that script.
|
||||
:::caution pass
|
||||
|
||||
When this demo was tested against ViteJS `2.9.18`, the build failed:
|
||||
|
||||
```
|
||||
src/App.vue:8:3 - error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists.
|
||||
|
||||
8 <img alt="Vue logo" src="./assets/logo.png" />
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
**As it affects the project template, this is a bug in ViteJS.**
|
||||
|
||||
The simplest workaround is to force upgrade the `vue-tsc` dependency:
|
||||
|
||||
```bash
|
||||
npm i vue-tsc@latest
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
15) To confirm that the object data is not present in the page, view the page
|
||||
source. The code will reference a script `/assets/index-HASH.js` where `HASH` is
|
||||
a string of characters. Open that script.
|
||||
|
||||
Searching for `BESSELJ` should match the code:
|
||||
|
||||
@ -356,8 +636,10 @@ embedded in the final site and the data is parsed when the page is loaded.
|
||||
[^1]: See ["Using Plugins"](https://vitejs.dev/guide/using-plugins.html) in the ViteJS documentation.
|
||||
[^2]: See ["Static Asset Handling"](https://vitejs.dev/guide/assets.html) in the ViteJS documentation.
|
||||
[^3]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^4]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
|
||||
[^5]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^6]: See [the "base64" type in "Reading Files"](/docs/api/parse-options#input-type)
|
||||
[^7]: See [`SheetJS/sheetjs-vite`](https://git.sheetjs.com/sheetjs/sheetjs-vite/) on the SheetJS git server.
|
||||
[^8]: See ["Server-Side Rendering"](https://vitejs.dev/guide/ssr.html) in the ViteJS documentation.
|
||||
[^6]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^7]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^8]: See [the "base64" type in "Reading Files"](/docs/api/parse-options#input-type)
|
||||
[^9]: See [`examples/sheetjs-vite`](https://git.sheetjs.com/examples/sheetjs-vite/) on the SheetJS git server.
|
||||
[^10]: See ["Server-Side Rendering"](https://vitejs.dev/guide/ssr.html) in the ViteJS documentation.
|
@ -57,9 +57,23 @@ flowchart LR
|
||||
|
||||
### Webpack Config
|
||||
|
||||
A special rule should be added to `module.rules`:
|
||||
The Webpack configuration is normally saved to `webpack.config.js`.
|
||||
|
||||
```js title="webpack.config.js"
|
||||
#### Required Settings
|
||||
|
||||
`module.rules` is an array of rule objects that controls module synthesis.[^2]
|
||||
For the SheetJS Webpack integration, the following properties are required:
|
||||
|
||||
- `test` describes whether the rule is relevant. If the property is a regular
|
||||
expression, Webpack will test the filename against the `test` property.
|
||||
|
||||
- `use` lists the loaders that will process files matching the `test`. The
|
||||
loaders are specified using the `loader` property of the loader object.
|
||||
|
||||
The following example instructs Webpack to use the `sheetjs-loader.js` script
|
||||
when the file name ends in `.numbers` or `.xls` or `.xlsx` or `.xlsb`:
|
||||
|
||||
```js title="webpack.config.js (define loader)"
|
||||
// ...
|
||||
module.exports = {
|
||||
// ...
|
||||
@ -68,7 +82,7 @@ module.exports = {
|
||||
// highlight-start
|
||||
{
|
||||
/* `test` matches file extensions */
|
||||
test: /\.(numbers|xls|xlsx|xlsb)/,
|
||||
test: /\.(numbers|xls|xlsx|xlsb)$/,
|
||||
/* use the loader script */
|
||||
use: [ { loader: './sheetjs-loader' } ]
|
||||
}
|
||||
@ -78,24 +92,21 @@ module.exports = {
|
||||
};
|
||||
```
|
||||
|
||||
Hot Module Replacement enables reloading when files are updated:
|
||||
#### Recommended Settings
|
||||
|
||||
```js title="webpack.config.js"
|
||||
// ...
|
||||
module.exports = {
|
||||
// ...
|
||||
// highlight-start
|
||||
devServer: {
|
||||
static: './dist',
|
||||
hot: true,
|
||||
}
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
It is strongly recommended to enable other Webpack features:
|
||||
|
||||
It is strongly recommended to add an alias to simplify imports:
|
||||
- `resolve.alias` defines path aliases. If data files are stored in one folder,
|
||||
an alias ensures that each page can reference the files using the same name[^3].
|
||||
|
||||
```js title="webpack.config.js"
|
||||
- `devServer.hot` enables "hot module replacement"[^4], ensuring that pages will
|
||||
refresh in development mode when spreadsheets are saved.
|
||||
|
||||
The following example instructs Webpack to treat `~` as the root of the project
|
||||
(so `~/data/pres.xlsx` refers to `pres.xlsx` in the data folder) and to enable
|
||||
live reloading:
|
||||
|
||||
```js title="webpack.config.js (other recommended settings)"
|
||||
// ...
|
||||
module.exports = {
|
||||
// ...
|
||||
@ -107,21 +118,32 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
// highlight-end
|
||||
// ...
|
||||
// highlight-start
|
||||
/* enable live reloading in development mode */
|
||||
devServer: { static: './dist', hot: true }
|
||||
// highlight-end
|
||||
};
|
||||
```
|
||||
|
||||
### SheetJS Loader
|
||||
|
||||
The SheetJS loader script must export a `raw` property that is set to `true`.
|
||||
The SheetJS loader script must be saved to the script referenced in the Webpack
|
||||
configuration (`sheetjs-loader.js`).
|
||||
|
||||
As with [ViteJS](/docs/demos/static/vitejs), Webpack will interpret data as
|
||||
UTF-8 strings. This corrupts binary formats including XLSX and XLS. To suppress
|
||||
this behavior and instruct Webpack to pass a NodeJS `Buffer` object, the loader
|
||||
script must export a `raw` property that is set to `true`[^5].
|
||||
|
||||
The base export is expected to be the loader function. The loader receives the
|
||||
file bytes as a Buffer, which can be parsed with the SheetJS `read` method[^2].
|
||||
`read` returns a SheetJS workbook object[^3].
|
||||
file bytes as a Buffer, which can be parsed with the SheetJS `read` method[^6].
|
||||
`read` returns a SheetJS workbook object[^7].
|
||||
|
||||
The loader in this demo will parse the workbook, pull the first worksheet, and
|
||||
generate an array of row objects using the `sheet_to_json` method[^4]:
|
||||
generate an array of row objects using the `sheet_to_json` method[^8]:
|
||||
|
||||
```js title="sheetjs-loader.js"
|
||||
```js title="sheetjs-loader.js (Webpack loader)"
|
||||
const XLSX = require("xlsx");
|
||||
|
||||
function loader(content) {
|
||||
@ -131,8 +153,11 @@ function loader(content) {
|
||||
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;
|
||||
|
||||
/* export the loader */
|
||||
module.exports = loader;
|
||||
```
|
||||
|
||||
@ -141,7 +166,7 @@ module.exports = loader;
|
||||
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"
|
||||
```js title="src/index.js (main script)"
|
||||
import data from '~/data/pres.xlsx';
|
||||
/* `data` is an array of objects from data/pres.xlsx */
|
||||
|
||||
@ -159,7 +184,7 @@ document.body.appendChild(elt);
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2023 December 04 against Webpack 5.89.0
|
||||
This demo was last tested on 2024 April 06 against Webpack 5.91.0
|
||||
|
||||
:::
|
||||
|
||||
@ -171,7 +196,7 @@ This demo was last tested on 2023 December 04 against Webpack 5.89.0
|
||||
mkdir sheetjs-wp5
|
||||
cd sheetjs-wp5
|
||||
npm init -y
|
||||
npm install webpack@5.89.0 webpack-cli@5.1.4 webpack-dev-server@4.15.1 --save
|
||||
npm install webpack@5.91.0 webpack-cli@5.1.4 webpack-dev-server@5.0.4 --save
|
||||
mkdir -p dist
|
||||
mkdir -p src
|
||||
mkdir -p data
|
||||
@ -235,7 +260,7 @@ module.exports = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(numbers|xls|xlsx|xlsb)/,
|
||||
test: /\.(numbers|xls|xlsx|xlsb)$/,
|
||||
use: [ { loader: './sheetjs-loader' } ]
|
||||
}
|
||||
]
|
||||
@ -260,10 +285,10 @@ loader.raw = true;
|
||||
module.exports = loader;
|
||||
```
|
||||
|
||||
6) Download <https://sheetjs.com/pres.xlsx> and save to the `data` folder:
|
||||
6) Download https://docs.sheetjs.com/pres.xlsx and save to the `data` folder:
|
||||
|
||||
```bash
|
||||
curl -L -o data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
curl -L -o data/pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
### Live Reload Test
|
||||
@ -287,9 +312,10 @@ The terminal will print URLs for the development server:
|
||||
|
||||
It should display a table of Presidents with "Name" and "Index" columns
|
||||
|
||||
10) Add a new row to the spreadsheet and save the file.
|
||||
10) Add a new row to the spreadsheet (set `A7` to "SheetJS Dev" and `B7` to 47)
|
||||
and save the file.
|
||||
|
||||
Upon saving, the page should refresh with the new data.
|
||||
After saving the file, the page should automatically refresh with the new data.
|
||||
|
||||
### Static Site Test
|
||||
|
||||
@ -320,6 +346,10 @@ To verify that the data was added to the page, append `main.js` to the URL
|
||||
president names. It will not include SheetJS library references!
|
||||
|
||||
[^1]: See ["Plugins"](https://webpack.js.org/concepts/plugins/) in the Webpack documentation.
|
||||
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^3]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^2]: See [`module.rules`](https://webpack.js.org/configuration/module/#modulerules) in the Webpack documentation.
|
||||
[^3]: See [`resolve.alias`](https://webpack.js.org/configuration/resolve/#resolvealias) in the Webpack documentation.
|
||||
[^4]: See ["Hot Module Replacement"](https://webpack.js.org/concepts/hot-module-replacement/) in the Webpack documentation.
|
||||
[^5]: See ["Raw" Loader](https://webpack.js.org/api/loaders/#raw-loader) in the Webpack documentation.
|
||||
[^6]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^7]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^8]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
|
@ -91,8 +91,8 @@ module.exports = (eleventyConfig) => {
|
||||
Spreadsheet files added in the `_data` subdirectory are accessible from template
|
||||
files using the name stem.
|
||||
|
||||
For example, [`pres.numbers`](https://sheetjs.com/pres.numbers) can be accessed
|
||||
using the variable `pres` in a template:
|
||||
For example, [`pres.numbers`](https://docs.sheetjs.com/pres.numbers) can be
|
||||
accessed using the variable `pres` in a template:
|
||||
|
||||
```liquid title="index.njk"
|
||||
<table><thead><tr><th>Name</th><th>Index</th></tr></thead>
|
||||
@ -151,11 +151,11 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @11ty/e
|
||||
</Tabs>
|
||||
|
||||
3) Make a new `_data` subdirectory in the project. Download the example file
|
||||
[`pres.xlsx`](https://sheetjs.com/pres.xlsx) into `_data`:
|
||||
[`pres.xlsx`](https://docs.sheetjs.com/pres.xlsx) into `_data`:
|
||||
|
||||
```bash
|
||||
mkdir _data
|
||||
curl -Lo _data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
curl -Lo _data/pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
4) Download the following files to the project folder:
|
||||
|
@ -31,18 +31,18 @@ The ["Demo"](#demo) uses NextJS and SheetJS to pull data from a spreadsheet.
|
||||
We'll explore how to create asset modules that process spreadsheet data at build
|
||||
time and how to read files on the server in NextJS lifecycle methods.
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
NextJS collects telemetry by default. The `telemetry` subcommand can disable it:
|
||||
|
||||
```js
|
||||
npx next@13.5.6 telemetry disable
|
||||
npx -y next@13.5.6 telemetry disable
|
||||
```
|
||||
|
||||
The setting can be verified by running
|
||||
|
||||
```js
|
||||
npx next@13.5.6 telemetry status
|
||||
npx -y next@13.5.6 telemetry status
|
||||
```
|
||||
|
||||
:::
|
||||
@ -75,12 +75,26 @@ This demo was tested in the following environments:
|
||||
|
||||
| NextJS | NodeJS | Date |
|
||||
|:----------|:----------|:-----------|
|
||||
| ` 9.5.5` | `16.20.2` | 2023-12-04 |
|
||||
| `10.2.3` | `16.20.2` | 2023-12-04 |
|
||||
| `11.1.4` | `16.20.2` | 2023-12-04 |
|
||||
| `12.3.4` | `20.10.0` | 2023-12-04 |
|
||||
| `13.5.6` | `20.10.0` | 2023-12-04 |
|
||||
| `14.0.3` | `20.10.0` | 2023-12-04 |
|
||||
| ` 9.5.5` | `16.20.2` | 2024-06-07 |
|
||||
| `10.2.3` | `16.20.2` | 2024-06-07 |
|
||||
| `11.1.4` | `16.20.2` | 2024-06-07 |
|
||||
| `12.3.4` | `20.14.0` | 2024-06-07 |
|
||||
| `13.5.6` | `20.14.0` | 2024-06-07 |
|
||||
| `14.2.3` | `20.14.0` | 2024-06-07 |
|
||||
|
||||
:::
|
||||
|
||||
:::info pass
|
||||
|
||||
SheetJS libraries work in legacy NextJS apps. Older versions of this demo have
|
||||
been tested against versions `3.2.3`, `4.2.3`, `5.1.0`, `6.1.2` and `7.0.3`.
|
||||
|
||||
NextJS has made a number of breaking changes over the years. Older versions of
|
||||
NextJS use legacy versions of ReactJS that do not support function components
|
||||
and other idioms.
|
||||
|
||||
[`examples/reactjs-legacy`](https://git.sheetjs.com/examples/reactjs-legacy) on
|
||||
the SheetJS git server includes code samples for legacy NextJS versions.
|
||||
|
||||
:::
|
||||
|
||||
@ -196,7 +210,7 @@ export async function getStaticProps() {
|
||||
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
|
||||
imported from page scripts.
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
[The SheetJS ESM build](/docs/getting-started/installation/nodejs#esm-import)
|
||||
does not load NodeJS native modules directly. The Installation section includes
|
||||
@ -243,7 +257,7 @@ export async function getServerSideProps() {
|
||||
}
|
||||
```
|
||||
|
||||
:::warning Reading and writing files during the build process
|
||||
:::danger Reading and writing files during the build process
|
||||
|
||||
As the NextJS workaround is non-traditional, it bears repeating:
|
||||
|
||||
@ -554,13 +568,13 @@ When upgrading NextJS is not an option, NodeJS should be downgraded to v16.
|
||||
0) Disable NextJS telemetry:
|
||||
|
||||
```js
|
||||
npx next@13.5.6 telemetry disable
|
||||
npx -y next@13.5.6 telemetry disable
|
||||
```
|
||||
|
||||
Confirm it is disabled by running
|
||||
|
||||
```js
|
||||
npx next@13.5.6 telemetry status
|
||||
npx -y next@13.5.6 telemetry status
|
||||
```
|
||||
|
||||
1) Set up folder structure. At the end, a `pages` folder with a `sheets`
|
||||
@ -583,7 +597,7 @@ curl -LO https://docs.sheetjs.com/next/sheetjs.xlsx
|
||||
|
||||
:::note pass
|
||||
|
||||
The `next@13.5.6` dependency can be adjusted to pick a different version. For
|
||||
The `next@13.5.6` depefndency can be adjusted to pick a different version. For
|
||||
example, NextJS `12.3.4` is installed with
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
@ -699,6 +713,13 @@ As explained in the summary, the `/getStaticPaths` and `/getStaticProps` routes
|
||||
are completely static. 2 `/sheets/#` pages were generated, corresponding to 2
|
||||
worksheets in the file. `/getServerSideProps` is server-rendered.
|
||||
|
||||
:::info pass
|
||||
|
||||
NextJS historically used lowercase Lambda (`λ`) to denote dynamic paths. This
|
||||
was changed to a stylized lowercase F (`ƒ`) in recent versions of NextJS.
|
||||
|
||||
:::
|
||||
|
||||
9) Try to build a static site:
|
||||
|
||||
<Tabs groupId="nextver">
|
||||
@ -711,7 +732,7 @@ npx next export
|
||||
</TabItem>
|
||||
<TabItem value="14" label="NextJS 14">
|
||||
|
||||
:::warning NextJS breaking changes
|
||||
:::danger NextJS breaking changes
|
||||
|
||||
**NextJS 14 removed the `export` subcommand!**
|
||||
|
||||
@ -741,7 +762,13 @@ This build will fail. A static page cannot be generated at this point because
|
||||
|
||||
### Static Site
|
||||
|
||||
10) Delete `pages/getServerSideProps.js` and rebuild:
|
||||
10) Delete `pages/getServerSideProps.js`:
|
||||
|
||||
```bash
|
||||
rm -f pages/getServerSideProps.js
|
||||
```
|
||||
|
||||
11) Rebuild the static site:
|
||||
|
||||
<Tabs groupId="nextver">
|
||||
<TabItem value="13" label="NextJS 9 - 13">
|
||||
@ -758,17 +785,16 @@ module.exports = {
|
||||
webpack: (config) => {
|
||||
```
|
||||
|
||||
After editing `next.config.js`:
|
||||
After editing `next.config.js`, run the build command:
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
```bash
|
||||
rm -f pages/getServerSideProps.js
|
||||
npx next build
|
||||
```
|
||||
|
||||
Inspecting the output, there should be no lines with the `λ` symbol:
|
||||
Inspecting the output, there should be no lines with `λ` or `ƒ`:
|
||||
|
||||
```
|
||||
Route (pages) Size First Load JS
|
||||
@ -782,7 +808,7 @@ Route (pages) Size First Load JS
|
||||
└ /sheets/1
|
||||
```
|
||||
|
||||
11) Generate the static site:
|
||||
12) Generate the static site:
|
||||
|
||||
<Tabs groupId="nextver">
|
||||
<TabItem value="13" label="NextJS 9 - 13">
|
||||
@ -814,7 +840,7 @@ npx next build
|
||||
|
||||
The static site will be written to the `out` subfolder
|
||||
|
||||
12) Serve the static site:
|
||||
13) Serve the static site:
|
||||
|
||||
```bash
|
||||
npx http-server out
|
||||
@ -825,16 +851,16 @@ testing the generated site. Note that `/getServerSideProps` will 404 since the
|
||||
page was removed.
|
||||
|
||||
[^1]: See the ["Webpack" asset module demo](/docs/demos/static/webpack) for more details.
|
||||
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options).
|
||||
[^3]: See ["SheetJS Data Model"](/docs/csf/) for more details.
|
||||
[^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^5]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
|
||||
[^6]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output).
|
||||
[^5]: See [`readFile` in "Reading Files"](/docs/api/parse-options).
|
||||
[^6]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output).
|
||||
[^7]: See [`getStaticProps`](https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props) in the NextJS documentation.
|
||||
[^8]: See [`getStaticPaths`](https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-paths) in the NextJS documentation.
|
||||
[^9]: See [`getServerSideProps`](https://nextjs.org/docs/pages/building-your-application/data-fetching/get-server-side-props) in the NextJS documentation.
|
||||
[^10]: See [`fallback` in getStaticPaths](https://nextjs.org/docs/pages/api-reference/functions/get-static-paths#fallback-false) in the NextJS documentation.
|
||||
[^11]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
|
||||
[^12]: [`dangerouslySetInnerHTML`](https://react.dev/reference/react-dom/components/common#common-props) is a ReactJS prop supported for all built-in components.
|
||||
[^13]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^14]: See ["Array of Objects" in the ReactJS demo](/docs/demos/frontend/react#rendering-data)
|
||||
[^13]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output).
|
||||
[^14]: See ["Array of Objects" in the ReactJS demo](/docs/demos/frontend/react#rendering-data).
|
||||
|
@ -48,12 +48,12 @@ This demo was tested in the following environments:
|
||||
|
||||
| Nuxt Content | Nuxt | Date |
|
||||
|:-------------|:---------|:-----------|
|
||||
| `1.15.1` | `2.17.2` | 2023-12-04 |
|
||||
| `2.9.0` | `3.8.2` | 2023-12-04 |
|
||||
| `1.15.1` | `2.17.3` | 2024-06-04 |
|
||||
| `2.12.1` | `3.11.2` | 2024-06-04 |
|
||||
|
||||
:::
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
Nuxt embeds telemetry. According to the docs, it can be disabled with:
|
||||
|
||||
@ -61,7 +61,7 @@ Nuxt embeds telemetry. According to the docs, it can be disabled with:
|
||||
npx nuxt telemetry disable
|
||||
```
|
||||
|
||||
**At the time the demo was last tested, this command did not work.**
|
||||
**When the demo was last tested, this command did not work.**
|
||||
|
||||
Disabling telemetry requires a few steps:
|
||||
|
||||
@ -100,6 +100,14 @@ Click "OK" in each window (3 windows) and restart your computer.
|
||||
telemetry.enabled=false
|
||||
```
|
||||
|
||||
The following command can be run in the Linux / MacOS terminal:
|
||||
|
||||
```bash
|
||||
cat >~/.nuxtrc <<EOF
|
||||
telemetry.enabled=false
|
||||
EOF
|
||||
```
|
||||
|
||||
3) For Nuxt 3 sites, set the `telemetry` option in the Nuxt config file (either `nuxt.config.ts` or `nuxt.config.js`):
|
||||
|
||||
```js title="nuxt.config.js"
|
||||
@ -265,18 +273,18 @@ npx create-nuxt-app@4.0.0 sheetjs-nuxt
|
||||
|
||||
When prompted, enter the following options:
|
||||
|
||||
- `Project name`: press Enter (use default `sheetjs-nuxt`)
|
||||
- `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`
|
||||
- `Project name`: press <kbd>Enter</kbd> (use default `sheetjs-nuxt`)
|
||||
- `Programming language`: press <kbd>↓</kbd> (`TypeScript` selected) then <kbd>Enter</kbd>
|
||||
- `Package manager`: select `Npm` and press <kbd>Enter</kbd>
|
||||
- `UI framework`: select `None` and press <kbd>Enter</kbd>
|
||||
- `Nuxt.js modules`: scroll to `Content`, select with <kbd>Space</kbd>, then press <kbd>Enter</kbd>
|
||||
- `Linting tools`: press <kbd>Enter</kbd> (do not select any Linting tools)
|
||||
- `Testing framework`: select `None` and press <kbd>Enter</kbd>
|
||||
- `Rendering mode`: select `Universal (SSR / SSG)` and press <kbd>Enter</kbd>
|
||||
- `Deployment target`: select `Static (Static/Jamstack hosting)` and press <kbd>Enter</kbd>
|
||||
- `Development tools`: press <kbd>Enter</kbd> (do not select any Development tools)
|
||||
- `What is your GitHub username?`: press <kbd>Enter</kbd> (use default)
|
||||
- `Version control system`: select `None` and press <kbd>Enter</kbd>
|
||||
|
||||
The project will be configured and modules will be installed.
|
||||
|
||||
@ -296,17 +304,17 @@ When the build finishes, the terminal will display a URL like:
|
||||
|
||||
The server is listening on that URL. Open the link in a web browser.
|
||||
|
||||
3) Download <https://sheetjs.com/pres.xlsx> and move to the `content` folder.
|
||||
3) Download https://docs.sheetjs.com/pres.xlsx and move to the `content` folder.
|
||||
|
||||
```bash
|
||||
curl -L -o content/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
curl -L -o content/pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
4) Modify `nuxt.config.js` as follows:
|
||||
|
||||
- Add the following to the top of the script:
|
||||
|
||||
```js
|
||||
```js title="nuxt.config.js (add to top)"
|
||||
import { readFile, utils } from 'xlsx';
|
||||
|
||||
// This will be called when the files change
|
||||
@ -327,7 +335,7 @@ const parseSheet = (file, { path }) => {
|
||||
|
||||
Replace the property with the following definition:
|
||||
|
||||
```js
|
||||
```js title="nuxt.config.js (replace content key in object)"
|
||||
// content.extendParser allows us to hook into the parsing step
|
||||
content: {
|
||||
extendParser: {
|
||||
@ -391,21 +399,31 @@ The page should automatically refresh with the new content:
|
||||
|
||||
![Nuxt Demo end of step 6](pathname:///nuxt/nuxt6.png)
|
||||
|
||||
7) Stop the server (press `CTRL+C` in the terminal window) and run
|
||||
7) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window).
|
||||
|
||||
8) Build the static site:
|
||||
|
||||
```bash
|
||||
npm run generate
|
||||
```
|
||||
|
||||
This will create a static site in the `dist` folder, which can be served with:
|
||||
This will create a static site in the `dist` folder.
|
||||
|
||||
9) Serve the static site:
|
||||
|
||||
```bash
|
||||
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.
|
||||
Access the displayed URL (typically `http://localhost:8080`) in a web browser.
|
||||
|
||||
To confirm that the spreadsheet data is added to the site, view the page source.
|
||||
|
||||
Searching for `Bill Clinton` reveals the following encoded HTML row:
|
||||
|
||||
```html
|
||||
<tr><td>Bill Clinton</td> <td>42</td></tr>
|
||||
```
|
||||
|
||||
## Nuxt Content v2
|
||||
|
||||
@ -485,7 +503,8 @@ The data is stored in the `body` property of the final object.
|
||||
|
||||
NuxtJS modules are the main mechanism for adding transformers to the pipeline.
|
||||
|
||||
<details><summary><b>Module Details</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Module Details</b> (click to show)</summary>
|
||||
|
||||
Due to the structure of the NuxtJS system, modules must be defined in separate
|
||||
script files. The module script is expected to export a module configured with
|
||||
@ -590,7 +609,7 @@ The recommended solution is to switch to Node 18.
|
||||
1) Create a stock app and install dependencies:
|
||||
|
||||
```bash
|
||||
npx -y nuxi init -t content sheetjs-nc2
|
||||
npx -y nuxi init -t content --packageManager yarn --no-gitInit sheetjs-nc2
|
||||
cd sheetjs-nc2
|
||||
npx -y yarn install
|
||||
npx -y yarn add --dev @types/node
|
||||
@ -612,10 +631,10 @@ When the build finishes, the terminal will display a URL like:
|
||||
|
||||
The server is listening on that URL. Open the link in a web browser.
|
||||
|
||||
3) Download <https://sheetjs.com/pres.xlsx> and move to the `content` folder.
|
||||
3) Download https://docs.sheetjs.com/pres.xlsx and move to the `content` folder.
|
||||
|
||||
```bash
|
||||
curl -L -o content/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
curl -L -o content/pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
4) Create the transformer. Two files must be saved at the root of the project:
|
||||
@ -650,7 +669,7 @@ export default defineNuxtConfig({
|
||||
});
|
||||
```
|
||||
|
||||
Restart the dev server by exiting the process (Control+C) and running:
|
||||
Stop the dev server (<kbd>CTRL</kbd>+<kbd>C</kbd>) and run the following:
|
||||
|
||||
```bash
|
||||
npx -y nuxi clean
|
||||
@ -683,7 +702,8 @@ Loading `http://localhost:3000/pres` should show some JSON data:
|
||||
```bash
|
||||
curl -o pages/pres.vue https://docs.sheetjs.com/nuxt/3/pres.vue
|
||||
```
|
||||
Restart the dev server by exiting the process (Control+C) and running:
|
||||
|
||||
Stop the dev server (<kbd>CTRL</kbd>+<kbd>C</kbd>) and run the following:
|
||||
|
||||
```bash
|
||||
npx -y nuxi clean
|
||||
@ -694,13 +714,15 @@ npx -y yarn run dev
|
||||
The browser should now display an HTML table.
|
||||
|
||||
6) To verify that hot loading works, open `pres.xlsx` from the `content` folder
|
||||
with Excel or another spreadsheet editor.
|
||||
with a spreadsheet editor.
|
||||
|
||||
Set cell `A7` to "SheetJS Dev" and set `B7` to `47`. Save the spreadsheet.
|
||||
|
||||
The page should automatically refresh with the new content.
|
||||
|
||||
7) Stop the server (press `CTRL+C` in the terminal window) and run
|
||||
7) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window).
|
||||
|
||||
8) Build the static site:
|
||||
|
||||
```bash
|
||||
npx -y yarn run generate
|
||||
@ -712,9 +734,15 @@ This will create a static site in `.output/public`, which can be served with:
|
||||
npx -y http-server .output/public
|
||||
```
|
||||
|
||||
Accessing `http://localhost:8080/pres` will show the page contents. Verifying
|
||||
the static nature is trivial: make another change in Excel and save. The page
|
||||
will not change.
|
||||
Access the displayed URL (typically `http://localhost:8080`) in a web browser.
|
||||
|
||||
To confirm that the spreadsheet data is added to the site, view the page source.
|
||||
|
||||
Searching for `Bill Clinton` reveals the following encoded HTML row:
|
||||
|
||||
```html
|
||||
<tr><td>Bill Clinton</td><td>42</td></tr>
|
||||
```
|
||||
|
||||
[^1]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
|
||||
[^2]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
|
@ -49,10 +49,10 @@ flowchart LR
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Svelte | Kit | Date |
|
||||
|:----------------|:---------|:-----------|
|
||||
| `4.2.8` | `1.27.6` | 2023-12-04 |
|
||||
| `5.0.0-next.17` | `1.27.6` | 2023-12-04 |
|
||||
| SvelteJS | Kit | Date |
|
||||
|:-----------------|:---------|:-----------|
|
||||
| `4.2.17` | `2.5.10` | 2024-06-03 |
|
||||
| `5.0.0-next.149` | `2.5.10` | 2024-06-03 |
|
||||
|
||||
:::
|
||||
|
||||
@ -178,6 +178,12 @@ a simple HTML table without any reference to the existing spreadsheet file!
|
||||
|
||||
## Complete Example
|
||||
|
||||
:::caution pass
|
||||
|
||||
When this demo was last tested, SvelteKit required NodeJS major version 20.
|
||||
|
||||
:::
|
||||
|
||||
### Initial Setup
|
||||
|
||||
1) Create a new site:
|
||||
@ -190,11 +196,11 @@ When prompted:
|
||||
|
||||
- `Which Svelte app template?` select `Skeleton Project`
|
||||
- `Add type checking with TypeScript?` select `Yes, using JavaScript with JSDoc`
|
||||
- `Select additional options` press Enter (do not select options)
|
||||
- `Select additional options` press <kbd>Enter</kbd> (do not select options)
|
||||
|
||||
:::note pass
|
||||
|
||||
To test the Svelte 5 beta, select "Try out Svelte 5 beta" before pressing Enter.
|
||||
To test the Svelte 5 beta, select `Try the Svelte 5 preview (unstable!)`
|
||||
|
||||
:::
|
||||
|
||||
@ -205,12 +211,12 @@ cd sheetjs-svelte
|
||||
npm i
|
||||
```
|
||||
|
||||
3) Fetch the example file [`pres.xlsx`](https://sheetjs.com/pres.xlsx) and move
|
||||
to a `data` subdirectory in the root of the project:
|
||||
3) Fetch the example file [`pres.xlsx`](https://docs.sheetjs.com/pres.xlsx) and
|
||||
move to a `data` subdirectory in the root of the project:
|
||||
|
||||
```bash
|
||||
mkdir -p data
|
||||
curl -Lo data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
curl -Lo data/pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
4) Install the SheetJS library:
|
||||
@ -219,7 +225,7 @@ curl -Lo data/pres.xlsx https://sheetjs.com/pres.xlsx
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
5) Replace the contents of `vite.config.js` with the following:
|
||||
5) Replace the contents of `vite.config.js` with the following codeblock:
|
||||
|
||||
```js title="vite.config.js"
|
||||
import { sveltekit } from '@sveltejs/kit/vite';
|
||||
@ -249,7 +255,8 @@ declare global {
|
||||
}
|
||||
```
|
||||
|
||||
7) Replace the contents of `src/routes/+page.server.js` with following:
|
||||
7) Replace the contents of `src/routes/+page.server.js` with the following code.
|
||||
Create the file if it does not exist.
|
||||
|
||||
```js title="src/routes/+page.server.js"
|
||||
import b64 from "../../data/pres.xlsx";
|
||||
@ -266,9 +273,8 @@ export async function load({ params }) {
|
||||
}
|
||||
```
|
||||
|
||||
If the file does not exist, create a new file.
|
||||
|
||||
8) Replace the contents of `src/routes/+page.svelte` with the following:
|
||||
8) Replace the contents of `src/routes/+page.svelte` with the following code.
|
||||
Create the file if it does not exist.
|
||||
|
||||
```html title="src/routes/+page.svelte"
|
||||
<script>
|
||||
|
@ -36,7 +36,7 @@ flowchart LR
|
||||
aoo --> |index.astro\ntemplate body| html
|
||||
```
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
AstroJS enables telemetry by default. The tool has an option to disable telemetry:
|
||||
|
||||
@ -50,10 +50,10 @@ npx astro telemetry disable
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| AstroJS | Date |
|
||||
|:---------------|:-----------|
|
||||
| `3.6.4` | 2023-12-04 |
|
||||
| `4.0.0-beta.4` | 2023-12-04 |
|
||||
| AstroJS | Template | Date |
|
||||
|:--------|:-----------------|:-----------|
|
||||
| `3.6.5` | Starlight 0.14.0 | 2024-04-14 |
|
||||
| `4.6.1` | Starlight 0.21.5 | 2024-04-14 |
|
||||
|
||||
:::
|
||||
|
||||
@ -69,7 +69,7 @@ AstroJS has introduced a number of breaking changes in minor releases.
|
||||
|
||||
:::info pass
|
||||
|
||||
This demo uses ["Base64 Loader"](/docs/demos/static/vitejs#base64-loader)
|
||||
This demo uses ["Base64 Loader"](/docs/demos/static/vitejs#base64-plugin)
|
||||
from the ViteJS demo.
|
||||
|
||||
The ViteJS demo used the query `?b64` to identify files. To play nice with
|
||||
@ -212,10 +212,13 @@ cd sheetjs-astro
|
||||
|
||||
:::note pass
|
||||
|
||||
To test the AstroJS 4 beta release, run the following command:
|
||||
To test an older version of AstroJS, install the specific version of `astro` and
|
||||
a supported starter template after creating the project.
|
||||
|
||||
For major version 3, Starlight must be version `0.14.0`:
|
||||
|
||||
```bash
|
||||
npm install --force @astrojs/starlight@^0.14.0 astro@4.0.0-beta.4
|
||||
npm install --force astro@3.6.5 @astrojs/starlight@0.14.0
|
||||
```
|
||||
|
||||
The version can be verified by running:
|
||||
@ -226,11 +229,11 @@ npx astro --version
|
||||
|
||||
:::
|
||||
|
||||
2) Fetch the example file [`pres.numbers`](https://sheetjs.com/pres.numbers):
|
||||
2) Fetch the example file [`pres.numbers`](https://docs.sheetjs.com/pres.numbers):
|
||||
|
||||
```bash
|
||||
mkdir -p src/data
|
||||
curl -Lo src/data/pres.numbers https://sheetjs.com/pres.numbers
|
||||
curl -Lo src/data/pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
3) Install the SheetJS library:
|
||||
@ -251,7 +254,7 @@ declare module '*.xlsx' { const data: string; export default data; }
|
||||
|
||||
- At the top of the script, import `readFileSync`:
|
||||
|
||||
```js title="astro.config.mjs"
|
||||
```js title="astro.config.mjs (add higlighted lines)"
|
||||
// highlight-start
|
||||
/* import `readFileSync` at the top of the script*/
|
||||
import { readFileSync } from 'fs';
|
||||
@ -261,7 +264,7 @@ import { defineConfig } from 'astro/config';
|
||||
|
||||
- In the object argument to `defineConfig`, add a `vite` section:
|
||||
|
||||
```js title="astro.config.mjs"
|
||||
```js title="astro.config.mjs (add highlighted lines)"
|
||||
export default defineConfig({
|
||||
// highlight-start
|
||||
/* this vite section should be added as a property of the object */
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: React Native
|
||||
title: Sheets on the Go with React Native
|
||||
sidebar_label: React Native
|
||||
description: Build data-intensive mobile apps with React Native. Seamlessly integrate spreadsheets into your app using SheetJS. Securely process and generate Excel files in the field.
|
||||
pagination_prev: demos/static/index
|
||||
@ -9,8 +9,6 @@ sidebar_custom_props:
|
||||
summary: React + Native Rendering
|
||||
---
|
||||
|
||||
# Sheets on the Go with React Native
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
@ -69,7 +67,9 @@ imported from any component or script in the app.
|
||||
|
||||
For simplicity, this demo uses an "Array of Arrays"[^2] as the internal state.
|
||||
|
||||
<table><thead><tr><th>Spreadsheet</th><th>Array of Arrays</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>Array of Arrays</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
@ -207,11 +207,11 @@ row. This neatly skips the first header row.
|
||||
|
||||
React Native versions starting from `0.72.0`[^5] support binary data in `fetch`.
|
||||
|
||||
This snippet downloads and parses <https://sheetjs.com/pres.xlsx>:
|
||||
This snippet downloads and parses https://docs.sheetjs.com/pres.xlsx:
|
||||
|
||||
```js
|
||||
/* fetch data into an ArrayBuffer */
|
||||
const ab = await (await fetch("https://sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
const ab = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
|
||||
/* parse data */
|
||||
const wb = XLSX.read(ab);
|
||||
```
|
||||
@ -222,14 +222,6 @@ const wb = XLSX.read(ab);
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | RN | Dev Platform | Date |
|
||||
|:-----------|:------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `darwin-x64` | 2024-03-13 |
|
||||
| iOS 17.4 | iPhone 15 Pro Max | `0.73.6` | `darwin-x64` | 2024-03-13 |
|
||||
| Android 34 | Pixel 3a | `0.73.5` | `win10-x64` | 2024-03-05 |
|
||||
|
||||
**Real Devices**
|
||||
|
||||
| OS | Device | RN | Date |
|
||||
@ -237,12 +229,53 @@ This demo was tested in the following environments:
|
||||
| iOS 15.1 | iPhone 12 Pro Max | `0.73.6` | 2024-03-13 |
|
||||
| Android 29 | NVIDIA Shield | `0.73.6` | 2024-03-13 |
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | RN | Dev Platform | Date |
|
||||
|:-----------|:------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `darwin-x64` | 2024-03-13 |
|
||||
| iOS 17.4 | iPhone 15 Pro Max | `0.73.6` | `darwin-x64` | 2024-03-13 |
|
||||
| Android 34 | Pixel 3a | `0.73.5` | `win10-x64` | 2024-03-05 |
|
||||
| Android 34 | Pixel 3a | `0.73.7` | `linux-x64` | 2024-04-29 |
|
||||
|
||||
:::
|
||||
|
||||
0) Install React Native dependencies
|
||||
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
On the Steam Deck, JDK17 was installed using `pacman`:
|
||||
|
||||
```bash
|
||||
sudo pacman -Syu jdk17-openjdk
|
||||
```
|
||||
|
||||
[The Android Studio tarball](https://developer.android.com/studio) was
|
||||
downloaded and extracted. After extracting:
|
||||
|
||||
```bash
|
||||
cd ./android-studio/bin
|
||||
./studio.sh
|
||||
```
|
||||
|
||||
In Android Studio, select "SDK Manager" and switch to the "SDK Tools" tab. Check
|
||||
"Show Package Details" and install "Android SDK Command-line Tools (latest)".
|
||||
|
||||
When this demo was last tested, the following environment variables were used:
|
||||
|
||||
```bash
|
||||
export ANDROID_HOME=~/Android/Sdk
|
||||
export PATH=$PATH:$ANDROID_HOME/emulator:$ANDROID_HOME/platform-tools
|
||||
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
1) Create project:
|
||||
|
||||
```bash
|
||||
npx -y react-native@0.73.6 init SheetJSRNFetch --version="0.73.6"
|
||||
npx -y react-native@0.73.7 init SheetJSRNFetch --version="0.73.7"
|
||||
```
|
||||
|
||||
2) Install shared dependencies:
|
||||
@ -282,6 +315,20 @@ OpenJDK 64-Bit Server VM Temurin-17.0.10+7 (build 17.0.10+7, mixed mode)
|
||||
npx react-native run-android
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
On Linux, the command may silently stall. It is strongly recommended to launch
|
||||
the interactive CLI tool:
|
||||
|
||||
```bash
|
||||
npx react-native start
|
||||
```
|
||||
|
||||
Once the dev server is ready, the terminal will display a few options. Press `a`
|
||||
to run on Android.
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
If the initial launch fails with an error referencing the emulator, manually
|
||||
@ -298,6 +345,55 @@ This error can be resolved by installing and switching to the requested version.
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
When this demo was last tested on Linux, the process failed to launch the emulator:
|
||||
|
||||
<pre>
|
||||
<b {...y}>warn</b> Please launch an emulator manually or connect a device. Otherwise app may fail to launch.
|
||||
</pre>
|
||||
|
||||
|
||||
**This is a known bug in React Native!**
|
||||
|
||||
If an emulator is installed, run the following command:
|
||||
|
||||
```bash
|
||||
npx react-native doctor
|
||||
```
|
||||
|
||||
Under `Android`, there will be one error:
|
||||
|
||||
<pre>
|
||||
<span {...gr}>Android</span> {`\n`}
|
||||
{` `}<span {...r}>✖</span> Adb - No devices and/or emulators connected. Please create emulator with Android Studio or connect Android device.
|
||||
</pre>
|
||||
|
||||
Press `f` and a list of available emulators will be shown. Select the emulator
|
||||
(typically the last line) and press Enter.
|
||||
|
||||
<pre>
|
||||
<span {...g}>✔</span> <b>Select the device / emulator you want to use</b> <span {...gr}>›</span> <b>Emulator</b> <span {...g}>Pixel_3a_API_34_extension_level_7_x86_64</span> (disconnected)
|
||||
</pre>
|
||||
|
||||
The text in green is the name of the virtual device
|
||||
(`Pixel_3a_API_34_extension_level_7_x86_64` in this example).
|
||||
Run the following command to manually start the emulator:
|
||||
|
||||
```bash
|
||||
$ANDROID_HOME/tools/emulator -avd Pixel_3a_API_34_extension_level_7_x86_64
|
||||
```
|
||||
|
||||
(replace `Pixel_3a_API_34_extension_level_7_x86_64` with the name of the virtual device)
|
||||
|
||||
To confirm React Native detects the emulator, run the following command again:
|
||||
|
||||
```bash
|
||||
npx react-native doctor
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
6) When opened, the app should look like the "Before" screenshot below. After
|
||||
tapping "Import data from a spreadsheet", verify that the app shows new data:
|
||||
|
||||
@ -316,7 +412,7 @@ tapping "Import data from a spreadsheet", verify that the app shows new data:
|
||||
|
||||
**iOS Testing**
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
**iOS testing can only be performed on Apple hardware running macOS!**
|
||||
|
||||
@ -376,7 +472,8 @@ If the device asks to trust the computer, tap "Trust" and enter the passcode.
|
||||
|
||||
15) Enable developer code signing certificates[^7].
|
||||
|
||||
<details open><summary><b>Enabling Code Signing</b> (click to show)</summary>
|
||||
<details open>
|
||||
<summary><b>Enabling Code Signing</b> (click to show)</summary>
|
||||
|
||||
These instructions were verified against Xcode 15.3.
|
||||
|
||||
@ -541,7 +638,7 @@ Click on the icon and select the real device from the list.
|
||||
|
||||
## Local Files
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
React Native does not provide a native file picker or a method for reading and
|
||||
writing data from documents on the devices. A third-party library must be used.
|
||||
@ -566,7 +663,8 @@ The following table lists tested file plugins. "OS" lists tested platforms
|
||||
Due to privacy concerns, apps must request file access. There are special APIs
|
||||
for accessing data and are subject to change in future platform versions.
|
||||
|
||||
<details><summary><b>Technical Details</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Technical Details</b> (click to show)</summary>
|
||||
|
||||
**iOS**
|
||||
|
||||
@ -698,7 +796,8 @@ is the continuation of other libraries that date back to 2016.
|
||||
The `ascii` type returns an array of numbers corresponding to the raw bytes.
|
||||
A `Uint8Array` from the data is compatible with the `buffer` type.
|
||||
|
||||
<details><summary><b>Reading and Writing snippets</b> (click to hide)</summary>
|
||||
<details>
|
||||
<summary><b>Reading and Writing snippets</b> (click to hide)</summary>
|
||||
|
||||
_Reading Data_
|
||||
|
||||
@ -779,7 +878,8 @@ is a filesystem API that uses modern iOS and Android development patterns.
|
||||
|
||||
The `base64` encoding returns strings compatible with the `base64` type:
|
||||
|
||||
<details><summary><b>Reading and Writing snippets</b> (click to hide)</summary>
|
||||
<details>
|
||||
<summary><b>Reading and Writing snippets</b> (click to hide)</summary>
|
||||
|
||||
_Reading Data_
|
||||
|
||||
@ -839,7 +939,8 @@ The [`expo-document-picker`](#expo-document-picker) snippet makes a local copy.
|
||||
|
||||
The `EncodingType.Base64` encoding is compatible with `base64` type.
|
||||
|
||||
<details><summary><b>Reading and Writing snippets</b> (click to hide)</summary>
|
||||
<details>
|
||||
<summary><b>Reading and Writing snippets</b> (click to hide)</summary>
|
||||
|
||||
_Reading Data_
|
||||
|
||||
@ -903,14 +1004,6 @@ try {
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | RN | Dev Platform | Date |
|
||||
|:-----------|:------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `darwin-x64` | 2024-03-31 |
|
||||
| iOS 17.4 | iPhone 15 Pro Max | `0.73.6` | `darwin-x64` | 2024-03-31 |
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `win10-x64` | 2024-03-31 |
|
||||
|
||||
**Real Devices**
|
||||
|
||||
| OS | Device | RN | Date |
|
||||
@ -918,9 +1011,18 @@ This demo was tested in the following environments:
|
||||
| iOS 15.5 | iPhone 13 Pro Max | `0.73.6` | 2024-03-31 |
|
||||
| Android 29 | NVIDIA Shield | `0.73.6` | 2024-03-31 |
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | RN | Dev Platform | Date |
|
||||
|:-----------|:------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `darwin-x64` | 2024-03-31 |
|
||||
| iOS 17.4 | iPhone 15 Pro Max | `0.73.6` | `darwin-x64` | 2024-03-31 |
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `win10-x64` | 2024-03-31 |
|
||||
| Android 34 | Pixel 3a | `0.73.6` | `linux-x64` | 2024-03-31 |
|
||||
|
||||
:::
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
There are many moving parts and pitfalls with React Native apps. It is strongly
|
||||
recommended to follow the official React Native tutorials for iOS and Android
|
||||
@ -1196,7 +1298,7 @@ npx react-native doctor
|
||||
|
||||
:::
|
||||
|
||||
8) Download <https://sheetjs.com/pres.numbers> and open the Downloads folder.
|
||||
8) Download https://docs.sheetjs.com/pres.numbers and open the Downloads folder.
|
||||
|
||||
9) Click and drag `pres.numbers` from the Downloads folder into the simulator.
|
||||
|
||||
@ -1254,7 +1356,7 @@ npx xlsx-cli sheetjsw.xlsx
|
||||
|
||||
**iOS Testing**
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
**iOS testing can only be performed on Apple hardware running macOS!**
|
||||
|
||||
@ -1276,7 +1378,7 @@ cd ios; pod install; cd -
|
||||
npx react-native run-ios
|
||||
```
|
||||
|
||||
17) Download <https://sheetjs.com/pres.numbers> and open the Downloads folder.
|
||||
17) Download https://docs.sheetjs.com/pres.numbers and open the Downloads folder.
|
||||
|
||||
18) In the simulator, click the Home icon to return to the home screen.
|
||||
|
||||
@ -1352,7 +1454,7 @@ If the device asks to allow USB debugging, tap "Allow".
|
||||
npx react-native run-android
|
||||
```
|
||||
|
||||
30) Download <https://sheetjs.com/pres.numbers> on the device.
|
||||
30) Download https://docs.sheetjs.com/pres.numbers on the device.
|
||||
|
||||
31) Switch back to the "SheetJSRN" app.
|
||||
|
||||
@ -1441,7 +1543,7 @@ npx react-native run-ios
|
||||
If the build fails, some troubleshooting notes are included in the "iOS Device
|
||||
Testing" part of the [Fetch Demo](#fetch-demo) (step 17).
|
||||
|
||||
41) Download <https://sheetjs.com/pres.numbers> on the device.
|
||||
41) Download https://docs.sheetjs.com/pres.numbers on the device.
|
||||
|
||||
42) Switch back to the "SheetJSRN" app.
|
||||
|
||||
@ -1471,7 +1573,7 @@ The Numbers app will load the spreadsheet, confirming that the file is valid.
|
||||
[^2]: See ["Array of Arrays" in the API reference](/docs/api/utilities/array#array-of-arrays)
|
||||
[^3]: See ["Array Output" in "Utility Functions"](/docs/api/utilities/array#array-output)
|
||||
[^4]: See ["Array of Arrays Input" in "Utility Functions"](/docs/api/utilities/array#array-of-arrays-input)
|
||||
[^5]: React-Native commit [`5b597b5`](https://github.com/facebook/react-native/commit/5b597b5ff94953accc635ed3090186baeecb3873) added the final piece required for `fetch` support. It landed in version `0.72.0-rc.1` and is available in official releases starting from `0.72.0`.
|
||||
[^5]: React-Native commit [`5b597b5`](https://github.com/facebook/react-native/commit/5b597b5ff94953accc635ed3090186baeecb3873) added the final piece required for `fetch` support. It is available in official releases starting from `0.72.0`.
|
||||
[^6]: When the demo was last tested, the Temurin distribution of Java 17 was installed through the macOS Brew package manager by running `brew install temurin17`. [Direct downloads are available at `adoptium.net`](https://adoptium.net/temurin/releases/?version=17)
|
||||
[^7]: See ["Running On Device"](https://reactnative.dev/docs/running-on-device) in the React Native documentation
|
||||
[^8]: See [`UIFileSharingEnabled`](https://developer.apple.com/documentation/bundleresources/information_property_list/uifilesharingenabled) in the Apple Developer Documentation.
|
||||
|
@ -13,7 +13,7 @@ import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export const g = {style: {color:"green"}};
|
||||
export const r = {style: {color:"red"}};
|
||||
export const y = {style: {color:"yellow"}};
|
||||
export const y = {style: {color:"gold"}};
|
||||
|
||||
[NativeScript](https://nativescript.org/) is a mobile app framework. It builds
|
||||
iOS and Android apps that use JavaScript for describing layouts and events.
|
||||
@ -25,7 +25,8 @@ This demo uses NativeScript and SheetJS to process and generate spreadsheets.
|
||||
We'll explore how to load SheetJS in a NativeScript app; parse and generate
|
||||
spreadsheets stored on the device; and fetch and parse remote files.
|
||||
|
||||
The "Complete Example" creates an app that looks like the screenshots below:
|
||||
The ["Complete Example"](#complete-example) creates an app that looks like the
|
||||
screenshots below:
|
||||
|
||||
<table><thead><tr>
|
||||
<th><a href="#complete-example">iOS</a></th>
|
||||
@ -51,16 +52,24 @@ Angular and TypeScript is assumed.
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS | Type | Device | NS | Date |
|
||||
|:-----------|:-----|:--------------------|:---------|:-----------|
|
||||
| Android 34 | Sim | Pixel 3a | `8.6.1` | 2023-12-04 |
|
||||
| iOS 17.0.1 | Sim | iPhone SE (3rd gen) | `8.6.1` | 2023-12-04 |
|
||||
| Android 29 | Real | NVIDIA Shield | `8.6.1` | 2023-12-04 |
|
||||
| iOS 15.1 | Real | iPad Pro | `8.6.1` | 2023-12-04 |
|
||||
**Real Devices**
|
||||
|
||||
| OS | Device | NS | Date |
|
||||
|:-----------|:--------------------|:---------|:-----------|
|
||||
| Android 30 | NVIDIA Shield | `8.7.2` | 2024-06-09 |
|
||||
| iOS 15.1 | iPad Pro | `8.7.2` | 2024-06-09 |
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | NS | Dev Platform | Date |
|
||||
|:-----------|:--------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `8.7.2` | `darwin-arm` | 2024-06-09 |
|
||||
| iOS 17.5 | iPhone SE (3rd gen) | `8.7.2` | `darwin-arm` | 2024-06-09 |
|
||||
| Android 34 | Pixel 3a | `8.6.5` | `win10-x64` | 2024-04-07 |
|
||||
|
||||
:::
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
Before starting this demo, manually disable telemetry.
|
||||
|
||||
@ -88,9 +97,9 @@ imported from any component or script in the app.
|
||||
|
||||
The `@nativescript/core/file-system` package provides classes for file access.
|
||||
The `File` class does not support binary data, but the file access singleton
|
||||
from `@nativescript/core` does support reading and writing `ArrayBuffer`.
|
||||
from `@nativescript/core` does support reading and writing `ArrayBuffer` data.
|
||||
|
||||
Reading and writing data require a URL. The following snippet searches typical
|
||||
Reading and writing data require a URL. The following snippet searches typical
|
||||
document folders for a specified filename:
|
||||
|
||||
```ts
|
||||
@ -102,6 +111,69 @@ function get_url_for_filename(filename: string): string {
|
||||
}
|
||||
```
|
||||
|
||||
### App Configuration
|
||||
|
||||
Due to privacy concerns, apps must request file access. There are special APIs
|
||||
for accessing data and are subject to change in future platform versions.
|
||||
|
||||
<details>
|
||||
<summary><b>Technical Details</b> (click to show)</summary>
|
||||
|
||||
**Android**
|
||||
|
||||
Android security has evolved over the years. In newer Android versions, the
|
||||
following workarounds were required:
|
||||
|
||||
- `READ_EXTERNAL_STORAGE` and `WRITE_EXTERNAL_STORAGE` allow apps to access
|
||||
files outside of the app scope. These are required for scoped storage access.
|
||||
|
||||
When the demo was last tested, this option was enabled by default.
|
||||
|
||||
- `android:requestLegacyExternalStorage="true"` enabled legacy behavior in some
|
||||
older releases.
|
||||
|
||||
The manifest is saved to `App_Resources/Android/src/main/AndroidManifest.xml`:
|
||||
|
||||
```xml title="App_Resources/Android/src/main/AndroidManifest.xml (add highlighted lines)"
|
||||
<application
|
||||
<!-- highlight-next-line -->
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:name="com.tns.NativeScriptApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:hardwareAccelerated="true">
|
||||
```
|
||||
|
||||
- Permissions must be explicitly requested.
|
||||
|
||||
`@nativescript-community/perms` is a community module for managing permissions:
|
||||
|
||||
```ts title="App script or component"
|
||||
import { request } from '@nativescript-community/perms';
|
||||
import { File } from '@nativescript/core/file-system';
|
||||
```
|
||||
|
||||
Storage access must be requested before writing data:
|
||||
|
||||
```ts title="App script or component (before writing file)"
|
||||
/* request permissions */
|
||||
const res = await request('storage');
|
||||
```
|
||||
|
||||
The external paths can be resolved using the low-level APIs:
|
||||
|
||||
```ts title="App script or component (writing to downloads folder)"
|
||||
/* find Downloads folder */
|
||||
const dl_dir = android.os.Environment.DIRECTORY_DOWNLOADS;
|
||||
const dl = android.os.Environment.getExternalStoragePublicDirectory(dl_dir).getAbsolutePath();
|
||||
/* write to file */
|
||||
File.fromPath(dl + "/SheetJSNS.xls").writeSync(data);
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Reading Local Files
|
||||
|
||||
`getFileAccess().readBufferAsync` can read data into an `ArrayBuffer` object.
|
||||
@ -176,7 +248,7 @@ import { read } from 'xlsx';
|
||||
const temp: string = path.join(knownFolders.temp().path, "pres.xlsx");
|
||||
|
||||
/* download file */
|
||||
const file = await getFile("https://sheetjs.com/pres.xlsx", temp)
|
||||
const file = await getFile("https://docs.sheetjs.com/pres.xlsx", temp)
|
||||
|
||||
/* get data */
|
||||
const ab: ArrayBuffer = await getFileAccess().readBufferAsync(file.path);
|
||||
@ -204,10 +276,9 @@ When the demo was last tested, the latest version of the Android API was 34.
|
||||
NativeScript did not support that API level. The exact error message from
|
||||
`npx -p nativescript ns doctor ios` clearly stated supported versions:
|
||||
|
||||
(x is red, body text is yellow)
|
||||
```
|
||||
✖ No compatible version of the Android SDK Build-tools are installed on your system. You can install any version in the following range: '>=23 <=33'.
|
||||
```
|
||||
<pre>
|
||||
<span {...r}>✖</span> No compatible version of the Android SDK Build-tools are installed on your system. You can install any version in the following range: '>=23 <=33'.
|
||||
</pre>
|
||||
|
||||
The SDK Platform `Android 13.0 ("Tiramisu")` was compatible with NativeScript.
|
||||
Until NativeScript properly supports API level 34, "Tiramisu" must be used.
|
||||
@ -226,20 +297,21 @@ npx -p nativescript ns doctor android
|
||||
|
||||
In the last macOS test, the following output was displayed:
|
||||
|
||||
<details open><summary><b>Expected output</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>Expected output</b> (click to hide)</summary>
|
||||
|
||||
<pre>
|
||||
<span {...g}>✔</span> Getting environment information{'\n'}
|
||||
{'\n'}
|
||||
<b>No issues were detected.</b>{'\n'}
|
||||
<span {...g}>✔</span> Your ANDROID_HOME environment variable is set and points to correct directory.{'\n'}
|
||||
<span {...g}>✔</span> Your adb from the Android SDK is correctly installed.{'\n'}
|
||||
<span {...g}>✔</span> The Android SDK is installed.{'\n'}
|
||||
<span {...g}>✔</span> A compatible Android SDK for compilation is found.{'\n'}
|
||||
<span {...g}>✔</span> Javac is installed and is configured properly.{'\n'}
|
||||
<span {...g}>✔</span> The Java Development Kit (JDK) is installed and is configured properly.{'\n'}
|
||||
<span {...g}>✔</span> Getting NativeScript components versions information...{'\n'}
|
||||
<span {...g}>✔</span> Component nativescript has 8.6.1 version and is up to date.
|
||||
<span {...g}>✔</span> Getting environment information
|
||||
|
||||
<b>No issues were detected.</b>
|
||||
<span {...g}>✔</span> Your ANDROID_HOME environment variable is set and points to correct directory.
|
||||
<span {...g}>✔</span> Your adb from the Android SDK is correctly installed.
|
||||
<span {...g}>✔</span> The Android SDK is installed.
|
||||
<span {...g}>✔</span> A compatible Android SDK for compilation is found.
|
||||
<span {...g}>✔</span> Javac is installed and is configured properly.
|
||||
<span {...g}>✔</span> The Java Development Kit (JDK) is installed and is configured properly.
|
||||
<span {...g}>✔</span> Getting NativeScript components versions information...
|
||||
<span {...g}>✔</span> Component nativescript has 8.7.2 version and is up to date.
|
||||
</pre>
|
||||
|
||||
</details>
|
||||
@ -252,23 +324,23 @@ npx -p nativescript ns doctor ios
|
||||
|
||||
In the last macOS test, the following output was displayed:
|
||||
|
||||
<details open><summary><b>Expected output</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>Expected output</b> (click to hide)</summary>
|
||||
|
||||
<pre>
|
||||
<span {...g}>✔</span> Getting environment information{'\n'}
|
||||
{'\n'}
|
||||
No issues were detected.{'\n'}
|
||||
<span {...g}>✔</span> Xcode is installed and is configured properly.{'\n'}
|
||||
<span {...g}>✔</span> xcodeproj is installed and is configured properly.{'\n'}
|
||||
<span {...g}>✔</span> CocoaPods are installed.{'\n'}
|
||||
<span {...g}>✔</span> CocoaPods update is not required.{'\n'}
|
||||
<span {...g}>✔</span> CocoaPods are configured properly.{'\n'}
|
||||
<span {...g}>✔</span> Your current CocoaPods version is newer than 1.0.0.{'\n'}
|
||||
<span {...g}>✔</span> Python installed and configured correctly.{'\n'}
|
||||
<span {...g}>✔</span> The Python 'six' package is found.{'\n'}
|
||||
<span {...g}>✔</span> Xcode version 15.0.1 satisfies minimum required version 10.{'\n'}
|
||||
<span {...g}>✔</span> Getting NativeScript components versions information...{'\n'}
|
||||
<span {...g}>✔</span> Component nativescript has 8.6.1 version and is up to date.
|
||||
<span {...g}>✔</span> Getting environment information
|
||||
|
||||
<b>No issues were detected.</b>
|
||||
<span {...g}>✔</span> Xcode is installed and is configured properly.
|
||||
<span {...g}>✔</span> xcodeproj is installed and is configured properly.
|
||||
<span {...g}>✔</span> CocoaPods are installed.
|
||||
<span {...g}>✔</span> CocoaPods update is not required.
|
||||
<span {...g}>✔</span> CocoaPods are configured properly.
|
||||
<span {...g}>✔</span> Your current CocoaPods version is newer than 1.0.0.
|
||||
<span {...g}>✔</span> Python installed and configured correctly.
|
||||
<span {...g}>✔</span> Xcode version 15.4.0 satisfies minimum required version 10.
|
||||
<span {...g}>✔</span> Getting NativeScript components versions information...
|
||||
<span {...g}>✔</span> Component nativescript has 8.7.2 version and is up to date.
|
||||
</pre>
|
||||
|
||||
</details>
|
||||
@ -291,7 +363,8 @@ npx -p nativescript ns run android
|
||||
(this may take a while)
|
||||
|
||||
Once the simulator launches and the test app is displayed, end the script by
|
||||
selecting the terminal and entering the key sequence `CTRL + C`
|
||||
selecting the terminal and pressing <kbd>CTRL</kbd>+<kbd>C</kbd>. On Windows, if
|
||||
prompted to `Terminate batch job`, type `y` and press Enter.
|
||||
|
||||
:::note pass
|
||||
|
||||
@ -303,12 +376,6 @@ Emulator start failed with: No emulator image available for device identifier 'u
|
||||
|
||||
:::
|
||||
|
||||
6) From the project folder, install the library:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
### Add SheetJS
|
||||
|
||||
:::note pass
|
||||
@ -317,10 +384,16 @@ The goal of this section is to display the SheetJS library version number.
|
||||
|
||||
:::
|
||||
|
||||
6) From the project folder, install the SheetJS NodeJS module:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
7) Edit `src/app/item/items.component.ts` so that the component imports the
|
||||
SheetJS version string and adds it to a `version` variable in the component:
|
||||
|
||||
```ts title="src/app/item/items.component.ts"
|
||||
```ts title="src/app/item/items.component.ts (add highlighted lines)"
|
||||
// highlight-next-line
|
||||
import { version } from 'xlsx';
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
@ -339,7 +412,7 @@ export class ItemsComponent implements OnInit {
|
||||
8) Edit the template `src/app/item/items.component.html` to reference `version`
|
||||
in the title of the action bar:
|
||||
|
||||
```xml title="src/app/item/items.component.html"
|
||||
```xml title="src/app/item/items.component.html (edit highlighted line)"
|
||||
<!-- highlight-next-line -->
|
||||
<ActionBar [title]="version"></ActionBar>
|
||||
|
||||
@ -347,7 +420,7 @@ in the title of the action bar:
|
||||
<!-- ... -->
|
||||
```
|
||||
|
||||
9) Relaunch the app in the Android simulator:
|
||||
9) End the script and relaunch the app in the Android simulator:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
@ -361,7 +434,7 @@ The title bar should show the version.
|
||||
|
||||
10) Add the Import and Export buttons to the template:
|
||||
|
||||
```xml title="src/app/item/items.component.html"
|
||||
```xml title="src/app/item/items.component.html (add highlighted lines)"
|
||||
<ActionBar [title]="version"></ActionBar>
|
||||
|
||||
<!-- highlight-start -->
|
||||
@ -424,13 +497,19 @@ export class ItemsComponent implements OnInit {
|
||||
}
|
||||
```
|
||||
|
||||
12) Restart the app process. Two buttons should show up at the top:
|
||||
12) End the script and relaunch the app in the Android simulator:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
```
|
||||
|
||||
Two buttons should appear just below the header:
|
||||
|
||||
![NativeScript Step 5](pathname:///nativescript/step5.png)
|
||||
|
||||
13) Implement import and export by adding the highlighted lines:
|
||||
|
||||
```ts title="src/app/item/items.component.ts"
|
||||
```ts title="src/app/item/items.component.ts (add highlighted lines)"
|
||||
/* Import button */
|
||||
async import() {
|
||||
// highlight-start
|
||||
@ -486,21 +565,22 @@ export class ItemsComponent implements OnInit {
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
````
|
||||
```
|
||||
|
||||
If the app does not automatically launch, manually open the `SheetJSNS` app.
|
||||
|
||||
15) Tap "Export File". A dialog will print where the file was written. Typically
|
||||
the URL is `/data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls`
|
||||
|
||||
16) Pull the file from the simulator:
|
||||
16) Pull the file from the simulator. The following commands should be run in a
|
||||
new terminal or PowerShell window:
|
||||
|
||||
```bash
|
||||
adb root
|
||||
adb pull /data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls SheetJSNS.xls
|
||||
```
|
||||
|
||||
If the emulator cannot be rooted:
|
||||
If the emulator cannot be rooted, the following command works in macOS:
|
||||
|
||||
```bash
|
||||
adb shell "run-as org.nativescript.SheetJSNS cat /data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls" > SheetJSNS.xls
|
||||
@ -510,8 +590,9 @@ adb shell "run-as org.nativescript.SheetJSNS cat /data/user/0/org.nativescript.S
|
||||
|
||||
After the header row, insert a row with cell A2 = 0, B2 = SheetJS, C2 = Library:
|
||||
|
||||
```
|
||||
```text
|
||||
id | name | role
|
||||
# highlight-next-line
|
||||
0 | SheetJS | Library
|
||||
1 | Ter Stegen | Goalkeeper
|
||||
3 | Piqué | Defender
|
||||
@ -524,7 +605,7 @@ id | name | role
|
||||
adb push SheetJSNS.xls /data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls
|
||||
```
|
||||
|
||||
If the emulator cannot be rooted:
|
||||
If the emulator cannot be rooted, the following command works in macOS:
|
||||
|
||||
```bash
|
||||
dd if=SheetJSNS.xls | adb shell "run-as org.nativescript.SheetJSNS dd of=/data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls"
|
||||
@ -533,8 +614,20 @@ dd if=SheetJSNS.xls | adb shell "run-as org.nativescript.SheetJSNS dd of=/data/u
|
||||
19) Tap "Import File". A dialog will print the path of the file that was read.
|
||||
The first item in the list will change.
|
||||
|
||||
![NativeScript Step 6](pathname:///nativescript/step6.png)
|
||||
|
||||
### iOS
|
||||
|
||||
:::danger pass
|
||||
|
||||
**iOS testing can only be performed on Apple hardware running macOS!**
|
||||
|
||||
Xcode and iOS simulators are not available on Windows or Linux.
|
||||
|
||||
Scroll down to ["Fetching Files"](#android-device) for Android device testing.
|
||||
|
||||
:::
|
||||
|
||||
20) Launch the app in the iOS Simulator:
|
||||
|
||||
```bash
|
||||
@ -547,8 +640,9 @@ npx -p nativescript ns run ios
|
||||
|
||||
After the header row, insert a row with cell A2 = 0, B2 = SheetJS, C2 = Library:
|
||||
|
||||
```
|
||||
```text
|
||||
id | name | role
|
||||
# highlight-next-line
|
||||
0 | SheetJS | Library
|
||||
1 | Ter Stegen | Goalkeeper
|
||||
3 | Piqué | Defender
|
||||
@ -566,7 +660,7 @@ The first item in the list will change:
|
||||
|
||||
25) In `src/app/item/items.component.ts`, make `ngOnInit` asynchronous:
|
||||
|
||||
```ts title="src/app/item/items.component.ts"
|
||||
```ts title="src/app/item/items.component.ts (replace existing function)"
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.items = await this.itemService.getItems()
|
||||
}
|
||||
@ -589,9 +683,9 @@ export class ItemService {
|
||||
private items: Array<Item>;
|
||||
|
||||
async getItems(): Promise<Array<Item>> {
|
||||
/* fetch https://sheetjs.com/pres.xlsx */
|
||||
/* fetch https://docs.sheetjs.com/pres.xlsx */
|
||||
const temp: string = path.join(knownFolders.temp().path, "pres.xlsx");
|
||||
const ab = await getFile("https://sheetjs.com/pres.xlsx", temp)
|
||||
const ab = await getFile("https://docs.sheetjs.com/pres.xlsx", temp)
|
||||
/* read the temporary file */
|
||||
const wb = read(await getFileAccess().readBufferAsync(ab.path));
|
||||
/* translate the first worksheet to the required Item type */
|
||||
@ -605,11 +699,11 @@ export class ItemService {
|
||||
}
|
||||
```
|
||||
|
||||
27) Relaunch the app in the Android simulator:
|
||||
27) End the script and relaunch the app in the Android simulator:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
````
|
||||
```
|
||||
|
||||
The app should show Presidential data.
|
||||
|
||||
@ -621,7 +715,61 @@ If the device asks to allow USB debugging, tap "Allow".
|
||||
|
||||
29) Close any Android / iOS emulators.
|
||||
|
||||
30) Build APK and run on device:
|
||||
30) Enable "Legacy External Storage" in the Android app. The manifest is stored
|
||||
at `App_Resources/Android/src/main/AndroidManifest.xml`:
|
||||
|
||||
```xml title="App_Resources/Android/src/main/AndroidManifest.xml (add highlighted line)"
|
||||
<application
|
||||
<!-- highlight-next-line -->
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:name="com.tns.NativeScriptApplication"
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:hardwareAccelerated="true">
|
||||
```
|
||||
|
||||
31) Install the `@nativescript-community/perms` dependency:
|
||||
|
||||
```bash
|
||||
npm i --save @nativescript-community/perms
|
||||
```
|
||||
|
||||
32) Add the highlighted lines to `items.component.ts`:
|
||||
|
||||
- Import `File` from NativeScript core and `request` from the new dependency:
|
||||
|
||||
```ts title="items.component.ts (add highlighted lines)"
|
||||
import { Dialogs, getFileAccess, Utils } from '@nativescript/core';
|
||||
// highlight-start
|
||||
import { request } from '@nativescript-community/perms';
|
||||
import { Folder, knownFolders, path, File } from '@nativescript/core/file-system';
|
||||
// highlight-end
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
// ...
|
||||
```
|
||||
|
||||
- Add a new write operation to the `export` method:
|
||||
|
||||
```ts title="items.component.ts (add highlighted lines)"
|
||||
/* attempt to save Uint8Array to file */
|
||||
await getFileAccess().writeBufferAsync(url, global.isAndroid ? (Array.from(u8) as any) : u8);
|
||||
await Dialogs.alert(`Wrote to SheetJSNS.xls at ${url}`);
|
||||
|
||||
/* highlight-start */
|
||||
if(global.isAndroid) {
|
||||
/* request permissions */
|
||||
const res = await request('storage');
|
||||
/* write to Downloads folder */
|
||||
const dl = android.os.Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
|
||||
File.fromPath(dl + "/SheetJSNS.xls").writeSync(Array.from(u8));
|
||||
}
|
||||
/* highlight-end */
|
||||
} catch(e) { await Dialogs.alert(e.message); }
|
||||
```
|
||||
|
||||
33) Build APK and run on device:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
@ -630,26 +778,54 @@ npx -p nativescript ns run android
|
||||
If the Android emulators are closed and an Android device is connected, the last
|
||||
command will build an APK and install on the device.
|
||||
|
||||
<details open>
|
||||
<summary><b>Android Device Testing</b> (click to hide)</summary>
|
||||
|
||||
When the app launches, if the SheetJS library is loaded and if the device is
|
||||
connected to the Internet, a list of Presidents should be displayed.
|
||||
|
||||
Tap "Export File". The app will show an alert. Tap "OK".
|
||||
|
||||
Switch to the "Files" app and open the "Downloads" folder. There should be a new
|
||||
file named `SheetJSNS.xls`.
|
||||
|
||||
</details>
|
||||
|
||||
### iOS Device
|
||||
|
||||
31) Connect an iOS device using a USB cable
|
||||
34) Connect an iOS device using a USB cable
|
||||
|
||||
32) Close any Android / iOS emulators.
|
||||
35) Close any Android / iOS emulators.
|
||||
|
||||
33) Enable developer code signing certificates[^9]
|
||||
36) Enable developer code signing certificates:
|
||||
|
||||
34) Run on device:
|
||||
Open `platforms/ios/SheetJSNS.xcodeproj/project.xcworkspace` in Xcode. Select
|
||||
the "Project Navigator" and select the "App" project. In the main view, select
|
||||
"Signing & Capabilities". Under "Signing", select a team in the dropdown menu.
|
||||
|
||||
37) Run on device:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run ios
|
||||
```
|
||||
|
||||
<details open>
|
||||
<summary><b>iOS Device Testing</b> (click to hide)</summary>
|
||||
|
||||
When the app launches, if the SheetJS library is loaded and if the device is
|
||||
connected to the Internet, a list of Presidents should be displayed.
|
||||
|
||||
Tap "Export File". The app will show an alert. Tap "OK".
|
||||
|
||||
Switch to the "Files" app and open the "Downloads" folder. There should be a new
|
||||
file named `SheetJSNS.xls`.
|
||||
|
||||
</details>
|
||||
|
||||
[^1]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^2]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^3]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^4]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
[^5]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^6]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^7]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^8]: See ["Local setup"](https://docs.nativescript.org/setup/#local-setup) in the NativeScript documentation. For Windows and Linux, follow the "Android" instructions. For macOS, follow both the iOS and Android instructions.
|
||||
[^9]: The [Flutter documentation](https://docs.flutter.dev/get-started/install/macos?tab=ios15#enable-developer-code-signing-certificates) covers the instructions in more detail. The correct workspace is `platforms/ios/SheetJSNS.xcodeproj/project.xcworkspace`
|
||||
[^7]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
@ -41,10 +41,19 @@ The ["Demo"](#demo) creates an app that looks like the screenshots below:
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS | Type | Device | Quasar | Date |
|
||||
|:-----------|:-----|:--------------------|:---------|:-----------|
|
||||
| Android 34 | Sim | Pixel 3a | `2.14.1` | 2023-12-04 |
|
||||
| iOS 17.0.1 | Sim | iPhone SE (3rd gen) | `2.14.1` | 2023-12-04 |
|
||||
**Real Devices**
|
||||
|
||||
| OS | Device | Quasar | Date |
|
||||
|:-----------|:--------------------|:---------|:-----------|
|
||||
| Android 30 | NVIDIA Shield | `2.16.4` | 2024-06-09 |
|
||||
| iOS 15.1 | iPad Pro | `2.16.4` | 2024-06-09 |
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | Quasar | Dev Platform | Date |
|
||||
|:-----------|:--------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `2.16.4` | `darwin-arm` | 2024-06-09 |
|
||||
| iOS 17.5 | iPhone SE (3rd gen) | `2.16.4` | `darwin-arm` | 2024-06-09 |
|
||||
|
||||
:::
|
||||
|
||||
@ -165,6 +174,13 @@ npm i -g @quasar/cli cordova
|
||||
|
||||
(you may need to run `sudo npm i -g` if there are permission issues)
|
||||
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
Quasar requires Java 17
|
||||
|
||||
</details>
|
||||
|
||||
1) Create a new app:
|
||||
|
||||
```bash
|
||||
@ -175,19 +191,19 @@ npm init quasar
|
||||
|
||||
When prompted:
|
||||
|
||||
- "What would you like to build?": `App with Quasar CLI`
|
||||
- "What would you like to build?": `App with Quasar CLI, let's go!`
|
||||
- "Project folder": `SheetJSQuasar`
|
||||
- "Pick Quasar version": `Quasar v2 (Vue 3 | latest and greatest)`
|
||||
- "Pick script type": `Typescript`
|
||||
- "Pick Quasar App CLI variant": `Quasar App CLI with Vite`
|
||||
- "Package name": (just press enter, it will use the default `sheetjsquasar`
|
||||
- "Package name": (press <kbd>Enter</kbd>, it will use the default `sheetjsquasar`)
|
||||
- "Project product name": `SheetJSQuasar`
|
||||
- "Project description": `SheetJS + Quasar`
|
||||
- "Author": (just press enter, it will use your git config settings)
|
||||
- "Author": (press <kbd>Enter</kbd>, it will use your git config settings)
|
||||
- "Pick a Vue component style": `Composition API`
|
||||
- "Pick your CSS preprocessor": `None`
|
||||
- "Check the features needed for your project": Deselect everything
|
||||
- "Install project dependencies": `No`
|
||||
- "Check the features needed for your project": Deselect everything (scroll down to each selected item and press <kbd>Space</kbd>)
|
||||
- "Install project dependencies": `Yes, use npm`
|
||||
|
||||
2) Install dependencies:
|
||||
|
||||
@ -234,7 +250,7 @@ Return to the project directory:
|
||||
cd ..
|
||||
```
|
||||
|
||||
11) Enable file sharing and make the documents folder visible in the iOS app.
|
||||
4) Enable file sharing and make the documents folder visible in the iOS app.
|
||||
The following lines must be added to `src-cordova/platforms/ios/SheetJSQuasar/SheetJSQuasar-Info.plist`:
|
||||
|
||||
```xml title="src-cordova/platforms/ios/SheetJSQuasar/SheetJSQuasar-Info.plist (add to file)"
|
||||
@ -258,6 +274,8 @@ The following lines must be added to `src-cordova/platforms/ios/SheetJSQuasar/Sh
|
||||
quasar dev -m ios
|
||||
```
|
||||
|
||||
If prompted to select an external IP, press <kbd>Enter</kbd>.
|
||||
|
||||
:::caution pass
|
||||
|
||||
If the app is blank or not refreshing, delete the app and close the simulator,
|
||||
@ -267,7 +285,7 @@ then restart the development process.
|
||||
|
||||
6) Add the Dialog plugin to `quasar.config.js`:
|
||||
|
||||
```js title="quasar.config.js"
|
||||
```js title="quasar.config.js (add highlighted line)"
|
||||
framework: {
|
||||
config: {},
|
||||
// ...
|
||||
@ -280,7 +298,7 @@ then restart the development process.
|
||||
7) In the template section of `src/pages/IndexPage.vue`, replace the example
|
||||
with a Table, Save button and Load file picker component:
|
||||
|
||||
```html title="src/pages/IndexPage.vue"
|
||||
```html title="src/pages/IndexPage.vue (change highlighted lines)"
|
||||
<template>
|
||||
<q-page class="row items-center justify-evenly">
|
||||
<!-- highlight-start -->
|
||||
@ -296,7 +314,7 @@ then restart the development process.
|
||||
|
||||
This uses two functions that should be added to the component script:
|
||||
|
||||
```ts title="src/pages/IndexPage.vue"
|
||||
```ts title="src/pages/IndexPage.vue (add highlighted lines)"
|
||||
const meta = ref<Meta>({
|
||||
totalCount: 1200
|
||||
});
|
||||
@ -324,7 +342,7 @@ then restart the development process.
|
||||
|
||||
8) Wire up the `updateFile` function:
|
||||
|
||||
```ts title="src/pages/IndexPage.vue"
|
||||
```ts title="src/pages/IndexPage.vue (add highlighted lines)"
|
||||
import { defineComponent, ref } from 'vue';
|
||||
// highlight-start
|
||||
import { read, write, utils } from 'xlsx';
|
||||
@ -356,7 +374,7 @@ export default defineComponent({
|
||||
|
||||
To test that reading works:
|
||||
|
||||
- Download <https://sheetjs.com/pres.numbers>
|
||||
- Download https://docs.sheetjs.com/pres.numbers
|
||||
- In the simulator, click the Home icon to return to the home screen
|
||||
- Click on the "Files" icon
|
||||
- Click and drag `pres.numbers` from a Finder window into the simulator.
|
||||
@ -373,7 +391,7 @@ Once selected, the screen should refresh with new contents.
|
||||
|
||||
9) Wire up the `saveFile` function:
|
||||
|
||||
```ts title="src/pages/IndexPage.vue"
|
||||
```ts title="src/pages/IndexPage.vue (add highlighted lines)"
|
||||
function saveFile() {
|
||||
// highlight-start
|
||||
/* generate workbook from state */
|
||||
@ -471,6 +489,8 @@ cd ..
|
||||
quasar dev -m android
|
||||
```
|
||||
|
||||
If prompted to select an external IP, press <kbd>Enter</kbd>.
|
||||
|
||||
To test that reading works:
|
||||
|
||||
- Click and drag `pres.numbers` from a Finder window into the simulator.
|
||||
@ -487,6 +507,80 @@ adb exec-out run-as org.sheetjs.quasar cat files/files/SheetJSQuasar.xlsx > /tmp
|
||||
npx xlsx-cli /tmp/SheetJSQuasar.xlsx
|
||||
```
|
||||
|
||||
**iOS Device**
|
||||
|
||||
12) Close all open emulators and simulators.
|
||||
|
||||
13) Disconnect any iOS or Android devices connected to the computer.
|
||||
|
||||
14) Connect the iOS device to the computer.
|
||||
|
||||
15) Open the Xcode project:
|
||||
|
||||
```bash
|
||||
open src-cordova/platforms/ios/SheetJSQuasar.xcodeproj
|
||||
```
|
||||
|
||||
Select "SheetJSQuasar" in the Navigator. In the main pane, select "Signing &
|
||||
Capabilities" and ensure a Team is selected. Save and close the project.
|
||||
|
||||
16) Start the dev process:
|
||||
|
||||
```bash
|
||||
quasar dev -m ios
|
||||
```
|
||||
|
||||
If prompted to select an external IP, press <kbd>Enter</kbd>.
|
||||
|
||||
17) Test the application:
|
||||
|
||||
- Press the Home button (or swipe up with one finger) and switch to Safari.
|
||||
- Download https://docs.sheetjs.com/pres.numbers
|
||||
- Press the Home button (or swipe up with one finger) and select the `SheetJSQuasar` app
|
||||
- Tap the "Load" button, then select "Choose File" and select the downloaded `pres.numbers`
|
||||
|
||||
The table will update with new data.
|
||||
|
||||
- Tap "Save File"
|
||||
- Press the Home button (or swipe up with one finger) and switch to Files.
|
||||
- Tap `<` until the main "Browse" window is displayed, then select "On My iPhone"
|
||||
- Look for the "SheetJSQuasar" folder and tap `SheetJSQuasar.xlsx`.
|
||||
|
||||
If Numbers is installed on the device, it will display the contents of the new file.
|
||||
|
||||
**Android Device**
|
||||
|
||||
18) Close all open emulators and simulators.
|
||||
|
||||
19) Disconnect any iOS or Android devices connected to the computer.
|
||||
|
||||
20) Connect the Android device to the computer.
|
||||
|
||||
21) Start the dev process:
|
||||
|
||||
```bash
|
||||
quasar dev -m android
|
||||
```
|
||||
|
||||
If prompted to select an external IP, press <kbd>Enter</kbd>.
|
||||
|
||||
22) Test the application:
|
||||
|
||||
- Press the Home button (or swipe up with one finger) and switch to Browser.
|
||||
- Download https://docs.sheetjs.com/pres.numbers
|
||||
- Press the Home button (or swipe up with one finger) and select the `SheetJSQuasar` app
|
||||
- Tap the "Load" button, then select "Choose File" and select the downloaded `pres.numbers`
|
||||
|
||||
The table will update with new data.
|
||||
|
||||
:::warning pass
|
||||
|
||||
The "Save File" process will write files. However, Android 30+ requires special
|
||||
methods ("Storage Access Framework") that are not implemented in Quasar.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
[^1]: See ["File Picker"](https://quasar.dev/vue-components/file-picker) in the Quasar documentation.
|
||||
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^3]: See ["SheetJS Data Model"](/docs/csf/) for more details on workbooks, worksheets, and other concepts.
|
||||
|
@ -49,21 +49,34 @@ The [CapacitorJS demo](/docs/demos/mobile/capacitor) covers CapacitorJS apps.
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS | Type | Device | Date |
|
||||
|:-----------|:-----|:--------------------|:-----------|
|
||||
| Android 34 | Sim | Pixel 3a | 2023-12-04 |
|
||||
| iOS 17.0.1 | Sim | iPhone SE (3rd gen) | 2023-12-04 |
|
||||
**Real Devices**
|
||||
|
||||
`ionic info` showed:
|
||||
| OS | Device | Config | Date |
|
||||
|:-----------|:--------------------|:-------|:-----------|
|
||||
| Android 30 | NVIDIA Shield | A | 2024-05-30 |
|
||||
| iOS 15.1 | iPad Pro | A | 2024-05-30 |
|
||||
|
||||
- Ionic: `@ionic/angular 7.5.7`, `@ionic/angular-toolkit 9.0.0`
|
||||
- Cordova: `cordova-lib@12.0.1`, `android 12.0.1, ios 7.0.1`
|
||||
**Simulators**
|
||||
|
||||
The file integration uses `@awesome-cordova-plugins/file` version `6.4.0`.
|
||||
| OS | Device | Config | Dev Platform | Date |
|
||||
|:-----------|:--------------------|:-------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | A | `darwin-arm` | 2024-05-30 |
|
||||
| iOS 17.5 | iPhone SE (3rd gen) | A | `darwin-arm` | 2024-05-30 |
|
||||
|
||||
<details>
|
||||
<summary><b>Configurations</b> (click to show)</summary>
|
||||
|
||||
Configuration A:
|
||||
|
||||
- Ionic: `@ionic/angular 8.2.0`, `@ionic/angular-toolkit 11.0.1`
|
||||
- Cordova: `cordova-lib@12.0.1`, `android 13.0.0, ios 7.1.0`
|
||||
- File Integration: `@awesome-cordova-plugins/file` version `6.7.0`
|
||||
|
||||
</details>
|
||||
|
||||
:::
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
Before starting this demo, manually disable telemetry. On Linux and MacOS:
|
||||
|
||||
@ -132,7 +145,18 @@ simplifies iteration over the array of arrays:
|
||||
|
||||
### File Operations
|
||||
|
||||
`@awesome-cordova-plugins/file` reads and writes files on devices.
|
||||
The `cordova-plugin-file` plugin reads and writes files on devices.
|
||||
|
||||
:::caution pass
|
||||
|
||||
For Android 30+, due to scoped storage rules, the standard file module writes
|
||||
private files that cannot be accessed from the Files app.
|
||||
|
||||
A Storage Access Framework plugin must be used to write external files.
|
||||
|
||||
:::
|
||||
|
||||
`@awesome-cordova-plugins/file` is a wrapper designed for Ionic + Angular apps.
|
||||
|
||||
:::info pass
|
||||
|
||||
@ -193,7 +217,7 @@ this.file.writeFile(url, filename, blob, {replace: true});
|
||||
|
||||
The app in this demo will display data in a table.
|
||||
|
||||
On load, a [test file](https://sheetjs.com/pres.numbers) will be processed.
|
||||
On load, a [test file](https://docs.sheetjs.com/pres.numbers) will be processed.
|
||||
|
||||
When a document is selected with the file picker, it will be processed and the
|
||||
table will refresh to show the contents.
|
||||
@ -211,12 +235,29 @@ known location. After writing, an alert will display the location of the file.
|
||||
|
||||
1) Follow the official instructions for iOS and Android development[^9].
|
||||
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
Ionic requires Java 17.
|
||||
|
||||
</details>
|
||||
|
||||
2) Install required global dependencies:
|
||||
|
||||
```bash
|
||||
npm i -g cordova cordova-res @angular/cli native-run @ionic/cli
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
In some systems, the command must be run as the root user:
|
||||
|
||||
```bash
|
||||
sudo npm i -g cordova cordova-res @angular/cli native-run @ionic/cli
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### Base Project
|
||||
|
||||
3) Create a new project:
|
||||
@ -233,9 +274,9 @@ If a prompt asks about creating an Ionic account, enter `N` to opt out.
|
||||
|
||||
:::caution pass
|
||||
|
||||
Due to conflicts in the dependency tree, the command failed in the last test.
|
||||
Due to conflicts in the dependency tree, the command failed in some test runs.
|
||||
|
||||
The fix is to force install all modules:
|
||||
If the package installation fails, forcefully install all modules:
|
||||
|
||||
```bash
|
||||
cd SheetJSIonic
|
||||
@ -471,7 +512,7 @@ brew install gradle
|
||||
|
||||
:::
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
When the demo was last tested on Android, reading files worked as expected.
|
||||
However, the generated files were not externally visible from the Files app.
|
||||
@ -488,4 +529,5 @@ However, the generated files were not externally visible from the Files app.
|
||||
[^6]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
|
||||
[^7]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^8]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
[^9]: See ["Developing for iOS"](https://ionicframework.com/docs/v6/developing/ios) and ["Developing for Android"](https://ionicframework.com/docs/v6/developing/android) in the v6 Ionic framework documentation.
|
||||
[^9]: See ["Developing for iOS"](https://ionic-docs-o31kiyk8l-ionic1.vercel.app/docs/v6/developing/ios) and ["Developing for Android"](https://ionic-docs-o31kiyk8l-ionic1.vercel.app/docs/v6/developing/android). The Ionic team removed these pages from the official docs site and recommend the `vercel.app` docs site.
|
||||
[^10]: See the [JDK Archive](https://jdk.java.net/archive/) for Java 17 JDK download links.
|
||||
|
@ -1,5 +1,6 @@
|
||||
---
|
||||
title: CapacitorJS
|
||||
title: Storing Sheets with CapacitorJS
|
||||
sidebar_label: CapacitorJS
|
||||
pagination_prev: demos/static/index
|
||||
pagination_next: demos/desktop/index
|
||||
sidebar_position: 5
|
||||
@ -10,10 +11,17 @@ sidebar_custom_props:
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
|
||||
imported from any component or script in the app.
|
||||
[CapacitorJS](https://capacitorjs.com/) is a mobile app runtime for building iOS
|
||||
and Android apps.
|
||||
|
||||
The "Complete Example" creates an app that looks like the screenshots below:
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses CapacitorJS and SheetJS to process data and export spreadsheets.
|
||||
We'll explore how to load SheetJS in an CapacitorJS app and use APIs and plugins
|
||||
to extract data from, and write data to, spreadsheet files on the device.
|
||||
|
||||
The ["Demo"](#demo) creates an app that looks like the screenshots below:
|
||||
|
||||
<table><thead><tr>
|
||||
<th><a href="#demo">iOS</a></th>
|
||||
@ -32,16 +40,26 @@ The "Complete Example" creates an app that looks like the screenshots below:
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS | Type | Device | CapacitorJS + FS | Date |
|
||||
|:-----------|:-----|:--------------------|:------------------|:-----------|
|
||||
| Android 34 | Sim | Pixel 3a | `5.5.1` / `5.1.4` | 2023-12-04 |
|
||||
| iOS 17.0.1 | Sim | iPhone 15 Pro Max | `5.5.1` / `5.1.4` | 2023-12-04 |
|
||||
| Android 29 | Real | NVIDIA Shield | `5.5.1` / `5.1.4` | 2023-12-04 |
|
||||
| iOS 15.1 | Real | iPad Pro | `5.5.1` / `5.1.4` | 2023-12-04 |
|
||||
**Real Devices**
|
||||
|
||||
| OS | Device | CapacitorJS + FS | Date |
|
||||
|:-----------|:--------------------|:------------------|:-----------|
|
||||
| Android 30 | NVIDIA Shield | `6.0.0` / `6.0.0` | 2024-06-02 |
|
||||
| iOS 15.1 | iPad Pro | `6.0.0` / `6.0.0` | 2024-06-02 |
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | CapacitorJS + FS | Dev Platform | Date |
|
||||
|:-----------|:--------------------|:------------------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `6.0.0` / `6.0.0` | `darwin-x64` | 2024-06-02 |
|
||||
| iOS 17.5 | iPhone 15 Pro Max | `6.0.0` / `6.0.0` | `darwin-x64` | 2024-06-02 |
|
||||
| Android 34 | Pixel 3a | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 |
|
||||
| iOS 17.5 | iPhone 15 Pro Max | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 |
|
||||
| Android 34 | Pixel 3a | `6.0.0` / `6.0.0` | `win10-x64` | 2024-05-28 |
|
||||
|
||||
:::
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
Before starting this demo, manually disable telemetry. On Linux and MacOS:
|
||||
|
||||
@ -59,13 +77,26 @@ npx @capacitor/cli telemetry
|
||||
|
||||
## Integration Details
|
||||
|
||||
This example uses Svelte, but the same principles apply to other frameworks.
|
||||
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
|
||||
imported from any component or script in the app.
|
||||
|
||||
This demo uses [SvelteJS](/docs/demos/frontend/svelte), but the same principles
|
||||
apply to other frameworks.
|
||||
|
||||
#### Reading data
|
||||
|
||||
The standard HTML5 File Input element logic works in CapacitorJS:
|
||||
The standard [HTML5 File Input](/docs/demos/local/file#file-api) API works as
|
||||
expected in CapacitorJS.
|
||||
|
||||
```html
|
||||
Apps will typically include an `input type="file"` element. When the element is
|
||||
activated, CapacitorJS will show a file picker. After the user selects a file,
|
||||
the element will receive a `change` event.
|
||||
|
||||
The following example parses the selected file using the SheetJS `read`[^1]
|
||||
method, generates a HTML table from the first sheet using `sheet_to_html`[^2],
|
||||
and displays the table by setting the `innerHTML` attribute of a `div` element:
|
||||
|
||||
```html title="Sample component for data import"
|
||||
<script>
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
@ -91,28 +122,39 @@ async function importFile(evt) {
|
||||
|
||||
#### Writing data
|
||||
|
||||
`@capacitor/filesystem` can write Base64 strings:
|
||||
Starting from a SheetJS workbook object[^3], the `write` method with the option
|
||||
`type: "base64"`[^4] will generate Base64-encoded files.
|
||||
|
||||
```html
|
||||
The `@capacitor/filesystem` plugin can write Base64 strings to the device.
|
||||
|
||||
The following example uses the SheetJS `table_to_book` method[^5] to create a
|
||||
workbook object from a HTML table. The workbook object is exported to the XLSX
|
||||
format and written to the device.
|
||||
|
||||
```html title="Sample component for data export"
|
||||
<script>
|
||||
import { Filesystem, Directory } from '@capacitor/filesystem';
|
||||
import { utils, writeXLSX } from 'xlsx';
|
||||
import { utils, write } from 'xlsx';
|
||||
|
||||
let html = "";
|
||||
let tbl;
|
||||
|
||||
/* get state data and export to XLSX */
|
||||
async function exportFile() {
|
||||
/* generate workbook object from HTML table */
|
||||
const elt = tbl.getElementsByTagName("TABLE")[0];
|
||||
const wb = utils.table_to_book(elt);
|
||||
/* generate Base64 string for Capacitor */
|
||||
|
||||
// highlight-start
|
||||
const data = writeXLSX(wb, { type: "base64" });
|
||||
/* export to XLSX encoded in a Base64 string */
|
||||
const data = write(wb, { bookType: "xlsx", type: "base64" });
|
||||
|
||||
/* attempt to write to the device */
|
||||
await Filesystem.writeFile({
|
||||
data,
|
||||
path: "SheetJSCap.xlsx",
|
||||
directory: Directory.Documents
|
||||
}); // write file
|
||||
});
|
||||
// highlight-end
|
||||
}
|
||||
|
||||
@ -124,11 +166,45 @@ async function exportFile() {
|
||||
</main>
|
||||
```
|
||||
|
||||
:::caution pass
|
||||
|
||||
`Filesystem.writeFile` cannot overwrite existing files. Production apps should
|
||||
attempt to delete the file before writing:
|
||||
|
||||
```js
|
||||
/* attempt to delete file first */
|
||||
try {
|
||||
await Filesystem.deleteFile({
|
||||
path: "SheetJSCap.xlsx",
|
||||
directory: Directory.Documents
|
||||
});
|
||||
} catch(e) {}
|
||||
/* attempt to write to the device */
|
||||
await Filesystem.writeFile({
|
||||
data,
|
||||
path: "SheetJSCap.xlsx",
|
||||
directory: Directory.Documents
|
||||
});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
## Demo
|
||||
|
||||
The app in this demo will display data in a table.
|
||||
|
||||
When the app is launched, a [test file](https://docs.sheetjs.com/pres.numbers)
|
||||
will be fetched and processed.
|
||||
|
||||
When a document is selected with the file picker, it will be processed and the
|
||||
table will refresh to show the contents.
|
||||
|
||||
"Export XLSX" will attempt to export the table data to `SheetJSCap.xlsx` in the
|
||||
app Documents folder. An alert will display the location of the file.
|
||||
|
||||
### Base Project
|
||||
|
||||
0) Follow the official "Environment Setup"[^1] instructions to set up Android
|
||||
0) Follow the official "Environment Setup"[^6] instructions to set up Android
|
||||
and iOS targets
|
||||
|
||||
:::caution pass
|
||||
@ -137,7 +213,8 @@ iOS development is only supported on macOS.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Installation Notes</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
CapacitorJS requires Java 17.
|
||||
|
||||
@ -180,7 +257,7 @@ npm run build
|
||||
|
||||
:::note pass
|
||||
|
||||
If prompted to create an Ionic account, type `N` and press Enter.
|
||||
If prompted to create an Ionic account, type `N` and press <kbd>Enter</kbd>.
|
||||
|
||||
:::
|
||||
|
||||
@ -215,7 +292,7 @@ the `Permissions` comment:
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
```
|
||||
|
||||
8) Run the app in the simulator
|
||||
8) Run the app in the simulator:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
@ -223,27 +300,70 @@ npx cap sync
|
||||
npx cap run android
|
||||
```
|
||||
|
||||
9) Test the app
|
||||
The app should look like the screenshot at the top of the page.
|
||||
|
||||
Open the app and observe that presidents are listed in the table.
|
||||
9) Test the export functionality.
|
||||
|
||||
Touch "Export XLSX" and the emulator will ask for permission:
|
||||
Touch "Export XLSX" and the emulator will ask for permission. Tap "Allow" and a
|
||||
popup will be displayed with a path.
|
||||
|
||||
Tap "Allow" and a popup will be displayed with a path.
|
||||
Open the "Files" app in the simulator, tap the `≡` icon and tap "Documents". Tap
|
||||
the "Documents" folder to find `SheetJSCap.xlsx`.
|
||||
|
||||
To see the generated file, switch to the "Files" app in the simulator, tap the
|
||||
`≡` icon and tap "Documents". Tap "Documents" folder to find `SheetJSCap.xlsx`.
|
||||
<details open>
|
||||
<summary><b>Downloading the generated file</b> (click to hide)</summary>
|
||||
|
||||
`adb` must be run from the root user:
|
||||
|
||||
```bash
|
||||
adb root
|
||||
```
|
||||
|
||||
The file location can be found by searching for `SheetJSCap.xlsx`:
|
||||
|
||||
```bash
|
||||
adb exec-out find / -name SheetJSCap.xlsx
|
||||
```
|
||||
|
||||
The first line of the output starting with `/` is the desired path:
|
||||
|
||||
```text
|
||||
find: /proc/8533/task/8533/exe: No such file or directory
|
||||
find: /proc/8533/exe: No such file or directory
|
||||
// highlight-next-line
|
||||
/data/media/0/Documents/SheetJSCap.xlsx
|
||||
/storage/emulated/0/Documents/SheetJSCap.xlsx
|
||||
```
|
||||
|
||||
`adb pull` can download the file:
|
||||
|
||||
```bash
|
||||
adb pull "/data/media/0/Documents/SheetJSCap.xlsx" SheetJSCap.xlsx
|
||||
```
|
||||
|
||||
`SheetJSCap.xlsx` can be opened with a spreadsheet editor such as Excel.
|
||||
|
||||
</details>
|
||||
|
||||
10) Test the import functionality.
|
||||
|
||||
Create a spreadsheet or find an existing file. Click and drag the file into the
|
||||
Android emulator window. The file will be uploaded to a Downloads folder in the
|
||||
emulator.
|
||||
|
||||
Tap on "Choose File" in the app. In the selector, tap `≡` and select "Downloads"
|
||||
to find the uploaded file. After selecting the file, the table will refresh.
|
||||
|
||||
### iOS
|
||||
|
||||
10) Create iOS app
|
||||
11) Create iOS app
|
||||
|
||||
```bash
|
||||
npm i --save @capacitor/ios
|
||||
npx cap add ios
|
||||
```
|
||||
|
||||
11) Enable file sharing and make the documents folder visible in the iOS app.
|
||||
12) Enable file sharing and make the documents folder visible in the iOS app.
|
||||
The following lines must be added to `ios/App/App/Info.plist`:
|
||||
|
||||
```xml title="ios/App/App/Info.plist (add to file)"
|
||||
@ -260,7 +380,7 @@ The following lines must be added to `ios/App/App/Info.plist`:
|
||||
|
||||
(The root element of the document is `plist` and it contains one `dict` child)
|
||||
|
||||
12) Run the app in the simulator
|
||||
13) Run the app in the simulator
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
@ -270,24 +390,45 @@ npx cap run ios
|
||||
|
||||
If prompted to select a target device, select "iPhone 15 Pro Max (simulator)".
|
||||
|
||||
13) Test the app
|
||||
The app should look like the screenshot at the top of the page.
|
||||
|
||||
Open the app and observe that presidents are listed in the table.
|
||||
14) Test the export functionality.
|
||||
|
||||
Touch "Export XLSX" and a popup will be displayed.
|
||||
|
||||
To see the generated file, switch to the "Files" app in the simulator and look
|
||||
for `SheetJSCap.xlsx` in "On My iPhone" > "`sheetjs-cap`"
|
||||
|
||||
<details open>
|
||||
<summary><b>Downloading the generated file</b> (click to hide)</summary>
|
||||
|
||||
The app files are available in the filesystem in `~/Library/Developer`. Open a
|
||||
terminal and run the following command to find the file:
|
||||
|
||||
```bash
|
||||
find ~/Library/Developer -name SheetJSCap.xlsx
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
15) Test the import functionality.
|
||||
|
||||
Create a spreadsheet or find an existing file. Click and drag the file into the
|
||||
iOS simulator window. The simulator will show a picker for saving the file.
|
||||
Select the `sheetjs-cap` folder and tap "Save".
|
||||
|
||||
Tap on "Choose File" in the app and "Choose File" in the popup. In the picker,
|
||||
tap "Recents" and select the new file. After selecting the file, the table will refresh.
|
||||
|
||||
### Android Device
|
||||
|
||||
14) Connect an Android device using a USB cable.
|
||||
16) Connect an Android device using a USB cable.
|
||||
|
||||
If the device asks to allow USB debugging, tap "Allow".
|
||||
|
||||
15) Close any Android / iOS emulators.
|
||||
17) Close any Android / iOS emulators.
|
||||
|
||||
16) Build APK and run on device:
|
||||
18) Build APK and run on device:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
@ -298,6 +439,13 @@ npx cap run android
|
||||
If the Android emulators are closed and an Android device is connected, the last
|
||||
command will build an APK and install on the device.
|
||||
|
||||
:::note pass
|
||||
|
||||
In some tests, the last command asked for a target device. Select the Android
|
||||
device in the list and press <kbd>Enter</kbd>
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
For real devices running API level 29 or below, the following line must be added
|
||||
@ -319,13 +467,17 @@ to the `application` open tag in `android/app/src/main/AndroidManifest.xml`:
|
||||
|
||||
### iOS Device
|
||||
|
||||
17) Connect an iOS device using a USB cable
|
||||
19) Connect an iOS device using a USB cable
|
||||
|
||||
18) Close any Android / iOS emulators.
|
||||
20) Close any Android / iOS emulators.
|
||||
|
||||
19) Enable developer code signing certificates[^2]
|
||||
21) Enable developer code signing certificates.
|
||||
|
||||
19) Run on device:
|
||||
Open `ios/App/App.xcworkspace` in Xcode. Select the "Project Navigator" and
|
||||
select the "App" project. In the main view, select "Signing & Capabilities".
|
||||
Under "Signing", select a team in the dropdown menu.
|
||||
|
||||
22) Run on device:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
@ -335,5 +487,9 @@ npx cap run ios
|
||||
|
||||
When prompted to select a target device, select the real device in the list.
|
||||
|
||||
[^1]: See ["Environment Setup"](https://capacitorjs.com/docs/getting-started/environment-setup) in the CapacitorJS documentation.
|
||||
[^2]: The [Flutter documentation](https://docs.flutter.dev/get-started/install/macos?tab=ios15#enable-developer-code-signing-certificates) covers the instructions in more detail. The correct workspace is `ios/App/App.xcworkspace`
|
||||
[^1]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^2]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
|
||||
[^3]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^4]: See [the "base64" type in "Writing Files"](/docs/api/write-options#output-type)
|
||||
[^5]: See [`table_to_book` in "HTML" Utilities](/docs/api/utilities/html#create-new-sheet)
|
||||
[^6]: See ["Environment Setup"](https://capacitorjs.com/docs/getting-started/environment-setup) in the CapacitorJS documentation.
|
@ -10,6 +10,8 @@ sidebar_custom_props:
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
Dart[^1] + Flutter[^2] is a popular cross-platform app framework. JavaScript
|
||||
@ -41,16 +43,23 @@ The "Demo" creates an app that looks like the screenshots below:
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS | Type | Device | Dart | Flutter | Date |
|
||||
|:-----------|:-----|:------------------|:--------|:---------|:-----------|
|
||||
| Android 34 | Sim | Pixel 3a | `3.2.2` | `3.16.2` | 2023-12-04 |
|
||||
| iOS 17.0.1 | Sim | iPhone 15 Pro Max | `3.2.2` | `3.16.2` | 2023-12-04 |
|
||||
| Android 29 | Real | NVIDIA Shield | `3.2.2` | `3.16.2` | 2023-12-04 |
|
||||
| iOS 15.1 | Real | iPad Pro | `3.2.2` | `3.16.2` | 2023-12-04 |
|
||||
**Real Devices**
|
||||
|
||||
| OS | Device | Dart | Flutter | Date |
|
||||
|:-----------|:------------------|:--------|:---------|:-----------|
|
||||
| Android 30 | NVIDIA Shield | `3.4.3` | `3.22.2` | 2024-06-09 |
|
||||
| iOS 15.1 | iPad Pro | `3.4.3` | `3.22.2` | 2024-06-09 |
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | Dart | Flutter | Dev Platform | Date |
|
||||
|:-----------|:------------------|:--------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `3.4.3` | `3.22.2` | `darwin-x64` | 2024-06-09 |
|
||||
| iOS 17.5 | iPhone 15 Pro Max | `3.4.3` | `3.22.2` | `darwin-x64` | 2024-06-09 |
|
||||
|
||||
:::
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
Before starting this demo, manually disable telemetry. On MacOS:
|
||||
|
||||
@ -212,15 +221,35 @@ class SheetJSFlutterState extends State<SheetJSFlutter> {
|
||||
|
||||
Run `flutter doctor` and confirm the following items are checked:
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="linux" label="Linux">
|
||||
|
||||
```
|
||||
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
|
||||
[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
|
||||
[✓] Android Studio (version 2022.3)
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="macos" label="macOS" default>
|
||||
|
||||
```
|
||||
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
|
||||
[✓] Xcode - develop for iOS and macOS (Xcode 15.4)
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
```
|
||||
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
(the actual version numbers may differ)
|
||||
|
||||
<details open><summary><b>Installation Notes</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>Installation Notes</b> (click to hide)</summary>
|
||||
|
||||
:::note pass
|
||||
|
||||
@ -282,6 +311,22 @@ If Chromium is installed, the environment variable should be manually assigned:
|
||||
export CHROME_EXECUTABLE=/Applications/Chromium.app/Contents/MacOS/Chromium
|
||||
```
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="linux" label="Linux">
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="macos" label="macOS">
|
||||
|
||||
```bash
|
||||
export CHROME_EXECUTABLE=/Applications/Chromium.app/Contents/MacOS/Chromium
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::
|
||||
|
||||
</details>
|
||||
@ -289,17 +334,18 @@ export CHROME_EXECUTABLE=/Applications/Chromium.app/Contents/MacOS/Chromium
|
||||
Run `flutter emulators` and check for both `ios` and `android` emulators:
|
||||
|
||||
```
|
||||
apple_ios_simulator • iOS Simulator • Apple • ios
|
||||
Pixel_3a_API_34 • Pixel 3a API 34 • Google • android
|
||||
Id • Name • Manufacturer • Platform
|
||||
|
||||
apple_ios_simulator • iOS Simulator • Apple • ios
|
||||
Pixel_3a_API_34 • Pixel 3a API 34 • Google • android
|
||||
```
|
||||
|
||||
1) Disable telemetry.
|
||||
1) Disable telemetry. The following commands were confirmed to work:
|
||||
|
||||
```bash
|
||||
dart --disable-telemetry
|
||||
dart --disable-analytics
|
||||
flutter config --no-analytics
|
||||
flutter config --disable-telemetry
|
||||
```
|
||||
|
||||
### Base Project
|
||||
@ -313,7 +359,8 @@ cd sheetjs_flutter
|
||||
|
||||
3) Start the Android emulator.
|
||||
|
||||
<details open><summary><b>Details</b> (click to hide)</summary>
|
||||
<details open>
|
||||
<summary><b>Details</b> (click to hide)</summary>
|
||||
|
||||
**Android Studio**
|
||||
|
||||
@ -360,7 +407,8 @@ emulator -avd Pixel_3a_API_34
|
||||
flutter run
|
||||
```
|
||||
|
||||
<details><summary><b>If emulator is not detected</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>If emulator is not detected</b> (click to show)</summary>
|
||||
|
||||
In some test runs, `flutter run` did not automatically detect the emulator.
|
||||
|
||||
@ -440,12 +488,12 @@ curl -L -o lib/main.dart https://docs.sheetjs.com/flutter/main.dart
|
||||
flutter run
|
||||
```
|
||||
|
||||
The app fetches <https://sheetjs.com/pres.numbers>, parses, converts data to an
|
||||
array of arrays, and presents the data in a Flutter `Table` widget.
|
||||
The app fetches https://docs.sheetjs.com/pres.numbers, parses, converts data to
|
||||
an array of arrays, and presents the data in a Flutter `Table` widget.
|
||||
|
||||
:::caution pass
|
||||
:::info pass
|
||||
|
||||
When the demo was last run, there was a build error:
|
||||
In some demo runs, the build failed with an Android SDK error:
|
||||
|
||||
```
|
||||
│ The plugin flutter_js requires a higher Android SDK version. │
|
||||
@ -485,8 +533,8 @@ Searching for `minSdkVersion` should reveal the following line:
|
||||
flutter run
|
||||
```
|
||||
|
||||
The app fetches <https://sheetjs.com/pres.numbers>, parses, converts data to an
|
||||
array of arrays, and presents the data in a Flutter `Table` widget.
|
||||
The app fetches https://docs.sheetjs.com/pres.numbers, parses, converts data to
|
||||
an array of arrays, and presents the data in a Flutter `Table` widget.
|
||||
|
||||
### Android Device
|
||||
|
||||
@ -503,7 +551,7 @@ flutter devices
|
||||
The list should include the device:
|
||||
|
||||
```
|
||||
SheetJS (mobile) • 1234567890 • android-arm64 • Android 10 (API 29)
|
||||
SheetJS (mobile) • 726272627262726272 • android-arm64 • Android 11 (API 30)
|
||||
^^^^^^^--- the first column is the name
|
||||
```
|
||||
|
||||
@ -519,7 +567,9 @@ flutter build apk --release
|
||||
flutter install
|
||||
```
|
||||
|
||||
The script will ask for a device:
|
||||
:::note pass
|
||||
|
||||
The script may ask for a device:
|
||||
|
||||
```
|
||||
[1]: SheetJS (1234567890)
|
||||
@ -531,7 +581,9 @@ Please choose one (or "q" to quit):
|
||||
|
||||
Select the number corresponding to the device.
|
||||
|
||||
18) Launch the installed `sheetjs_flutter` app on the device
|
||||
:::
|
||||
|
||||
18) Launch the installed `sheetjs_flutter` app on the device.
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -554,7 +606,7 @@ flutter devices
|
||||
The list should include the device:
|
||||
|
||||
```
|
||||
SheetPad (mobile) • 00000000-0000000000000000 • ios • iOS 15.1 19B74
|
||||
SheetPad (mobile) • 00000000-0000000000000000 • ios • iOS 15.1 19B74
|
||||
^^^^^^^^--- the first column is the name
|
||||
```
|
||||
|
||||
@ -564,8 +616,57 @@ The list should include the device:
|
||||
flutter run -d SheetPad
|
||||
```
|
||||
|
||||
[^1]: <https://dart.dev/> is the official site for the Dart Programming Language.
|
||||
[^2]: <https://flutter.dev/> is the official site for the Flutter Framework.
|
||||
In debug mode, "Flutter tools" will attempt to connect to the running app. The
|
||||
device will ask for permission:
|
||||
|
||||
> "Sheetjs Flutter" would like to find and connect to devices on your local network.
|
||||
|
||||
Tap "OK" to continue.
|
||||
|
||||
:::caution pass
|
||||
|
||||
When this demo was last tested, the build failed with an error:
|
||||
|
||||
```text
|
||||
Could not build the precompiled application for the device.
|
||||
Error (Xcode): No profiles for 'com.example.sheetjsFlutter' were found: Xcode couldn't find any iOS App Development provisioning profiles matching 'com.example.sheetjsFlutter'. Automatic signing is disabled and unable to generate a profile. To enable automatic signing, pass -allowProvisioningUpdates to xcodebuild.
|
||||
```
|
||||
|
||||
The message includes a hint:
|
||||
|
||||
```
|
||||
Verify that the Bundle Identifier in your project is your signing id in Xcode
|
||||
open ios/Runner.xcworkspace
|
||||
```
|
||||
|
||||
Open the workspace and select the "Runner" project in the Navigator. In the main
|
||||
pane, select "Signing & Capabilities" and ensure a Team is selected. From
|
||||
the menu bar, select "Product" > "Run" to run the app.
|
||||
|
||||
:::
|
||||
|
||||
:::info pass
|
||||
|
||||
If there is an "Untrusted Developer" error, the certificate must be trusted on
|
||||
the device. The following steps were verified in iOS 15.1:
|
||||
|
||||
1) Open the "Settings" app on the device
|
||||
|
||||
In the "APPS FROM DEVELOPER" section of the new screen, "Sheetjs Flutter" should
|
||||
be displayed. If it is missing, tap the "<" button near the top of the screen
|
||||
and select a different certificate from the list.
|
||||
|
||||
2) Select "General" > "VPN & Device Management".
|
||||
|
||||
3) In the "DEVELOPER APP" section, tap the certificate that is "Not Trusted".
|
||||
|
||||
4) After confirming "Sheetjs Flutter" is in the list, tap the "Trust" button and
|
||||
tap "Trust" in the popup.
|
||||
|
||||
:::
|
||||
|
||||
[^1]: https://dart.dev/ is the official site for the Dart Programming Language.
|
||||
[^2]: https://flutter.dev/ is the official site for the Flutter Framework.
|
||||
[^3]: [The `flutter_js` package](https://pub.dev/packages/flutter_js) is hosted on the Dart package repository.
|
||||
[^4]: See [the dedicated "Swift + JavaScriptCore" demo](/docs/demos/engines/jsc) for more details.
|
||||
[^5]: See [the dedicated "C + QuickJS" demo](/docs/demos/engines/quickjs) for more details.
|
||||
|
@ -1,18 +1,28 @@
|
||||
---
|
||||
title: iOS and Android Apps
|
||||
title: Tables on Tablets and Mobile Devices
|
||||
sidebar_label: iOS and Android Apps
|
||||
pagination_prev: demos/static/index
|
||||
pagination_next: demos/desktop/index
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import EngineData from '/data/mobile.js'
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
Many mobile app frameworks mix JavaScript / CSS / HTML5 concepts with native
|
||||
extensions and libraries to create a hybrid development experience. Developers
|
||||
well-versed in web technologies can now build actual mobile applications that
|
||||
run on iOS and Android!
|
||||
|
||||
:::warning pass
|
||||
The demos in this section showcase a number of mobile frameworks. In each case,
|
||||
we will build a sample app that loads SheetJS library scripts and processes
|
||||
on-device and remote spreadsheet files.
|
||||
|
||||
:::danger pass
|
||||
|
||||
**The ecosystem has broken backwards-compatibility many times!**
|
||||
|
||||
@ -24,10 +34,6 @@ MacOS is required for the iOS demos. The Android demos were tested on MacOS.
|
||||
|
||||
:::
|
||||
|
||||
The ["JavaScript Engines"](/docs/demos/engines) section includes samples for JS
|
||||
engines used in the mobile app frameworks. SheetJS libraries have been tested
|
||||
in the relevant engines and should "just work" with some caveats.
|
||||
|
||||
Demos for common tools are included in separate pages. Each demo section will
|
||||
mention test dates and platform versions.
|
||||
|
||||
@ -40,6 +46,14 @@ mention test dates and platform versions.
|
||||
</li>);
|
||||
})}</ul>
|
||||
|
||||
:::info pass
|
||||
|
||||
The ["JavaScript Engines"](/docs/demos/engines) section includes samples for JS
|
||||
engines used in the mobile app frameworks. SheetJS libraries have been tested
|
||||
in the relevant engines.
|
||||
|
||||
:::
|
||||
|
||||
:::note Recommendation
|
||||
|
||||
React Native is extremely popular and is the recommended choice for greenfield
|
||||
@ -47,9 +61,9 @@ projects that can use community modules. However, its "lean core" approach
|
||||
forces developers to learn iOS/Android programming or use community modules to
|
||||
provide basic app features.
|
||||
|
||||
The original Web View framework was PhoneGap/Cordova. The modern frameworks
|
||||
are built atop Cordova. Cordova is waning in popularity but it has a deep
|
||||
library of community modules to solve many problems.
|
||||
The original Web View framework was PhoneGap/Cordova. The modern frameworks are
|
||||
built atop Cordova. Cordova is waning in popularity but it has a deep library of
|
||||
community modules to solve many problems.
|
||||
|
||||
Before creating a new app, it is important to identify what features the app
|
||||
should support and investigate community modules. If there are popular modules
|
||||
@ -57,3 +71,16 @@ for features that must be included, or for teams that are comfortable with
|
||||
native app development, React Native is the obvious choice.
|
||||
|
||||
:::
|
||||
|
||||
### Platforms
|
||||
|
||||
The following frameworks have been tested:
|
||||
|
||||
<EngineData/>
|
||||
|
||||
:::info pass
|
||||
|
||||
When this table was last updated, it was not possible to build an iOS app from
|
||||
Linux or Windows. Android tooling runs on MacOS, Linux and Windows.
|
||||
|
||||
:::
|
||||
|
@ -189,11 +189,11 @@ This demo was tested in the following environments:
|
||||
| OS and Version | Architecture | Electron | Date |
|
||||
|:---------------|:-------------|:---------|:-----------|
|
||||
| macOS 14.4 | `darwin-x64` | `29.1.4` | 2024-03-15 |
|
||||
| macOS 14.1.2 | `darwin-arm` | `27.1.3` | 2023-12-01 |
|
||||
| macOS 14.5 | `darwin-arm` | `30.0.8` | 2024-05-28 |
|
||||
| Windows 10 | `win10-x64` | `28.2.0` | 2024-03-04 |
|
||||
| Windows 11 | `win11-arm` | `27.1.3` | 2023-12-01 |
|
||||
| Windows 11 | `win11-arm` | `30.0.8` | 2024-05-28 |
|
||||
| Linux (HoloOS) | `linux-x64` | `29.1.4` | 2024-03-21 |
|
||||
| Linux (Debian) | `linux-arm` | `27.1.3` | 2023-12-01 |
|
||||
| Linux (Debian) | `linux-arm` | `30.0.8` | 2024-05-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -268,15 +268,18 @@ The program will run on ARM64 Windows.
|
||||
|
||||
### Testing
|
||||
|
||||
5) Download [the test file `pres.numbers`](https://sheetjs.com/pres.numbers)
|
||||
5) Download [the test file `pres.numbers`](https://docs.sheetjs.com/pres.numbers)
|
||||
|
||||
6) Launch the generated application:
|
||||
|
||||
| Architecture | Command |
|
||||
|:-------------|:--------------------------------------------------------------|
|
||||
| `darwin-x64` | `open ./out/sheetjs-electron-darwin-x64/sheetjs-electron.app` |
|
||||
| `win10-x64` | `.\out\sheetjs-electron-win32-x64\sheetjs-electron.exe` |
|
||||
| `linux-x64` | `./out/sheetjs-electron-linux-x64/sheetjs-electron` |
|
||||
| `darwin-x64` |`open ./out/sheetjs-electron-darwin-x64/sheetjs-electron.app` |
|
||||
| `darwin-arm` |`open ./out/sheetjs-electron-darwin-arm64/sheetjs-electron.app`|
|
||||
| `win10-x64` |`.\out\sheetjs-electron-win32-x64\sheetjs-electron.exe` |
|
||||
| `win11-arm` |`.\out\sheetjs-electron-win32-x64\sheetjs-electron.exe` |
|
||||
| `linux-x64` |`./out/sheetjs-electron-linux-x64/sheetjs-electron` |
|
||||
| `linux-x64` |`./out/sheetjs-electron-linux-arm64/sheetjs-electron` |
|
||||
|
||||
#### Electron API
|
||||
|
||||
@ -319,7 +322,7 @@ and select `pres.numbers`.
|
||||
## Electron Breaking Changes
|
||||
|
||||
The first version of this demo used Electron 1.7.5. The current demo includes
|
||||
the required changes for Electron 28.2.0.
|
||||
the required changes for Electron 30.0.8.
|
||||
|
||||
There are no Electron-specific workarounds in the library, but Electron broke
|
||||
backwards compatibility multiple times. A summary of changes is noted below.
|
||||
|
@ -111,16 +111,14 @@ input.click();
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | NW.js | Date |
|
||||
|:---------------|:-------------|:---------|:-----------|
|
||||
| macOS 14.3.1 | `darwin-x64` | `0.85.0` | 2024-03-12 |
|
||||
| macOS 14.1.2 | `darwin-arm` | `0.82.0` | 2023-12-01 |
|
||||
| Windows 10 | `win10-x64` | `0.83.0` | 2024-03-04 |
|
||||
| Windows 11 | `win11-arm` | `0.82.0` | 2023-12-01 |
|
||||
| Linux (HoloOS) | `linux-x64` | `0.85.0` | 2024-03-12 |
|
||||
|
||||
There is no official Linux ARM64 release. The community release[^1] was tested
|
||||
and verified on 2023-09-27.
|
||||
| OS and Version | Architecture | NW.js | Date | Notes |
|
||||
|:---------------|:-------------|:---------|:-----------|:---------------------|
|
||||
| macOS 14.3.1 | `darwin-x64` | `0.85.0` | 2024-03-12 | |
|
||||
| macOS 14.5 | `darwin-arm` | `0.88.0` | 2024-05-28 | |
|
||||
| Windows 10 | `win10-x64` | `0.83.0` | 2024-03-04 | |
|
||||
| Windows 11 | `win11-arm` | `0.88.0` | 2024-05-28 | |
|
||||
| Linux (HoloOS) | `linux-x64` | `0.85.0` | 2024-03-12 | |
|
||||
| Linux (Debian) | `linux-arm` | `0.60.0` | 2024-05-23 | Unofficial build[^1] |
|
||||
|
||||
:::
|
||||
|
||||
@ -140,7 +138,7 @@ cd sheetjs-nwjs
|
||||
"version": "0.0.0",
|
||||
"main": "index.html",
|
||||
"dependencies": {
|
||||
"nw": "0.85.0",
|
||||
"nw": "0.88.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz"
|
||||
}
|
||||
}`}
|
||||
@ -173,13 +171,18 @@ npm i
|
||||
npx nw .
|
||||
```
|
||||
|
||||
The app will show and you should be able to verify reading and writing by using
|
||||
the file input element to select a spreadsheet and clicking the export button.
|
||||
On launch, the app will fetch and parse https://docs.sheetjs.com/pres.numbers .
|
||||
|
||||
Using the file input element, a file can be selected from the filesystem and the
|
||||
table will refresh with the contents of the selected file.
|
||||
|
||||
Click "Export Data!" and save the generated file to `SheetJSNWDemo.xlsx`. This
|
||||
file can be opened in Excel or another spreadsheet editor.
|
||||
|
||||
5) To build a standalone app, run the builder:
|
||||
|
||||
```bash
|
||||
npx -p nw-builder nwbuild --mode=build --version=0.85.0 --glob=false --outDir=../out ./
|
||||
npx -p nw-builder nwbuild --mode=build --version=0.88.0 --glob=false --outDir=../out ./
|
||||
```
|
||||
|
||||
This will generate the standalone app in the `..\out\` folder.
|
||||
|
@ -298,17 +298,18 @@ This demo was tested in the following environments:
|
||||
| OS and Version | Architecture | Wails | Date |
|
||||
|:---------------|:-------------|:---------|:-----------|
|
||||
| macOS 14.4 | `darwin-x64` | `v2.8.0` | 2024-03-15 |
|
||||
| macOS 14.1.2 | `darwin-arm` | `v2.6.0` | 2023-12-01 |
|
||||
| macOS 14.5 | `darwin-arm` | `v2.8.2` | 2024-05-28 |
|
||||
| Windows 10 | `win10-x64` | `v2.8.0` | 2024-03-24 |
|
||||
| Windows 11 | `win11-arm` | `v2.6.0` | 2023-12-01 |
|
||||
| Windows 11 | `win11-arm` | `v2.8.2` | 2024-05-28 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v2.8.0` | 2024-03-21 |
|
||||
| Linux (Debian) | `linux-arm` | `v2.6.0` | 2023-12-01 |
|
||||
| Linux (Debian) | `linux-arm` | `v2.8.2` | 2024-05-28 |
|
||||
|
||||
:::
|
||||
|
||||
0) Read the Wails "Getting Started" guide[^14] and install dependencies.
|
||||
|
||||
<details><summary><b>Installation Notes</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
Wails will require:
|
||||
|
||||
@ -333,7 +334,7 @@ On macOS and Linux, the `PATH` environment variable must include `~/go/bin`. If
|
||||
`wails` cannot be found, run the following command in the terminal session:
|
||||
|
||||
```bash
|
||||
export PATH="$PATH:~/go/bin"
|
||||
export PATH="$PATH":~/go/bin
|
||||
```
|
||||
|
||||
:::
|
||||
@ -403,7 +404,7 @@ It will print the path to the generated program (typically in `build/bin/`).
|
||||
|
||||
**Testing**
|
||||
|
||||
The program will download [`pres.xlsx`](https://sheetjs.com/pres.xlsx) and
|
||||
The program will download [`pres.xlsx`](https://docs.sheetjs.com/pres.xlsx) and
|
||||
display the contents of the first worksheet in a table.
|
||||
|
||||
To test export features, click "Export XLSX". The app will ask for a file name
|
||||
|
@ -9,13 +9,15 @@ sidebar_custom_props:
|
||||
summary: Webview + Rust Backend
|
||||
---
|
||||
|
||||
# Data Wrangling in Tauri Apps
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export const y = {style: {color:"gold"}};
|
||||
export const g = {style: {color:"green"}};
|
||||
export const B = {style: {fontWeight:"bold"}};
|
||||
|
||||
[Tauri](https://tauri.app/) is a modern toolkit for building desktop apps. Tauri
|
||||
apps leverage platform-native browser engines to build lightweight programs.
|
||||
|
||||
@ -210,7 +212,7 @@ function SheetJSImportKaioponent() {
|
||||
<table><tbody>{data.map((row) =>
|
||||
<tr>{row.map((cell) => <td>{cell}</td>)}</tr>
|
||||
)}</tbody></table>
|
||||
</>);
|
||||
</> );
|
||||
}
|
||||
```
|
||||
|
||||
@ -329,7 +331,6 @@ function SheetJSExportKaioponent() {
|
||||
|
||||
return ( <button type="button" onclick={save_callback}>Save Data</button> );
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@ -343,18 +344,19 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Tauri | Date |
|
||||
|:---------------|:-------------|:----------|:-----------|
|
||||
| macOS 14.4 | `darwin-x64` | `v1.5.11` | 2024-03-15 |
|
||||
| macOS 14.0 | `darwin-arm` | `v1.5.2` | 2023-10-18 |
|
||||
| macOS 14.4 | `darwin-x64` | `v1.5.11` | 2024-04-20 |
|
||||
| macOS 14.5 | `darwin-arm` | `v1.5.14` | 2024-05-26 |
|
||||
| Windows 10 | `win10-x64` | `v1.5.11` | 2024-03-24 |
|
||||
| Windows 11 | `win11-arm` | `v1.5.7` | 2023-12-01 |
|
||||
| Windows 11 | `win11-arm` | `v1.5.14` | 2024-05-28 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v1.5.11` | 2024-03-21 |
|
||||
| Linux (Debian) | `linux-arm` | `v1.5.7` | 2023-12-01 |
|
||||
| Linux (Debian) | `linux-arm` | `v1.5.14` | 2024-05-28 |
|
||||
|
||||
:::
|
||||
|
||||
0) Read Tauri "Getting Started" guide and install prerequisites.[^16]
|
||||
|
||||
<details><summary><b>Installation Notes</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
At a high level, the following software is required for building Tauri apps:
|
||||
|
||||
@ -371,18 +373,18 @@ npx @tauri-apps/cli info
|
||||
If required dependencies are installed, the output will show a checkmark next to
|
||||
"Environment". The output from the most recent macOS test is shown below:
|
||||
|
||||
```
|
||||
[✔] Environment
|
||||
- OS: Mac OS 14.4.0 X64
|
||||
✔ Xcode Command Line Tools: installed
|
||||
✔ rustc: 1.76.0 (07dca489a 2024-02-04)
|
||||
✔ cargo: 1.76.0 (c84b36747 2024-01-18)
|
||||
✔ rustup: 1.27.0 (bbb9276d2 2024-03-08)
|
||||
✔ Rust toolchain: stable-x86_64-apple-darwin (default)
|
||||
- node: 20.11.1
|
||||
- npm: 10.2.4
|
||||
- bun: 1.0.31
|
||||
```
|
||||
<pre>
|
||||
<span {...g}>[✔]</span> <span style={{...y.style,...B.style}}>Environment</span>
|
||||
{` `}<span {...g}>-</span> <span {...B}>OS</span>: Mac OS 14.4.1 X64
|
||||
{` `}<span {...g}>✔</span> <span {...B}>Xcode Command Line Tools</span>: installed
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustc</span>: 1.77.2 (25ef9e3d8 2024-04-09)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>cargo</span>: 1.77.2 (e52e36006 2024-03-26)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustup</span>: 1.27.0 (bbb9276d2 2024-03-08)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>Rust toolchain</span>: stable-x86_64-apple-darwin (default)
|
||||
{` `}<span {...g}>-</span> <span {...B}>node</span>: 20.12.1
|
||||
{` `}<span {...g}>-</span> <span {...B}>npm</span>: 10.5.0
|
||||
{` `}<span {...g}>-</span> <span {...B}>bun</span>: 1.1.4
|
||||
</pre>
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -434,6 +436,8 @@ npm i --save-dev @tauri-apps/cli`}
|
||||
</TabItem>
|
||||
<TabItem value="kaioken" label="Kaioken" default>
|
||||
|
||||
Install the Kaioken dependencies:
|
||||
|
||||
```bash
|
||||
npm add kaioken --save
|
||||
npm add vite-plugin-kaioken -D --save
|
||||
@ -463,14 +467,22 @@ npm add vite-plugin-kaioken -D --save
|
||||
// highlight-end
|
||||
```
|
||||
|
||||
In the same file, look for the `"identifier"` key and replace the value with `com.sheetjs.tauri`:
|
||||
In the same file, look for `"title"` and change the value to `SheetJS x Tauri`:
|
||||
|
||||
```json title="src-tauri/tauri.conf.json (edit highlighted line)"
|
||||
"icons/icon.ico"
|
||||
],
|
||||
{
|
||||
// highlight-next-line
|
||||
"title": "SheetJS x Tauri",
|
||||
"width": 800,
|
||||
```
|
||||
|
||||
In the same file, look for `"identifier"` and change the value to `com.sheetjs.tauri`:
|
||||
|
||||
```json title="src-tauri/tauri.conf.json (edit highlighted line)"
|
||||
"targets": "all",
|
||||
// highlight-next-line
|
||||
"identifier": "com.sheetjs.tauri",
|
||||
"longDescription": "",
|
||||
"icon": [
|
||||
```
|
||||
|
||||
<Tabs groupId="framework">
|
||||
@ -493,19 +505,11 @@ curl -o src/App.vue https://docs.sheetjs.com/tauri/App.vue
|
||||
```ts title="vite.config.ts (add highlighted lines)"
|
||||
import { defineConfig } from "vite";
|
||||
// highlight-next-line
|
||||
import kaioken from "vite-plugin-kaioken"
|
||||
import kaioken from "vite-plugin-kaioken";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig(async () => ({
|
||||
// highlight-start
|
||||
esbuild: {
|
||||
jsxInject: `import * as kaioken from "kaioken"`,
|
||||
jsx: "transform",
|
||||
jsxFactory: "kaioken.createElement",
|
||||
jsxFragment: "kaioken.fragment",
|
||||
loader: "tsx",
|
||||
include: ["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js"],
|
||||
},
|
||||
plugins: [kaioken()],
|
||||
// highlight-end
|
||||
```
|
||||
@ -625,7 +629,7 @@ or
|
||||
|
||||
The following features should be manually verified:
|
||||
|
||||
- When it is loaded, the app will download <https://sheetjs.com/pres.numbers>
|
||||
- When it is loaded, the app will download https://docs.sheetjs.com/pres.numbers
|
||||
and display the data in a table.
|
||||
- Clicking "Save Data" will show a save dialog. After selecting a path and name,
|
||||
the app will write a file. That file can be opened in a spreadsheet editor.
|
||||
@ -665,7 +669,7 @@ sudo pacman -S openssl
|
||||
|
||||
:::note pass
|
||||
|
||||
During the last macOS test, the build failed with the following error message:
|
||||
In some macOS tests, the build failed with the following error message:
|
||||
|
||||
```
|
||||
Error failed to bundle project: error running bundle_dmg.sh
|
||||
@ -690,6 +694,14 @@ select "Automation" in the body. Look for "Terminal", expand the section, and en
|
||||
|
||||
:::
|
||||
|
||||
:::note pass
|
||||
|
||||
In some tests, the fonts did not match the screenshots.
|
||||
|
||||
**The Inter font static TTFs must be manually downloaded and installed.**[^17]
|
||||
|
||||
:::
|
||||
|
||||
[^1]: See ["Security"](https://tauri.app/v1/references/architecture/security#allowing-api) in the Tauri documentation
|
||||
[^2]: See [`FsAllowlistConfig`](https://tauri.app/v1/api/config/#fsallowlistconfig) in the Tauri documentation
|
||||
[^3]: See [`DialogAllowlistConfig`](https://tauri.app/v1/api/config/#dialogallowlistconfig) in the Tauri documentation
|
||||
@ -705,4 +717,5 @@ select "Automation" in the body. Look for "Terminal", expand the section, and en
|
||||
[^13]: See [`fs`](https://tauri.app/v1/api/js/fs#writebinaryfile) in the Tauri documentation
|
||||
[^14]: See ["Array of Arrays Input" in "Utility Functions"](/docs/api/utilities/array#array-of-arrays-input)
|
||||
[^15]: See ["Workbook Helpers" in "Utility Functions"](/docs/api/utilities/wb)
|
||||
[^16]: See ["Prerequisites"](https://tauri.app/v1/guides/getting-started/prerequisites) in the Tauri documentation
|
||||
[^16]: See ["Prerequisites"](https://tauri.app/v1/guides/getting-started/prerequisites) in the Tauri documentation
|
||||
[^17]: Click "Get font" in the [Inter Google Fonts listing](https://fonts.google.com/specimen/Inter)
|
@ -193,18 +193,22 @@ This demo was tested in the following environments:
|
||||
| OS and Version | Architecture | Server | Client | Date |
|
||||
|:---------------|:-------------|:---------|:---------|:-----------|
|
||||
| macOS 14.4 | `darwin-x64` | `5.0.0` | `5.0.1` | 2024-03-15 |
|
||||
| macOS 14.0 | `darwin-arm` | `4.14.1` | `3.12.0` | 2023-10-18 |
|
||||
| macOS 14.5 | `darwin-arm` | `5.1.0` | `5.1.0` | 2024-05-25 |
|
||||
| Windows 10 | `win10-x64` | `5.1.0` | `5.1.0` | 2024-03-24 |
|
||||
| Windows 11 | `win11-arm` | `4.14.1` | `3.12.0` | 2023-12-01 |
|
||||
| Windows 11 | `win11-arm` | `5.1.0` | `5.1.1` | 2024-05-28 |
|
||||
| Linux (HoloOS) | `linux-x64` | `5.0.0` | `5.0.1` | 2024-03-21 |
|
||||
| Linux (Debian) | `linux-arm` | `4.14.1` | `3.12.0` | 2023-12-01 |
|
||||
| Linux (Debian) | `linux-arm` | `5.1.0` | `5.1.1` | 2024-05-28 |
|
||||
|
||||
On `win11-arm`, the Electron runner is a proper ARM64 binary but the binaries
|
||||
generated by Electron Forge are x64. The x64 binaries run in Windows on ARM.
|
||||
|
||||
:::
|
||||
|
||||
The app core state will be the HTML table. Reading files will add the table to
|
||||
the window. Writing files will parse the table into a spreadsheet.
|
||||
|
||||
<details><summary><b>Installation Notes</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
NeutralinoJS uses `portable-file-dialogs`[^12] to show open and save dialogs. On
|
||||
Linux, Zenity or KDialog are require.
|
||||
@ -302,7 +306,7 @@ table {
|
||||
|
||||
6) Print the version number in the `showInfo` method of `resources/js/main.js`:
|
||||
|
||||
```js title="resources/js/main.js"
|
||||
```js title="resources/js/main.js (add highlighted lines)"
|
||||
function showInfo() {
|
||||
document.getElementById('info').innerHTML = `
|
||||
${NL_APPID} is running on port ${NL_PORT} inside ${NL_OS}
|
||||
@ -328,14 +332,18 @@ npx @neutralinojs/neu run
|
||||
|
||||
```js title="resources/js/main.js (add to end)"
|
||||
(async() => {
|
||||
const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer();
|
||||
const ab = await (await fetch("https://docs.sheetjs.com/pres.numbers")).arrayBuffer();
|
||||
const wb = XLSX.read(ab);
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
document.getElementById('info').innerHTML = XLSX.utils.sheet_to_html(ws);
|
||||
})();
|
||||
```
|
||||
|
||||
9) Close the app and relaunch the app with `npx @neutralinojs/neu run`
|
||||
9) Close the app. Run the app again:
|
||||
|
||||
```bash
|
||||
npx @neutralinojs/neu run
|
||||
```
|
||||
|
||||
When the app loads, a table should show in the main screen.
|
||||
|
||||
@ -370,7 +378,11 @@ async function exportData() {
|
||||
}
|
||||
```
|
||||
|
||||
11) Close the app and re-run with `npx @neutralinojs/neu run`
|
||||
11) Close the app. Run the app again:
|
||||
|
||||
```bash
|
||||
npx @neutralinojs/neu run
|
||||
```
|
||||
|
||||
When the app loads, click the "Import File" button and select a spreadsheet to
|
||||
see the contents.
|
||||
@ -397,8 +409,15 @@ save as `SheetJSNeu` will not automatically add the `.xlsx` extension!
|
||||
npx @neutralinojs/neu build
|
||||
```
|
||||
|
||||
Platform-specific programs will be created in the `dist` folder. For example,
|
||||
the `darwin-arm` program will be `./dist/sheetjs-neu/sheetjs-neu-mac_arm64`
|
||||
Platform-specific programs will be created in the `dist` folder:
|
||||
|
||||
| Platform | Path to binary |
|
||||
|:-------------|:---------------------------------------------|
|
||||
| `darwin-arm` | `./dist/sheetjs-neu/sheetjs-neu-mac_arm64` |
|
||||
| `win11-arm` | `.\dist\sheetjs-neu\sheetjs-neu-win_x64.exe` |
|
||||
| `linux-arm` | `.\dist\sheetjs-neu\sheetjs-neu-linux_arm64` |
|
||||
|
||||
Run the generated app and confirm that Presidential data is displayed.
|
||||
|
||||
[^1]: See [`nativeAllowList`](https://neutralino.js.org/docs/configuration/neutralino.config.json#nativeallowlist-string) in the NeutralinoJS documentation
|
||||
[^2]: See [`os.showOpenDialog`](https://neutralino.js.org/docs/api/os#osshowopendialogtitle-options) in the NeutralinoJS documentation
|
||||
|
@ -46,11 +46,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | RN Platform | Date |
|
||||
|:---------------|:-------------|:------------|:-----------|
|
||||
| Windows 10 | `win10-x64` | `v0.73.11` | 2024-03-24 |
|
||||
| Windows 11 | `win11-x64` | `v0.72.12` | 2023-10-14 |
|
||||
| Windows 11 | `win11-arm` | `v0.72.20` | 2023-12-01 |
|
||||
| Windows 10 | `win10-x64` | `v0.74.6` | 2024-05-28 |
|
||||
| Windows 11 | `win11-x64` | `v0.74.6` | 2024-05-28 |
|
||||
| Windows 11 | `win11-arm` | `v0.74.5` | 2024-05-25 |
|
||||
| MacOS 14.4 | `darwin-x64` | `v0.73.22` | 2024-03-24 |
|
||||
| MacOS 14.1.2 | `darwin-arm` | `v0.72.11` | 2023-12-01 |
|
||||
| MacOS 14.5 | `darwin-arm` | `v0.73.30` | 2024-05-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -61,7 +61,7 @@ applications, [check the mobile demo](/docs/demos/mobile/reactnative)
|
||||
|
||||
:::
|
||||
|
||||
:::warning Telemetry
|
||||
:::danger Telemetry
|
||||
|
||||
**React Native for Windows + macOS commands include telemetry without proper**
|
||||
**disclaimer or global opt-out.**
|
||||
@ -84,7 +84,9 @@ imported from any component or script in the app.
|
||||
|
||||
For simplicity, this demo uses an "Array of Arrays"[^2] as the internal state.
|
||||
|
||||
<table><thead><tr><th>Spreadsheet</th><th>Array of Arrays</th></tr></thead><tbody><tr><td>
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>Array of Arrays</th></tr></thead>
|
||||
<tbody><tr><td>
|
||||
|
||||
![`pres.xlsx` data](pathname:///pres.png)
|
||||
|
||||
@ -133,7 +135,8 @@ function update_state(wb) {
|
||||
|
||||
The demos use native `View` elements from `react-native` to display data.
|
||||
|
||||
<details><summary><b>Explanation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Explanation</b> (click to show)</summary>
|
||||
|
||||
Since some spreadsheets may have empty cells between cells containing data,
|
||||
looping over the rows may skip values!
|
||||
@ -379,7 +382,7 @@ RCT_EXPORT_METHOD(PickAndRead:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromi
|
||||
|
||||
## Windows Demo
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
There is no simple standalone executable file at the end of the process.
|
||||
|
||||
@ -404,7 +407,8 @@ used to switch the NodeJS version.
|
||||
|
||||
:::
|
||||
|
||||
<details><summary><b>Installation Notes</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
When the demo was last tested, a PowerShell script installed dependencies:
|
||||
|
||||
@ -420,10 +424,10 @@ setup instructions" to find instructions for manual installation.
|
||||
|
||||
### Project Setup
|
||||
|
||||
1) Create a new project using React Native `0.73.6`:
|
||||
1) Create a new project using React Native `0.74.1`:
|
||||
|
||||
```bash
|
||||
npx react-native init SheetJSWin --template react-native@0.73.6
|
||||
npx react-native init SheetJSWin --template react-native@0.74.1
|
||||
cd SheetJSWin
|
||||
```
|
||||
|
||||
@ -478,7 +482,7 @@ Specific Windows SDK versions can be installed through Visual Studio Installer.
|
||||
npx react-native run-windows --no-telemetry --arch=X86
|
||||
```
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
The ARM64 binary is normally built with
|
||||
|
||||
@ -612,7 +616,7 @@ npx react-native run-windows --no-telemetry
|
||||
npx react-native run-windows --no-telemetry --arch=X86
|
||||
```
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
The ARM64 binary is normally built with
|
||||
|
||||
@ -629,7 +633,7 @@ When this demo was last tested on Windows 11 ARM, the build failed.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
9) Download <https://sheetjs.com/pres.xlsx>.
|
||||
9) Download https://docs.sheetjs.com/pres.xlsx.
|
||||
|
||||
10) In the app, click "Click here to Open File!" and use the file picker to
|
||||
select `pres.xlsx` . The app will refresh and display the data from the file.
|
||||
@ -669,10 +673,10 @@ npx -y react-native-macos-init --no-telemetry
|
||||
|
||||
:::caution pass
|
||||
|
||||
In the most recent x64 test, the build failed due to `visionos` errors:
|
||||
In some macOS tests, the build failed due to `visionos` errors:
|
||||
|
||||
```
|
||||
[!] Failed to load 'React-RCTFabric' podspec:
|
||||
[!] Failed to load 'React-RCTFabric' podspec:
|
||||
[!] Invalid `React-RCTFabric.podspec` file: undefined method `visionos' for #<Pod::Specification name="React-RCTFabric">.
|
||||
```
|
||||
|
||||
@ -682,6 +686,14 @@ This error was resolved by upgrading CocoaPods to `1.15.2`:
|
||||
sudo gem install cocoapods
|
||||
```
|
||||
|
||||
After upgrading CocoaPods, reinstall the project pods:
|
||||
|
||||
```bash
|
||||
cd macos
|
||||
pod install
|
||||
cd ..
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
3) Install the SheetJS library:
|
||||
@ -698,16 +710,16 @@ npx react-native run-macos
|
||||
|
||||
Close the running app from the dock and close the Metro terminal window.
|
||||
|
||||
:::warning pass
|
||||
:::danger pass
|
||||
|
||||
When the demo was last tested on x64, the app failed with a warning
|
||||
When the demo was last tested, the app failed with a warning
|
||||
|
||||
> No bundle URL present.
|
||||
|
||||
**As this affects the default app, this is a bug in React Native macOS!**
|
||||
|
||||
The production builds work as expected. If there are errors, the recommended
|
||||
approach is to [make a release build](#production) every time.
|
||||
The production builds work as expected. If there are errors, click "Dismiss" to
|
||||
dismiss the error, close the app, and [make a release build](#production).
|
||||
|
||||
:::
|
||||
|
||||
@ -785,7 +797,6 @@ B) Copy the highlighted lines and paste under `/* Begin PBXFileReference section
|
||||
4717DC6828CC495400A9BE56 /* RCTDocumentPicker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RCTDocumentPicker.h; path = "SheetJSMacOS-macOS/RCTDocumentPicker.h"; sourceTree = "<group>"; };
|
||||
4717DC6928CC499A00A9BE56 /* RCTDocumentPicker.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RCTDocumentPicker.m; path = "SheetJSMacOS-macOS/RCTDocumentPicker.m"; sourceTree = "<group>"; };
|
||||
// highlight-end
|
||||
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = "<group>"; };
|
||||
```
|
||||
|
||||
:::
|
||||
@ -912,7 +923,7 @@ Close the running app from the dock and close the Metro terminal window.
|
||||
curl -LO https://docs.sheetjs.com/reactnative/rnm/App.tsx
|
||||
```
|
||||
|
||||
10) Download <https://sheetjs.com/pres.xlsx> to the Downloads folder.
|
||||
10) Download https://docs.sheetjs.com/pres.xlsx to the Downloads folder.
|
||||
|
||||
#### Development
|
||||
|
||||
@ -955,9 +966,9 @@ xcodebuild -workspace macos/SheetJSmacOS.xcworkspace -scheme SheetJSmacOS-macOS
|
||||
```
|
||||
|
||||
When the demo was last tested, the path to the generated app was displayed in
|
||||
the terminal. Search for `Release/SheetJSmacOS.app` and look for `touch`:
|
||||
the terminal. Search for `Release/SheetJSmacOS.app` and look for `touch -c`:
|
||||
|
||||
```
|
||||
```text title="Sample result when searching for 'touch -c'"
|
||||
/usr/bin/touch -c /Users/sheetjs/Library/Developer/Xcode/DerivedData/SheetJSmacOS-abcdefghijklmnopqrstuvwxyzab/Build/Products/Release/SheetJSmacOS.app
|
||||
```
|
||||
|
||||
|
@ -2,13 +2,43 @@
|
||||
title: Desktop Applications
|
||||
pagination_prev: demos/mobile/index
|
||||
pagination_next: demos/cli/index
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
import FrameworkData from '/data/desktop.js'
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
Web technologies including JavaScript and HTML can power traditional software.
|
||||
|
||||
This demo covers a number of desktop app frameworks. In each demo, we will build
|
||||
an app that uses SheetJS libraries to read and write spreadsheet files.
|
||||
|
||||
## Strategies
|
||||
|
||||
There are two different integration strategies. The "WebView" strategy embeds a
|
||||
mini web browser and adds supporting native components. The "Engine" strategy
|
||||
uses an embedded JavaScript engine that fits into the desktop app.
|
||||
|
||||
### WebView
|
||||
|
||||
WebViews are special web browser components designed to be embedded within apps.
|
||||
As the browser components are available across all major platforms, desktop apps
|
||||
can use the WebView as the main user interface. This approach allows small teams
|
||||
to build software that works across operating systems and architectures.
|
||||
|
||||
The app is designed in HTML and CSS. [Web Frameworks](/docs/demos/frontend) can
|
||||
be used but are typically not required.
|
||||
|
||||
### Engine
|
||||
|
||||
JavaScript engines including [V8](/docs/demos/engines/v8) can be directly added
|
||||
to traditional desktop software. This approach is explored in greater detail in
|
||||
the ["JavaScript Engines" demo](/docs/demos/engines/).
|
||||
|
||||
## Desktop Apps
|
||||
|
||||
Desktop app frameworks bundle a JavaScript engine and a windowing framework to
|
||||
@ -38,6 +68,12 @@ Frameworks like React Native generate applications that use native UI elements.
|
||||
|
||||
:::
|
||||
|
||||
## Command-Line Tools
|
||||
#### Platform Support
|
||||
|
||||
The following frameworks have been tested on the following platforms:
|
||||
|
||||
<FrameworkData/>
|
||||
|
||||
#### Command-Line Tools
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/cli)**
|
||||
|
187
docz/docs/03-demos/20-cli/03-nexe.md
Normal file
187
docz/docs/03-demos/20-cli/03-nexe.md
Normal file
@ -0,0 +1,187 @@
|
||||
---
|
||||
title: Spreadsheet Tools with Nexe
|
||||
sidebar_label: nexe
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/data/index
|
||||
sidebar_custom_props:
|
||||
summary: Prebuilt NodeJS packages
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export const r = {style: {color:"red"}};
|
||||
export const B = {style: {fontWeight:"bold"}};
|
||||
|
||||
`nexe`[^1] is a tool for generating command-line tools that embed scripts.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses `nexe` and SheetJS to create a standalone CLI tool for parsing
|
||||
spreadsheets and converting to other formats.
|
||||
|
||||
:::info pass
|
||||
|
||||
The latest prebuilt package matches NodeJS version `14.15.3`.
|
||||
|
||||
`nexe` can build the required packages for newer NodeJS versions.
|
||||
|
||||
:::
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | NodeJS | Source | Date |
|
||||
|:-------------|:-------------|:----------|:----------|:-----------|
|
||||
| `darwin-x64` | `4.0.0-rc.6` | `14.15.3` | Pre-built | 2024-05-28 |
|
||||
| `darwin-arm` | `4.0.0-rc.6` | `18.20.3` | Compiled | 2024-05-25 |
|
||||
| `win10-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-04-18 |
|
||||
| `win11-arm` | `4.0.0-rc.6` | `20.10.0` | Compiled | 2024-05-28 |
|
||||
| `linux-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-03-21 |
|
||||
| `linux-arm` | `4.0.0-rc.6` | `18.20.3` | Compiled | 2024-05-26 |
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
|
||||
required from scripts. `nexe` will automatically handle packaging.
|
||||
|
||||
### Script Requirements
|
||||
|
||||
Scripts that exclusively use SheetJS libraries and NodeJS built-in modules can
|
||||
be bundled using `nexe`.
|
||||
|
||||
The demo script [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js) runs in NodeJS. It
|
||||
is a simple command-line tool for reading and writing spreadsheets.
|
||||
|
||||
## Complete Example
|
||||
|
||||
0) Download the test file https://docs.sheetjs.com/pres.numbers:
|
||||
|
||||
```bash
|
||||
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
1) Download [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js)
|
||||
|
||||
```bash
|
||||
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
|
||||
```
|
||||
|
||||
2) Install the dependencies:
|
||||
|
||||
<Tabs groupId="pm">
|
||||
<TabItem value="npm" label="npm">
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="pnpm" label="pnpm">
|
||||
<CodeBlock language="bash">{`\
|
||||
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="yarn" label="Yarn" default>
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
3) Create the standalone program:
|
||||
|
||||
```bash
|
||||
npx nexe -t 14.15.3 xlsx-cli.js
|
||||
```
|
||||
|
||||
<details open>
|
||||
<summary><b>Building from source (click to hide)</b></summary>
|
||||
|
||||
When the demo was tested on ARM targets, the Nexe pre-built packages were
|
||||
missing. For unsupported NodeJS versions, packages must be built from source:
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="unix" label="Linux/MacOS">
|
||||
|
||||
```bash
|
||||
npx nexe xlsx-cli.js --build --python=$(which python3) --make="-j8"
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
On Windows x64, the `--build` flag suffices:
|
||||
|
||||
```bash
|
||||
npx nexe xlsx-cli.js --build --make="-j8"
|
||||
```
|
||||
|
||||
On Windows ARM, the target `windows-arm64-20.10.0` must be specified:
|
||||
|
||||
```bash
|
||||
npx nexe xlsx-cli.js --build --make="-j8" --target=windows-arm64-20.10.0
|
||||
```
|
||||
|
||||
**`vcbuild.bat` issues**
|
||||
|
||||
The Windows ARM build may fail with a `vcbuild.bat` error:
|
||||
|
||||
```
|
||||
Error: vcbuild.bat nosign release arm64 exited with code: 1
|
||||
```
|
||||
|
||||
Pass the `-v` flag for more details. In the most recent test, the error stemmed
|
||||
from a Python version mismatch:
|
||||
|
||||
```
|
||||
Node.js configure: found Python 2.7.18
|
||||
Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or python3.6
|
||||
```
|
||||
|
||||
The resolved version of Python can be found with
|
||||
|
||||
```cmd
|
||||
where python
|
||||
```
|
||||
|
||||
In the most recent test, a Python 2 version appeared first. This was fixed by
|
||||
finding the Python 3 location and prepending it to `PATH`:
|
||||
|
||||
```cmd
|
||||
set PATH="C:\correct\path\to\python\three";%PATH%
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
</details>
|
||||
|
||||
This generates `xlsx-cli` or `xlsx-cli.exe` depending on platform.
|
||||
|
||||
5) Run the generated program, passing `pres.numbers` as the argument:
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="unix" label="Linux/MacOS">
|
||||
|
||||
```bash
|
||||
./xlsx-cli pres.numbers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
```powershell
|
||||
.\xlsx-cli.exe pres.numbers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
[^1]: The project does not have a website. The [source repository](https://github.com/nexe/nexe) is publicly available.
|
||||
[^2]: The NodeJS website hosts [prebuilt installers](https://nodejs.org/en/download/prebuilt-installer).
|
169
docz/docs/03-demos/20-cli/05-pkg.md
Normal file
169
docz/docs/03-demos/20-cli/05-pkg.md
Normal file
@ -0,0 +1,169 @@
|
||||
---
|
||||
title: Packing Sheets with pkg
|
||||
sidebar_label: pkg
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/data/index
|
||||
sidebar_custom_props:
|
||||
summary: Prebuilt NodeJS packages
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export const r = {style: {color:"red"}};
|
||||
export const B = {style: {fontWeight:"bold"}};
|
||||
|
||||
`pkg`[^1] is a tool for generating command-line tools that embed scripts.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses `pkg` and SheetJS to create a standalone CLI tool for parsing
|
||||
spreadsheets and converting to other formats.
|
||||
|
||||
:::caution pass
|
||||
|
||||
With the official release of [NodeJS SEA](/docs/demos/cli/nodesea), Vercel opted
|
||||
to deprecate `pkg`. It is still useful for deploying apps embedding NodeJS v18
|
||||
or earlier since those versions do not support NodeJS SEA.
|
||||
|
||||
:::
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | NodeJS | Date |
|
||||
|:-------------|:--------|:---------|:-----------|
|
||||
| `darwin-x64` | `5.8.1` | `18.5.0` | 2024-05-28 |
|
||||
| `darwin-arm` | `5.8.1` | `18.5.0` | 2024-05-25 |
|
||||
| `win10-x64` | `5.8.1` | `18.5.0` | 2024-04-18 |
|
||||
| `win11-arm` | `5.8.1` | `18.5.0` | 2024-05-28 |
|
||||
| `linux-x64` | `5.8.1` | `18.5.0` | 2024-03-21 |
|
||||
| `linux-arm` | `5.8.1` | `18.5.0` | 2024-05-26 |
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
|
||||
required from scripts. `pkg` will automatically handle packaging.
|
||||
|
||||
### Script Requirements
|
||||
|
||||
Scripts that exclusively use SheetJS libraries and NodeJS built-in modules can
|
||||
be bundled using `pkg`.
|
||||
|
||||
The demo script [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js) runs in NodeJS. It
|
||||
is a simple command-line tool for reading and writing spreadsheets.
|
||||
|
||||
### Limitations
|
||||
|
||||
:::danger pass
|
||||
|
||||
When this demo was last tested, `pkg` failed with an error referencing `node20`:
|
||||
|
||||
```
|
||||
> Targets not specified. Assuming:
|
||||
node20-linux-arm64, node20-macos-arm64, node20-win-arm64
|
||||
> Error! No available node version satisfies 'node20'
|
||||
```
|
||||
|
||||
**`pkg` does not support NodeJS 20 or 22!**
|
||||
|
||||
The local NodeJS version must be rolled back to version 18.
|
||||
|
||||
If `nvm` or `nvm-windows` was used to install NodeJS:
|
||||
|
||||
```bash
|
||||
nvm install 18
|
||||
nvm use 18
|
||||
```
|
||||
|
||||
Otherwise, on macOS and Linux, `n` can manage the global installation:
|
||||
|
||||
```bash
|
||||
sudo npm i -g n
|
||||
sudo n 18
|
||||
```
|
||||
|
||||
On Windows, it is recommended to use a prebuilt installer[^2]
|
||||
|
||||
:::
|
||||
|
||||
|
||||
## Complete Example
|
||||
|
||||
0) Downgrade NodeJS to major version 18 or earlier.
|
||||
|
||||
1) Download the test file https://docs.sheetjs.com/pres.numbers:
|
||||
|
||||
```bash
|
||||
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
2) Download [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js)
|
||||
|
||||
```bash
|
||||
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
|
||||
```
|
||||
|
||||
3) Install the dependencies:
|
||||
|
||||
<Tabs groupId="pm">
|
||||
<TabItem value="npm" label="npm">
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="pnpm" label="pnpm">
|
||||
<CodeBlock language="bash">{`\
|
||||
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="yarn" label="Yarn" default>
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
4) Create the standalone program:
|
||||
|
||||
```bash
|
||||
npx pkg xlsx-cli.js
|
||||
```
|
||||
|
||||
This generates `xlsx-cli-linux`, `xlsx-cli-macos`, and `xlsx-cli-win.exe` .
|
||||
|
||||
5) Run the generated program, passing `pres.numbers` as the argument:
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="linux" label="Linux">
|
||||
|
||||
```bash
|
||||
./xlsx-cli-linux pres.numbers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="macos" label="macOS">
|
||||
|
||||
```bash
|
||||
./xlsx-cli-macos pres.numbers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
```powershell
|
||||
.\xlsx-cli-win.exe pres.numbers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
[^1]: The project does not have a website. The [source repository](https://github.com/vercel/pkg) is publicly available.
|
||||
[^2]: The NodeJS website hosts [prebuilt installers](https://nodejs.org/en/download/prebuilt-installer).
|
214
docz/docs/03-demos/20-cli/08-boxednode.md
Normal file
214
docz/docs/03-demos/20-cli/08-boxednode.md
Normal file
@ -0,0 +1,214 @@
|
||||
---
|
||||
title: Sheets in a Box with boxednode
|
||||
sidebar_label: boxednode
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/data/index
|
||||
sidebar_custom_props:
|
||||
summary: NodeJS binaries with scripts, built from source
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
export const r = {style: {color:"red"}};
|
||||
export const B = {style: {fontWeight:"bold"}};
|
||||
|
||||
`boxednode`[^1] is a tool for generating command-line tools that embed scripts.
|
||||
It automates the process of building NodeJS from source.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses `boxednode` and SheetJS to create a standalone CLI tool for
|
||||
parsing spreadsheets and converting to other formats.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | NodeJS | Date |
|
||||
|:-------------|:--------|:----------|:-----------|
|
||||
| `darwin-x64` | `2.4.0` | `22.2.0` | 2024-05-28 |
|
||||
| `darwin-arm` | `2.4.3` | `22.2.0` | 2024-05-25 |
|
||||
| `win10-x64` | `2.4.2` | `16.20.2` | 2024-04-18 |
|
||||
| `linux-x64` | `2.4.0` | `21.7.1` | 2024-03-21 |
|
||||
| `linux-arm` | `2.4.3` | `20.13.1` | 2024-05-26 |
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
|
||||
required from scripts. `boxednode` will automatically handle packaging.
|
||||
|
||||
### Script Requirements
|
||||
|
||||
Scripts that exclusively use SheetJS libraries and NodeJS built-in modules can
|
||||
be bundled using `boxednode`
|
||||
|
||||
The demo script [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js) runs in NodeJS. It
|
||||
is a simple command-line tool for reading and writing spreadsheets.
|
||||
|
||||
## Complete Example
|
||||
|
||||
0) Download the test file https://docs.sheetjs.com/pres.numbers:
|
||||
|
||||
```bash
|
||||
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
1) Download [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js)
|
||||
|
||||
```bash
|
||||
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
|
||||
```
|
||||
|
||||
2) Install the dependencies:
|
||||
|
||||
<Tabs groupId="pm">
|
||||
<TabItem value="npm" label="npm">
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="pnpm" label="pnpm">
|
||||
<CodeBlock language="bash">{`\
|
||||
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="yarn" label="Yarn" default>
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
3) Create the standalone program:
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="unix" label="Linux/MacOS">
|
||||
|
||||
```bash
|
||||
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli
|
||||
```
|
||||
|
||||
:::caution pass
|
||||
|
||||
When this demo was last tested in `linux-arm`, the build failed with an error:
|
||||
|
||||
<pre>
|
||||
../deps/v8/src/base/small-vector.h: In instantiation of <span {...B}>‘class v8::base::SmallVector<std::pair<const v8::internal::compiler::turboshaft::PhiOp*, const v8::internal::compiler::turboshaft::OpIndex>, 16>’</span>:
|
||||
<span {...B}>../deps/v8/src/compiler/turboshaft/loop-unrolling-reducer.h:444:11:</span> required from here
|
||||
<span {...B}>../deps/v8/src/base/macros.h:206:55:</span> <span style={{...r.style,...B.style}}>error:</span> static assertion failed: T should be trivially copyable
|
||||
{" 206 |"} static_assert(::v8::base::is_trivially_copyable<T>::<span style={{...r.style,...B.style}}>value</span>, \\
|
||||
{" |"} ^~~~~
|
||||
</pre>
|
||||
|
||||
This affects NodeJS `22.2.0`, but does not affect `20.13.1`. It affects the
|
||||
[V8 JavaScript Engine](/docs/demos/engines/v8#build-v8).
|
||||
|
||||
The `-n` flag controls the target NodeJS version. For this demo, the following
|
||||
command uses NodeJS `20.13.1`:
|
||||
|
||||
```bash
|
||||
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli -n 20.13.1
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
```bash
|
||||
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli.exe -n 16.20.2
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
The Windows 10 build requires Visual Studio with "Desktop development with C++"
|
||||
workload, Python 3.11, and NASM[^2].
|
||||
|
||||
**The build command must be run in "x64 Native Tools Command Prompt"**
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
When the demo was last tested, the build failed:
|
||||
|
||||
```
|
||||
Not an executable Python program
|
||||
Could not find Python.
|
||||
```
|
||||
|
||||
By default, Windows aliases `python` to a Microsoft Store installer. If the
|
||||
official installer was used, the alias should be disabled manually:
|
||||
|
||||
1) Open Start menu and type "app alias". Click "Manage app execution aliases".
|
||||
|
||||
2) Disable the App Installer for all items with `python` in the name.
|
||||
|
||||
Using Python 3.12, the build fails with an error:
|
||||
|
||||
```
|
||||
Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or python3.6.
|
||||
```
|
||||
|
||||
In the most recent test, Python 3.11.8 was installed from the official site.
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
When the demo was last tested on Windows, the build failed:
|
||||
|
||||
```
|
||||
error MSB8020: The build tools for Visual Studio 2019 (Platform Toolset = 'v142') cannot be found. To build using the v142 build tools, please install Visual Studio 2019 build tools.
|
||||
```
|
||||
|
||||
This error was fixed by installing the `v142` build tools through the Visual
|
||||
Studio installer.
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
In the most recent Windows test against NodeJS `20.8.0`, the build failed due
|
||||
to an issue in the OpenSSL dependency:
|
||||
|
||||
```
|
||||
...\node-v20.8.0\deps\openssl\openssl\crypto\cversion.c(75,33): error C2153: integer literals must have at least one digit [...\node-v20.8.0\deps\openssl\openssl.vcxproj]
|
||||
```
|
||||
|
||||
SheetJS libraries are compatible with NodeJS versions dating back to `v0.8`. The
|
||||
workaround is to select NodeJS `v16.20.2` using the `-n` flag. This version was
|
||||
was chosen since NodeJS `v18` upgraded the OpenSSL dependency.
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
4) Run the generated program, passing `pres.numbers` as the argument:
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="unix" label="Linux/MacOS">
|
||||
|
||||
```bash
|
||||
./xlsx-cli pres.numbers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
```powershell
|
||||
.\xlsx-cli.exe pres.numbers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
[^1]: The project does not have a website. The [source repository](https://github.com/mongodb-js/boxednode) is publicly available.
|
||||
[^2]: Downloads can be found [at the main NASM project website](https://www.nasm.us/)
|
@ -158,9 +158,20 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | NodeJS | Date |
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `20.11.1` | 2024-03-17 |
|
||||
| `darwin-x64` | `22.2.0` | 2024-05-28 |
|
||||
| `darwin-arm` | `22.2.0` | 2024-05-29 |
|
||||
| `win10-x64` | `20.12.0` | 2024-03-26 |
|
||||
| `win11-x64` | `20.13.1` | 2024-05-22 |
|
||||
| `win11-arm` | `20.14.0` | 2024-06-11 |
|
||||
| `linux-x64` | `20.11.1` | 2024-03-18 |
|
||||
| `linux-arm` | `20.14.0` | 2024-06-10 |
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
NodeJS on Windows on ARM uses the X64 compatibility layer. It does not generate
|
||||
a native ARM64 binary!
|
||||
|
||||
:::
|
||||
|
||||
@ -222,10 +233,10 @@ local NodeJS platform.
|
||||
|
||||
:::
|
||||
|
||||
4) Download the test file <https://sheetjs.com/pres.numbers>:
|
||||
4) Download the test file https://docs.sheetjs.com/pres.numbers:
|
||||
|
||||
```bash
|
||||
curl -o pres.numbers https://sheetjs.com/pres.numbers
|
||||
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
5) Run the script and pass `pres.numbers` as the first argument:
|
||||
@ -236,7 +247,7 @@ node sheet2csv.js pres.numbers
|
||||
|
||||
The script should display CSV contents from the first sheet:
|
||||
|
||||
```
|
||||
```text title="Expected Output"
|
||||
Name,Index
|
||||
Bill Clinton,42
|
||||
GeorgeW Bush,43
|
||||
@ -290,7 +301,7 @@ Application node.exe 20.12.0.0 C:
|
||||
Copy the program (listed in the "Source" column) to `sheet2csv.exe`:
|
||||
|
||||
```powershell
|
||||
PS C:\sheetjs-sea> copy "C:\Program Files\nodejs\node.exe" sheet2csv.exe
|
||||
copy "C:\Program Files\nodejs\node.exe" sheet2csv.exe
|
||||
```
|
||||
|
||||
9) Remove the code signature.
|
||||
@ -299,6 +310,12 @@ PS C:\sheetjs-sea> copy "C:\Program Files\nodejs\node.exe" sheet2csv.exe
|
||||
signtool remove /s .\sheet2csv.exe
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
`signtool` is included in the Windows SDK[^4].
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="linux-x64" label="Linux">
|
||||
|
||||
@ -416,3 +433,4 @@ This error is expected.
|
||||
[^1]: See ["Single Executable Applications"](https://nodejs.org/api/single-executable-applications.html) in the NodeJS documentation.
|
||||
[^2]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
|
||||
[^3]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
|
||||
[^4]: See [Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/) in the Windows Dev Center documentation.
|
153
docz/docs/03-demos/20-cli/12-bunsea.md
Normal file
153
docz/docs/03-demos/20-cli/12-bunsea.md
Normal file
@ -0,0 +1,153 @@
|
||||
---
|
||||
title: BunJS SEA
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/data/index
|
||||
sidebar_custom_props:
|
||||
summary: BunJS Single-file Executables
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[BunJS](https://bun.sh/docs/bundler/executables) is a JavaScript runtime with
|
||||
support for compiling scripts into self-contained executables.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses the Bun compiler and SheetJS to create a standalone CLI tool for
|
||||
parsing spreadsheets and generating CSV rows.
|
||||
|
||||
:::info pass
|
||||
|
||||
It is strongly recommended to install BunJS on systems using SheetJS libraries
|
||||
in command-line tools. This workaround should only be considered if a standalone
|
||||
binary is considered desirable.
|
||||
|
||||
:::
|
||||
|
||||
:::caution BunJS support is considered experimental.
|
||||
|
||||
Great open source software grows with user tests and reports. Any issues should
|
||||
be reported to the BunJS project for further diagnosis.
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS BunJS module](/docs/getting-started/installation/bun) can be
|
||||
imported from BunJS scripts.
|
||||
|
||||
`bun build --compile` generates a standalone executable that includes the BunJS
|
||||
runtime, user JS code and supporting scripts and assets
|
||||
|
||||
### Script Requirements
|
||||
|
||||
Scripts that exclusively use SheetJS libraries and BunJS built-in modules can be
|
||||
bundled using BunJS. The module should be required directly:
|
||||
|
||||
<CodeBlock language="ts">{`\
|
||||
const XLSX = require("xlsx");`}
|
||||
</CodeBlock>
|
||||
|
||||
For example, the following script accepts one command line argument, parses the
|
||||
specified file using the SheetJS `readFile` method[^1], generates CSV text from
|
||||
the first worksheet using `sheet_to_csv`[^2], and prints to terminal:
|
||||
|
||||
<CodeBlock language="ts" title="sheet2csv.ts">{`\
|
||||
const XLSX = require("xlsx");
|
||||
\n\
|
||||
/* process.argv[2] is the first argument to the script */
|
||||
const filename = process.argv[2];
|
||||
\n\
|
||||
/* read file */
|
||||
const wb = XLSX.readFile(filename);
|
||||
\n\
|
||||
/* generate CSV of first sheet */
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
const csv = XLSX.utils.sheet_to_csv(ws);
|
||||
\n\
|
||||
/* print to terminal */
|
||||
console.log(csv);`}
|
||||
</CodeBlock>
|
||||
|
||||
## Complete Example
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested in the following deployments:
|
||||
|
||||
| Architecture | BunJS | Date |
|
||||
|:-------------|:---------|:-----------|
|
||||
| `darwin-x64` | `1.1.10` | 2024-05-28 |
|
||||
| `darwin-arm` | `1.1.10` | 2024-05-29 |
|
||||
| `win10-x64` | `1.1.12` | 2024-06-10 |
|
||||
| `linux-x64` | `1.1.12` | 2024-06-09 |
|
||||
| `linux-arm` | `1.1.12` | 2024-06-10 |
|
||||
|
||||
:::
|
||||
|
||||
0) Install or update BunJS.[^3]
|
||||
|
||||
1) Download the test file https://docs.sheetjs.com/pres.numbers:
|
||||
|
||||
```bash
|
||||
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
2) Save the [contents of the `sheet2csv.ts` code block](#script-requirements)
|
||||
to `sheet2csv.ts` in the project folder.
|
||||
|
||||
3) Install the SheetJS dependency:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::caution pass
|
||||
|
||||
On Windows, the command failed with a `ENOTEMPTY` error:
|
||||
|
||||
```
|
||||
error: InstallFailed extracting tarball for https://cdn.sheetjs.com/xlsx-0.20.1/xlsx-0.20.1.tgz
|
||||
error: moving "https://cdn.sheetjs.com/xlsx-0.20.1/xlsx-0.20.1.tgz" to cache dir failed
|
||||
ENOTEMPTY: Directory not empty (NtSetInformationFile())
|
||||
```
|
||||
|
||||
The workaround is to prepend `xlsx@` to the URL:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
bun install xlsx@https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
4) Test the script with `bun run`:
|
||||
|
||||
```bash
|
||||
bun run sheet2csv.ts pres.numbers
|
||||
```
|
||||
|
||||
The script should display CSV contents from the first sheet:
|
||||
|
||||
```text title="Expected Output"
|
||||
Name,Index
|
||||
Bill Clinton,42
|
||||
GeorgeW Bush,43
|
||||
Barack Obama,44
|
||||
Donald Trump,45
|
||||
Joseph Biden,46
|
||||
```
|
||||
|
||||
5) Compile and run `sheet2csv`:
|
||||
|
||||
```bash
|
||||
bun build ./sheet2csv.ts --compile --outfile sheet2csv
|
||||
./sheet2csv pres.numbers
|
||||
```
|
||||
|
||||
The program should display the same CSV contents as the script (from step 2)
|
||||
|
||||
[^1]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
|
||||
[^2]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
|
||||
[^3]: See ["Installation"](https://bun.sh/docs/installation) in the BunJS documentation for instructions.
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Deno Compiler
|
||||
title: Deno SEA
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/data/index
|
||||
sidebar_custom_props:
|
||||
@ -69,7 +69,7 @@ const wb = XLSX.readFile(filename);
|
||||
\n\
|
||||
/* generate CSV of first sheet */
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
const csv = utils.sheet_to_csv(ws);
|
||||
const csv = XLSX.utils.sheet_to_csv(ws);
|
||||
\n\
|
||||
/* print to terminal */
|
||||
console.log(csv);`}
|
||||
@ -99,22 +99,22 @@ This demo was last tested in the following deployments:
|
||||
|
||||
| Architecture | Deno | Date |
|
||||
|:-------------|:---------|:-----------|
|
||||
| `darwin-x64` | `1.41.3` | 2024-03-15 |
|
||||
| `darwin-arm` | `1.37.2` | 2023-10-18 |
|
||||
| `darwin-x64` | `1.43.6` | 2024-05-28 |
|
||||
| `darwin-arm` | `1.43.6` | 2024-05-23 |
|
||||
| `win10-x64` | `1.41.3` | 2024-03-24 |
|
||||
| `win11-x64` | `1.37.2` | 2023-10-14 |
|
||||
| `win11-arm` | `1.38.4` | 2023-12-01 |
|
||||
| `win11-x64` | `1.43.6` | 2024-05-25 |
|
||||
| `win11-arm` | `1.43.6` | 2024-05-25 |
|
||||
| `linux-x64` | `1.41.3` | 2024-03-18 |
|
||||
| `linux-arm` | `1.38.4` | 2023-12-01 |
|
||||
| `linux-arm` | `1.43.6` | 2024-05-25 |
|
||||
|
||||
:::
|
||||
|
||||
0) Install Deno.[^6]
|
||||
|
||||
1) Download the test file <https://sheetjs.com/pres.numbers>:
|
||||
1) Download the test file https://docs.sheetjs.com/pres.numbers:
|
||||
|
||||
```bash
|
||||
curl -o pres.numbers https://sheetjs.com/pres.numbers
|
||||
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
2) Test the script with `deno run`:
|
||||
@ -125,7 +125,7 @@ deno run -r --allow-read https://docs.sheetjs.com/cli/sheet2csv.ts pres.numbers
|
||||
|
||||
The script should display CSV contents from the first sheet:
|
||||
|
||||
```
|
||||
```text title="Expected Output"
|
||||
Name,Index
|
||||
Bill Clinton,42
|
||||
GeorgeW Bush,43
|
@ -1,5 +1,7 @@
|
||||
---
|
||||
title: Command-Line Tools
|
||||
title: Sheets on the Command Line
|
||||
sidebar_label: Command-Line Tools
|
||||
hide_table_of_contents: true
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/data/index
|
||||
---
|
||||
@ -9,6 +11,10 @@ import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
||||
import FrameworkData from '/data/cli.js'
|
||||
|
||||
export const r = {style: {color:"red"}};
|
||||
export const B = {style: {fontWeight:"bold"}};
|
||||
|
||||
With the availability of JS engines and the success of server-side platforms,
|
||||
it is possible to build standalone command-line tools from JavaScript code.
|
||||
@ -21,9 +27,8 @@ processors. The ultimate goal is to use SheetJS libraries to generate CSV output
|
||||
from arbitrary spreadsheet files. The generated command-line tool will accept an
|
||||
argument, parse the specified workbook, and print CSV rows to the terminal.
|
||||
|
||||
>**Sample terminal session**
|
||||
```bash
|
||||
$ xlsx-cli.exe pres.numbers
|
||||
```bash title="Sample terminal session"
|
||||
> xlsx-cli.exe pres.numbers
|
||||
Name,Index
|
||||
Bill Clinton,42
|
||||
GeorgeW Bush,43
|
||||
@ -43,10 +48,16 @@ Demos for common standalone CLI tools are included in separate pages:
|
||||
</li>);
|
||||
})}</ul>
|
||||
|
||||
#### Platform Support
|
||||
|
||||
The following frameworks have been tested on the following platforms:
|
||||
|
||||
<FrameworkData/>
|
||||
|
||||
:::tip pass
|
||||
|
||||
The [`xlsx-cli`](https://cdn.sheetjs.com/xlsx-cli/) NodeJS script is available
|
||||
as a package on the SheetJS CDN. It is an easy-to-use command-line tool for
|
||||
as a package on the SheetJS CDN. It is a straightforward command-line tool for
|
||||
translating files between supported spreadsheet file formats.
|
||||
|
||||
:::
|
||||
@ -63,419 +74,33 @@ server-side scripting platform cannot be installed on the target computer.
|
||||
|
||||
:::
|
||||
|
||||
## NodeJS
|
||||
#### NodeJS
|
||||
|
||||
There are a few popular tools for compiling NodeJS scripts to CLI programs.
|
||||
This demo has been organized by framework:
|
||||
|
||||
The demo script presents a friendly command line interface including flags:
|
||||
- [`boxednode`](/docs/demos/cli/boxednode)
|
||||
- [`nexe`](/docs/demos/cli/nexe)
|
||||
- [`pkg`](/docs/demos/cli/pkg)
|
||||
|
||||
```bash
|
||||
$ ./xlsx-cli -h
|
||||
Usage: xlsx-cli [options] <file> [sheetname]
|
||||
#### V8
|
||||
|
||||
Options:
|
||||
-V, --version output the version number
|
||||
-f, --file <file> use specified workbook
|
||||
-s, --sheet <sheet> print specified sheet (default first sheet)
|
||||
...
|
||||
```
|
||||
**[The exposition has been moved to the "V8" demo.](/docs/demos/engines/v8#snapshots)**
|
||||
|
||||
:::note Tested Deployments
|
||||
#### BunJS
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
<Tabs groupId="njs">
|
||||
<TabItem value="nexe" label="Nexe">
|
||||
|
||||
| Architecture | Version | NodeJS | Source | Date |
|
||||
|:-------------|:-------------|:----------|:----------|:-----------|
|
||||
| `darwin-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-03-15 |
|
||||
| `darwin-arm` | `4.0.0-rc.2` | `18.18.0` | Compiled | 2023-12-01 |
|
||||
| `win10-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-03-04 |
|
||||
| `win11-arm` | `4.0.0-rc.2` | `20.10.0` | Compiled | 2023-12-01 |
|
||||
| `linux-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-03-21 |
|
||||
| `linux-arm` | `4.0.0-rc.2` | `20.10.0` | Compiled | 2023-12-01 |
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="pkg" label="pkg">
|
||||
|
||||
| Architecture | Version | NodeJS | Date |
|
||||
|:-------------|:--------|:---------|:-----------|
|
||||
| `darwin-x64` | `5.8.1` | `18.5.0` | 2024-03-15 |
|
||||
| `darwin-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
|
||||
| `win10-x64` | `5.8.1` | `18.5.0` | 2024-03-24 |
|
||||
| `win11-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
|
||||
| `linux-x64` | `5.8.1` | `18.5.0` | 2024-03-21 |
|
||||
| `linux-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="boxednode" label="boxednode">
|
||||
|
||||
| Architecture | Version | NodeJS | Date |
|
||||
|:-------------|:--------|:----------|:-----------|
|
||||
| `darwin-x64` | `2.4.0` | `21.7.1` | 2024-03-15 |
|
||||
| `darwin-arm` | `2.3.0` | `21.3.0` | 2023-12-01 |
|
||||
| `win10-x64` | `2.4.0` | `16.20.2` | 2024-03-24 |
|
||||
| `linux-x64` | `2.4.0` | `21.7.1` | 2024-03-21 |
|
||||
| `linux-arm` | `2.3.0` | `21.3.0` | 2023-12-01 |
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::
|
||||
|
||||
0) Download the test file <https://sheetjs.com/pres.numbers>:
|
||||
|
||||
```bash
|
||||
curl -o pres.numbers https://sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
1) Download [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js)
|
||||
|
||||
```bash
|
||||
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
|
||||
```
|
||||
|
||||
2) Install the dependencies:
|
||||
|
||||
<Tabs groupId="pm">
|
||||
<TabItem value="npm" label="npm">
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="pnpm" label="pnpm">
|
||||
<CodeBlock language="bash">{`\
|
||||
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="yarn" label="Yarn" default>
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
3) Follow tooling steps:
|
||||
|
||||
<Tabs groupId="njs">
|
||||
<TabItem value="nexe" label="Nexe">
|
||||
|
||||
Run `nexe` and manually specify NodeJS version 14.15.3
|
||||
|
||||
```bash
|
||||
npx nexe -t 14.15.3 xlsx-cli.js
|
||||
```
|
||||
|
||||
This generates `xlsx-cli` or `xlsx-cli.exe` depending on platform.
|
||||
|
||||
:::caution pass
|
||||
|
||||
When the demo was tested on ARM targets, the Nexe pre-built packages were
|
||||
missing. The package must be built from source:
|
||||
|
||||
```bash
|
||||
npx nexe xlsx-cli.js --build --python=$(which python3) --make="-j8"
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
On Windows ARM, the target `windows-arm64-20.10.0` must be specified:
|
||||
|
||||
```bash
|
||||
npx nexe xlsx-cli.js --build --make="-j8" --target=windows-arm64-20.10.0
|
||||
```
|
||||
|
||||
The Windows build may fail with a `vcbuild.bat` error:
|
||||
|
||||
```
|
||||
Error: vcbuild.bat nosign release arm64 exited with code: 1
|
||||
```
|
||||
|
||||
Pass the `-v` flag for more details. In the most recent test, the error stemmed
|
||||
from a Python version mismatch:
|
||||
|
||||
```
|
||||
Node.js configure: found Python 2.7.18
|
||||
Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or python3.6
|
||||
```
|
||||
|
||||
The resolved version of Python can be found with
|
||||
|
||||
```cmd
|
||||
where python
|
||||
```
|
||||
|
||||
In the most recent test, a Python 2 version appeared first. This was fixed by
|
||||
finding the Python 3 location and prepending it to `PATH`:
|
||||
|
||||
```cmd
|
||||
set PATH="C:\correct\path\to\python\three";%PATH%
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="pkg" label="pkg">
|
||||
|
||||
:::warning pass
|
||||
|
||||
When this demo was last tested, `pkg` failed with an error referencing `node20`:
|
||||
|
||||
```
|
||||
> Targets not specified. Assuming:
|
||||
node20-linux-arm64, node20-macos-arm64, node20-win-arm64
|
||||
> Error! No available node version satisfies 'node20'
|
||||
```
|
||||
|
||||
**`pkg` does not support NodeJS 20!**
|
||||
|
||||
The local NodeJS version must be rolled back to version 18.
|
||||
|
||||
If `n` is installed:
|
||||
|
||||
```bash
|
||||
sudo n 18
|
||||
```
|
||||
|
||||
If `nvm` was used to install NodeJS:
|
||||
|
||||
```bash
|
||||
nvm install 18
|
||||
nvm use 18
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
Run `pkg`:
|
||||
|
||||
```bash
|
||||
npx pkg xlsx-cli.js
|
||||
```
|
||||
|
||||
This generates `xlsx-cli-linux`, `xlsx-cli-macos`, and `xlsx-cli-win.exe` .
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="boxednode" label="boxednode">
|
||||
|
||||
Run `boxednode`:
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="unix" label="Linux/MacOS">
|
||||
|
||||
```bash
|
||||
npx boxednode@2.4.0 -s xlsx-cli.js -t xlsx-cli
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
```bash
|
||||
npx boxednode@2.4.0 -s xlsx-cli.js -t xlsx-cli.exe -n 16.20.2
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
The Windows 10 build requires Visual Studio with "Desktop development with C++"
|
||||
workload, Python 3.11, and NASM[^1].
|
||||
|
||||
**The build command must be run in "x64 Native Tools Command Prompt"**
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
When the demo was last tested, the build failed:
|
||||
|
||||
```
|
||||
Not an executable Python program
|
||||
Could not find Python.
|
||||
```
|
||||
|
||||
By default, Windows aliases `python` to a Microsoft Store installer. If the
|
||||
official installer was used, the alias should be disabled manually:
|
||||
|
||||
1) Open Start menu and type "app alias". Click "Manage app execution aliases".
|
||||
|
||||
2) Disable the App Installer for all items with `python` in the name.
|
||||
|
||||
Using Python 3.12, the build fails with an error:
|
||||
|
||||
```
|
||||
Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or python3.6.
|
||||
```
|
||||
|
||||
In the most recent test, Python 3.11.8 was installed from the official site.
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
When the demo was last tested on Windows, the build failed:
|
||||
|
||||
```
|
||||
error MSB8020: The build tools for Visual Studio 2019 (Platform Toolset = 'v142') cannot be found. To build using the v142 build tools, please install Visual Studio 2019 build tools.
|
||||
```
|
||||
|
||||
This error was fixed by installing the `v142` build tools through the Visual
|
||||
Studio installer.
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
In the most recent Windows test against NodeJS `20.8.0`, the build failed due
|
||||
to an issue in the OpenSSL dependency:
|
||||
|
||||
```
|
||||
...\node-v20.8.0\deps\openssl\openssl\crypto\cversion.c(75,33): error C2153: integer literals must have at least one digit [...\node-v20.8.0\deps\openssl\openssl.vcxproj]
|
||||
```
|
||||
|
||||
SheetJS libraries are compatible with NodeJS versions dating back to `v0.8`. The
|
||||
workaround is to select NodeJS `v16.20.2` using the `-n` flag. This version was
|
||||
was chosen since NodeJS `v18` upgraded the OpenSSL dependency.
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
4) Run the generated program, passing `pres.numbers` as the argument. For
|
||||
example, `nexe` generates `xlsx-cli` in macOS so the command is:
|
||||
|
||||
```bash
|
||||
./xlsx-cli pres.numbers
|
||||
```
|
||||
|
||||
`nexe` generates `xlsx-cli.exe` in Windows, so the command is:
|
||||
|
||||
```powershell
|
||||
.\xlsx-cli.exe 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.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested in the following deployments:
|
||||
|
||||
| Architecture | V8 Version | Crate | Date |
|
||||
|:-------------|:--------------|:---------|:-----------|
|
||||
| `darwin-x64` | `12.3.219.9` | `0.88.0` | 2024-03-15 |
|
||||
| `darwin-arm` | `11.8.172.13` | `0.79.2` | 2023-10-18 |
|
||||
| `win10-x64` | `12.3.219.9` | `0.88.0` | 2024-03-24 |
|
||||
| `win11-x64` | `11.8.172.13` | `0.79.2` | 2023-10-14 |
|
||||
| `linux-x64` | `12.3.219.9` | `0.88.0` | 2024-03-18 |
|
||||
| `linux-arm` | `12.0.267.8` | `0.82.0` | 2023-12-01 |
|
||||
|
||||
:::
|
||||
|
||||
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 -o Cargo.toml https://docs.sheetjs.com/cli/Cargo.toml
|
||||
curl -o snapshot.rs https://docs.sheetjs.com/cli/snapshot.rs
|
||||
curl -o sheet2csv.rs https://docs.sheetjs.com/cli/sheet2csv.rs
|
||||
```
|
||||
|
||||
2) Download the SheetJS Standalone script and move to the project directory:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
</ul>
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl -o xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Build the V8 snapshot:
|
||||
|
||||
```bash
|
||||
cargo build --bin snapshot
|
||||
cargo run --bin snapshot
|
||||
```
|
||||
|
||||
:::caution pass
|
||||
|
||||
With some versions of the `v8` crate, the Linux AArch64 build failed with an error:
|
||||
|
||||
```
|
||||
error[E0080]: evaluation of constant value failed
|
||||
|
||||
|
|
||||
1715 | assert!(size_of::<TypeId>() == size_of::<u64>());
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: size_of::<TypeId>() == size_of::<u64>()'
|
||||
```
|
||||
|
||||
Versions `0.75.1` and `0.82.0` are known to work.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
4) Build `sheet2csv` (`sheet2csv.exe` in Windows):
|
||||
|
||||
```bash
|
||||
cargo build --release --bin sheet2csv
|
||||
```
|
||||
|
||||
5) Download the test file <https://sheetjs.com/pres.numbers>:
|
||||
|
||||
```bash
|
||||
curl -o pres.numbers https://sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
6) Test the application:
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="unix" label="Linux/MacOS">
|
||||
|
||||
```bash
|
||||
mv target/release/sheet2csv .
|
||||
./sheet2csv pres.numbers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
```bash
|
||||
mv target/release/sheet2csv.exe .
|
||||
.\sheet2csv.exe pres.numbers
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/cli/bunsea)**
|
||||
|
||||
#### Deno
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/cli/deno)**
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/cli/denosea)**
|
||||
|
||||
## Dedicated Engines
|
||||
#### Dedicated Engines
|
||||
|
||||
The following demos for JS engines produce standalone programs:
|
||||
|
||||
- [V8](/docs/demos/engines/v8)
|
||||
- [Duktape](/docs/demos/engines/duktape)
|
||||
- [ChakraCore](/docs/demos/engines/chakra)
|
||||
- [QuickJS](/docs/demos/engines/quickjs)
|
||||
- [Goja](/docs/demos/engines/goja)
|
||||
- [JavaScriptCore](/docs/demos/engines/jsc)
|
||||
|
||||
[^1]: Downloads can be found [at the main NASM project website](https://www.nasm.us/)
|
@ -9,12 +9,18 @@ sidebar_custom_props:
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
Structured Query Language ("SQL") is a popular declarative language for issuing
|
||||
commands to database servers.
|
||||
|
||||
## Raw SQL Operations
|
||||
|
||||
### Generating Tables
|
||||
|
||||
This example will fetch <https://sheetjs.com/data/cd.xls>, scan the columns of the
|
||||
This example will fetch https://docs.sheetjs.com/cd.xls, scan the columns of the
|
||||
first worksheet to determine data types, and generate 6 PostgreSQL statements.
|
||||
|
||||
<details><summary><b>Explanation</b> (click to show)</summary>
|
||||
<details>
|
||||
<summary><b>Explanation</b> (click to show)</summary>
|
||||
|
||||
The relevant `generate_sql` function takes a worksheet name and a table name:
|
||||
|
||||
@ -118,7 +124,7 @@ function SheetJSQLWriter() {
|
||||
if(fields.length) return `INSERT INTO \`${wsname}\` (${fields.join(", ")}) VALUES (${values.join(", ")})`;
|
||||
})).filter(x => x).slice(0, 6);
|
||||
}
|
||||
const [url, setUrl] = React.useState("https://sheetjs.com/data/cd.xls");
|
||||
const [url, setUrl] = React.useState("https://docs.sheetjs.com/cd.xls");
|
||||
const set_url = (evt) => setUrl(evt.target.value);
|
||||
const [out, setOut] = React.useState("");
|
||||
const xport = React.useCallback(async() => {
|
||||
@ -147,7 +153,7 @@ types and other database minutiae.
|
||||
|
||||
### Other SQL Databases
|
||||
|
||||
The `generate_sql` function from ["Building Schemas from Worksheets"](#building-schemas-from-worksheets)
|
||||
The `generate_sql` function from ["Generating Tables"](#generating-tables)
|
||||
can be adapted to generate SQL statements for a variety of databases, including:
|
||||
|
||||
**PostgreSQL**
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user