forked from sheetjs/docs.sheetjs.com
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 042edb00b0 | |||
| 1241cd92d7 | |||
| a881bc8924 | |||
| 7b5a73be0d | |||
| e996b02688 | |||
| 20a52fe655 | |||
| f77d0bd788 | |||
| f9dbcc069b | |||
| 38b268d40c | |||
| fc5a19d6cd | |||
| f5aabe0c29 | |||
| 7bb2ddcaea | |||
| a0e35dd7e1 | |||
| d922ad6246 | |||
| 5633b2387a | |||
| ef89abda1f | |||
| 6532f9fea8 | |||
| 67d7c1f993 | |||
| def11cf796 | |||
| b205f3f6a1 | |||
| f1a4f192d3 | |||
| 1327b2f98c | |||
| f39d01eb84 | |||
| 3875a9ee91 | |||
| d74827a012 | |||
| ac0f80025a | |||
| 609f7ff5f2 | |||
| e5d9d1c15e | |||
| 2d6b139ef7 | |||
| 4e3a0637ea | |||
| 8a65ff5698 | |||
| d77a40c6bf | |||
| 9af5473755 | |||
| 1f87dda979 | |||
| 1b242c12ef |
3
.gitignore
vendored
3
.gitignore
vendored
@ -4,4 +4,5 @@ package-lock.json
|
||||
pnpm-lock.yaml
|
||||
/docs
|
||||
node_modules
|
||||
.idea
|
||||
.idea
|
||||
.vscode
|
||||
2
Makefile
2
Makefile
@ -12,7 +12,7 @@ init:
|
||||
|
||||
.PHONY: dev
|
||||
dev:
|
||||
cd docz; npm run start -- --host=0.0.0.0 --no-open; cd ..
|
||||
cd docz; npm run start -- --host=0.0.0.0 --port 6996 --no-open; cd ..
|
||||
|
||||
.PHONY: serve
|
||||
serve:
|
||||
|
||||
@ -16,7 +16,7 @@ $ make init # install dependencies
|
||||
$ make # build static site
|
||||
$ make serve # serve static site
|
||||
|
||||
$ make dev # run dev server
|
||||
$ make dev # run dev server on port 6996
|
||||
$ make spell # spell check (.spelling custom dictionary)
|
||||
$ make graph # build format graph and legend
|
||||
```
|
||||
@ -99,7 +99,7 @@ tables in <https://docs.sheetjs.com/docs/demos/engines/>. The component script
|
||||
### Formats Graph
|
||||
|
||||
The formats graph and legend are written in the DOT language. Rebuilding the
|
||||
graphs will require Graphviz (`brew install graphviz` on macOS)
|
||||
graphs will require Graphviz and the "Indie Flower" font.
|
||||
|
||||
## Live Demos
|
||||
|
||||
|
||||
@ -1,417 +1,417 @@
|
||||
<?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="Engines">
|
||||
<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"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Row>
|
||||
<Cell ss:MergeAcross="1" 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">Engine</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Lang</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/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>
|
||||
<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#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>
|
||||
<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 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"><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/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>
|
||||
<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/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>
|
||||
<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/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"><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/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>
|
||||
</Row>
|
||||
<Row>
|
||||
<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>
|
||||
<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/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>
|
||||
<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/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>
|
||||
<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/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"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<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>
|
||||
<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/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"><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/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"><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>
|
||||
<Worksheet ss:Name="Bindings">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="20" 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:MergeAcross="1" 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">Engine</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Lang</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/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"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<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"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<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"/>
|
||||
<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/duktape#rust"><Data ss:Type="String">Duktape</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>
|
||||
<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/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"><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#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>
|
||||
<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 ss:StyleID="s20" ss:HRef="/docs/demos/engines/v8#java"><Data ss:Type="String">V8</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"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/v8#c"><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>
|
||||
<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#python"><Data ss:Type="String">V8</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"><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/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>
|
||||
<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/jsc#rust"><Data ss:Type="String">JSC</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>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
</Row>
|
||||
<Row>
|
||||
<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>
|
||||
</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>
|
||||
<Selected/>
|
||||
<FreezePanes/>
|
||||
<FrozenNoSplit/>
|
||||
<SplitHorizontal>2</SplitHorizontal>
|
||||
<TopRowBottomPane>2</TopRowBottomPane>
|
||||
<ActivePane>2</ActivePane>
|
||||
<Panes>
|
||||
<Pane>
|
||||
<Number>3</Number>
|
||||
</Pane>
|
||||
<Pane>
|
||||
<Number>2</Number>
|
||||
<ActiveRow>3</ActiveRow>
|
||||
<ActiveCol>1</ActiveCol>
|
||||
</Pane>
|
||||
</Panes>
|
||||
<ProtectObjects>False</ProtectObjects>
|
||||
<ProtectScenarios>False</ProtectScenarios>
|
||||
</WorksheetOptions>
|
||||
</Worksheet>
|
||||
</Workbook>
|
||||
<?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="Engines">
|
||||
<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"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Row>
|
||||
<Cell ss:MergeAcross="1" 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">Engine</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Lang</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/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>
|
||||
<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#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>
|
||||
<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 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"><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/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>
|
||||
<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/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>
|
||||
<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/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"><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/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>
|
||||
</Row>
|
||||
<Row>
|
||||
<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>
|
||||
<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/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>
|
||||
<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/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>
|
||||
<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/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"><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/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>
|
||||
<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/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"><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/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"><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>
|
||||
<Worksheet ss:Name="Bindings">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="20" 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:MergeAcross="1" 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">Engine</Data></Cell>
|
||||
<Cell ss:StyleID="s17"><Data ss:Type="String">Lang</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/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"><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/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"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<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"><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/duktape#rust"><Data ss:Type="String">Duktape</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>
|
||||
<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/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"><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#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>
|
||||
<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#java"><Data ss:Type="String">V8</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/v8#c"><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>
|
||||
<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#python"><Data ss:Type="String">V8</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"><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/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>
|
||||
<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/jsc#rust"><Data ss:Type="String">JSC</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>
|
||||
<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/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>
|
||||
</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>
|
||||
<Selected/>
|
||||
<FreezePanes/>
|
||||
<FrozenNoSplit/>
|
||||
<SplitHorizontal>2</SplitHorizontal>
|
||||
<TopRowBottomPane>2</TopRowBottomPane>
|
||||
<ActivePane>2</ActivePane>
|
||||
<Panes>
|
||||
<Pane>
|
||||
<Number>3</Number>
|
||||
</Pane>
|
||||
<Pane>
|
||||
<Number>2</Number>
|
||||
<ActiveRow>3</ActiveRow>
|
||||
<ActiveCol>1</ActiveCol>
|
||||
</Pane>
|
||||
</Panes>
|
||||
<ProtectObjects>False</ProtectObjects>
|
||||
<ProtectScenarios>False</ProtectScenarios>
|
||||
</WorksheetOptions>
|
||||
</Worksheet>
|
||||
</Workbook>
|
||||
|
||||
@ -16,7 +16,7 @@ Each standalone release script is available at https://cdn.sheetjs.com/.
|
||||
|
||||
<CodeBlock language="html">{`\
|
||||
<!-- use version ${current} -->
|
||||
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
|
||||
<script type="text/javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
|
||||
</CodeBlock>
|
||||
|
||||
:::tip pass
|
||||
@ -44,7 +44,7 @@ reading and writing many spreadsheet formats.
|
||||
|
||||
<CodeBlock language="html">{`\
|
||||
<!-- use xlsx.full.min.js from version ${current} -->
|
||||
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
|
||||
<script type="text/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:
|
||||
@ -60,7 +60,7 @@ A single script tag should be added at the top of the HTML page:
|
||||
|
||||
<CodeBlock language="html">{`\
|
||||
<!-- use xlsx.mini.min.js from version ${current} -->
|
||||
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.mini.min.js"></script>`}
|
||||
<script type="text/javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.mini.min.js"></script>`}
|
||||
</CodeBlock>
|
||||
|
||||
</details>
|
||||
@ -118,20 +118,20 @@ importScripts("https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.mi
|
||||
|
||||
### Type Checker
|
||||
|
||||
:::danger VSCode Telemetry and Data Exfiltration
|
||||
:::danger VS Code Telemetry and Data Exfiltration
|
||||
|
||||
The official Microsoft builds of Visual Studio Code ("VSCode") embed telemetry
|
||||
and send information to external servers.
|
||||
The official builds of Visual Studio Code ("VS Code" or "VSCode") embed
|
||||
telemetry and send information to Microsoft servers.
|
||||
|
||||
**[VSCodium](https://vscodium.com/) is a telemetry-free fork of VSCode.**
|
||||
**[VSCodium](https://vscodium.com/) is a telemetry-free fork of VS Code.**
|
||||
|
||||
When writing code that may process personally identifiable information (PII),
|
||||
the SheetJS team strongly encourages building VSCode from source or using IDEs
|
||||
the SheetJS team strongly encourages building VS Code from source or using IDEs
|
||||
that do not exfiltrate data.
|
||||
|
||||
:::
|
||||
|
||||
The type checker integrated in VSCodium and VSCode does not currently provide
|
||||
The type checker integrated in VSCodium and VS Code does not currently provide
|
||||
type hints when using the standalone build. Using the JSDoc `@type` directive
|
||||
coupled with type imports, VSCodium will recognize the types:
|
||||
|
||||
@ -176,7 +176,7 @@ The `.d.ts` file extension must be omitted.
|
||||
|
||||
JSDoc types using the `@import` directive are not supported in `<script>` tags.
|
||||
|
||||
**This is a known bug with VSCode!**
|
||||
**This is a known bug with VS Code!**
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -121,12 +121,12 @@ This demo was last tested in the following deployments:
|
||||
|
||||
| Architecture | BunJS | Date |
|
||||
|:-------------|:---------|:-----------|
|
||||
| `darwin-x64` | `1.2.8` | 2025-03-31 |
|
||||
| `darwin-arm` | `1.2.7` | 2025-03-30 |
|
||||
| `win11-x64` | `1.2.8` | 2025-04-17 |
|
||||
| `win11-arm` | `1.2.3` | 2025-02-23 |
|
||||
| `linux-x64` | `1.2.10` | 2025-04-21 |
|
||||
| `linux-arm` | `1.2.2` | 2025-02-16 |
|
||||
| `darwin-x64` | `1.3.6` | 2026-01-20 |
|
||||
| `darwin-arm` | `1.3.6` | 2026-01-19 |
|
||||
| `win11-x64` | `1.3.6` | 2026-01-28 |
|
||||
| `win11-arm` | `1.3.10` | 2026-03-07 |
|
||||
| `linux-x64` | `1.3.6` | 2026-01-18 |
|
||||
| `linux-arm` | `1.3.10` | 2026-03-07 |
|
||||
|
||||
BunJS on Windows on ARM uses the X64 compatibility layer.
|
||||
|
||||
@ -137,42 +137,9 @@ BunJS on Windows on ARM uses the X64 compatibility layer.
|
||||
```bash
|
||||
mkdir sheetjs-bun-dle
|
||||
cd sheetjs-bun-dle
|
||||
echo "{}" > package.json
|
||||
bun init -y
|
||||
```
|
||||
|
||||
:::caution PowerShell Encoding Errors
|
||||
|
||||
The PowerShell file redirect will use the `UTF-16 LE` encoding. Bun does not
|
||||
support the encoding and will fail to install the package:
|
||||
|
||||
```
|
||||
bun add v1.1.42 (50eec002)
|
||||
1 | <20><>
|
||||
^
|
||||
error: Unexpected <20><>
|
||||
at <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>:1:1
|
||||
```
|
||||
|
||||
The file must be resaved in UTF8 (without BOM) or ASCII.
|
||||
|
||||
0) Open `package.json` in VSCodium.
|
||||
|
||||
The current encoding is displayed in the lower-right corner:
|
||||
|
||||

|
||||
|
||||
1) Click the displayed encoding.
|
||||
|
||||
2) In the "Select Action" popup, select "Save with Encoding"
|
||||
|
||||
3) In the new list, select `UTF-8 utf8`:
|
||||
|
||||

|
||||
|
||||
VSCodium will automatically re-save the file.
|
||||
|
||||
:::
|
||||
|
||||
1) Install the SheetJS package tarball:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
|
||||
@ -469,14 +469,16 @@ The result is an array of "simple" objects with no nesting:
|
||||
|
||||
## Create a Workbook
|
||||
|
||||
With the cleaned dataset, `XLSX.utils.json_to_sheet`[^3] generates a worksheet:
|
||||
The [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input) method
|
||||
can generate a SheetJS worksheet from the cleaned dataset:
|
||||
|
||||
```js
|
||||
const worksheet = XLSX.utils.json_to_sheet(rows);
|
||||
```
|
||||
|
||||
`XLSX.utils.book_new`[^4] creates a new workbook and `XLSX.utils.book_append_sheet`[^5]
|
||||
appends a worksheet to the workbook. The new worksheet will be called "Dates":
|
||||
[`XLSX.utils.book_new`](/docs/api/utilities/wb) creates a new workbook and
|
||||
[`XLSX.utils.book_append_sheet`](/docs/api/utilities/wb) appends a worksheet to
|
||||
the workbook. The new worksheet will be called "Dates":
|
||||
|
||||
```js
|
||||
const workbook = XLSX.utils.book_new();
|
||||
@ -503,10 +505,12 @@ cell styling and frozen rows.
|
||||
<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".
|
||||
the headers come from the JS object keys: "name" and "birthday". The headers are
|
||||
written to the first row.
|
||||
|
||||
The headers are in cells `A1` and `B1`. `XLSX.utils.sheet_add_aoa`[^6] can write
|
||||
text values to the existing worksheet starting at cell `A1`:
|
||||
[`XLSX.utils.sheet_add_aoa`](/docs/api/utilities/array#array-of-arrays-input)
|
||||
can overwrite data in the worksheet. The following line will set `A1` to "Name"
|
||||
and set `B1` to "Birthday":
|
||||
|
||||
```js
|
||||
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
|
||||
@ -518,7 +522,7 @@ XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
|
||||
<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]
|
||||
stored in the [`"!cols"` worksheet property](/docs/csf/features/colprops).
|
||||
|
||||
The following line sets the width of column A to approximately 10 characters:
|
||||
|
||||
@ -541,9 +545,9 @@ After cleanup, the generated workbook looks like the screenshot below:
|
||||
|
||||
## Export a File
|
||||
|
||||
`XLSX.writeFile`[^8] creates a spreadsheet file and tries to write it to the
|
||||
system. In the browser, it will try to prompt the user to download the file. In
|
||||
NodeJS, it will write to the local directory.
|
||||
[`XLSX.writeFile`](/docs/api/write-options) creates a spreadsheet file and tries
|
||||
to write it to the system. In the browser, it will try to prompt the user to
|
||||
download the file. In NodeJS, it will write to the local directory.
|
||||
|
||||
```js
|
||||
XLSX.writeFile(workbook, "Presidents.xlsx", { compression: true });
|
||||
@ -644,7 +648,7 @@ After saving the file, run a local web server in the folder with the HTML file.
|
||||
For example, if NodeJS is installed:
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
The server process will display a URL (typically `http://127.0.0.1:8080`). Open
|
||||
@ -1165,14 +1169,8 @@ 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.
|
||||
dedicated the content to the public domain. When this demo was last tested,
|
||||
[^2]: See ["The Executive Branch"](https://github.com/unitedstates/congress-legislators#the-executive-branch)
|
||||
in the dataset documentation.
|
||||
[^3]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^4]: See [`book_new` in "Utilities"](/docs/api/utilities/wb)
|
||||
[^5]: See [`book_append_sheet` in "Utilities"](/docs/api/utilities/wb)
|
||||
[^6]: See [`sheet_add_aoa` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
|
||||
[^7]: See ["Column Properties"](/docs/csf/features/colprops)
|
||||
[^8]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
@ -148,14 +148,15 @@ The file data is stored in an `ArrayBuffer`.
|
||||
|
||||
## Parse File
|
||||
|
||||
With the file data in hand, `XLSX.read`[^2] parses the workbook:
|
||||
With the file data in hand, [`XLSX.read`](/docs/api/parse-options) parses the
|
||||
file and generates a SheetJS workbook object:
|
||||
|
||||
```js
|
||||
const workbook = XLSX.read(file);
|
||||
```
|
||||
|
||||
The `workbook` object follows the "Common Spreadsheet Format"[^3], an in-memory
|
||||
format for representing workbooks, worksheets, cells, and spreadsheet features.
|
||||
The `workbook` object follows the ["Common Spreadsheet Format"](/docs/csf/), an
|
||||
in-memory schema for workbooks, worksheets, cells, and spreadsheet features.
|
||||
|
||||
|
||||
## Explore Dataset
|
||||
@ -170,8 +171,8 @@ To determine how to process the data, it is best to inspect the file first.
|
||||
|
||||
### List Sheet Names
|
||||
|
||||
As explained in the "Workbook Object"[^4] section, the `SheetNames` property is
|
||||
a ordered list of the sheet names in the workbook.
|
||||
As explained in the ["Workbook Object"](/docs/csf/book) page, the `SheetNames`
|
||||
property is a list of the sheet names in the workbook.
|
||||
|
||||
The following live code block displays an ordered list of the sheet names:
|
||||
|
||||
@ -195,21 +196,25 @@ function SheetJSheetNames() {
|
||||
|
||||
### Inspect Worksheet Data
|
||||
|
||||
The `Sheets` property of the workbook object[^5] is an object whose keys are
|
||||
sheet names and whose values are sheet objects. For example, the first worksheet
|
||||
is pulled by indexing `SheetNames` and using the name to index `Sheets`:
|
||||
The [`Sheets` property of the workbook object](/docs/csf/book) is an object
|
||||
whose keys are sheet names and whose values are sheet objects.
|
||||
|
||||
For example, the first worksheet can be pulled by indexing `SheetNames` and
|
||||
using the name to index `Sheets`:
|
||||
|
||||
```js
|
||||
var first_sheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
```
|
||||
|
||||
The actual worksheet object can be inspected directly[^6], but it is strongly
|
||||
recommended to use utility functions to present JS-friendly data structures.
|
||||
The [worksheet object](/docs/csf/sheet) can be inspected directly, but it is
|
||||
strongly recommended to use utility functions to extract relevant data.
|
||||
|
||||
### Preview HTML
|
||||
|
||||
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:
|
||||
The [`sheet_to_html` function](/docs/api/utilities/html#html-table-output)
|
||||
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>
|
||||
@ -254,7 +259,8 @@ The key points from looking at the table are:
|
||||
|
||||
### Extract Raw Data
|
||||
|
||||
`XLSX.utils.sheet_to_json`[^8] generates arrays of data from worksheet objects.
|
||||
The [`sheet_to_json` function](/docs/api/utilities/array#array-output) generates
|
||||
arrays of data from worksheet objects.
|
||||
|
||||
For a complex layout like this, it is easiest to generate an "array of arrays"
|
||||
where each row is an array of cell values. The screenshot shows rows 5-8:
|
||||
@ -277,7 +283,7 @@ Row 7 includes the data for FY2007:
|
||||
```
|
||||
|
||||
`XLSX.utils.sheet_to_json` will generate an array of arrays if the option
|
||||
`header: 1` is specified[^9]:
|
||||
[`header: 1`](/docs/api/utilities/array#array-output) is specified:
|
||||
|
||||
```js
|
||||
const worksheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
@ -332,7 +338,9 @@ function SheetJSAoAHoles() {
|
||||
|
||||
</details>
|
||||
|
||||
The worksheet `!merges` property[^10] includes every merge range in the sheet.
|
||||
The [worksheet `!merges` property](/docs/csf/features/merges) includes every
|
||||
merge range in the sheet.
|
||||
|
||||
It is possible to loop through every merge block and fill cells, but in this
|
||||
case it is easier to post-process the raw data:
|
||||
|
||||
@ -489,20 +497,20 @@ function SheetJSAoAFilled() {
|
||||
### Select Data Rows
|
||||
|
||||
At this point, each data row will have the year in column `A` and dollar value
|
||||
in column `C`. The year (first value in the row) will be between 2007 and 2024.
|
||||
in column `C`. The year (first value in the row) will be between 2007 and 2029.
|
||||
The value (third value) will be positive. The following function tests a row
|
||||
against the requirements:
|
||||
|
||||
```js
|
||||
const is_valid_row = r =>
|
||||
r[0] >= 2007 && r[0] <= 2024 // year (column A) is between 2007 and 2024
|
||||
r[0] >= 2007 && r[0] <= 2029 // year (column A) is between 2007 and 2029
|
||||
&& r[2] > 0; // dollar value (column C) is positive
|
||||
```
|
||||
|
||||
`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);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2029 && r[2] > 0);
|
||||
```
|
||||
|
||||
<details>
|
||||
@ -522,7 +530,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] <= 2024 && r[2] > 0);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2029 && r[2] > 0);
|
||||
/* display data */
|
||||
setRows(rows);
|
||||
})(); }, []);
|
||||
@ -539,7 +547,7 @@ Looking at the headers:
|
||||

|
||||
|
||||
The desired data is in column `I`. The column index can be calculated using
|
||||
`XLSX.utils.decode_col`[^11].
|
||||
the [`decode_col` utility function](/docs/csf/general#column-names).
|
||||
|
||||
<details>
|
||||
<summary><b>Column Index calculation</b> (click to show)</summary>
|
||||
@ -598,7 +606,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] <= 2024 && r[2] > 0);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2029 && r[2] > 0);
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
/* display data */
|
||||
@ -617,7 +625,7 @@ At this point, `objects` is an array of objects.
|
||||
### ReactJS
|
||||
|
||||
The live demos in this example use ReactJS. In ReactJS, arrays of objects are
|
||||
best presented in simple HTML tables[^12]:
|
||||
best presented in [simple tables](/docs/demos/frontend/react#array-of-objects):
|
||||
|
||||
```jsx
|
||||
<table>
|
||||
@ -706,7 +714,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] <= 2024 && r[2] > 0);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2029 && r[2] > 0);
|
||||
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
@ -761,7 +769,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] <= 2024 && r[2] > 0);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2029 && r[2] > 0);
|
||||
\n\
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
@ -781,7 +789,7 @@ After saving the file, run a local web server in the folder with the HTML file.
|
||||
For example, if NodeJS is installed:
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
The server process will display a URL (typically `http://127.0.0.1:8080`). Open
|
||||
@ -827,7 +835,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] <= 2024 && r[2] > 0);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2029 && r[2] > 0);
|
||||
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
@ -900,7 +908,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] <= 2024 && r[2] > 0);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2029 && r[2] > 0);
|
||||
\n\
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
@ -1001,7 +1009,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] <= 2024 && r[2] > 0);
|
||||
const rows = raw_data.filter(r => r[0] >= 2007 && r[0] <= 2029 && r[2] > 0);
|
||||
|
||||
/* generate row objects */
|
||||
const objects = rows.map(r => ({FY: r[0], FQ: r[1], total: r[8]}));
|
||||
@ -1053,7 +1061,7 @@ Press `a` to run on Android.
|
||||
|
||||
:::info Device Testing
|
||||
|
||||
The demo also runs on real Android devices! After enabling USB debugging[^13],
|
||||
The demo also runs on real Android devices! After enabling USB debugging[^2],
|
||||
the Android device can be connected to the computer with a USB cable.
|
||||
|
||||
:::
|
||||
@ -1088,15 +1096,4 @@ When the app is loaded, the data will be displayed in rows.
|
||||
</Tabs>
|
||||
|
||||
[^1]: The dataset URL has changed many times over the years. The current location for the CC0-licensed dataset can be found by [searching for "National Student Loan Data System" on `data.gov`](https://catalog.data.gov/dataset/?q=national+student+loan+data+system&publisher=Office+of+Federal+Student+Aid+%28FSA%29&organization=ed-gov). `PortfolioSummary.xls` is the file name within the dataset.
|
||||
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^3]: See ["SheetJS Data Model"](/docs/csf/)
|
||||
[^4]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^5]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^6]: See ["Sheet Objects"](/docs/csf/sheet)
|
||||
[^7]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output)
|
||||
[^8]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^9]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^10]: See ["Merged Cells" in "SheetJS Data Model"](/docs/csf/features/merges)
|
||||
[^11]: See ["Column Names" in "Addresses and Ranges"](/docs/csf/general#column-names)
|
||||
[^12]: See ["Array of Objects" in "ReactJS"](/docs/demos/frontend/react#array-of-objects)
|
||||
[^13]: See ["Running on Device"](https://reactnative.dev/docs/running-on-device) in the React Native documentation for more details.
|
||||
[^2]: See ["Running on Device"](https://reactnative.dev/docs/running-on-device) in the React Native documentation for more details.
|
||||
@ -33,40 +33,56 @@ SheetJS Loader to answer questions based on data from a XLS workbook.
|
||||
|
||||
This demo was tested in the following configurations:
|
||||
|
||||
| Platform | Architecture | Date |
|
||||
|:------------------------------------------------------------------|:-------------|:-----------|
|
||||
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | 2025-04-17 |
|
||||
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | 2025-01-28 |
|
||||
| AMD RX 7900 XTX (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | 2025-01-12 |
|
||||
| AMD RX 7900 XTX (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | 2025-01-29 |
|
||||
| Intel Arc B580 (12 GB VRAM) + Ryzen Z1 Extreme (24 GB RAM) | `win11-x64` | 2025-01-24 |
|
||||
| Intel Arc B580 (12 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | 2025-02-08 |
|
||||
| Apple M4 Max 16-Core CPU + 40-Core GPU (48 GB unified memory) | `darwin-arm` | 2025-03-06 |
|
||||
| Apple M2 Max 12-Core CPU + 30-Core GPU (32 GB unified memory) | `darwin-arm` | 2025-03-25 |
|
||||
| Platform | Architecture | Backend | Date |
|
||||
|:---------------------------------------------------------------------|:-------------|:------------|:-----------|
|
||||
| NVIDIA RTX PRO 6000 (96 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `win11-x64` | Ollama | 2025-11-15 |
|
||||
| NVIDIA RTX PRO 6000 (96 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `linux-x64` | Ollama | 2025-11-15 |
|
||||
| NVIDIA RTX 5090 (32 GB VRAM) + Ryzen AI Z2 Extreme (24 GB RAM) | `win11-x64` | `llama.cpp` | 2026-05-05 |
|
||||
| NVIDIA RTX 5090 (32 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `linux-x64` | Ollama | 2025-11-15 |
|
||||
| NVIDIA RTX 5060 Ti (16 GB VRAM) + Ryzen Z2 Extreme (32 GB RAM) | `win11-x64` | `llama.cpp` | 2026-06-05 |
|
||||
| AMD AI PRO R9700 (32 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | Ollama | 2026-01-17 |
|
||||
| AMD AI PRO R9700 (32 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | Ollama | 2026-01-17 |
|
||||
| AMD RX 9070 XT (16 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `win11-x64` | Ollama | 2026-01-17 |
|
||||
| AMD RX 9070 XT (16 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `linux-x64` | Ollama | 2026-01-17 |
|
||||
| AMD RX 7900 XTX (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | Ollama | 2025-11-15 |
|
||||
| AMD RX 7900 XTX (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | Ollama | 2025-11-15 |
|
||||
| Intel Arc B580 (12 GB VRAM) + Ryzen Z1 Extreme (24 GB RAM) | `win11-x64` | Ollama | 2025-11-15 |
|
||||
| Intel Arc B580 (12 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | Ollama | 2025-11-15 |
|
||||
| AMD Ryzen AI MAX+ 395 + Radeon 8060S (128 GB unified memory) | `linux-x64` | Ollama | 2025-11-15 |
|
||||
| AMD Ryzen AI MAX+ 395 + Radeon 8060S (128 GB unified memory) | `win11-x64` | Ollama | 2025-11-15 |
|
||||
| AMD Ryzen AI 9 HX 370 + Radeon 890M (64 GB unified memory) | `win11-x64` | `llama.cpp` | 2026-05-12 |
|
||||
| Apple M4 Max 16-Core CPU + 40-Core GPU (48 GB unified memory) | `darwin-arm` | Ollama | 2025-11-15 |
|
||||
|
||||
SheetJS users have verified this demo in other configurations:
|
||||
|
||||
<details>
|
||||
<summary><b>Other tested configurations</b> (click to show)</summary>
|
||||
|
||||
| Platform | Architecture | Demo |
|
||||
| Platform | Architecture | Backend |
|
||||
|:---------------------------------------------------------------------|:-------------|:------------|
|
||||
| NVIDIA L40 (48 GB VRAM) + i9-13900K (32 GB RAM) | `linux-x64` | LangChainJS |
|
||||
| NVIDIA RTX 4080 SUPER (16 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | LangChainJS |
|
||||
| NVIDIA RTX 4070 Ti SUPER (16 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | LangChainJS |
|
||||
| NVIDIA RTX 4070 Ti (12 GB VRAM) + Ryzen 7 5800x (64 GB RAM) | `win11-x64` | LangChainJS |
|
||||
| NVIDIA RTX 4060 (8 GB VRAM) + Ryzen 7 5700g (32 GB RAM) | `win11-x64` | LangChainJS |
|
||||
| NVIDIA RTX 3090 (24 GB VRAM) + Ryzen 9 3900XT (128 GB RAM) | `win11-x64` | LangChainJS |
|
||||
| NVIDIA RTX 3080 (12 GB VRAM) + Ryzen 7 5800X (32 GB RAM) | `win11-x64` | LangChainJS |
|
||||
| NVIDIA RTX 3070 (8 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | LangChainJS |
|
||||
| NVIDIA RTX 3060 (12 GB VRAM) + i5-11400 (32 GB RAM) | `win10-x64` | LangChainJS |
|
||||
| NVIDIA RTX 2080 (12 GB VRAM) + i7-9700K (16 GB RAM) | `win10-x64` | LangChainJS |
|
||||
| NVIDIA RTX 2070 (8 GB VRAM) + Ryzen 7 3700x (80 GB RAM) | `linux-x64` | LangChainJS |
|
||||
| NVIDIA RTX 2060 (6 GB VRAM) + Ryzen 5 3600 (32 GB RAM) | `win10-x64` | LangChainJS |
|
||||
| NVIDIA GTX 1080 (8 GB VRAM) + Ryzen 7 5800x (64 GB RAM) | `win10-x64` | LangChainJS |
|
||||
| NVIDIA GTX 1070 (8 GB VRAM) + Ryzen 7 7700x (32 GB RAM) | `win11-x64` | LangChainJS |
|
||||
| AMD RX 6800 XT (16 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | LangChainJS |
|
||||
| Apple M4 10-Core CPU + 10-Core GPU (24 GB unified memory) | `darwin-arm` | LangChainJS |
|
||||
| NVIDIA L40 (48 GB VRAM) + i9-13900K (32 GB RAM) | `linux-x64` | Ollama |
|
||||
| NVIDIA RTX 5090 (32 GB VRAM) + Ryzen AI Z2 Extreme (24 GB RAM) | `win11-x64` | Ollama |
|
||||
| NVIDIA RTX 5090 Mobile (24 GB VRAM) + Ryzen Z1 Extreme (24 GB RAM) | `win11-x64` | `llama.cpp` |
|
||||
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `win11-x64` | Ollama |
|
||||
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `linux-x64` | Ollama |
|
||||
| NVIDIA RTX 4080 SUPER (16 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | Ollama |
|
||||
| NVIDIA RTX 4080 SUPER (16 GB VRAM) + Ryzen Z2 Go (32 GB RAM) | `linux-x64` | Ollama |
|
||||
| NVIDIA RTX 4070 Ti SUPER (16 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | Ollama |
|
||||
| NVIDIA RTX 4070 Ti (12 GB VRAM) + Ryzen 7 5800x (64 GB RAM) | `win11-x64` | Ollama |
|
||||
| NVIDIA RTX 4060 (8 GB VRAM) + Ryzen 7 5700g (32 GB RAM) | `win11-x64` | Ollama |
|
||||
| NVIDIA RTX 3090 (24 GB VRAM) + Ryzen 9 3900XT (128 GB RAM) | `win11-x64` | Ollama |
|
||||
| NVIDIA RTX 3080 (12 GB VRAM) + Ryzen 7 5800X (32 GB RAM) | `win11-x64` | Ollama |
|
||||
| NVIDIA RTX 3070 (8 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | Ollama |
|
||||
| NVIDIA RTX 3060 (12 GB VRAM) + i5-11400 (32 GB RAM) | `win10-x64` | Ollama |
|
||||
| NVIDIA RTX 2080 (12 GB VRAM) + i7-9700K (16 GB RAM) | `win10-x64` | Ollama |
|
||||
| NVIDIA RTX 2070 (8 GB VRAM) + Ryzen 7 3700x (80 GB RAM) | `linux-x64` | Ollama |
|
||||
| NVIDIA RTX 2060 (6 GB VRAM) + Ryzen 5 3600 (32 GB RAM) | `win10-x64` | Ollama |
|
||||
| NVIDIA GTX 1080 (8 GB VRAM) + Ryzen 7 5800x (64 GB RAM) | `win10-x64` | Ollama |
|
||||
| NVIDIA GTX 1070 (8 GB VRAM) + Ryzen 7 7700x (32 GB RAM) | `win11-x64` | Ollama |
|
||||
| AMD RX 6800 XT (16 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | Ollama |
|
||||
| Apple M4 10-Core CPU + 10-Core GPU (24 GB unified memory) | `darwin-arm` | Ollama |
|
||||
| Apple M3 Ultra 28-Core CPU + 60-Core GPU (96 GB unified memory) | `darwin-arm` | Ollama |
|
||||
| Apple M2 Max 12-Core CPU + 30-Core GPU (32 GB unified memory) | `darwin-arm` | Ollama |
|
||||
|
||||
</details>
|
||||
|
||||
@ -377,7 +393,7 @@ includes one header row and a number of data rows.
|
||||
|
||||
```js title="loadofsheet.mjs"
|
||||
import { Document } from "@langchain/core/documents";
|
||||
import { BufferLoader } from "langchain/document_loaders/fs/buffer";
|
||||
import { BufferLoader } from "@langchain/classic/document_loaders/fs/buffer";
|
||||
import { read, utils } from "xlsx";
|
||||
|
||||
/**
|
||||
@ -516,7 +532,7 @@ export class CSVLoader extends TextLoader {
|
||||
The SheetJS `read` method supports NodeJS Buffer objects directly[^6]:
|
||||
|
||||
```js title="Parsing a workbook in a BufferLoader"
|
||||
import { BufferLoader } from "langchain/document_loaders/fs/buffer";
|
||||
import { BufferLoader } from "@langchain/classic/document_loaders/fs/buffer";
|
||||
import { read, utils } from "xlsx";
|
||||
|
||||
export default class LoadOfSheet extends BufferLoader {
|
||||
@ -722,33 +738,49 @@ a [sample cars dataset](pathname:///cd.xls) and displays the results.
|
||||
|
||||
:::caution pass
|
||||
|
||||
This demo was tested using the ChatQA-1.5 model[^9] in Ollama.
|
||||
This demo was tested with the Phi-4[^9] open model, using up to 10GB VRAM.
|
||||
|
||||
The tested model used up to 10GB VRAM. It is strongly recommended to run the
|
||||
demo on a GPU with at least 12GB VRAM or a newer Apple Silicon Mac with at least
|
||||
32GB unified memory.
|
||||
It is strongly recommended to run the demo on a GPU with at least 12GB VRAM or a
|
||||
computer with at least 32GB memory.
|
||||
|
||||
:::
|
||||
|
||||
0) Install pre-requisites:
|
||||
0) Install prerequisites:
|
||||
|
||||
- [NodeJS LTS (version 20+)](https://nodejs.org/)
|
||||
- [Ollama](https://ollama.com/download)
|
||||
- [NodeJS LTS (version 24+)](https://nodejs.org/)
|
||||
- LLM Server
|
||||
|
||||
:::note pass
|
||||
:::info pass
|
||||
|
||||
Ollama should be installed on the same platform as NodeJS. If NodeJS is run
|
||||
within WSL, Ollama should also be installed within WSL.
|
||||
The LLM server should be installed on the same platform as NodeJS. If NodeJS is
|
||||
run within WSL, the LLM server should also be installed within WSL.
|
||||
|
||||
:::
|
||||
|
||||
:::note Recommendation
|
||||
|
||||
`llama.cpp` is strongly recommended for new deployments, as it supports exotic
|
||||
deployments. The learning curve has flattened in recent years.
|
||||
|
||||
Previous iterations of this demo used Ollama. It is easier to deploy Ollama in
|
||||
common scenarios including Apple Silicon Macs, but support for newer hardware
|
||||
and models typically lags `llama.cpp`.
|
||||
|
||||
:::
|
||||
|
||||
<Tabs groupId="llm">
|
||||
<TabItem value="ollama" label="Ollama">
|
||||
|
||||
Binary packages are available at https://ollama.com/download . They generally
|
||||
work for Apple Silicon Macs and for Windows and Linux machines with NVIDIA GPUs.
|
||||
|
||||
:::danger pass
|
||||
|
||||
Intel ARC GPUs require the Intel Extension for PyTorch (IPEX) and a special
|
||||
version of Ollama that ships with the associated LLM Library (IPEX-LLM).
|
||||
|
||||
<details>
|
||||
<summary><b>ARC Instructions</b> (click to show)</summary>
|
||||
<summary><b>ARC Instructions on Windows</b> (click to show)</summary>
|
||||
|
||||
These instructions are based on the official Intel recommendations.
|
||||
|
||||
@ -805,8 +837,175 @@ This window should be kept open throughout the demo.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>ARC Instructions on Linux</b> (click to show)</summary>
|
||||
|
||||
These instructions are based on the official Intel recommendations.
|
||||
|
||||
A) Install the dependencies from the [Battlemage quickstart](https://github.com/intel/ipex-llm/blob/main/docs/mddocs/Quickstart/bmg_quickstart.md#11-install-prerequisites)
|
||||
|
||||
B) Download and extract the [Ollama Portable Zip](https://github.com/intel/ipex-llm/blob/main/docs/mddocs/Quickstart/ollama_portable_zip_quickstart.md#linux-quickstart).
|
||||
|
||||
C) When this demo was last tested, the computer had an AMD processor. To force
|
||||
Ollama to use the GPU, uncomment the "single GPU" line in `start-ollama.sh`:
|
||||
|
||||
```bash title="start-ollama.sh (uncomment line)"
|
||||
export ONEAPI_DEVICE_SELECTOR=level_zero:0
|
||||
```
|
||||
|
||||
D) Run the `start-ollama.sh` script from the extracted folder.
|
||||
|
||||
</details>
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
AMD GPUs may require special ROCm / HIP libraries.
|
||||
|
||||
<details>
|
||||
<summary><b>AMD Instructions on Windows</b> (click to show)</summary>
|
||||
|
||||
[`ollama-for-amd`](https://github.com/likelovewant/ollama-for-amd) is a
|
||||
community fork that provides support for many AMD GPUs.
|
||||
|
||||
[Installers](https://github.com/ByronLeeeee/Ollama-For-AMD-Installer/releases)
|
||||
are also provided by the community.
|
||||
|
||||
There are separate drivers for each GPU family. The following GPUs were tested:
|
||||
|
||||
| Name | GPU | Identifier |
|
||||
|:-----------------|:--------|:-----------|
|
||||
| AMD AI PRO R9700 | Navi 48 | `gfx1200` |
|
||||
| AMD RX 9070 XT | Navi 48 | `gfx1201` |
|
||||
| AND RX 7900 XTX | Navi 31 | `gfx1100` |
|
||||
|
||||
When this demo was last tested, the installer claimed `gfx1200` corresponded to
|
||||
Navi 48. `gfx1200` should be used for the PRO R9700, while `gfx1201` should be
|
||||
used for the 9070 XT.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>AMD Instructions on Linux</b> (click to show)</summary>
|
||||
|
||||
The official Ollama release is compatible with AMD cards. However, in some test
|
||||
runs, Ollama will try to use the CPU. Some environment variables were required:
|
||||
|
||||
```bash
|
||||
export OLLAMA_USE_ROCM=1
|
||||
export OLLAMA_GPU_LAYERS=999
|
||||
export OLLAMA_VULKAN=1
|
||||
```
|
||||
|
||||
In addition, `HSA_OVERRIDE_GFX_VERSION` must be set to a specific version based
|
||||
on the card, which may not match the official version:
|
||||
|
||||
| Name | Value | Command |
|
||||
|:-----------------|:---------|:-------------------------------------------|
|
||||
| AMD AI PRO R9700 | `12.0.0` | `export HSA_OVERRIDE_GFX_VERSION="12.0.0"` |
|
||||
| AMD RX 9070 XT | `12.0.0` | `export HSA_OVERRIDE_GFX_VERSION="12.0.0"` |
|
||||
| AND RX 7900 XTX | `11.0.0` | `export HSA_OVERRIDE_GFX_VERSION="11.0.0"` |
|
||||
|
||||
These environment variables may not be used by the Ollama service, so it is
|
||||
strongly recommended to stop the default service and run `ollama serve` in a
|
||||
separate terminal window.
|
||||
|
||||
</details>
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="llama-cpp" label="llama.cpp">
|
||||
|
||||
[The "Quick Start" section](https://github.com/ggml-org/llama.cpp#quick-start)
|
||||
of the `llama.cpp` documentation recommends pre-built binaries.
|
||||
|
||||
Package managers typically include generic versions that support CPU inference
|
||||
and Vulkan. They do not typically support CUDA, ROCm/HIP, or SYCL. It is
|
||||
strongly recommended to manually download and run a specific release:
|
||||
|
||||
<details>
|
||||
<summary><b>NVIDIA Instructions on Windows</b> (click to show)</summary>
|
||||
|
||||
In a new PowerShell window, run `nvidia-smi` and look for "CUDA version". It
|
||||
will be in the first row of the table:
|
||||
|
||||
```text title="Sample output when last tested"
|
||||
+-----------------------------------------------------------------------------------------+
|
||||
| NVIDIA-SMI 596.36 Driver Version: 596.36 CUDA Version: 13.2 |
|
||||
+-----------------------------------------+------------------------+----------------------+
|
||||
```
|
||||
|
||||
In [the "Releases" section](https://github.com/ggml-org/llama.cpp/releases),
|
||||
download the "Windows x64 (CUDA)" and "CUDA DLLs" for the matching CUDA version.
|
||||
|
||||
For example, when this demo was last tested, `nvidia-smi` listed CUDA 13.2. This
|
||||
corresponds to the "Windows x64 (CUDA 13)" release and the "CUDA 13.1 DLLs":
|
||||
|
||||
```pwsh
|
||||
cd ~/Downloads
|
||||
mkdir llama
|
||||
cd llama
|
||||
curl.exe -LO https://github.com/ggml-org/llama.cpp/releases/download/b9012/llama-b9012-bin-win-cuda-13.1-x64.zip
|
||||
Expand-Archive llama-*.zip -DestinationPath "."
|
||||
curl.exe -LO https://github.com/ggml-org/llama.cpp/releases/download/b9033/cudart-llama-bin-win-cuda-13.1-x64.zip
|
||||
Expand-Archive cudart-*.zip -DestinationPath "."
|
||||
```
|
||||
|
||||
If `llama.cpp` can detect relevant GPUs, `./llama-cli.exe --list-devices` will
|
||||
list a CUDA device under "Available devices". The following output was captured
|
||||
on a machine with a RTX 5090:
|
||||
|
||||
```text title="Devices detected by llama.cpp"
|
||||
> ./llama-cli.exe --list-devices
|
||||
...
|
||||
Available devices:
|
||||
// highlight-next-line
|
||||
CUDA0: NVIDIA GeForce RTX 5090 (32606 MiB, 30994 MiB free)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>AMD Instructions on Windows</b> (click to show)</summary>
|
||||
|
||||
[The `llamacpp-rocm` project](https://github.com/lemonade-sdk/llamacpp-rocm)
|
||||
builds `llama.cpp` binaries with ROCm support. There are specific releases for
|
||||
different families of GPUs. The following GPUs were tested:
|
||||
|
||||
| Name | Identifier |
|
||||
|:--------------------------|:-----------|
|
||||
| Radeon 890M (Strix Point) | `gfx1150` |
|
||||
|
||||
The Windows release artifact for the specific `gfx` version musta be downloaded.
|
||||
For example, Strix Point uses `gfx1150`:
|
||||
|
||||
```pwsh
|
||||
cd ~/Downloads
|
||||
mkdir llama
|
||||
cd llama
|
||||
curl.exe -LO https://github.com/lemonade-sdk/llamacpp-rocm/releases/download/b1265/llama-b1265-windows-rocm-gfx1150-x64.zip
|
||||
Expand-Archive llama-*.zip -DestinationPath "."
|
||||
```
|
||||
|
||||
If `llama.cpp` can detect relevant GPUs, `./llama-cli.exe --list-devices` will
|
||||
list a ROCm device under "Available devices". The following output was captured
|
||||
on a Strix Point machine:
|
||||
|
||||
```text title="Devices detected by llama.cpp"
|
||||
> ./llama-cli.exe --list-devices
|
||||
...
|
||||
Available devices:
|
||||
// highlight-next-line
|
||||
ROCm0: AMD Radeon(TM) 890M Graphics (26989 MiB, 26837 MiB free)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
After installing dependencies, start a new terminal session.
|
||||
|
||||
1) Create a new project:
|
||||
@ -853,7 +1052,7 @@ npm i --save https://sheet.lol/balls/xlsx-${current}.tgz`}
|
||||
4) Install dependencies:
|
||||
|
||||
```bash
|
||||
npm i --save @langchain/core@0.3.44 langchain@0.3.21 @langchain/ollama@0.2.0 peggy@3.0.2
|
||||
npm i --save @langchain/core@1.1.15 langchain@1.2.10 @langchain/classic@1.0.9 @langchain/ollama@1.2.0 @langchain/openai@1.2.0 peggy@5.0.6
|
||||
```
|
||||
|
||||
:::note pass
|
||||
@ -862,7 +1061,7 @@ In some test runs, there were error messages relating to dependency and peer
|
||||
dependency versions. The `--force` flag will suppress version mismatch errors:
|
||||
|
||||
```bash
|
||||
npm i --save @langchain/core@0.3.44 langchain@0.3.21 @langchain/ollama@0.2.0 peggy@3.0.2 --force
|
||||
npm i --save @langchain/core@1.1.15 langchain@1.2.10 @langchain/classic@1.0.9 @langchain/ollama@1.2.0 @langchain/openai@1.2.0 peggy@5.0.6 --force
|
||||
```
|
||||
|
||||
:::
|
||||
@ -889,16 +1088,19 @@ curl.exe -LO https://docs.sheetjs.com/cd.xls
|
||||
|
||||
:::
|
||||
|
||||
6) Install the `llama3-chatqa:8b-v1.5-q8_0` model using Ollama:
|
||||
6) Install the `phi4:14b` model:
|
||||
|
||||
<Tabs groupId="llm">
|
||||
<TabItem value="ollama" label="Ollama">
|
||||
|
||||
```bash
|
||||
ollama pull llama3-chatqa:8b-v1.5-q8_0
|
||||
ollama pull phi4:14b
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary><b>Additional steps for Intel GPUs</b> (click to show)</summary>
|
||||
<summary><b>Additional steps for Intel GPUs and AMD Strix Halo</b> (click to show)</summary>
|
||||
|
||||
A different embedding model must be used on Intel GPUs:
|
||||
A different embedding model must be used on Intel GPUs and AMD Strix Halo:
|
||||
|
||||
A) Install the `nomic-embed-text:latest` model through Ollama:
|
||||
|
||||
@ -916,7 +1118,96 @@ const embeddings = new OllamaEmbeddings({ baseUrl: "http://127.0.0.1:11434", mod
|
||||
|
||||
</details>
|
||||
|
||||
7) Run the demo script
|
||||
7) Run the demo script:
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="llama-cpp" label="llama.cpp">
|
||||
|
||||
[The official `phi-4-gguf` repo](https://huggingface.co/microsoft/phi-4-gguf)
|
||||
includes `llama.cpp`-compatible weights. `Q4_K` weights should be downloaded to
|
||||
the same folder as the `llama.cpp` package.
|
||||
|
||||
[`nomic-embed-text`](https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF)
|
||||
is the recommended embedding model. The `Q8_0` weights should be downloaded.
|
||||
|
||||
```bash
|
||||
cd ~/Downloads/llama
|
||||
curl -LO https://huggingface.co/microsoft/phi-4-gguf/resolve/main/phi-4-Q4_K.gguf
|
||||
curl -LO https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF/resolve/main/nomic-embed-text-v1.5.Q8_0.gguf
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
In PowerShell, the command may fail with a parameter error:
|
||||
|
||||
```
|
||||
Invoke-WebRequest : A parameter cannot be found that matches parameter name 'LO'.
|
||||
```
|
||||
|
||||
`curl.exe` must be invoked directly:
|
||||
|
||||
```pwsh
|
||||
cd ~/Downloads/llama
|
||||
curl.exe -LO https://huggingface.co/microsoft/phi-4-gguf/resolve/main/phi-4-Q4_K.gguf
|
||||
curl.exe -LO https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF/resolve/main/nomic-embed-text-v1.5.Q8_0.gguf
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
7) Serve the generation model with `llama-server` in a separate window:
|
||||
|
||||
```bash title="Serve Phi4 (in a new window)"
|
||||
cd ~/Downloads/llama
|
||||
./llama-server -m ./phi-4-Q4_K.gguf -ngl 99 --host 0.0.0.0 --port 11434
|
||||
```
|
||||
|
||||
When the service is ready, the terminal will display:
|
||||
|
||||
```
|
||||
main: server is listening on http://0.0.0.0:11434
|
||||
```
|
||||
|
||||
Leave this window running in the background.
|
||||
|
||||
8) Serve the embedding model with `llama-server` in a new window:
|
||||
|
||||
```bash title="Serve nomic-embed-text (in a new window)"
|
||||
cd ~/Downloads/llama
|
||||
./llama-server -m ./nomic-embed-text-v1.5.Q8_0.gguf -ngl 99 --host 0.0.0.0 --port 11433 --embeddings
|
||||
```
|
||||
|
||||
When the service is ready, the terminal will display:
|
||||
|
||||
```
|
||||
main: server is listening on http://0.0.0.0:11433
|
||||
```
|
||||
|
||||
Leave this window running in the background.
|
||||
|
||||
9) Edit `query.mjs` to use the local OpenAI-compatible servers:
|
||||
|
||||
```js title="query.mjs (snippet, edit highlighted line)"
|
||||
// highlight-start
|
||||
import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai";
|
||||
// highlight-end
|
||||
import { MemoryVectorStore } from "@langchain/classic/vectorstores/memory";
|
||||
|
||||
// ...
|
||||
|
||||
console.log(`Using model ${model}`);
|
||||
|
||||
// highlight-start
|
||||
const llm = new ChatOpenAI({ apiKey: "not-needed", configuration: { baseURL: "http://127.0.0.1:11434/v1" }, model });
|
||||
const embeddings = new OpenAIEmbeddings({ apiKey: "not-needed", configuration: { baseURL: "http://127.0.0.1:11433/v1" }, model: "nomic-embed-text:latest"});
|
||||
// highlight-end
|
||||
|
||||
// ...
|
||||
```
|
||||
|
||||
10) Run the demo script:
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
```bash
|
||||
node query.mjs
|
||||
@ -974,5 +1265,5 @@ charts, tables, and other features.
|
||||
[^6]: See ["Supported Output Formats" type in "Writing Files"](/docs/api/write-options#supported-output-formats)
|
||||
[^7]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^8]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^9]: See [the official ChatQA website](https://chatqa-project.github.io/) for the ChatQA paper and other model details.
|
||||
[^9]: See [the Phi-4 Technical Report](https://arxiv.org/abs/2412.08905) for more details.
|
||||
[^10]: Select ["Windows" `x86_64`](https://conda-forge.org/download/) in the Installation page.
|
||||
|
||||
@ -40,9 +40,9 @@ This browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 133 | 2025-03-30 |
|
||||
| Safari 18.3 | 2025-03-30 |
|
||||
| Konqueror 22 | 2025-04-23 |
|
||||
| Chromium 146 | 2026-05-07 |
|
||||
| Safari 26.2 | 2026-05-07 |
|
||||
| Konqueror 25 | 2026-05-07 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ pagination_next: demos/frontend/index
|
||||
---
|
||||
|
||||
<head>
|
||||
<script src="https://cdn.jsdelivr.net/npm/danfojs@1.1.2/lib/bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/danfojs@1.2.0/lib/bundle.min.js"></script>
|
||||
</head>
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
@ -23,8 +23,8 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Platform | Version | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| Chromium 131 | `1.1.2` | 2025-01-01 |
|
||||
| Safari 18.2 | `1.1.2` | 2025-01-01 |
|
||||
| Chromium 147 | `1.2.0` | 2026-05-22 |
|
||||
| Safari 18.5 | `1.2.0` | 2025-06-16 |
|
||||
| Konqueror 22 | `1.1.2` | 2025-04-23 |
|
||||
|
||||
:::
|
||||
@ -34,7 +34,7 @@ This demo was tested in the following deployments:
|
||||
The live demos on this page include the DanfoJS browser bundle:
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/danfojs@1.1.2/lib/bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/danfojs@1.2.0/lib/bundle.min.js"></script>
|
||||
```
|
||||
|
||||
There are known issues with the documentation generator. If a demo explicitly
|
||||
|
||||
@ -36,7 +36,7 @@ Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | TF.js | Date |
|
||||
|:-------------|:----------|:-----------|
|
||||
| Chromium 133 | `4.22.0` | 2025-04-21 |
|
||||
| Chromium 147 | `4.22.0` | 2026-05-22 |
|
||||
| Safari 18.3 | `4.22.0` | 2025-04-21 |
|
||||
| Konqueror 22 | `4.22.0` | 2025-04-23 |
|
||||
|
||||
@ -44,14 +44,15 @@ The NodeJS demo was tested in the following environments:
|
||||
|
||||
| NodeJS | TF.js | Date |
|
||||
|:------------|:----------|:-----------|
|
||||
| `22.14.0` | `4.22.0` | 2025-04-21 |
|
||||
| `20.18.0` | `4.22.0` | 2025-04-21 |
|
||||
| `24.13.0` | `4.22.0` | 2026-01-28 |
|
||||
| `22.22.0` | `4.22.0` | 2026-01-28 |
|
||||
| `20.20.0` | `4.22.0` | 2026-01-28 |
|
||||
|
||||
The Kaioken demo was tested in the following environments:
|
||||
|
||||
| Kaioken | TF.js | Date |
|
||||
|:------------|:----------|:-----------|
|
||||
| `0.37.0` | `4.22.0` | 2025-04-21 |
|
||||
| `0.44.3` | `4.22.0` | 2025-11-15 |
|
||||
|
||||
:::
|
||||
|
||||
@ -71,7 +72,7 @@ can be loaded after the TF.js standalone script.
|
||||
<!-- latest version of TF.js -->
|
||||
<script src="https://unpkg.com/@tensorflow/tfjs@latest/dist/tf.min.js"></script>
|
||||
<!-- use version ${current} -->
|
||||
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
|
||||
<script type="text/javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
|
||||
</CodeBlock>
|
||||
|
||||
#### Frameworks and Bundlers
|
||||
@ -417,7 +418,7 @@ The SheetJS team strongly recommends using Kaioken in projects using TF.js.
|
||||
1) Create a new site.
|
||||
|
||||
```bash
|
||||
npm create vite sheetjs-tfjs-kaioken -- --template vanilla-ts
|
||||
npm create vite sheetjs-tfjs-kaioken -- --template vanilla-ts --no-rolldown --no-interactive
|
||||
cd sheetjs-tfjs-kaioken
|
||||
npm add --save kaioken
|
||||
npm add --save vite-plugin-kaioken -D
|
||||
@ -443,7 +444,14 @@ export default defineConfig({
|
||||
"jsx": "preserve",
|
||||
```
|
||||
|
||||
4) Replace `src/main.ts` with the following codeblock:
|
||||
4) Edit `tsconfig.json` and remove any lines referencing `verbatimModuleSyntax`.
|
||||
When the demo was last tested, the file had the following line:
|
||||
|
||||
```js title="tsconfig.json (remove this line if present)"
|
||||
"verbatimModuleSyntax": true,
|
||||
```
|
||||
|
||||
5) Replace `src/main.ts` with the following codeblock:
|
||||
|
||||
```js title="src/main.ts"
|
||||
import { mount } from "kaioken";
|
||||
@ -453,19 +461,19 @@ const root = document.getElementById("app");
|
||||
mount(App, root!);
|
||||
```
|
||||
|
||||
5) Download [`SheetJSTF.tsx`](pathname:///tfjs/SheetJSTF.tsx) to the `src` directory:
|
||||
6) Download [`SheetJSTF.tsx`](pathname:///tfjs/SheetJSTF.tsx) to the `src` directory:
|
||||
|
||||
```bash
|
||||
curl -L -o src/SheetJSTF.tsx https://docs.sheetjs.com/tfjs/SheetJSTF.tsx
|
||||
```
|
||||
|
||||
6) Install SheetJS and TF.js dependencies:
|
||||
7) Install SheetJS and TF.js dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @tensorflow/tfjs`}
|
||||
</CodeBlock>
|
||||
|
||||
7) Start the development server:
|
||||
8) Start the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
@ -40,12 +40,12 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | JS Engine | Pandas | Python | Date |
|
||||
|:-------------|:----------------|:-------|:-------|:-----------|
|
||||
| `darwin-x64` | Duktape `2.7.0` | 2.2.3 | 3.13.1 | 2025-03-31 |
|
||||
| `darwin-arm` | Duktape `2.7.0` | 2.2.3 | 3.13.2 | 2025-03-30 |
|
||||
| `win11-x64` | Duktape `2.7.0` | 2.2.3 | 3.11.8 | 2024-12-21 |
|
||||
| `win11-arm` | Duktape `2.7.0` | 2.2.3 | 3.13.2 | 2025-02-23 |
|
||||
| `linux-x64` | Duktape `2.7.0` | 1.5.3 | 3.11.7 | 2025-01-01 |
|
||||
| `linux-arm` | Duktape `2.7.0` | 1.5.3 | 3.11.2 | 2025-02-16 |
|
||||
| `darwin-x64` | Duktape `2.7.0` | 3.0.1 | 3.13.7 | 2026-03-07 |
|
||||
| `darwin-arm` | Duktape `2.7.0` | 2.3.3 | 3.9.6 | 2026-01-25 |
|
||||
| `win11-x64` | Duktape `2.7.0` | 3.0.1 | 3.11.9 | 2026-03-08 |
|
||||
| `win11-arm` | Duktape `2.7.0` | 2.2.3 | 3.11.5 | 2026-03-07 |
|
||||
| `linux-x64` | Duktape `2.7.0` | 3.0.1 | 3.13.9 | 2026-03-07 |
|
||||
| `linux-arm` | Duktape `2.7.0` | 2.2.3 | 3.13.5 | 2026-03-07 |
|
||||
|
||||
:::
|
||||
|
||||
@ -203,7 +203,7 @@ DataFrame. The DataFrame will be exported to the binary XLSB spreadsheet format.
|
||||
:::note pass
|
||||
|
||||
The Windows build requires Visual Studio with "Desktop development with C++".
|
||||
Commands must be run in a "Native Tools Command Prompt" session.
|
||||
**Commands must be run in a "Native Tools Command Prompt" session.**
|
||||
|
||||
:::
|
||||
|
||||
@ -215,6 +215,14 @@ python3 -m pip install pandas
|
||||
|
||||
:::info pass
|
||||
|
||||
On Windows, Python may be available as `python.exe`:
|
||||
|
||||
```bash
|
||||
python.exe -m pip install pandas
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
On macOS and Linux, the install command may require root access:
|
||||
|
||||
```bash
|
||||
@ -305,15 +313,13 @@ cd ..
|
||||
</TabItem>
|
||||
<TabItem value="win11-x64" label="Windows">
|
||||
|
||||
- Download and extract the source tarball. Commands must be run in WSL `bash`:
|
||||
- Download and extract the source tarball:
|
||||
|
||||
```bash
|
||||
curl -LO https://duktape.org/duktape-2.7.0.tar.xz
|
||||
tar -xJf duktape-2.7.0.tar.xz
|
||||
```
|
||||
|
||||
(Run `bash`, then run the aforementioned commands, then run `exit` to exit WSL)
|
||||
|
||||
- Enter the source folder:
|
||||
|
||||
```bash
|
||||
@ -472,6 +478,17 @@ def eval_file(ctx, path):
|
||||
python3 SheetJSPandas.py pres.numbers
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
On Windows, Python may be available as `python.exe`:
|
||||
|
||||
```bash
|
||||
python.exe SheetJSPandas.py pres.numbers
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
|
||||
If successful, the script will display DataFrame metadata:
|
||||
|
||||
```
|
||||
@ -525,14 +542,14 @@ The Pandas example requires a few slight changes to work with Polars:
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | JS Engine | Polars | Python | Date |
|
||||
|:-------------|:----------------|:--------|:-------|:-----------|
|
||||
| `darwin-x64` | Duktape `2.7.0` | 1.26.0 | 3.13.1 | 2025-03-31 |
|
||||
| `darwin-arm` | Duktape `2.7.0` | 1.26.0 | 3.13.2 | 2025-03-30 |
|
||||
| `win11-x64` | Duktape `2.7.0` | 1.17.1 | 3.11.8 | 2024-12-21 |
|
||||
| `win11-arm` | Duktape `2.7.0` | 1.23.0 | 3.13.2 | 2025-02-23 |
|
||||
| `linux-x64` | Duktape `2.7.0` | 1.18.0 | 3.11.7 | 2025-01-01 |
|
||||
| `linux-arm` | Duktape `2.7.0` | 1.22.0 | 3.11.2 | 2025-02-16 |
|
||||
| Architecture | JS Engine | Polars | Python | Date |
|
||||
|:-------------|:----------------|:-------|:-------|:-----------|
|
||||
| `darwin-x64` | Duktape `2.7.0` | 1.38.1 | 3.13.7 | 2026-03-07 |
|
||||
| `darwin-arm` | Duktape `2.7.0` | 1.36.1 | 3.9.6 | 2026-01-25 |
|
||||
| `win11-x64` | Duktape `2.7.0` | 1.38.1 | 3.11.9 | 2026-03-08 |
|
||||
| `win11-arm` | Duktape `2.7.0` | 1.23.0 | 3.11.5 | 2026-03-07 |
|
||||
| `linux-x64` | Duktape `2.7.0` | 1.38.1 | 3.13.9 | 2026-03-07 |
|
||||
| `linux-arm` | Duktape `2.7.0` | 1.38.1 | 3.13.5 | 2026-03-07 |
|
||||
|
||||
:::
|
||||
|
||||
@ -599,10 +616,18 @@ python3 -m pip install polars
|
||||
|
||||
:::info pass
|
||||
|
||||
On Windows, Python may be available as `python.exe`:
|
||||
|
||||
```bash
|
||||
python.exe -m pip install polars
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
On macOS and Linux, the install command may require root access:
|
||||
|
||||
```bash
|
||||
sudo python3 -m pip install pandas
|
||||
sudo python3 -m pip install polars
|
||||
```
|
||||
|
||||
:::
|
||||
@ -631,7 +656,7 @@ It is recommended to use a virtual environment.
|
||||
- Debian and Ubuntu distributions:
|
||||
|
||||
```bash
|
||||
sudo apt-get install python3.11-venv
|
||||
sudo apt-get install python3-venv
|
||||
```
|
||||
|
||||
- `venv` is included in the `python` package in Arch Linux-based platforms.
|
||||
@ -662,6 +687,16 @@ cp ../libduktape.* ../SheetJSPandas.py ../sheetjs.py ../*.js ../*.numbers .
|
||||
python3 SheetJSPandas.py pres.numbers
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
On Windows, Python may be available as `python.exe`:
|
||||
|
||||
```bash
|
||||
python.exe SheetJSPandas.py pres.numbers
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::note pass
|
||||
|
||||
If the virtual environment was configured in the previous step, run:
|
||||
@ -692,7 +727,7 @@ shape: (5, 2)
|
||||
It will also export the DataFrame to `SheetJSPolars.xlsb`. The file can be
|
||||
inspected with a spreadsheet editor that supports XLSB files.
|
||||
|
||||
[^1]: See ["Other Languages"](/docs/demos/engines/) for more examples.
|
||||
[^1]: See ["JavaScript Engines"](/docs/demos/engines/) for more examples.
|
||||
[^2]: See [`ctypes`](https://docs.python.org/3/library/ctypes.html) in the Python documentation.
|
||||
[^3]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^4]: See ["Workbook Object"](/docs/csf/book)
|
||||
|
||||
@ -360,9 +360,9 @@ export default function SheetJSKaiokenAoO() {
|
||||
{ /* error message */
|
||||
!pres && !loading && ( <tr><td colSpan="2">{error.message}</td></tr> )
|
||||
}
|
||||
</tbody><tfoot><td colSpan={2}>
|
||||
</tbody><tfoot><tr><td colSpan={2}>
|
||||
<button onclick={exportFile}>Export XLSX</button>
|
||||
</td></tfoot></table>);
|
||||
</td></tr></tfoot></table>);
|
||||
}
|
||||
```
|
||||
|
||||
@ -429,9 +429,9 @@ export default function SheetJSKaiokenAoO() {
|
||||
<td>{pres.Index}</td>
|
||||
</tr>))
|
||||
}
|
||||
</tbody><tfoot><td colSpan={2}>
|
||||
</tbody><tfoot><tr><td colSpan={2}>
|
||||
<button onclick={exportFile}>Export XLSX</button>
|
||||
</td></tfoot></table>);
|
||||
</td></tr></tfoot></table>);
|
||||
}
|
||||
```
|
||||
|
||||
@ -450,14 +450,14 @@ This demo was tested in the following environments:
|
||||
|
||||
| Kaioken | ViteJS | Date |
|
||||
|:----------|:--------|:-----------|
|
||||
| `0.35.10` | `6.1.0` | 2025-02-11 |
|
||||
| `0.44.3` | `6.4.1` | 2026-03-14 |
|
||||
|
||||
:::
|
||||
|
||||
1) Create a new site.
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-kaioken -- --template vanilla-ts
|
||||
npm create vite@latest sheetjs-kaioken -- --template vanilla-ts --no-rolldown --no-interactive
|
||||
cd sheetjs-kaioken
|
||||
npm add --save kaioken
|
||||
npm add --save vite-plugin-kaioken -D
|
||||
@ -518,7 +518,7 @@ The generated site will be placed in the `dist` folder.
|
||||
9) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -597,14 +597,14 @@ This demo was tested in the following environments:
|
||||
|
||||
| Kaioken | ViteJS | Date |
|
||||
|:----------|:--------|:-----------|
|
||||
| `0.35.10` | `6.1.0` | 2025-02-11 |
|
||||
| `0.44.3` | `6.4.1` | 2026-03-14 |
|
||||
|
||||
:::
|
||||
|
||||
1) Create a new site.
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-kaioken -- --template vanilla-ts
|
||||
npm create vite@latest sheetjs-kaioken -- --template vanilla-ts --no-rolldown --no-interactive
|
||||
cd sheetjs-kaioken
|
||||
npm add --save kaioken
|
||||
npm add --save vite-plugin-kaioken -D
|
||||
@ -665,7 +665,7 @@ The generated site will be placed in the `dist` folder.
|
||||
9) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
|
||||
@ -135,7 +135,7 @@ The SheetJS [`read`](/docs/api/parse-options) and [`sheet_to_json`](/docs/api/ut
|
||||
functions simplify state updates. They are best used in the function bodies of
|
||||
`useEffect`[^2] and `useCallback`[^3] hooks.
|
||||
|
||||
A `useEffect` hook can download and update state when a person loads the site:
|
||||
A `useEffect` hook can download and update state when the site is loaded:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
@ -150,12 +150,13 @@ flowchart LR
|
||||
wb --> |wb.Sheets\nselect sheet| ws
|
||||
ws --> |sheet_to_json\n\n| aoo
|
||||
aoo --> |setPres\nfrom `setState`| state
|
||||
linkStyle 1,2,3 color:blue,stroke:blue;
|
||||
```
|
||||
|
||||
<Tabs groupId="lang">
|
||||
<TabItem name="JS" value="JavaScript">
|
||||
|
||||
```js
|
||||
```js title="In a useEffect hook, update state with data from a remote workbook"
|
||||
import { useEffect } from 'react';
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
@ -182,7 +183,7 @@ useEffect(() => { (async() => {
|
||||
</TabItem>
|
||||
<TabItem name="TS" value="TypeScript" default>
|
||||
|
||||
```ts
|
||||
```ts title="In a useEffect hook, update state with data from a remote workbook"
|
||||
import { useEffect } from 'react';
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
@ -252,9 +253,10 @@ flowchart LR
|
||||
state --> |json_to_sheet\n\n| ws
|
||||
ws --> |book_new\nbook_append_sheet| wb
|
||||
wb --> |writeFile\n\n| file
|
||||
linkStyle 0,1,2 color:blue,stroke:blue;
|
||||
```
|
||||
|
||||
```ts
|
||||
```ts title="Export data from state to a new XLSX workbook"
|
||||
import { useCallback } from 'react';
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
|
||||
@ -332,14 +334,14 @@ This demo was tested in the following environments:
|
||||
|
||||
| ReactJS | ViteJS | Date |
|
||||
|:---------|:--------|:-----------|
|
||||
| `18.3.1` | `6.0.1` | 2024-12-12 |
|
||||
| `19.1.0` | `6.3.5` | 2025-05-11 |
|
||||
|
||||
:::
|
||||
|
||||
1) Create a new site:
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-react -- --template react
|
||||
npm create vite@latest sheetjs-react -- --template react --no-rolldown --no-interactive
|
||||
```
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
@ -369,7 +371,7 @@ The generated site will be placed in the `dist` folder.
|
||||
6) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -384,23 +386,14 @@ This demo was tested in the following environments:
|
||||
|
||||
| ReactJS | CRA | Date |
|
||||
|:---------|:--------|:-----------|
|
||||
| `18.2.0` | `5.0.1` | 2024-12-12 |
|
||||
| `19.1.0` | `5.1.0` | 2025-05-11 |
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
CRA has known compatibility issues with React 19[^5]. CRA no longer receives
|
||||
updates and the ReactJS docs no longer recommend using CRA. For new projects, it
|
||||
is strongly recommended to use ViteJS with the `react` or `react-ts` templates.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
1) Create a new site:
|
||||
|
||||
```bash
|
||||
npx -y create-react-app@5.0.1 --scripts-version=5.0.1 sheetjs-react
|
||||
npx -y create-react-app@5.1.0 sheetjs-react
|
||||
```
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
@ -408,7 +401,7 @@ npx -y create-react-app@5.0.1 --scripts-version=5.0.1 sheetjs-react
|
||||
<CodeBlock language="bash">{`\
|
||||
cd sheetjs-react
|
||||
npm i
|
||||
npm i react@18.2.0 react-dom@18.2.0 web-vitals --save --save-exact
|
||||
npm i react@19.1.0 react-dom@19.1.0 web-vitals --save --save-exact
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm start`}
|
||||
</CodeBlock>
|
||||
@ -431,7 +424,7 @@ The generated site will be placed in the `build` folder.
|
||||
6) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server build
|
||||
npx -y http-server build
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -446,7 +439,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| ReactJS | NextJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `19.0.0` | `15.1.0` | 2024-12-13 |
|
||||
| `19.1.0` | `15.3.2` | 2025-05-11 |
|
||||
|
||||
:::
|
||||
|
||||
@ -567,7 +560,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Preact | ViteJS | Date |
|
||||
|:----------|:----------|:-----------|
|
||||
| `10.22.1` | `5.3.3` | 2024-12-17 |
|
||||
| `10.26.6` | `5.4.19` | 2025-05-11 |
|
||||
|
||||
:::
|
||||
|
||||
@ -578,7 +571,12 @@ npm init preact sheetjs-preact
|
||||
```
|
||||
|
||||
This will initiate the project creation process. **Follow the on-screen prompts and
|
||||
press Enter to accept the default options.**
|
||||
press Enter to accept the default options:**
|
||||
|
||||
- `Project language:` JavaScript
|
||||
- `Use router?` No
|
||||
- `Prerender app (SSG)?` No
|
||||
- `Use ESLint?` No
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
|
||||
@ -620,7 +618,7 @@ The generated site will be placed in the `dist` folder.
|
||||
7) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -641,10 +639,149 @@ The main disadvantage of the Array of Objects approach is the specific nature
|
||||
of the columns. For more general use, passing around an Array of Arrays works.
|
||||
However, this does not handle merge cells[^6] well!
|
||||
|
||||
HTML Tables support elements with `rowspan` and `colspan` attributes.
|
||||
|
||||
#### State
|
||||
|
||||
The state will be the serialized HTML string:
|
||||
|
||||
<Tabs groupId="lang">
|
||||
<TabItem name="JS" value="JavaScript">
|
||||
|
||||
```ts
|
||||
import { useState } from 'react';
|
||||
|
||||
/* the component state is a string */
|
||||
const [__html, setHtml] = useState("");
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem name="TS" value="TypeScript" default>
|
||||
|
||||
```ts
|
||||
import { useState } from 'react';
|
||||
|
||||
/* the component state is a string */
|
||||
const [__html, setHtml] = useState<string>("");
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::info Use of the variable name `__html`
|
||||
|
||||
Examples use the name `__html` due to the design of `dangerouslySetInnerHTML`.
|
||||
|
||||
`dangerouslySetInnerHTML` expects objects of the form `{ __html: "html code" }`.
|
||||
|
||||
For example, the following snippet assumes `html` is the variable name:
|
||||
|
||||
```jsx
|
||||
<div ref={tbl} dangerouslySetInnerHTML={{ __html: html }} />
|
||||
```
|
||||
|
||||
By using the name `__html`, the ES6 shorthand syntax simplifies the code:
|
||||
|
||||
```jsx
|
||||
<div ref={tbl} dangerouslySetInnerHTML={{ __html }} />
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
#### Updating State
|
||||
|
||||
The [`sheet_to_html`](/docs/api/utilities/html#html-table-output) function
|
||||
generates HTML that is aware of merges and other worksheet features. ReactJS
|
||||
`dangerouslySetInnerHTML`[^7] prop allows code to set the `innerHTML` attribute,
|
||||
effectively inserting the code into the page.
|
||||
generates HTML that is aware of merges and other worksheet features.
|
||||
|
||||
A `useEffect` hook can download and update state when the site is loaded:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
url[(Remote\nFile)]
|
||||
ab[(Data\nArrayBuffer)]
|
||||
wb(SheetJS\nWorkbook)
|
||||
ws(SheetJS\nWorksheet)
|
||||
html(HTML\nTABLE)
|
||||
state((component\nstate))
|
||||
url --> |fetch\n\n| ab
|
||||
ab --> |read\n\n| wb
|
||||
wb --> |wb.Sheets\nselect sheet| ws
|
||||
ws --> |sheet_to_html\n\n| html
|
||||
html --> |setHtml\nfrom `setState`| state
|
||||
linkStyle 1,2,3 color:blue,stroke:blue;
|
||||
```
|
||||
|
||||
```js title="In a useEffect hook, update state with HTML generated from a remote workbook"
|
||||
import { useEffect } from 'react';
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
/* Fetch and update the state once */
|
||||
useEffect(() => { (async() => {
|
||||
/* 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
|
||||
/* parse */
|
||||
const wb = read(ab);
|
||||
|
||||
/* generate HTML TABLE from first worksheet */
|
||||
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
|
||||
const data = utils.sheet_to_html(ws); // generate objects
|
||||
|
||||
/* update state */
|
||||
setHtml(data); // update state
|
||||
// highlight-end
|
||||
})(); }, []);
|
||||
```
|
||||
|
||||
#### Rendering Data
|
||||
|
||||
ReactJS `dangerouslySetInnerHTML`[^7] prop allows code to set the `innerHTML`
|
||||
attribute, effectively inserting the code into the page.
|
||||
|
||||
It is strongly recommended to set the `innerHTML` of a parent `DIV` container.
|
||||
By attaching a `ref`, callbacks will be able to access the live `TABLE` element.
|
||||
|
||||
```jsx title="Example JSX for displaying HTML TABLE code"
|
||||
<div ref={tbl} dangerouslySetInnerHTML={{ __html }} />
|
||||
```
|
||||
|
||||
#### Exporting Data
|
||||
|
||||
The [`writeFile`](/docs/api/write-options) and [`table_to_book`](/docs/api/utilities/html#html-table-input)
|
||||
functions simplify exporting data. They are best used in the function bodies of
|
||||
`useCallback`[^4] hooks attached to button or other elements.
|
||||
|
||||
A callback can generate a local file when a user clicks a button:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
state((component\nstate))
|
||||
wb(SheetJS\nWorkbook)
|
||||
file[(XLSX\nexport)]
|
||||
state --> |table_to_book\n\n| wb
|
||||
wb --> |writeFile\n\n| file
|
||||
linkStyle 0,1 color:blue,stroke:blue;
|
||||
```
|
||||
|
||||
```ts title="Export data from HTML TABLE element to a new XLSX workbook"
|
||||
import { useCallback } from 'react';
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
|
||||
/* get data from live HTML TABLE and export to XLSX */
|
||||
const exportFile = useCallback(() => {
|
||||
/* get live reference to HTML TABLE element */
|
||||
const elt = tbl.current.getElementsByTagName("TABLE")[0];
|
||||
/* generate workbook from element */
|
||||
// highlight-next-line
|
||||
const wb = utils.table_to_book(elt);
|
||||
/* export to XLSX */
|
||||
writeFile(wb, "SheetJSReactAoO.xlsx");
|
||||
}, [pres]);
|
||||
```
|
||||
|
||||
#### Complete Component
|
||||
|
||||
In this example, the component attaches a `ref` to the `DIV` container. During
|
||||
export, the first `TABLE` child element can be parsed with [`table_to_book`](/docs/api/utilities/html#html-table-input) to
|
||||
@ -701,14 +838,14 @@ This demo was tested in the following environments:
|
||||
|
||||
| ReactJS | ViteJS | Date |
|
||||
|:---------|:--------|:-----------|
|
||||
| `18.3.1` | `6.0.1` | 2024-12-13 |
|
||||
| `19.1.0` | `6.3.5` | 2025-05-11 |
|
||||
|
||||
:::
|
||||
|
||||
1) Create a new site:
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-react -- --template react
|
||||
npm create vite@latest sheetjs-react -- --template react --no-rolldown --no-interactive
|
||||
```
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
@ -738,7 +875,7 @@ The generated site will be placed in the `dist` folder.
|
||||
6) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -753,22 +890,14 @@ This demo was tested in the following environments:
|
||||
|
||||
| ReactJS | CRA | Date |
|
||||
|:---------|:--------|:-----------|
|
||||
| `18.2.0` | `5.0.1` | 2024-12-31 |
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
CRA has known compatibility issues with React 19[^5]. CRA no longer receives
|
||||
updates and the ReactJS docs no longer recommend using CRA. For new projects, it
|
||||
is strongly recommended to use ViteJS with the `react` or `react-ts` templates.
|
||||
| `19.1.0` | `5.1.0` | 2025-05-11 |
|
||||
|
||||
:::
|
||||
|
||||
1) Create a new site:
|
||||
|
||||
```bash
|
||||
npx -y create-react-app@5.0.1 --scripts-version=5.0.1 sheetjs-react
|
||||
npx -y create-react-app@5.1.0 sheetjs-react
|
||||
```
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
@ -776,7 +905,7 @@ npx -y create-react-app@5.0.1 --scripts-version=5.0.1 sheetjs-react
|
||||
<CodeBlock language="bash">{`\
|
||||
cd sheetjs-react
|
||||
npm i
|
||||
npm i react@18.2.0 react-dom@18.2.0 web-vitals --save --save-exact
|
||||
npm i react@19.1.0 react-dom@19.1.0 web-vitals --save --save-exact
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm start`}
|
||||
</CodeBlock>
|
||||
@ -799,7 +928,7 @@ The generated site will be placed in the `build` folder.
|
||||
6) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server build
|
||||
npx -y http-server build
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -812,9 +941,9 @@ and test the page.
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Preact | ViteJS | Date |
|
||||
|:----------|:--------|:-----------|
|
||||
| `10.22.1` | `5.3.3` | 2024-12-17 |
|
||||
| Preact | ViteJS | Date |
|
||||
|:----------|:---------|:-----------|
|
||||
| `10.26.6` | `5.4.19` | 2025-05-11 |
|
||||
|
||||
:::
|
||||
|
||||
@ -823,11 +952,15 @@ npm init preact sheetjs-preact
|
||||
```
|
||||
|
||||
This will initiate the project creation process. **Follow the on-screen prompts and
|
||||
press Enter to accept the default options.**
|
||||
press Enter to accept the default options:**
|
||||
|
||||
- `Project language:` JavaScript
|
||||
- `Use router?` No
|
||||
- `Prerender app (SSG)?` No
|
||||
- `Use ESLint?` No
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
cd sheetjs-preact
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
@ -866,7 +999,7 @@ The generated site will be placed in the `dist` folder.
|
||||
7) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -913,8 +1046,8 @@ const columns = Array.from({ length: range.e.c + 1 }, (_, i) => ({
|
||||
|
||||
## Legacy Deployments
|
||||
|
||||
[The Standalone Scripts](/docs/getting-started/installation/standalone) play nice
|
||||
with legacy deployments that do not use a bundler.
|
||||
[SheetJS Standalone Scripts](/docs/getting-started/installation/standalone) use
|
||||
simple `SCRIPT` tags and work with legacy deployments that do not use a bundler.
|
||||
|
||||
[The legacy demo](pathname:///react/index.html) shows a simple ReactJS component
|
||||
transpiled in the browser using Babel standalone library.
|
||||
|
||||
@ -321,9 +321,9 @@ interface President { Name: string; Index: number };
|
||||
<td>{{row.Index}}</td>
|
||||
</tr>
|
||||
// highlight-end
|
||||
</tbody><tfoot>
|
||||
</tbody><tfoot><tr><td colspan="2">
|
||||
<button (click)="onSave()">Export XLSX</button>
|
||||
</tfoot>
|
||||
</td></tr></tfoot>
|
||||
</table></div>
|
||||
`
|
||||
})
|
||||
@ -379,9 +379,9 @@ interface President { Name: string; Index: number };
|
||||
</tr>
|
||||
}
|
||||
// highlight-end
|
||||
</tbody><tfoot>
|
||||
</tbody><tfoot><tr><td colspan="2">
|
||||
<button (click)="onSave()">Export XLSX</button>
|
||||
</tfoot>
|
||||
</td></tr></tfoot>
|
||||
</table></div>
|
||||
`
|
||||
})
|
||||
@ -425,10 +425,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| Angular | Date |
|
||||
|:----------|:-----------|
|
||||
| `19.0.5` | 2025-01-03 |
|
||||
| `18.2.13` | 2025-01-03 |
|
||||
| `17.3.12` | 2025-01-03 |
|
||||
| `16.2.12` | 2025-01-03 |
|
||||
| `20.3.1` | 2026-03-12 |
|
||||
| `19.2.17` | 2026-03-12 |
|
||||
| `18.2.14` | 2026-03-12 |
|
||||
| `17.3.12` | 2026-03-12 |
|
||||
| `16.2.16` | 2026-03-12 |
|
||||
|
||||
:::
|
||||
|
||||
@ -441,7 +442,7 @@ npx @angular/cli analytics disable -g
|
||||
1) Create a new project:
|
||||
|
||||
```bash
|
||||
npx @angular/cli@19 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
npx @angular/cli@20 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
```
|
||||
|
||||
:::note pass
|
||||
@ -468,8 +469,20 @@ npm start`}
|
||||
3) Open a web browser and access the displayed URL (`http://localhost:4200`)
|
||||
|
||||
4) In the previous `src/app/app.component.ts` code snippet, select the tab for
|
||||
the appropriate version of Angular ("Angular 2-16" or "Angular 17+"), copy the
|
||||
code contents and replace `src/app/app.component.ts` in the project.
|
||||
the appropriate version of Angular ("Angular 2-16" or "Angular 17+") and copy
|
||||
the code. Replace `src/app/app.component.ts` or `src/app/app.ts` in the project.
|
||||
|
||||
For Angular 20+, after replacing `src/app/app.ts`, edit the script and change
|
||||
the exported class name to `App`:
|
||||
|
||||
```ts title="src/app/app.ts (edit highlighted line if file exists)"
|
||||
// ...
|
||||
})
|
||||
// highlight-next-line
|
||||
export class App {
|
||||
rows: President[] = [ { Name: "SheetJS", Index: 0 }];
|
||||
// ...
|
||||
```
|
||||
|
||||
The page will refresh and show a table with an Export button. Click the button
|
||||
and the page will attempt to download `SheetJSAngularAoO.xlsx`. Open the file
|
||||
@ -621,10 +634,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| Angular | Date |
|
||||
|:----------|:-----------|
|
||||
| `19.0.5` | 2025-01-03 |
|
||||
| `18.2.13` | 2025-01-03 |
|
||||
| `17.3.12` | 2025-01-03 |
|
||||
| `16.2.12` | 2025-01-03 |
|
||||
| `20.3.1` | 2026-03-12 |
|
||||
| `19.2.17` | 2026-03-12 |
|
||||
| `18.2.14` | 2026-03-12 |
|
||||
| `17.3.12` | 2026-03-12 |
|
||||
| `16.2.16` | 2026-03-12 |
|
||||
|
||||
:::
|
||||
|
||||
@ -637,7 +651,7 @@ npx @angular/cli analytics disable -g
|
||||
1) Create a new project:
|
||||
|
||||
```bash
|
||||
npx @angular/cli@19 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
npx @angular/cli@20 new --minimal --defaults --no-interactive sheetjs-angular
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
@ -37,12 +37,20 @@ This demo focuses on VueJS concepts. Other demos cover general deployments:
|
||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
|
||||
installation with Yarn and other package managers.
|
||||
|
||||
The library can be imported directly from JS or JSX code with:
|
||||
In modern sites, the library can be imported directly from JS or JSX code:
|
||||
|
||||
```js
|
||||
import { read, utils, writeFile } from 'xlsx';
|
||||
```
|
||||
|
||||
In projects that use CommonJS, the library can be loaded with `require`:
|
||||
|
||||
```js
|
||||
var XLSX = require("xlsx");
|
||||
```
|
||||
|
||||
["Legacy Deployments"](#legacy-deployments) covers integration strategies for
|
||||
sites that require standalone scripts.
|
||||
|
||||
## Internal State
|
||||
|
||||
@ -51,14 +59,15 @@ 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.
|
||||
Typically, users will create a spreadsheet with data that should be imported to
|
||||
the site. The data sheets will typically store headers in the first row. In some
|
||||
applications, the data will follow a standardized template.
|
||||
|
||||
#### State
|
||||
|
||||
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, where the keys are specified in the first row:
|
||||
object for each data row, where the values in the first row are used as keys:
|
||||
|
||||
<table>
|
||||
<thead><tr><th>Spreadsheet</th><th>State</th></tr></thead>
|
||||
@ -106,7 +115,8 @@ const pres = ref<any[]>([]);
|
||||
</script>
|
||||
```
|
||||
|
||||
When the spreadsheet header row is known ahead of time, row typing is possible:
|
||||
`ref` is a generic method in TypeScript. If the spreadsheet header row is known
|
||||
ahead of time, each row object can be typed:
|
||||
|
||||
```html
|
||||
<script setup lang="ts">
|
||||
@ -341,28 +351,29 @@ function exportFile() {
|
||||
<td>{{ row.Name }}</td>
|
||||
<td>{{ row.Index }}</td>
|
||||
</tr>
|
||||
</tbody><tfoot><td colSpan={2}>
|
||||
</tbody><tfoot><tr><td colSpan={2}>
|
||||
<button @click="exportFile">Export XLSX</button>
|
||||
</td></tfoot></table>
|
||||
</td></tr></tfoot></table>
|
||||
</template>
|
||||
```
|
||||
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| VueJS | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `3.5.13` | `6.1.0` | 2025-02-15 |
|
||||
| VueJS | Deployment | Date |
|
||||
|:---------|:----------------|:-----------|
|
||||
| `3.5.17` | ViteJS `7.0.0` | 2025-06-29 |
|
||||
| `3.5.17` | NuxtJS `3.17.5` | 2025-06-29 |
|
||||
|
||||
:::
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
|
||||
1) Create a new site:
|
||||
|
||||
```bash
|
||||
@ -378,7 +389,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm run dev`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Open a web browser and access the displayed URL (`http://localhost:5173`)
|
||||
3) Access the "Local" URL (typically `http://localhost:5173`) in a web browser.
|
||||
|
||||
4) Replace `src/App.vue` with the `src/SheetJSVueAoO.vue` example.
|
||||
|
||||
@ -397,7 +408,7 @@ The generated site will be placed in the `dist` folder.
|
||||
6) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -406,20 +417,10 @@ and test the page.
|
||||
</TabItem>
|
||||
<TabItem name="nuxt" value="NuxtJS">
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| VueJS | NuxtJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `3.5.13` | `3.15.0` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
1) Create a new site:
|
||||
|
||||
```bash
|
||||
npx nuxi@latest init sheetjs-nuxt --packageManager npm --no-install --no-gitInit
|
||||
npx nuxi@latest init sheetjs-nuxt --packageManager npm --no-install --no-gitInit -M ,
|
||||
```
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
@ -431,7 +432,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm run dev`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Open a web browser and access the displayed URL (`http://localhost:3000`)
|
||||
3) Access the "Local" URL (typically `http://localhost:3000`) in a web browser.
|
||||
|
||||
4) Replace `app.vue` with the `src/SheetJSVueAoO.vue` example.
|
||||
|
||||
@ -449,7 +450,7 @@ The generated site will be placed in the `dist` folder.
|
||||
6) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server .output/public/
|
||||
npx -y http-server .output/public/
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -462,18 +463,19 @@ and test the page.
|
||||
|
||||
### HTML
|
||||
|
||||
The main disadvantage of the Array of Objects approach is the specific nature
|
||||
The main disadvantage of the "Array of Objects" approach is the specific nature
|
||||
of the columns. For more general use, passing around an Array of Arrays works.
|
||||
However, this does not handle merge cells[^5] well!
|
||||
However, this does not handle merged cells[^5] well!
|
||||
|
||||
The [`sheet_to_html`](/docs/api/utilities/html#html-table-output) function
|
||||
generates HTML that is aware of merges and other worksheet features. VueJS
|
||||
`v-html`[^6] attribute allows code to set the `innerHTML` attribute, effectively
|
||||
inserting the code into the page.
|
||||
|
||||
In this example, the component attaches a `ref` to the `DIV` container. During
|
||||
export, the first `TABLE` child element can be parsed with [`table_to_book`](/docs/api/utilities/html#html-table-input) to
|
||||
generate a workbook object.
|
||||
In this example, the component attaches a `ref` to the `DIV` container. When the
|
||||
"Export XLSX" button is clicked, the first `TABLE` child element will be parsed
|
||||
with the [`table_to_book`](/docs/api/utilities/html#html-table-input) method.
|
||||
The generated workbook object will be exported to XLSX using `writeFile`.
|
||||
|
||||
```html title="src/SheetJSVueHTML.vue"
|
||||
<script setup>
|
||||
@ -511,19 +513,20 @@ function exportFile() {
|
||||
<details open>
|
||||
<summary><b>How to run the example</b> (click to hide)</summary>
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| VueJS | ViteJS | Date |
|
||||
|:---------|:--------|:-----------|
|
||||
| `3.5.13` | `6.0.7` | 2025-01-02 |
|
||||
| VueJS | Deployment | Date |
|
||||
|:---------|:----------------|:-----------|
|
||||
| `3.5.17` | ViteJS `7.0.0` | 2025-06-29 |
|
||||
| `3.5.17` | NuxtJS `3.17.5` | 2025-06-29 |
|
||||
|
||||
:::
|
||||
|
||||
<Tabs groupId="starter">
|
||||
<TabItem name="vite" value="ViteJS">
|
||||
|
||||
1) Create a new site:
|
||||
|
||||
```bash
|
||||
@ -539,7 +542,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm run dev`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Open a web browser and access the displayed URL (`http://localhost:5173`)
|
||||
3) Access the "Local" URL (typically `http://localhost:5173`) in a web browser.
|
||||
|
||||
4) Replace `src/App.vue` with the `src/SheetJSVueHTML.vue` example.
|
||||
|
||||
@ -558,7 +561,7 @@ The generated site will be placed in the `dist` folder.
|
||||
6) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -567,20 +570,10 @@ and test the page.
|
||||
</TabItem>
|
||||
<TabItem name="nuxt" value="NuxtJS">
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| VueJS | NuxtJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `3.5.13` | `3.15.0` | 2025-01-02 |
|
||||
|
||||
:::
|
||||
|
||||
1) Create a new site:
|
||||
|
||||
```bash
|
||||
npx nuxi@latest init sheetjs-nuxt --packageManager npm --no-install --no-gitInit
|
||||
npx nuxi@latest init sheetjs-nuxt --packageManager npm --no-install --no-gitInit -M ,
|
||||
```
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
@ -592,7 +585,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm run dev`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Open a web browser and access the displayed URL (`http://localhost:3000`)
|
||||
3) Access the "Local" URL (typically `http://localhost:3000`) in a web browser.
|
||||
|
||||
4) Replace `app.vue` with the `src/SheetJSVueHTML.vue` example.
|
||||
|
||||
@ -610,7 +603,7 @@ The generated site will be placed in the `dist` folder.
|
||||
6) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server .output/public/
|
||||
npx -y http-server .output/public/
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
|
||||
@ -130,7 +130,7 @@ function exportFile() {
|
||||
<!-- highlight-end -->
|
||||
</tbody><tfoot><tr><td colSpan={2}>
|
||||
<button on:click={exportFile}>Export XLSX</button>
|
||||
</td></tfoot></tr></table>
|
||||
</td></tr></tfoot></table>
|
||||
</main>
|
||||
```
|
||||
|
||||
@ -143,14 +143,14 @@ This demo was tested in the following environments:
|
||||
|
||||
| SvelteJS | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `5.25.3` | `6.2.3` | 2025-03-30 |
|
||||
| `5.43.7` | `7.2.2` | 2025-11-15 |
|
||||
|
||||
:::
|
||||
|
||||
1) Create a new project:
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-svelte -- --template svelte-ts
|
||||
npm create vite@latest sheetjs-svelte -- --template svelte-ts --no-rolldown --no-interactive
|
||||
```
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
@ -245,14 +245,14 @@ This demo was tested in the following environments:
|
||||
|
||||
| SvelteJS | ViteJS | Date |
|
||||
|:---------|:---------|:-----------|
|
||||
| `5.25.3` | `6.2.3` | 2025-03-30 |
|
||||
| `5.43.7` | `7.2.2` | 2025-11-15 |
|
||||
|
||||
:::
|
||||
|
||||
1) Create a new project:
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-svelte -- --template svelte-ts
|
||||
npm create vite@latest sheetjs-svelte -- --template svelte-ts --no-rolldown --no-interactive
|
||||
```
|
||||
|
||||
2) Install the SheetJS dependency and start the dev server:
|
||||
|
||||
@ -36,9 +36,9 @@ This demo was tested in the following environments:
|
||||
|
||||
| Browser | Version | Date |
|
||||
|:-------------|:------------------|:-----------|
|
||||
| Chromium 133 | `1.8.2` (latest) | 2025-03-30 |
|
||||
| Chromium 147 | `1.8.2` (latest) | 2026-05-22 |
|
||||
| Konqueror 22 | `1.8.2` (latest) | 2025-04-23 |
|
||||
| Chromium 133 | `1.2.32` (legacy) | 2025-03-30 |
|
||||
| Chromium 147 | `1.2.32` (legacy) | 2026-05-22 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -76,7 +76,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Platform | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 133 | 2025-03-30 |
|
||||
| Chromium 147 | 2026-05-22 |
|
||||
| Konqueror 22 | 2025-04-23 |
|
||||
|
||||
Demos exclusively using Dojo Core were tested using Dojo Toolkit `1.17.3`.
|
||||
|
||||
@ -53,7 +53,7 @@ can be loaded in the root HTML page (typically `wwwroot/index.html`):
|
||||
|
||||
<CodeBlock language="html">{`\
|
||||
<!-- use version ${current} -->
|
||||
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
|
||||
<script type="text/javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
|
||||
</CodeBlock>
|
||||
|
||||
#### ECMAScript Module
|
||||
@ -104,7 +104,7 @@ It should be injected at the top of relevant Razor component scripts:
|
||||
|
||||
When exporting a file with the SheetJS `writeFile` method[^2], browser APIs do
|
||||
not provide success or error feedback. As a result, this demo invokes functions
|
||||
using the `InvokeVoidAsync` static method[^3].
|
||||
using the `InvokeVoidAsync` static method[^3].
|
||||
|
||||
The following C# method will invoke the `export_method` method in the browser:
|
||||
|
||||
@ -295,10 +295,10 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Date |
|
||||
|:-------------|:-----------|
|
||||
| `darwin-x64` | 2025-04-17 |
|
||||
| `darwin-arm` | 2025-04-24 |
|
||||
| `win11-x64` | 2025-04-17 |
|
||||
| `win11-arm` | 2025-04-24 |
|
||||
| `darwin-x64` | 2026-03-07 |
|
||||
| `darwin-arm` | 2026-03-07 |
|
||||
| `win11-x64` | 2026-05-08 |
|
||||
| `win11-arm` | 2026-05-09 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -91,7 +91,7 @@ in the ["API Reference"](/docs/api/) section of the documentation.
|
||||
|
||||
<!-- The SheetJS Standalone script must be loaded before the UI5 bootstrap -->
|
||||
<script src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>
|
||||
|
||||
|
||||
<!-- UI5 bootstrap script -->
|
||||
<script
|
||||
id="sap-ui-bootstrap"
|
||||
@ -260,7 +260,7 @@ flowchart LR
|
||||
linkStyle 1,2,3 color:blue,stroke:blue;
|
||||
```
|
||||
|
||||
Here is a sample method for exporting data from the UI5 `JSONModel` to XLSX:
|
||||
Here is a sample method for exporting data from the UI5 `JSONModel` to XLSX:
|
||||
|
||||
```js title="Fetch data from JSONModel and export to XLSX"
|
||||
/* get model data and export to XLSX */
|
||||
@ -365,7 +365,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| OpenUI5 | Date |
|
||||
|:----------|------------|
|
||||
| `1.132.1` | 2025-01-24 |
|
||||
| `1.145.0` | 2026-03-13 |
|
||||
|
||||
:::
|
||||
|
||||
@ -441,7 +441,7 @@ generated. The `dist` folder in this demo can be deployed on a static host.
|
||||
9) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
@ -535,7 +535,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| OpenUI5 | Date |
|
||||
|:----------|------------|
|
||||
| `1.132.1` | 2025-01-24 |
|
||||
| `1.145.0` | 2026-03-13 |
|
||||
|
||||
:::
|
||||
|
||||
@ -611,7 +611,7 @@ generated. The `dist` folder in this demo can be deployed on a static host.
|
||||
9) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser
|
||||
|
||||
@ -25,9 +25,9 @@ the shim script must be loaded first:
|
||||
|
||||
<CodeBlock language="html">{`\
|
||||
<!-- SheetJS version ${current} \`shim.min.js\` -->
|
||||
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js"></script>
|
||||
<!-- SheetJS version ${current} \`xlsx.full.min.js\` -->
|
||||
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>
|
||||
<script type="text/javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>
|
||||
<script>
|
||||
/* display SheetJS version */
|
||||
if(typeof console == "object" && console.log) console.log(XLSX.version);
|
||||
@ -211,8 +211,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| KnockoutJS | Date | Live Demo |
|
||||
|:-----------|:-----------|:-----------------------------------------------|
|
||||
| `3.5.0` | 2025-01-08 | [**KO3**](pathname:///knockout/knockout3.html) |
|
||||
| `2.3.0` | 2025-01-08 | [**KO2**](pathname:///knockout/knockout2.html) |
|
||||
| `3.5.0` | 2026-03-06 | [**KO3**](pathname:///knockout/knockout3.html) |
|
||||
| `2.3.0` | 2026-03-06 | [**KO2**](pathname:///knockout/knockout2.html) |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -41,10 +41,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| ViteJS | Date |
|
||||
|:---------|:-----------|
|
||||
| `6.2.3` | 2025-03-30 |
|
||||
| `5.4.15` | 2025-03-30 |
|
||||
| `4.5.10` | 2025-03-30 |
|
||||
| `3.2.11` | 2025-03-30 |
|
||||
| `7.3.1` | 2026-01-28 |
|
||||
| `6.4.1` | 2026-01-28 |
|
||||
| `5.4.21` | 2026-01-28 |
|
||||
| `4.5.14` | 2026-01-28 |
|
||||
| `3.2.11` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -74,7 +75,7 @@ It is strongly recommended to [upgrade to the latest version](/docs/getting-star
|
||||
1) Create a new ViteJS project:
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-vite -- --template vue-ts
|
||||
npm create vite@latest sheetjs-vite -- --template vue-ts --no-rolldown --no-interactive
|
||||
cd sheetjs-vite
|
||||
npm i
|
||||
```
|
||||
@ -173,7 +174,7 @@ npx vite build
|
||||
7) Verify the new site by running a local web server in the `dist` folder:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
8) Access the displayed URL (typically `http://localhost:8080`) in a web browser
|
||||
|
||||
@ -47,22 +47,25 @@ This demo was tested in the following environments:
|
||||
|
||||
| ESBuild | Date |
|
||||
|:----------|:-----------|
|
||||
| `0.24.2` | 2025-01-07 |
|
||||
| `0.23.1` | 2025-01-07 |
|
||||
| `0.22.0` | 2025-01-07 |
|
||||
| `0.21.5` | 2025-01-07 |
|
||||
| `0.20.2` | 2025-01-07 |
|
||||
| `0.19.12` | 2025-01-07 |
|
||||
| `0.18.20` | 2025-01-07 |
|
||||
| `0.17.19` | 2025-01-07 |
|
||||
| `0.16.17` | 2025-01-07 |
|
||||
| `0.15.18` | 2025-01-07 |
|
||||
| `0.14.54` | 2025-01-07 |
|
||||
| `0.13.15` | 2025-01-07 |
|
||||
| `0.12.29` | 2025-01-07 |
|
||||
| `0.11.23` | 2025-01-07 |
|
||||
| `0.10.2` | 2025-01-07 |
|
||||
| `0.9.7` | 2025-01-07 |
|
||||
| `0.27.2` | 2026-01-28 |
|
||||
| `0.26.0` | 2026-01-28 |
|
||||
| `0.25.12` | 2026-01-28 |
|
||||
| `0.24.2` | 2026-01-28 |
|
||||
| `0.23.1` | 2026-01-28 |
|
||||
| `0.22.0` | 2026-01-28 |
|
||||
| `0.21.5` | 2026-01-28 |
|
||||
| `0.20.2` | 2026-01-28 |
|
||||
| `0.19.12` | 2026-01-28 |
|
||||
| `0.18.20` | 2026-01-28 |
|
||||
| `0.17.19` | 2026-01-28 |
|
||||
| `0.16.17` | 2026-01-28 |
|
||||
| `0.15.18` | 2026-01-28 |
|
||||
| `0.14.54` | 2026-01-28 |
|
||||
| `0.13.15` | 2026-01-28 |
|
||||
| `0.12.29` | 2026-01-28 |
|
||||
| `0.11.23` | 2026-01-28 |
|
||||
| `0.10.2` | 2026-01-28 |
|
||||
| `0.9.7` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -90,7 +93,7 @@ Assuming the primary source file is `in.js`, the following command will bundle
|
||||
the script and generate `out.js`:
|
||||
|
||||
```bash
|
||||
npx -y esbuild@0.24.2 in.js --bundle --outfile=out.js
|
||||
npx -y esbuild@0.25.9 in.js --bundle --outfile=out.js
|
||||
```
|
||||
|
||||
### Browser Demo
|
||||
@ -139,13 +142,13 @@ curl -LO https://docs.sheetjs.com/esbuild/esbrowser.js
|
||||
4) Create bundle:
|
||||
|
||||
```bash
|
||||
npx -y esbuild@0.19.8 esbrowser.js --bundle --outfile=esb.browser.js
|
||||
npx -y esbuild@0.25.9 esbrowser.js --bundle --outfile=esb.browser.js
|
||||
```
|
||||
|
||||
5) Start a local HTTP server:
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser.
|
||||
@ -179,7 +182,7 @@ Assuming the primary source file is `in.js`, the following command will bundle
|
||||
the script for NodeJS and generate `out.js`:
|
||||
|
||||
```bash
|
||||
npx -y esbuild@0.19.8 in.js --bundle --platform=node --outfile=out.js
|
||||
npx -y esbuild@0.25.9 in.js --bundle --platform=node --outfile=out.js
|
||||
```
|
||||
|
||||
### NodeJS Demo
|
||||
@ -228,7 +231,7 @@ curl -LO https://docs.sheetjs.com/esbuild/esbnode.js
|
||||
3) Create bundle:
|
||||
|
||||
```bash
|
||||
npx -y esbuild@0.19.8 esbnode.js --bundle --platform=node --outfile=esb.node.js
|
||||
npx -y esbuild@0.25.9 esbnode.js --bundle --platform=node --outfile=esb.node.js
|
||||
```
|
||||
|
||||
4) Run the bundle:
|
||||
|
||||
@ -39,12 +39,12 @@ which covers SheetJS library usage in more detail.
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Version | Date | Required Workarounds |
|
||||
|:---------|:-----------|:------------------------------------|
|
||||
| `5.97.1` | 2025-01-03 | |
|
||||
| `4.47.0` | 2025-01-03 | |
|
||||
| `3.12.0` | 2025-01-03 | Import `xlsx/dist/xlsx.full.min.js` |
|
||||
| `2.7.0` | 2025-01-03 | Import `xlsx/dist/xlsx.full.min.js` |
|
||||
| Version | Date | Required Workarounds |
|
||||
|:----------|:-----------|:------------------------------------|
|
||||
| `5.104.1` | 2026-01-28 | |
|
||||
| `4.47.0` | 2026-01-28 | |
|
||||
| `3.12.0` | 2026-01-28 | Import `xlsx/dist/xlsx.full.min.js` |
|
||||
| `2.7.0` | 2026-01-28 | Import `xlsx/dist/xlsx.full.min.js` |
|
||||
|
||||
:::
|
||||
|
||||
@ -177,7 +177,7 @@ document.getElementById("xport").addEventListener("click", function() {
|
||||
prez.forEach(function(row) {
|
||||
row.start = row.terms.find(function(term) {
|
||||
return term.type === "prez";
|
||||
}).start
|
||||
}).start;
|
||||
});
|
||||
prez.sort(function(l,r) { return l.start.localeCompare(r.start); });
|
||||
|
||||
@ -322,15 +322,13 @@ npx webpack --mode=production
|
||||
6) Start a local HTTP server:
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
7) Load the displayed URL (typically `http://localhost:8080/`) in a web browser.
|
||||
|
||||
Click on "Click here to export" to generate a file.
|
||||
|
||||
## Miscellany
|
||||
|
||||
[^1]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^2]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^3]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
|
||||
@ -34,21 +34,21 @@ This demo was tested in the following environments:
|
||||
|
||||
| Browserify | Date |
|
||||
|:-----------|:-----------|
|
||||
| `17.0.1` | 2025-01-07 |
|
||||
| `16.5.2` | 2025-01-07 |
|
||||
| `15.2.0` | 2025-01-07 |
|
||||
| `14.5.0` | 2025-01-07 |
|
||||
| `13.3.0` | 2025-01-07 |
|
||||
| `12.0.2` | 2025-01-07 |
|
||||
| `11.2.0` | 2025-01-07 |
|
||||
| `10.2.6` | 2025-01-07 |
|
||||
| `9.0.8` | 2025-01-07 |
|
||||
| `8.1.3` | 2025-01-07 |
|
||||
| `7.1.0` | 2025-01-07 |
|
||||
| `6.3.4` | 2025-01-07 |
|
||||
| `5.13.1` | 2025-01-07 |
|
||||
| `4.2.3` | 2025-01-07 |
|
||||
| `3.46.1` | 2025-01-07 |
|
||||
| `17.0.1` | 2026-01-28 |
|
||||
| `16.5.2` | 2026-01-28 |
|
||||
| `15.2.0` | 2026-01-28 |
|
||||
| `14.5.0` | 2026-01-28 |
|
||||
| `13.3.0` | 2026-01-28 |
|
||||
| `12.0.2` | 2026-01-28 |
|
||||
| `11.2.0` | 2026-01-28 |
|
||||
| `10.2.6` | 2026-01-28 |
|
||||
| `9.0.8` | 2026-01-28 |
|
||||
| `8.1.3` | 2026-01-28 |
|
||||
| `7.1.0` | 2026-01-28 |
|
||||
| `6.3.4` | 2026-01-28 |
|
||||
| `5.13.1` | 2026-01-28 |
|
||||
| `4.2.3` | 2026-01-28 |
|
||||
| `3.46.1` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -115,7 +115,7 @@ document.getElementById("xport").addEventListener("click", function() {
|
||||
prez.forEach(function(row) {
|
||||
row.start = row.terms.find(function(term) {
|
||||
return term.type === "prez";
|
||||
}).start
|
||||
}).start;
|
||||
});
|
||||
prez.sort(function(l,r) { return l.start.localeCompare(r.start); });
|
||||
|
||||
@ -177,7 +177,7 @@ npm install --save browserify@3.46.1
|
||||
5) Start a local HTTP server:
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
6) Load the displayed URL (typically `http://localhost:8080/`) in a web browser.
|
||||
|
||||
@ -40,8 +40,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| RequireJS | Date |
|
||||
|:----------|:-----------|
|
||||
| `2.3.7` | 2025-01-07 |
|
||||
| `2.1.22` | 2025-01-07 |
|
||||
| `2.3.7` | 2026-01-25 |
|
||||
| `2.1.22` | 2026-01-25 |
|
||||
|
||||
:::
|
||||
|
||||
@ -209,7 +209,7 @@ uses normal functions and traditional Promise chains.
|
||||
3) Start a local HTTP server:
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
4) Load the displayed URL (typically `http://localhost:8080/`) in a web browser.
|
||||
|
||||
@ -46,11 +46,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Platform | Date |
|
||||
|:----------|:---------|:-----------|
|
||||
| `0.19.47` | NodeJS | 2025-01-03 |
|
||||
| `0.20.16` | Browser | 2025-01-03 |
|
||||
| `0.20.19` | NodeJS | 2025-03-03 |
|
||||
| `0.21.6` | NodeJS | 2025-03-03 |
|
||||
| `6.15.1` | NodeJS | 2025-01-03 |
|
||||
| `6.15.1` | NodeJS | 2026-01-28 |
|
||||
| `0.21.6` | NodeJS | 2026-01-28 |
|
||||
| `0.20.19` | NodeJS | 2026-01-28 |
|
||||
| `0.19.47` | NodeJS | 2026-01-28 |
|
||||
| `0.20.16` | Browser | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -34,10 +34,10 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `4.29.1` | 2025-01-03 |
|
||||
| `3.29.5` | 2025-01-03 |
|
||||
| `2.79.1` | 2025-01-03 |
|
||||
| `1.32.1` | 2025-01-03 |
|
||||
| `4.57.0` | 2026-01-28 |
|
||||
| `3.29.5` | 2026-01-28 |
|
||||
| `2.79.2` | 2026-01-28 |
|
||||
| `1.32.1` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -169,7 +169,7 @@ This step will create `bundle.js`
|
||||
5) Start a local HTTP server:
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080/`) in a web browser.
|
||||
|
||||
195
docz/docs/03-demos/02-frontend/19-bundler/18-rspack.md
Normal file
195
docz/docs/03-demos/02-frontend/19-bundler/18-rspack.md
Normal file
@ -0,0 +1,195 @@
|
||||
---
|
||||
title: Packing Sheets with Rspack
|
||||
sidebar_label: Rspack
|
||||
pagination_prev: demos/index
|
||||
pagination_next: demos/grid/index
|
||||
sidebar_position: 18
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[Rspack](https://rspack.rs/) is a fast module bundler for JavaScript.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses Rspack and SheetJS to export data. We'll explore how to add
|
||||
SheetJS to a site using Rspack and how to export data to spreadsheets.
|
||||
|
||||
:::note pass
|
||||
|
||||
This demo focuses on integration details with the Rspack bundler.
|
||||
|
||||
The demos follow the ["Export Tutorial"](/docs/getting-started/examples/export),
|
||||
which covers SheetJS library usage in more detail.
|
||||
|
||||
:::
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Rspack | Date |
|
||||
|:--------|:-----------|
|
||||
| `1.7.4` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
|
||||
installation with Yarn and other package managers.
|
||||
|
||||
After installing the SheetJS module in a Rspack project, `import` statements can
|
||||
load relevant parts of the library.
|
||||
|
||||
Projects that import data will use methods such as `read`[^1] to parse workbooks
|
||||
and `sheet_to_json`[^2] to generate usable data from files. As `sheet_to_json`
|
||||
is part of the `utils` object, the required import is:
|
||||
|
||||
```js
|
||||
import { read, utils } from 'xlsx';
|
||||
```
|
||||
|
||||
Projects that export data will use methods such as `json_to_sheet`[^3] to
|
||||
generate worksheets and `writeFile`[^4] to export files. As `json_to_sheet` is
|
||||
part of the `utils` object, the required import is:
|
||||
|
||||
```js
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
This demo follows the [Export Example](/docs/getting-started/examples/export).
|
||||
|
||||
0) Initialize a new project:
|
||||
|
||||
```bash
|
||||
mkdir sheetjs-rspack
|
||||
cd sheetjs-rspack
|
||||
npm init -y
|
||||
```
|
||||
|
||||
1) Install the dependencies using a package manager:
|
||||
|
||||
<Tabs groupId="pm">
|
||||
<TabItem value="npm" label="npm">
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @rspack/core @rspack/cli`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="pnpm" label="pnpm">
|
||||
<CodeBlock language="bash">{`\
|
||||
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @rspack/core @rspack/cli`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="yarn" label="Yarn" default>
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @rspack/core @rspack/cli`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
2) Save the following to `src/index.js`:
|
||||
|
||||
```js title="src/index.js"
|
||||
import { utils, writeFileXLSX } from 'xlsx';
|
||||
|
||||
document.getElementById("xport").addEventListener("click", async() => {
|
||||
/* fetch JSON data and parse */
|
||||
const url = "https://docs.sheetjs.com/executive.json";
|
||||
const raw_data = await (await fetch(url)).json();
|
||||
|
||||
/* filter for the Presidents */
|
||||
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
|
||||
|
||||
/* sort by first presidential term */
|
||||
prez.forEach(row => row.start = row.terms.find(term => term.type === "prez").start);
|
||||
prez.sort((l,r) => l.start.localeCompare(r.start));
|
||||
|
||||
/* flatten objects */
|
||||
const rows = prez.map(row => ({
|
||||
name: row.name.first + " " + row.name.last,
|
||||
birthday: row.bio.birthday
|
||||
}));
|
||||
|
||||
/* generate worksheet and workbook */
|
||||
const worksheet = utils.json_to_sheet(rows);
|
||||
const workbook = utils.book_new();
|
||||
utils.book_append_sheet(workbook, worksheet, "Dates");
|
||||
|
||||
/* fix headers */
|
||||
utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
|
||||
|
||||
/* calculate column width */
|
||||
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
|
||||
worksheet["!cols"] = [ { wch: max_width } ];
|
||||
|
||||
/* create an XLSX file and try to save to Presidents.xlsx */
|
||||
writeFileXLSX(workbook, "Presidents.xlsx");
|
||||
});
|
||||
```
|
||||
|
||||
3) Create bundle:
|
||||
|
||||
```bash
|
||||
npx -p @rspack/cli rspack build
|
||||
```
|
||||
|
||||
:::caution pass
|
||||
|
||||
This build may fail with a module error:
|
||||
|
||||
```
|
||||
ERROR in ./src/index.js
|
||||
× Module parse failed:
|
||||
╰─▶ × JavaScript parse error: 'import', and 'export' cannot be used outside of module code
|
||||
```
|
||||
|
||||
Some versions of the `npm` tool create `package.json` files with the option
|
||||
`"type": "commonjs"`. Rspack will fail if that option is specified. Edit
|
||||
`package.json` and remove the property:
|
||||
|
||||
```js title="package.json (remove highlighted line)"
|
||||
"license": "ISC",
|
||||
// highlight-next-line
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
This command will create the script `dist/main.js`
|
||||
|
||||
4) Create a small HTML page that loads the generated script:
|
||||
|
||||
```html title="index.html"
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head></head>
|
||||
<body>
|
||||
<h1>SheetJS Presidents Demo</h1>
|
||||
<button id="xport">Click here to export</button>
|
||||
<script src="dist/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
5) Start a local HTTP server:
|
||||
|
||||
```bash
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080`) with a web browser.
|
||||
|
||||
Click the "Click here to export" button to generate `Presidents.xlsx`
|
||||
|
||||
[^1]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^2]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^3]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^4]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
@ -34,8 +34,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `2.13.3` | 2024-12-31 |
|
||||
| `1.12.3` | 2024-12-31 |
|
||||
| `2.16.1` | 2026-01-28 |
|
||||
| `1.12.3` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -44,7 +44,7 @@ This demo was tested in the following environments:
|
||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
|
||||
installation with Yarn and other package managers.
|
||||
|
||||
After installing the SheetJS module in a RollupJS project, `import` statements
|
||||
After installing the SheetJS module in a ParcelJS project, `import` statements
|
||||
can load relevant parts of the library:
|
||||
|
||||
```js
|
||||
@ -239,7 +239,7 @@ The production site will be stored in the `dist` folder
|
||||
7) Start a local web server and serve the `dist` folder:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Access the displayed URL (typically `http://localhost:8080/`) in a web browser.
|
||||
|
||||
@ -35,7 +35,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:----------|:-----------|
|
||||
| `1.2.246` | 2025-01-07 |
|
||||
| `1.15.11` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -63,7 +63,7 @@ part of the `utils` object, the required import is:
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
```
|
||||
|
||||
:::danger pass
|
||||
:::caution pass
|
||||
|
||||
When this demo was tested against recent versions of `@swc/core`, `spack` crashed:
|
||||
|
||||
@ -75,7 +75,8 @@ thread '<unnamed>' panicked at 'cannot access a scoped thread local variable wit
|
||||
|
||||
This bug is known to affect versions `1.3.100`, `1.4.17`, and `1.10.6`.
|
||||
|
||||
Until the bug is fixed, it is strongly recommended to use `@swc/core@1.2.246`.
|
||||
This bug was fixed in version `1.12.1`. It is strongly recommended to upgrade
|
||||
existing projects to use `1.12.1` or to downgrade to `1.2.246`.
|
||||
|
||||
:::
|
||||
|
||||
@ -94,17 +95,17 @@ npm init -y
|
||||
<Tabs groupId="pm">
|
||||
<TabItem value="npm" label="npm">
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz regenerator-runtime @swc/cli @swc/core@1.2.246`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz regenerator-runtime @swc/cli @swc/core@1.13.5`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="pnpm" label="pnpm">
|
||||
<CodeBlock language="bash">{`\
|
||||
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz regenerator-runtime @swc/cli @swc/core@1.2.246`}
|
||||
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz regenerator-runtime @swc/cli @swc/core@1.13.5`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
<TabItem value="yarn" label="Yarn" default>
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz regenerator-runtime @swc/cli @swc/core@1.2.246`}
|
||||
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz regenerator-runtime @swc/cli @swc/core@1.13.5`}
|
||||
</CodeBlock>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@ -195,7 +196,7 @@ This command will create the script `lib/web.js`
|
||||
6) Start a local HTTP server, then go to `http://localhost:8080/`
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
Click on "Click here to export" to generate a file.
|
||||
|
||||
@ -62,7 +62,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:--------|:-----------|
|
||||
| `3.8.8` | 2025-01-07 |
|
||||
| `3.8.8` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -149,7 +149,7 @@ writeFileXLSX(workbook, "Presidents.xlsx");
|
||||
</html>
|
||||
```
|
||||
|
||||
:::note pass
|
||||
:::danger pass
|
||||
|
||||
Unlike other bundlers, Snowpack requires a full page including `HEAD` element.
|
||||
|
||||
@ -164,7 +164,7 @@ npx snowpack@3.8.8 build
|
||||
5) Start a local HTTP server:
|
||||
|
||||
```bash
|
||||
npx http-server build/
|
||||
npx -y http-server build/
|
||||
```
|
||||
|
||||
6) Open a web browser to the displayed URL (typically `http://localhost:8080/`).
|
||||
@ -194,7 +194,7 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Date |
|
||||
|:--------|:-----------|
|
||||
| `3.8.0` | 2025-01-07 |
|
||||
| `3.8.0` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -290,7 +290,7 @@ npx wmr@3.8.0 build
|
||||
5) Start a local HTTP server:
|
||||
|
||||
```bash
|
||||
npx http-server dist/
|
||||
npx -y http-server dist/
|
||||
```
|
||||
|
||||
6) Open a web browser to the displayed URL (typically `http://localhost:8080/`).
|
||||
|
||||
@ -90,7 +90,7 @@ Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 133 | 2025-03-30 |
|
||||
| Chromium 147 | 2026-05-22 |
|
||||
| Safari 18.3 | 2025-03-30 |
|
||||
| Konqueror 22 | 2025-04-23 |
|
||||
|
||||
@ -98,11 +98,40 @@ Each browser demo was tested in the following environments:
|
||||
|
||||
### XMLHttpRequest
|
||||
|
||||
For downloading data, the `arraybuffer` response type generates an `ArrayBuffer`
|
||||
that can be viewed as an `Uint8Array` and fed to the SheetJS `read` method. For
|
||||
legacy browsers, the option `type: "array"` should be specified:
|
||||
`XMLHttpRequest` is a browser API for performing network requests. Files can be
|
||||
downloaded from external sources in `GET` and `POST` requests.
|
||||
|
||||
The `responseType` property controls how `XMLHttpRequest` processes data. The
|
||||
SheetJS [`read`](/docs/api/parse-options/) method accepts a `type` option that
|
||||
specifies the data representation. SheetJS and `XMLHttpRequest` options must be
|
||||
set in tandem.
|
||||
|
||||
In modern browsers, when the response type is `"arraybuffer"`, `XMLHttpRequest`
|
||||
will generate an `ArrayBuffer` of raw data. The SheetJS `read` method directly
|
||||
processes `ArrayBuffer` objects.
|
||||
|
||||
```mermaid
|
||||
---
|
||||
title: XMLHttpRequest + SheetJS in modern browsers
|
||||
---
|
||||
flowchart LR
|
||||
file[(workbook\nfile)]
|
||||
ab[(file bytes\nArrayBuffer)]
|
||||
wb(((SheetJS\nWorkbook)))
|
||||
file --> |XMLHttpRequest\nresponseType="arraybuffer"| ab
|
||||
ab --> |SheetJS read\n\n|wb
|
||||
```
|
||||
|
||||
The following example fetches a file, generates an HTML `TABLE` from the first
|
||||
sheet using the [`sheet_to_html`](/docs/api/utilities/html#html-table-output)
|
||||
method, and inserts the `TABLE` in a `DIV` container:
|
||||
|
||||
```html title="Download and parse files with XMLHttpRequest and SheetJS"
|
||||
<div id="sheetjs-tbl"></div>
|
||||
<script>
|
||||
/* This file will be downloaded and processed */
|
||||
var url = "https://docs.sheetjs.com/pres.numbers";
|
||||
|
||||
```js
|
||||
/* set up an async GET request */
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", url, true);
|
||||
@ -110,11 +139,19 @@ req.responseType = "arraybuffer";
|
||||
|
||||
req.onload = function(e) {
|
||||
/* parse the data when it is received */
|
||||
var data = new Uint8Array(req.response);
|
||||
var workbook = XLSX.read(data, {type:"array"});
|
||||
var workbook = XLSX.read(req.response);
|
||||
|
||||
/* DO SOMETHING WITH workbook HERE */
|
||||
|
||||
/* generate HTML from the first worksheet */
|
||||
var first_sheet = workbook.Sheets[workbook.SheetNames[0]];
|
||||
var table_html = XLSX.utils.sheet_to_html(first_sheet);
|
||||
|
||||
/* add to page */
|
||||
document.getElementById("sheetjs-tbl").innerHTML = table_html;
|
||||
};
|
||||
req.send();
|
||||
</script>
|
||||
```
|
||||
|
||||
<details>
|
||||
@ -135,7 +172,7 @@ function SheetJSXHRDL() {
|
||||
req.responseType = "arraybuffer";
|
||||
req.onload = e => {
|
||||
/* Parse file */
|
||||
const wb = XLSX.read(new Uint8Array(req.response));
|
||||
const wb = XLSX.read(req.response);
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
|
||||
/* Generate HTML */
|
||||
@ -150,6 +187,35 @@ function SheetJSXHRDL() {
|
||||
|
||||
</details>
|
||||
|
||||
In browsers that do not support `ArrayBuffer`, including Internet Explorer and
|
||||
older versions of Firefox, `XMLHttpRequest` will return an array of unsigned
|
||||
bytes. In this case, the `read` method requires the option `type: "array"`:
|
||||
|
||||
```mermaid
|
||||
---
|
||||
title: XMLHttpRequest + SheetJS in browsers lacking ArrayBuffer support
|
||||
---
|
||||
flowchart LR
|
||||
file[(workbook\nfile)]
|
||||
ab[(file bytes\nArray)]
|
||||
wb(((SheetJS\nWorkbook)))
|
||||
file --> |XMLHttpRequest\nresponseType="arraybuffer"| ab
|
||||
ab --> |SheetJS read\ntype="array"|wb
|
||||
```
|
||||
|
||||
```js title="Download and parse files in legacy browsers (snippet)"
|
||||
/* set up an async GET request */
|
||||
var req = new XMLHttpRequest();
|
||||
req.open("GET", url, true);
|
||||
req.responseType = "arraybuffer";
|
||||
|
||||
req.onload = function(e) {
|
||||
/* parse the data when it is received */
|
||||
var workbook = XLSX.read(req.response, {type: "array"});
|
||||
/* DO SOMETHING WITH workbook HERE */
|
||||
};
|
||||
req.send();
|
||||
```
|
||||
|
||||
### fetch
|
||||
|
||||
|
||||
@ -135,7 +135,7 @@ Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 133 | 2025-03-30 |
|
||||
| Chromium 147 | 2026-05-22 |
|
||||
| Safari 18.3 | 2025-03-30 |
|
||||
| Konqueror 22 | 2025-04-23 |
|
||||
|
||||
@ -589,10 +589,11 @@ NodeJS `fetch`, available in version 20, mirrors the [browser `fetch`](#fetch).
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| NodeJS | Date |
|
||||
|:-----------|:-----------|
|
||||
| `22.13.0` | 2025-01-08 |
|
||||
| `20.18.1` | 2025-01-08 |
|
||||
| NodeJS | Date |
|
||||
|:-----------|:------------|
|
||||
| `24.11.1` | 2026-03-22 |
|
||||
| `22.22.1` | 2026-03-22 |
|
||||
| `20.18.0` | 2026-03-22 |
|
||||
|
||||
:::
|
||||
|
||||
@ -705,18 +706,19 @@ This demo was tested in the following environments:
|
||||
|
||||
| NodeJS | `request` | Date |
|
||||
|:-----------|:----------|:-----------|
|
||||
| `22.13.0` | `2.88.2` | 2025-01-08 |
|
||||
| `20.18.1` | `2.88.2` | 2025-01-08 |
|
||||
| `18.20.5` | `2.88.2` | 2025-01-08 |
|
||||
| `16.20.2` | `2.88.2` | 2025-01-08 |
|
||||
| `14.21.3` | `2.88.2` | 2025-01-08 |
|
||||
| `12.22.12` | `2.88.2` | 2025-01-08 |
|
||||
| `10.24.1` | `2.88.2` | 2025-01-08 |
|
||||
| `8.17.0` | `2.88.2` | 2025-01-08 |
|
||||
| `6.17.1` | `2.88.2` | 2025-01-08 |
|
||||
| `4.9.1` | `2.81.0` | 2025-01-08 |
|
||||
| `0.12.18` | `2.81.0` | 2025-01-08 |
|
||||
| `0.10.48` | `2.81.0` | 2025-01-08 |
|
||||
| `24.11.1` | `2.88.2` | 2026-03-22 |
|
||||
| `22.22.1` | `2.88.2` | 2026-03-22 |
|
||||
| `20.18.0` | `2.88.2` | 2026-03-22 |
|
||||
| `18.20.8` | `2.88.2` | 2026-03-22 |
|
||||
| `16.20.2` | `2.88.2` | 2026-03-22 |
|
||||
| `14.21.3` | `2.88.2` | 2026-03-22 |
|
||||
| `12.22.12` | `2.88.2` | 2026-03-22 |
|
||||
| `10.24.1` | `2.88.2` | 2026-03-22 |
|
||||
| `8.17.0` | `2.88.2` | 2026-03-22 |
|
||||
| `6.17.1` | `2.88.2` | 2026-03-22 |
|
||||
| `4.9.1` | `2.88.2` | 2026-03-22 |
|
||||
| `0.12.18` | `2.81.0` | 2026-03-22 |
|
||||
| `0.10.48` | `2.81.0` | 2026-03-22 |
|
||||
|
||||
:::
|
||||
|
||||
@ -735,9 +737,13 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz request
|
||||
|
||||
:::note pass
|
||||
|
||||
The current version of `request` requires NodeJS 6 or later. For older versions
|
||||
The current version of `request` requires NodeJS 4 or later. For older versions
|
||||
of NodeJS, `request` version `2.81.0` should be installed.
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz request@2.81.0`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
2) Save the following to `SheetJSRequest.js`:
|
||||
|
||||
@ -26,8 +26,8 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `4.21.2` | 2025-01-03 |
|
||||
| `5.0.1` | 2025-01-03 |
|
||||
| `4.21.2` | 2026-03-12 |
|
||||
| `5.2.1` | 2026-03-12 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -26,8 +26,8 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Drash | Deno | Date |
|
||||
|:--------|:-------|:-----------|
|
||||
| `2.8.1` | 1.44.1 | 2024-12-19 |
|
||||
| `2.8.1` | 2.1.4 | 2024-12-19 |
|
||||
| `2.8.1` | 1.46.0 | 2025-05-21 |
|
||||
| `2.8.1` | 2.3.3 | 2025-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
@ -133,7 +133,7 @@ deno run --allow-net SheetJSDrash.ts
|
||||
Deno 2 requires the `--allow-import` entitlement:
|
||||
|
||||
```bash
|
||||
deno run --allow-net --allow-write --allow-import SheetJSDenoDOM.ts
|
||||
deno run --allow-net --allow-write --allow-import SheetJSDrash.ts
|
||||
```
|
||||
|
||||
:::
|
||||
@ -142,9 +142,10 @@ deno run --allow-net --allow-write --allow-import SheetJSDenoDOM.ts
|
||||
|
||||
4) Open `http://localhost:7262/` in your browser.
|
||||
|
||||
Click "Choose File" and select `pres.numbers`. Then click "Submit"
|
||||
Click "Choose File" and select `pres.numbers` from the Downloads folder.
|
||||
|
||||
The page should show the contents of the file as an HTML table.
|
||||
Click "Submit" to make a request to the Drash server. The response should show
|
||||
the contents of the file as an HTML table.
|
||||
|
||||
5) Open `http://localhost:7262/export` in your browser.
|
||||
|
||||
|
||||
@ -23,9 +23,11 @@ The ["Complete Example"](#complete-example) section includes a complete server.
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Platform | HonoJS | Date |
|
||||
|:---------------|:---------|:-----------|
|
||||
| BunJS `1.1.40` | `4.6.14` | 2024-12-19 |
|
||||
| Platform | HonoJS | Date |
|
||||
|:---------------|:----------|:-----------|
|
||||
| BunJS `1.2.13` | `2.7.8` | 2025-05-21 |
|
||||
| BunJS `1.2.13` | `3.12.12` | 2025-05-21 |
|
||||
| BunJS `1.2.13` | `4.7.10` | 2025-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -26,8 +26,8 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Platform | ElysiaJS | Date |
|
||||
|:---------------|:---------|:-----------|
|
||||
| BunJS `1.1.40` | `0.8.17` | 2024-12-19 |
|
||||
| BunJS `1.1.40` | `1.1.26` | 2024-12-19 |
|
||||
| BunJS `1.2.13` | `0.8.17` | 2025-05-21 |
|
||||
| BunJS `1.2.13` | `1.3.1` | 2025-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -24,11 +24,12 @@ The ["Complete Example"](#complete-example) section includes a complete server.
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| NestJS | Date |
|
||||
|:----------|:-------------|
|
||||
| `10.4.15` | `2024-12-22` |
|
||||
| `9.4.3` | `2024-12-22` |
|
||||
| `8.4.7` | `2024-12-22` |
|
||||
| NestJS | Date |
|
||||
|:----------|:-----------|
|
||||
| `11.1.1` | 2025-05-21 |
|
||||
| `10.4.17` | 2025-05-21 |
|
||||
| `9.4.3` | 2025-05-21 |
|
||||
| `8.4.7` | 2025-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -25,8 +25,8 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `4.29.0` | 2025-01-02 |
|
||||
| `5.2.0` | 2025-01-02 |
|
||||
| `4.29.1` | 2025-09-13 |
|
||||
| `5.6.0` | 2025-09-13 |
|
||||
|
||||
:::
|
||||
|
||||
@ -37,10 +37,10 @@ imported from scripts that use FastifyJS.
|
||||
|
||||
### Exporting Data to Workbooks (GET)
|
||||
|
||||
The SheetJS `write` method[^1] with the option `type: "buffer"` generates NodeJS
|
||||
Buffer objects containing the raw file data.
|
||||
The SheetJS [`write`](/docs/api/write-options) method generates NodeJS `Buffer`
|
||||
objects containing the raw file data (using the option `type: "buffer"`[^1]).
|
||||
|
||||
FastifyJS can directly handle `Buffer` data in `Response#end`
|
||||
FastifyJS can directly handle `Buffer` data in `Response#end`.
|
||||
|
||||
The exported filename can be specified using the `Content-Disposition` header.
|
||||
|
||||
@ -162,7 +162,7 @@ fastify.listen({port: process.env.PORT || 3000}, (err, addr) => { if(err) throw
|
||||
1) Install dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz fastify@4.29.0 @fastify/multipart@8`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz fastify@4.29.1 @fastify/multipart@8`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Start server
|
||||
|
||||
@ -36,12 +36,13 @@ the file can be downloaded or previewed in the browser.
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Platform | Version | Date |
|
||||
|:-------------|:---------|:-----------|
|
||||
| Chromium 131 | `1.9.0` | 2024-12-22 |
|
||||
| Konqueror 22 | `1.9.0` | 2025-04-23 |
|
||||
| NodeJS 20 | `1.10.0` | 2024-12-22 |
|
||||
| BunJS 1.1 | `1.10.0` | 2024-12-22 |
|
||||
| Platform | Version | Date |
|
||||
|:--------------|:---------|:-----------|
|
||||
| Chromium 136 | `1.9.0` | 2025-05-07 |
|
||||
| Safari 17.5 | `1.9.0` | 2025-05-07 |
|
||||
| Konqueror 22 | `1.9.0` | 2025-05-07 |
|
||||
| NodeJS 24.0.0 | `1.11.0` | 2025-05-07 |
|
||||
| BunJS 1.2.10 | `1.11.0` | 2025-05-07 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -130,12 +130,13 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Puppeteer | Date |
|
||||
|:----------|:-----------|
|
||||
| `23.11.1` | 2024-12-31 |
|
||||
| `22.15.0` | 2024-12-31 |
|
||||
| `21.11.0` | 2024-12-31 |
|
||||
| `20.9.0` | 2024-12-31 |
|
||||
| `15.5.0` | 2024-12-31 |
|
||||
| `10.4.0` | 2024-12-31 |
|
||||
| `24.35.0` | 2026-01-21 |
|
||||
| `23.11.1` | 2026-01-21 |
|
||||
| `22.15.0` | 2026-01-21 |
|
||||
| `21.11.0` | 2026-01-21 |
|
||||
| `20.9.0` | 2026-01-21 |
|
||||
| `15.5.0` | 2026-01-21 |
|
||||
| `10.4.0` | 2026-01-21 |
|
||||
|
||||
:::
|
||||
|
||||
@ -145,14 +146,14 @@ This demo was tested in the following deployments:
|
||||
<TabItem value="nodejs" label="NodeJS">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz puppeteer@23.11.1`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz puppeteer@24.9.0`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bunjs" label="BunJS">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz puppeteer@23.11.1`}
|
||||
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz puppeteer@24.9.0`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
@ -236,9 +237,9 @@ const { webkit } = require('playwright'); // import desired browser
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Playwright | Date |
|
||||
|:-----------|:-----------|
|
||||
| `1.49.1` | 2024-12-31 |
|
||||
| Playwright | Browser | Date |
|
||||
|:-----------|:------------|:-----------|
|
||||
| `1.52.0` | Webkit 18.4 | 2025-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
@ -332,9 +333,9 @@ This demo was tested in the following environments:
|
||||
|
||||
| Architecture | PhantomJS | Date |
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `2.1.1` | 2025-03-31 |
|
||||
| `win11-x64` | `2.1.1` | 2025-01-19 |
|
||||
| `linux-x64` | `2.1.1` | 2025-01-07 |
|
||||
| `darwin-x64` | `2.1.1` | 2026-03-07 |
|
||||
| `win11-x64` | `2.1.1` | 2026-03-07 |
|
||||
| `linux-x64` | `2.1.1` | 2026-03-07 |
|
||||
|
||||
:::
|
||||
|
||||
@ -420,7 +421,7 @@ a different error after assignment:
|
||||
This error is resolved by ignoring SSL errors. The complete command is:
|
||||
|
||||
```bash
|
||||
env OPENSSL_CONF=/dev/null QT_QPA_PLATFORM=phantom ./phantomjs-2.1.1-linux-x86_64/bin/phantomjs --ignore-ssl-errors=true test.js
|
||||
env OPENSSL_CONF=/dev/null QT_QPA_PLATFORM=phantom ./phantomjs-2.1.1-linux-x86_64/bin/phantomjs --ignore-ssl-errors=true SheetJSPhantom.js
|
||||
```
|
||||
|
||||
:::
|
||||
@ -429,4 +430,4 @@ env OPENSSL_CONF=/dev/null QT_QPA_PLATFORM=phantom ./phantomjs-2.1.1-linux-x86_6
|
||||
|
||||
[^1]: See ["Workbook Object"](/docs/csf/book) for more details about the SheetJS workbook object.
|
||||
[^2]: See [`table_to_book` in "HTML" Utilities](/docs/api/utilities/html#create-new-sheet)
|
||||
[^3]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
[^3]: See [`write` in "Writing Files"](/docs/api/write-options)
|
||||
|
||||
@ -296,10 +296,9 @@ features to ensure that SheetJS DOM methods can process TABLE elements.
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| CheerioJS | Date |
|
||||
|:--------------|:-----------|
|
||||
| `1.0.0` | 2025-04-24 |
|
||||
| `1.0.0-rc.12` | 2025-04-24 |
|
||||
| CheerioJS | Date |
|
||||
|:----------|:-----------|
|
||||
| `1.2.0` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -309,7 +308,7 @@ This demo was tested in the following deployments:
|
||||
1) Install SheetJS and CheerioJS libraries:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz cheerio@1.0.0`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz cheerio@1.1.2`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Download [the sample script `SheetJSCheerio.js`](pathname:///dom/SheetJSCheerio.js):
|
||||
@ -339,7 +338,7 @@ The script will create a file `SheetJSCheerio.xlsx` that can be opened.
|
||||
### DenoDOM
|
||||
|
||||
[DenoDOM](https://deno.land/x/deno_dom) provides a DOM framework for Deno. For
|
||||
the tested version (`0.1.48`), the following patches were needed:
|
||||
the tested version (`0.1.56`), the following patches were needed:
|
||||
|
||||
- TABLE `rows` property (explained above)
|
||||
- TR `cells` property (explained above)
|
||||
@ -350,7 +349,7 @@ This example fetches [a sample table](pathname:///dom/SheetJSTable.html):
|
||||
// @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts"
|
||||
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs';
|
||||
\n\
|
||||
import { DOMParser } from 'https://deno.land/x/deno_dom@v0.1.48/deno-dom-wasm.ts';
|
||||
import { DOMParser } from 'https://deno.land/x/deno_dom@v0.1.56/deno-dom-wasm.ts';
|
||||
\n\
|
||||
const doc = new DOMParser().parseFromString(
|
||||
await (await fetch('https://docs.sheetjs.com/dom/SheetJSTable.html')).text(),
|
||||
@ -375,12 +374,12 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | DenoDOM | Deno | Date |
|
||||
|:-------------|:--------|:-------|:-----------|
|
||||
| `darwin-x64` | 0.1.48 | 2.2.6 | 2025-03-31 |
|
||||
| `darwin-arm` | 0.1.48 | 2.2.12 | 2025-04-24 |
|
||||
| `win11-x64` | 0.1.48 | 2.0.4 | 2024-10-30 |
|
||||
| `win11-arm` | 0.1.48 | 2.2.1 | 2025-02-23 |
|
||||
| `linux-x64` | 0.1.48 | 2.0.5 | 2025-01-10 |
|
||||
| `linux-arm` | 0.1.48 | 2.1.10 | 2025-02-16 |
|
||||
| `darwin-x64` | 0.1.48 | 2.7.4 | 2026-03-07 |
|
||||
| `darwin-arm` | 0.1.48 | 2.7.4 | 2026-03-12 |
|
||||
| `win11-x64` | 0.1.56 | 2.7.14 | 2026-05-09 |
|
||||
| `win11-arm` | 0.1.48 | 2.7.7 | 2026-03-22 |
|
||||
| `linux-x64` | 0.1.48 | 2.7.4 | 2026-03-07 |
|
||||
| `linux-arm` | 0.1.48 | 2.7.4 | 2026-03-07 |
|
||||
|
||||
:::
|
||||
|
||||
@ -392,17 +391,17 @@ This demo was tested in the following deployments:
|
||||
2) Run the script with `--allow-net` and `--allow-write` entitlements:
|
||||
|
||||
```bash
|
||||
deno run --allow-net --allow-write SheetJSDenoDOM.ts
|
||||
deno run --allow-net --allow-write --allow-import SheetJSDenoDOM.ts
|
||||
```
|
||||
|
||||
The script will create a file `SheetJSDenoDOM.xlsx` that can be opened.
|
||||
|
||||
:::caution pass
|
||||
:::note pass
|
||||
|
||||
Deno 2 additionally requires the `--allow-import` entitlement:
|
||||
In older versions of Deno, the `--allow-import` flag must be omitted:
|
||||
|
||||
```bash
|
||||
deno run --allow-net --allow-write --allow-import SheetJSDenoDOM.ts
|
||||
deno run --allow-net --allow-write SheetJSDenoDOM.ts
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
@ -20,8 +20,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 131 | 2024-12-31 |
|
||||
| Safari 18.2 | 2024-12-31 |
|
||||
| Chromium 136 | 2025-05-21 |
|
||||
| Safari 18.2 | 2025-05-21 |
|
||||
| Konqueror 22 | 2025-04-23 |
|
||||
|
||||
:::
|
||||
|
||||
@ -19,8 +19,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 131 | 2024-12-31 |
|
||||
| Safari 18.2 | 2024-12-31 |
|
||||
| Chromium 136 | 2025-05-21 |
|
||||
| Safari 18.2 | 2025-05-21 |
|
||||
| Konqueror 22 | 2025-04-23 |
|
||||
|
||||
:::
|
||||
|
||||
@ -24,7 +24,7 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Browser | Version | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| Chromium 133 | `6.3.1` | 2025-03-31 |
|
||||
| Chromium 147 | `6.3.1` | 2026-05-22 |
|
||||
| Konqueror 22 | `6.3.1` | 2025-04-23 |
|
||||
|
||||
:::
|
||||
228
docz/docs/03-demos/04-grid/05-handsontable.md
Normal file
228
docz/docs/03-demos/04-grid/05-handsontable.md
Normal file
@ -0,0 +1,228 @@
|
||||
---
|
||||
title: Handsontable
|
||||
pagination_prev: demos/frontend/index
|
||||
pagination_next: demos/net/index
|
||||
---
|
||||
|
||||
<head>
|
||||
<script src="https://cdn.jsdelivr.net/npm/handsontable@6.2.2/dist/handsontable.full.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/handsontable@6.2.2/dist/handsontable.full.css"/>
|
||||
</head>
|
||||
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
:::danger pass
|
||||
|
||||
**Handsontable has relicensed away from open source!**
|
||||
|
||||
The original MIT license still applies to version `6.2.2`.
|
||||
|
||||
After adding the new `licenseKey` requirement, basic integrations still work
|
||||
with version `17.1.0`.
|
||||
|
||||
:::
|
||||
|
||||
[Handsontable](https://handsontable.com/) is a robust JavaScript data grid.
|
||||
|
||||
The following live integrations use the standalone build:
|
||||
|
||||
- [Version `6.2.2` (MIT Licensed)](pathname:///handsontable/)
|
||||
- [Version `17.1.0` (Proprietary)](pathname:///handsontable/non-oss.html)
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 148 | 2026-06-09 |
|
||||
| Safari 18.2 | 2026-06-09 |
|
||||
|
||||
:::
|
||||
|
||||
:::tip pass
|
||||
|
||||
This demo barely scratches the surface. The underlying grid component includes
|
||||
many additional features that work with [SheetJS Pro](https://sheetjs.com/pro).
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
|
||||
installation with Yarn and other package managers.
|
||||
|
||||
Using the `npm` tool, the following command installs SheetJS and Handsontable:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz handsontable@6.2.2`}
|
||||
</CodeBlock>
|
||||
|
||||
Methods and components in both libraries can be loaded in pages using `import`:
|
||||
|
||||
```js
|
||||
import { read, utils, writeFile } from 'xlsx';
|
||||
import Handsontable from 'handsontable';
|
||||
import 'handsontable/dist/handsontable.css'
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
Official framework wrapper packages (e.g. `@handsontable/react-wrapper`) should
|
||||
be used in greenfield projects, as they encapsulate best practices.
|
||||
|
||||
Due to framework volatility, the pre-baked integrations may not work with older
|
||||
versions of ReactJS.
|
||||
|
||||
:::
|
||||
|
||||
### Internal State
|
||||
|
||||
Handsontable uses [arrays of arrays](/docs/api/utilities/array#array-of-arrays)
|
||||
under the hood by default. This is the most flexible approach for processing
|
||||
arbitrary data.
|
||||
|
||||
If a schema is passed when the table is constructed, Handsontable will use
|
||||
[arrays of objects](/docs/api/utilities/array#arrays-of-objects) instead[^1].
|
||||
|
||||
### Reading Data
|
||||
|
||||
The SheetJS [`read`](/docs/api/parse-options) function processes file data and
|
||||
returns a [workbook object](/docs/csf/book). After selecting a worksheet, the
|
||||
[`sheet_to_json` method](/docs/api/utilities/array#array-output) can return an
|
||||
array of arrays or array of objects.
|
||||
|
||||
The result of `sheet_to_json` can be passed directly to the `loadData` method[^2]
|
||||
of a Handsontable instance.
|
||||
|
||||
The following snippet fetches a file, extracts data from the first worksheet,
|
||||
and passes the data to the grid:
|
||||
|
||||
```js
|
||||
import { read, utils } from 'xlsx';
|
||||
import Handsontable from 'handsontable';
|
||||
|
||||
/* `hot` is assumed to be the Handsontable instance */
|
||||
// const hot = new Handsontable(/* ... */);
|
||||
|
||||
async function fetch_and_view_first_sheet() {
|
||||
/* fetch and parse https://docs.sheetjs.com/pres.numbers */
|
||||
const file = await (await fetch("https://docs.sheetjs.com/pres.numbers")).arrayBuffer();
|
||||
const wb = read(file);
|
||||
|
||||
// highlight-start
|
||||
/* Generate an array of arrays from the first worksheet */
|
||||
const first_sheet = wb.Sheets[wb.SheetNames[0]];
|
||||
const aoa = utils.sheet_to_json(first_sheet, { header: 1 });
|
||||
|
||||
/* load data into Handsontable instance */
|
||||
hot.loadData(aoa);
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
|
||||
### Writing Data
|
||||
|
||||
The `getData` method[^3] of a Handsontable instance returns the current data. By
|
||||
default, the method returns an array of arrays.
|
||||
|
||||
The SheetJS [`aoa_to_sheet`](/docs/api/utilities/array#array-of-arrays-input)
|
||||
method generates a worksheet object from the data. After creating a new workbook
|
||||
with [`book_new`](/docs/api/utilities/wb), [`writeFile`](/docs/api/write-options)
|
||||
|
||||
The following snippet pulls data from the grid and exports to `SheetJSHOT.xlsx`:
|
||||
|
||||
```js
|
||||
import { utils, writeFile } from 'xlsx';
|
||||
import Handsontable from 'handsontable';
|
||||
|
||||
function export_data_to_xlsx(hot) {
|
||||
/* pull data from the Handsontable instance */
|
||||
const aoa = hot.getData();
|
||||
|
||||
/* generate a SheetJS worksheet object */
|
||||
const ws = utils.aoa_to_sheet(aoa);
|
||||
|
||||
/* generate a single-sheet workbook and export to SheetJSHOT.xlsx */
|
||||
const wb = utils.book_new(ws, "Exported Data");
|
||||
writeFile(wb, "SheetJSHOT.xlsx");
|
||||
}
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
For framework-native state management, the recommended approach is to listen for
|
||||
grid events and explicitly update a separate copy of the data[^4].
|
||||
|
||||
:::
|
||||
|
||||
## Demo
|
||||
|
||||
This sample ReactJS-powered site uses SheetJS and Handsontable to display data
|
||||
from a [sample NUMBERS spreadsheet](pathname:///pres.numbers) and export data
|
||||
to a new file.
|
||||
|
||||
1) Create a new project from the ViteJS `react-ts` template:
|
||||
|
||||
```bash
|
||||
npm create vite@latest -- sheetjs-hot --template react-ts --no-interactive
|
||||
cd sheetjs-hot
|
||||
npm i
|
||||
```
|
||||
|
||||
2) Install SheetJS and Handsontable libraries:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz handsontable@6.2.2`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Start the dev server:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
4) Download [`App.tsx`](pathname:///handsontable/App.tsx) and replace `src/App.tsx`:
|
||||
|
||||
```bash
|
||||
curl -L -o src/App.tsx https://docs.sheetjs.com/handsontable/App.tsx
|
||||
```
|
||||
|
||||
#### Testing
|
||||
|
||||
5) Refresh the browser window. A grid and two buttons should be visible:
|
||||
|
||||

|
||||
|
||||
6) Press the "Fetch File" button. The grid will refresh with Presidential data:
|
||||
|
||||

|
||||
|
||||
7) Make some changes to the grid data.
|
||||
|
||||
:::note pass
|
||||
|
||||
Some statisticians believe President Grover Cleveland should be counted once.
|
||||
That would imply President Clinton should be index 41 and the indices of the
|
||||
other presidents should be decremented.
|
||||
|
||||
:::
|
||||
|
||||
Double-click on each cell in the Index column and decrement each value. The new
|
||||
values should be 41, 42, 43, 44, and 45, as shown in the screenshot below:
|
||||
|
||||

|
||||
|
||||
8) Click on the "Download" button. The browser should attempt to download a new
|
||||
spreadsheet (`SheetJSHOT.xlsx`). Save the file.
|
||||
|
||||
Open the generated file and verify the contents match the grid.
|
||||
|
||||
[^1]: See ["Array of Objects" in the "Data management"](https://handsontable.com/docs/javascript-data-grid/binding-to-data/#array-of-objects) section of the Handsontable documentation for more details.
|
||||
[^2]: See [`loadData`](https://handsontable.com/docs/javascript-data-grid/api/core/#loaddata) in the Handsontable API documentation for more details.
|
||||
[^3]: See [`getData`](https://handsontable.com/docs/javascript-data-grid/api/core/#getdata) in the Handsontable API documentation for more details.
|
||||
[^4]: See ["Events and hooks" in the "Data management"](https://handsontable.com/docs/javascript-data-grid/events-and-hooks/) section of the Handsontable documentation for more details.
|
||||
@ -7,7 +7,7 @@ pagination_next: demos/net/index
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[React Data Grid](https://adazzle.github.io/react-data-grid/) is a data grid
|
||||
[React Data Grid](https://comcast.github.io/react-data-grid/) is a data grid
|
||||
designed for the ReactJS web framework.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
|
||||
@ -54,6 +54,12 @@ through a special Export button. It handles the SheetJS operations internally.
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/grid/tabulator)**
|
||||
|
||||
#### Handsontable
|
||||
|
||||
[Click here for a live integration demo.](pathname:///handsontable/)
|
||||
|
||||
**[The exposition has been moved to a separate page.](/docs/demos/grid/handsontable)**
|
||||
|
||||
#### Angular UI Grid
|
||||
|
||||
:::danger pass
|
||||
|
||||
@ -8,6 +8,11 @@ sidebar_custom_props:
|
||||
type: native
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[Lume](https://lume.land/) is a lightweight unopinionated static site generator.
|
||||
It has a rich ecosystem of JavaScript-powered plugins[^1]
|
||||
|
||||
@ -23,8 +28,11 @@ powered by an XLSX spreadsheet.
|
||||
## Integration Details
|
||||
|
||||
The official "Sheets" plugin[^2] uses SheetJS to load data from spreadsheets.
|
||||
Under the hood, the plugin uses the SheetJS `read`[^3] method to parse files and
|
||||
the `sheet_to_json`[^4] method to generate arrays of objects.
|
||||
Under the hood, the plugin uses the following SheetJS methods:
|
||||
|
||||
- [`read`](/docs/api/parse-options) parses spreadsheet files.
|
||||
- [`sheet_to_json`](/docs/api/utilities/array#array-output) generates arrays of
|
||||
objects from worksheet data.
|
||||
|
||||
Lume supports refreshing data during development. The generated static sites
|
||||
include the raw data without referencing the underlying spreadsheet files.
|
||||
@ -113,7 +121,7 @@ named `"VicePresidents"`, then the following snippet would print data from the
|
||||
|
||||
#### File Formats
|
||||
|
||||
As explained in the official plugin documentation[^5], the loader loads XLSX.
|
||||
As explained in the official plugin documentation[^3], the loader loads XLSX.
|
||||
NUMBERS, and CSV files. Other extensions can be added through the `extensions`
|
||||
property in the argument to the `sheets` plugin:
|
||||
|
||||
@ -133,8 +141,9 @@ This demo was tested in the following environments:
|
||||
|
||||
| Lume | Date |
|
||||
|:---------|:-----------|
|
||||
| `1.19.4` | 2025-01-02 |
|
||||
| `2.4.3` | 2025-01-02 |
|
||||
| `1.19.4` | 2025-09-13 |
|
||||
| `2.5.3` | 2025-09-13 |
|
||||
| `3.0.9` | 2025-09-13 |
|
||||
|
||||
This example uses the Nunjucks template format. Lume plugins support additional
|
||||
template formats, including Markdown and JSX.
|
||||
@ -143,26 +152,24 @@ template formats, including Markdown and JSX.
|
||||
|
||||
### Initial Setup
|
||||
|
||||
0) Install Deno[^6]
|
||||
0) Install Deno[^4]
|
||||
|
||||
1) Create a stock site:
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="v1" label="v1">
|
||||
|
||||
```bash
|
||||
mkdir -p sheetjs-lume
|
||||
cd sheetjs-lume
|
||||
deno run -Ar https://deno.land/x/lume@v2.4.3/init.ts
|
||||
deno run -Ar https://deno.land/x/lume@v1.19.4/init.ts
|
||||
```
|
||||
|
||||
When prompted, enter the following options. The initialization script has
|
||||
changed over time, so not all questions will be asked.
|
||||
When prompted, enter the following options:
|
||||
|
||||
- `What kind of setup do you want?`: select `Basic + plugins`
|
||||
- `Choose the configuration file format`: select `_config.ts`
|
||||
- `Do you want to install some plugins now?`: select `Yes`
|
||||
- `Select the plugins to install`: select `sheets` and `nunjucks`
|
||||
- `Do you want to setup a CMS?`: select `No` or `Maybe later`
|
||||
|
||||
The project will be configured and modules will be installed.
|
||||
- `Select the plugins to install`: select `sheets` and press <kbd>Enter</kbd>
|
||||
|
||||
:::note pass
|
||||
|
||||
@ -170,6 +177,53 @@ The `nunjucks` plugin was included by default in Lume version 1.
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="v2" label="v2">
|
||||
|
||||
```bash
|
||||
mkdir -p sheetjs-lume
|
||||
cd sheetjs-lume
|
||||
deno run -Ar https://deno.land/x/lume@v2.5.3/init.ts
|
||||
```
|
||||
|
||||
When prompted, enter the following options:
|
||||
|
||||
- `What kind of setup do you want?`: select `Basic + plugins`
|
||||
- `Select the plugins to install`: select `sheets` and `nunjucks`
|
||||
- `Do you want to setup a CMS?`: select `No` or `Maybe later`
|
||||
|
||||
:::note pass
|
||||
|
||||
The `nunjucks` plugin is not included by default in Lume version 2.
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="v3" label="v3">
|
||||
|
||||
```bash
|
||||
mkdir -p sheetjs-lume
|
||||
cd sheetjs-lume
|
||||
deno run -A https://lume.land/init.ts
|
||||
```
|
||||
|
||||
When prompted, enter the following options:
|
||||
|
||||
- `What kind of setup do you want?`: select `Basic + plugins`
|
||||
- `Select the plugins to install`: select `sheets` and `nunjucks`
|
||||
- `Do you want to setup a CMS?`: select `No` or `Maybe later`
|
||||
|
||||
:::note pass
|
||||
|
||||
The `nunjucks` plugin is not included by default in Lume version 3.
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
The project will be configured and modules will be installed.
|
||||
|
||||
2) Download https://docs.sheetjs.com/pres.xlsx and place in a `_data` subfolder:
|
||||
|
||||
```bash
|
||||
@ -231,7 +285,7 @@ This will create a static site in the `_site` folder
|
||||
8) Test the generated site by starting a web server:
|
||||
|
||||
```bash
|
||||
npx http-server _site
|
||||
npx -y http-server _site
|
||||
```
|
||||
|
||||
The program will display a URL (typically `http://localhost:8080`). Accessing
|
||||
@ -244,7 +298,5 @@ This site is self-contained and ready for deployment!
|
||||
|
||||
[^1]: See ["Plugins"](https://lume.land/plugins/?status=all) in the Lume documentation
|
||||
[^2]: See ["Sheets"](https://lume.land/plugins/sheets/) in the Lume documentation
|
||||
[^3]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^5]: See ["Formats"](https://lume.land/plugins/sheets/#formats) in the Lume documentation
|
||||
[^6]: See ["Installation"](https://deno.com/manual/getting_started/installation) in the Deno documentation
|
||||
[^3]: See ["Formats"](https://lume.land/plugins/sheets/#formats) in the Lume documentation
|
||||
[^4]: See ["Installation"](https://docs.deno.com/runtime/getting_started/installation/) in the Deno documentation
|
||||
@ -191,8 +191,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| GatsbyJS | Date |
|
||||
|:---------|:-----------|
|
||||
| `5.14.1` | 2025-01-19 |
|
||||
| `4.25.8` | 2025-01-02 |
|
||||
| `5.15.0` | 2025-09-13 |
|
||||
| `4.25.8` | 2025-09-13 |
|
||||
|
||||
:::
|
||||
|
||||
@ -241,6 +241,7 @@ git clone https://github.com/gatsbyjs/gatsby-starter-default sheetjs-gatsby
|
||||
cd sheetjs-gatsby
|
||||
git checkout 6bc4466090845f20650117b3d27e68e6e46dc8d5
|
||||
npm install
|
||||
mkdir .cache
|
||||
cd ..
|
||||
```
|
||||
|
||||
@ -250,6 +251,7 @@ cd ..
|
||||
|
||||
```bash
|
||||
cd sheetjs-gatsby
|
||||
npm i
|
||||
npm run develop
|
||||
```
|
||||
|
||||
|
||||
@ -204,23 +204,26 @@ This demo was tested in the following environments:
|
||||
|
||||
| `esbuild` | Date |
|
||||
|:----------|:-----------|
|
||||
| `0.24.2` | 2025-01-07 |
|
||||
| `0.23.1` | 2025-01-07 |
|
||||
| `0.22.0` | 2025-01-07 |
|
||||
| `0.21.5` | 2025-01-07 |
|
||||
| `0.20.2` | 2025-01-07 |
|
||||
| `0.19.12` | 2025-01-07 |
|
||||
| `0.18.20` | 2025-01-07 |
|
||||
| `0.17.19` | 2025-01-07 |
|
||||
| `0.16.17` | 2025-01-07 |
|
||||
| `0.15.18` | 2025-01-07 |
|
||||
| `0.14.54` | 2025-01-07 |
|
||||
| `0.13.15` | 2025-01-07 |
|
||||
| `0.12.29` | 2025-01-07 |
|
||||
| `0.11.23` | 2025-01-07 |
|
||||
| `0.10.2` | 2025-01-07 |
|
||||
| `0.9.7` | 2025-01-07 |
|
||||
| `0.9.1` | 2025-01-07 |
|
||||
| `0.27.2` | 2026-01-28 |
|
||||
| `0.26.0` | 2026-01-28 |
|
||||
| `0.25.5` | 2026-01-28 |
|
||||
| `0.24.2` | 2026-01-28 |
|
||||
| `0.23.1` | 2026-01-28 |
|
||||
| `0.22.0` | 2026-01-28 |
|
||||
| `0.21.5` | 2026-01-28 |
|
||||
| `0.20.2` | 2026-01-28 |
|
||||
| `0.19.12` | 2026-01-28 |
|
||||
| `0.18.20` | 2026-01-28 |
|
||||
| `0.17.19` | 2026-01-28 |
|
||||
| `0.16.17` | 2026-01-28 |
|
||||
| `0.15.18` | 2026-01-28 |
|
||||
| `0.14.54` | 2026-01-28 |
|
||||
| `0.13.15` | 2026-01-28 |
|
||||
| `0.12.29` | 2026-01-28 |
|
||||
| `0.11.23` | 2026-01-28 |
|
||||
| `0.10.2` | 2026-01-28 |
|
||||
| `0.9.7` | 2026-01-28 |
|
||||
| `0.9.1` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -294,7 +297,7 @@ The final script will be saved to `out.js`
|
||||
7) Start a local web server to host the project folder:
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
The command will print a list of URLs.
|
||||
|
||||
@ -356,11 +356,12 @@ This demo was tested in the following environments:
|
||||
|
||||
| ViteJS | Date |
|
||||
|:---------|:-----------|
|
||||
| `6.2.3` | 2025-03-30 |
|
||||
| `5.4.15` | 2025-03-30 |
|
||||
| `4.5.10` | 2025-03-30 |
|
||||
| `3.2.11` | 2025-03-30 |
|
||||
| `2.9.18` | 2025-03-30 |
|
||||
| `7.2.2` | 2025-11-15 |
|
||||
| `6.4.1` | 2025-11-15 |
|
||||
| `5.4.21` | 2025-11-15 |
|
||||
| `4.5.14` | 2025-11-15 |
|
||||
| `3.2.11` | 2025-11-15 |
|
||||
| `2.9.18` | 2025-11-15 |
|
||||
|
||||
:::
|
||||
|
||||
@ -376,7 +377,7 @@ major version. For example, `npm create vite@3` will use ViteJS major version 3.
|
||||
:::
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm create vite@5 sheetjs-vite -- --template vue-ts
|
||||
npm create vite@5 sheetjs-vite -- --template vue-ts --no-rolldown --no-interactive
|
||||
cd sheetjs-vite
|
||||
npm i
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
@ -430,7 +431,7 @@ Save and refresh the page. A data table should be displayed
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx http-server dist/
|
||||
npx -y http-server dist/
|
||||
```
|
||||
|
||||
The terminal will display a URL, typically `http://127.0.0.1:8080` . Access
|
||||
@ -506,7 +507,7 @@ Save and refresh the page. A data table should be displayed
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx http-server dist/
|
||||
npx -y http-server dist/
|
||||
```
|
||||
|
||||
The terminal will display a URL, typically `http://127.0.0.1:8080` . Access
|
||||
@ -594,7 +595,7 @@ const data = utils.sheet_to_json<IPresident>(ws);
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npx http-server dist/
|
||||
npx -y http-server dist/
|
||||
```
|
||||
|
||||
The terminal will display a URL ( `http://127.0.0.1:8080` ). Access that page
|
||||
|
||||
@ -186,9 +186,9 @@ document.body.appendChild(elt);
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Version | Date |
|
||||
|:---------|:-----------|
|
||||
| `5.97.1` | 2025-01-08 |
|
||||
| Version | Date |
|
||||
|:----------|:-----------|
|
||||
| `5.105.2` | 2026-03-12 |
|
||||
|
||||
:::
|
||||
|
||||
@ -334,7 +334,7 @@ The final site will be placed in the `dist` folder.
|
||||
12) Start a local web server to host the `dist` folder:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
The command will print a list of URLs.
|
||||
|
||||
@ -32,6 +32,7 @@ flowchart LR
|
||||
file --> |.eleventy.js\ncustom parser| buffer
|
||||
buffer --> |.eleventy.js\ncustom parser| aoo
|
||||
aoo --> |index.njk\ntemplate| html
|
||||
linkStyle 1 color:blue,stroke:blue;
|
||||
```
|
||||
|
||||
:::tip No Telemetry
|
||||
@ -114,10 +115,11 @@ accessed using the variable `pres` in a template:
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Eleventy | Date |
|
||||
|:---------|:-----------|
|
||||
| `2.0.1` | 2024-12-23 |
|
||||
| `3.0.0` | 2024-12-23 |
|
||||
| Eleventy | Date |
|
||||
|:----------------|:-----------|
|
||||
| `4.0.0-alpha.6` | 2026-01-28 |
|
||||
| `3.1.2` | 2026-01-28 |
|
||||
| `2.0.1` | 2026-01-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -212,7 +214,7 @@ Eleventy will place the generated site in the `_site` subfolder.
|
||||
9) Start a web server to host the static site:
|
||||
|
||||
```bash
|
||||
npx http-server _site
|
||||
npx -y http-server _site
|
||||
```
|
||||
|
||||
Open a web browser and access the displayed URL ( `http://localhost:8080` ).
|
||||
|
||||
@ -33,6 +33,9 @@ Content v1 (paired with VueJS 2.x and NuxtJS 2.x)
|
||||
The ["Nuxt Content v2"](#nuxt-content-v2) section explores "transformers" for
|
||||
NuxtJS Content v2 (paired with VueJS 3.x and NuxtJS 3.x)
|
||||
|
||||
The ["Nuxt Content v3"](#nuxt-content-v3) section explores raw ViteJS modules
|
||||
(paired with VueJS 3.x and NuxtJS 3.x)
|
||||
|
||||
:::info pass
|
||||
|
||||
This demo focuses on server-side processing with NuxtJS and VueJS.
|
||||
@ -49,7 +52,8 @@ This demo was tested in the following environments:
|
||||
| Nuxt Content | Nuxt | Date |
|
||||
|:-------------|:-----------|:-----------|
|
||||
| `1.15.1` | `2.18.1` | 2025-04-23 |
|
||||
| `2.13.4` | `3.14.159` | 2024-11-14 |
|
||||
| `2.13.4` | `3.17.2` | 2025-05-12 |
|
||||
| `3.5.1` | `3.17.3` | 2025-05-18 |
|
||||
|
||||
:::
|
||||
|
||||
@ -525,8 +529,8 @@ script files. The module script is expected to export a module configured with
|
||||
- Add the transformer to Nuxt Content in the `content:context` hook
|
||||
|
||||
```js title="sheetmodule.ts (Module)"
|
||||
import { resolve } from 'path'
|
||||
import { defineNuxtModule } from '@nuxt/kit'
|
||||
import { resolve } from 'path';
|
||||
import { defineNuxtModule } from '@nuxt/kit';
|
||||
|
||||
export default defineNuxtModule({
|
||||
/* module setup method */
|
||||
@ -549,7 +553,7 @@ The module must be loaded in `nuxt.config.ts` and added to the `modules` array:
|
||||
|
||||
```ts title="nuxt.config.ts"
|
||||
// highlight-next-line
|
||||
import SheetJSModule from './sheetmodule'
|
||||
import SheetJSModule from './sheetmodule';
|
||||
|
||||
export default defineNuxtConfig({
|
||||
// @ts-ignore
|
||||
@ -606,7 +610,7 @@ from the script setup will be shaped like the return value from the transformer.
|
||||
:::caution pass
|
||||
|
||||
For some older versions, parts of the Nuxt dependency tree did not support
|
||||
NodeJS version 20. If the `yarn install` step fails with a message like
|
||||
NodeJS version 20. If the `pnpm install` step fails with a message like
|
||||
|
||||
```
|
||||
error @nuxt/kit@3.4.1: The engine "node" is incompatible with this module.
|
||||
@ -619,17 +623,18 @@ The recommended solution is to switch to Node 18.
|
||||
1) Create a stock app and install dependencies:
|
||||
|
||||
```bash
|
||||
npx -y nuxi init -t content --packageManager yarn --no-gitInit sheetjs-nc2
|
||||
npx -y nuxi init -t content --packageManager pnpm --no-gitInit sheetjs-nc2 -M ,
|
||||
cd sheetjs-nc2
|
||||
npx -y yarn install
|
||||
npx -y yarn add --dev @types/node
|
||||
npx -y pnpm install
|
||||
npx -y pnpm install @nuxt/content@2 --save
|
||||
npx -y pnpm install @types/node @nuxt/kit --save
|
||||
```
|
||||
|
||||
2) Install the SheetJS library and start the server:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npx -y yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npx -y yarn dev`}
|
||||
npx -y pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npx -y pnpm dev`}
|
||||
</CodeBlock>
|
||||
|
||||
|
||||
@ -639,7 +644,7 @@ When the build finishes, the terminal will display a URL like:
|
||||
> Local: http://localhost:3000/
|
||||
```
|
||||
|
||||
The server is listening on that URL. Open the link in a web browser.
|
||||
The server is listening on that URL. Open the link in a web browser.
|
||||
|
||||
3) Download https://docs.sheetjs.com/pres.xlsx and move to the `content` folder.
|
||||
|
||||
@ -649,12 +654,12 @@ 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:
|
||||
|
||||
- [`sheetformer.ts`](https://docs.sheetjs.com/nuxt/3/sheetformer.ts) (raw transformer module)
|
||||
- [`sheetformer.ts`](https://docs.sheetjs.com/nuxt/2/sheetformer.ts) (raw transformer module)
|
||||
- [`sheetmodule.ts`](https://docs.sheetjs.com/nuxt/3/sheetmodule.ts) (Nuxt configuration module)
|
||||
|
||||
```bash
|
||||
curl -O https://docs.sheetjs.com/nuxt/3/sheetformer.ts
|
||||
curl -O https://docs.sheetjs.com/nuxt/3/sheetmodule.ts
|
||||
curl -O https://docs.sheetjs.com/nuxt/2/sheetformer.ts
|
||||
curl -O https://docs.sheetjs.com/nuxt/2/sheetmodule.ts
|
||||
```
|
||||
|
||||
After creating the source files, the module must be added to `nuxt.config.ts`:
|
||||
@ -668,14 +673,13 @@ export default defineNuxtConfig({
|
||||
// @ts-ignore
|
||||
telemetry: false,
|
||||
// highlight-end
|
||||
devtools: { enabled: true },
|
||||
// highlight-start
|
||||
modules: [
|
||||
// highlight-next-line
|
||||
SheetJSModule,
|
||||
'@nuxt/content'
|
||||
],
|
||||
content: {}
|
||||
// highlight-end
|
||||
devtools: { enabled: true },
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
@ -684,33 +688,13 @@ Stop the dev server (<kbd>CTRL</kbd>+<kbd>C</kbd>) and run the following:
|
||||
```bash
|
||||
npx -y nuxi clean
|
||||
npx -y nuxi cleanup
|
||||
npx -y nuxi typecheck
|
||||
npx -y yarn run dev
|
||||
npx -y pnpm run dev
|
||||
```
|
||||
|
||||
Loading `http://localhost:3000/pres` should show some JSON data:
|
||||
|
||||
```json
|
||||
{
|
||||
// ...
|
||||
"data": {
|
||||
"_path": "/pres",
|
||||
// ...
|
||||
"_id": "content:pres.xlsx",
|
||||
"body": [
|
||||
{
|
||||
"name": "Sheet1", // <-- sheet name
|
||||
"data": [ // <-- array of data objects
|
||||
{
|
||||
"Name": "Bill Clinton",
|
||||
"Index": 42
|
||||
},
|
||||
```
|
||||
|
||||
5) Download [`pres.vue`](pathname:///nuxt/3/pres.vue) and save to `pages`:
|
||||
5) Download [`pres.vue`](pathname:///nuxt/2/pres.vue) and save to `app/pages`:
|
||||
|
||||
```bash
|
||||
curl -o pages/pres.vue https://docs.sheetjs.com/nuxt/3/pres.vue
|
||||
curl -o app/pages/pres.vue https://docs.sheetjs.com/nuxt/2/pres.vue
|
||||
```
|
||||
|
||||
Stop the dev server (<kbd>CTRL</kbd>+<kbd>C</kbd>) and run the following:
|
||||
@ -718,24 +702,247 @@ Stop the dev server (<kbd>CTRL</kbd>+<kbd>C</kbd>) and run the following:
|
||||
```bash
|
||||
npx -y nuxi clean
|
||||
npx -y nuxi cleanup
|
||||
npx -y yarn run dev
|
||||
npx -y pnpm run dev
|
||||
```
|
||||
|
||||
The browser should now display an HTML table.
|
||||
6) From the browser window in step 2, access `/pres` from the site. For example,
|
||||
if the URL in step 2 was `http://localhost:3000/`, the new page should be
|
||||
`http://localhost:3000/pres`.
|
||||
|
||||
6) To verify that hot loading works, open `pres.xlsx` from the `content` folder
|
||||
This page should now display an HTML table.
|
||||
|
||||
7) To verify that hot loading works, open `pres.xlsx` from the `content` folder
|
||||
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.
|
||||
|
||||
8) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window).
|
||||
|
||||
9) Copy `app/pages/pres.vue` to `app/pages/index.vue`:
|
||||
|
||||
```bash
|
||||
cp app/pages/pres.vue app/pages/index.vue
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
In older test runs, the Nuxt starter created a default `/` page. The most recent
|
||||
test did not create the index page, resulting in build errors. This step ensures
|
||||
some sort of index page exists.
|
||||
|
||||
:::
|
||||
|
||||
10) Build the static site:
|
||||
|
||||
```bash
|
||||
npx -y pnpm run generate
|
||||
```
|
||||
|
||||
This will create a static site in `.output/public`, which can be served with:
|
||||
|
||||
```bash
|
||||
npx -y http-server .output/public
|
||||
```
|
||||
|
||||
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 v3
|
||||
|
||||
:::danger pass
|
||||
|
||||
When this demo was last tested, the official Nuxt Content v3 custom transformers
|
||||
and custom collections examples did not work.
|
||||
|
||||
:::
|
||||
|
||||
[ViteJS modules](/docs/demos/static/vitejs) can be used in Nuxt v3.
|
||||
|
||||
### Installation
|
||||
|
||||
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
|
||||
safely imported from `nuxt.config.ts` or transformer or module scripts. As long
|
||||
as the SheetJS modules are not imported in the various `.vue` pages, the library
|
||||
will not be added to the final page bundle!
|
||||
|
||||
### Configuration
|
||||
|
||||
The `vite` property in the NuxtJS config is passed to ViteJS. Plugins and other
|
||||
configuration options can be copied to the object. `vite.config.js` for the
|
||||
[Pure Data Plugin](/docs/demos/static/vitejs#pure-data-plugin) is shown below:
|
||||
|
||||
```js title="vite.config.js (raw ViteJS)"
|
||||
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 ?sheetjs tags
|
||||
name: "vite-sheet",
|
||||
transform(_code, id) {
|
||||
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).replace(/\\/g, "\\\\")}')`;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
```
|
||||
|
||||
The `assetsInclude` and `plugins` properties should be added within the `vite`
|
||||
property in the object passed to `defineNuxtConfig`.
|
||||
|
||||
:::danger pass
|
||||
|
||||
NuxtJS does not properly honor the `?sheetjs` tag! As a result, the transform
|
||||
explicitly tests for the `.xlsx` extension.
|
||||
|
||||
:::
|
||||
|
||||
```ts title="nuxt.config.ts"
|
||||
import { readFileSync } from 'fs';
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
export default defineNuxtConfig({
|
||||
// highlight-next-line
|
||||
vite: { // these options are passed to ViteJS
|
||||
assetsInclude: ['**/*.xlsx'], // xlsx file should be treated as assets
|
||||
|
||||
plugins: [
|
||||
{ // this plugin handles .xlsx
|
||||
name: "vite-sheet",
|
||||
transform(_code, id) {
|
||||
if(!id.match(/\.xlsx$/)) 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).replace(/\\/g, "\\\\")}')`;
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
// ...
|
||||
```
|
||||
|
||||
### Template Use
|
||||
|
||||
Pages can reference spreadsheets using a relative file reference. The ViteJS
|
||||
plugin will transform files with the `.xlsx` extension.
|
||||
|
||||
```js title="Script section of .vue VueJS page"
|
||||
import data from '../../pres.xlsx'; // data is an array of objects
|
||||
```
|
||||
|
||||
In the template, `data` is an array of objects that works with `v-for`[^4]:
|
||||
|
||||
```xml title="Template section of .vue VueJS page"
|
||||
<table>
|
||||
<thead><tr><th>Name</th><th>Index</th></tr></thead><tbody>
|
||||
<!-- loop over the rows of each worksheet -->
|
||||
<tr v-for="row in data" v-bind:key="row.Index">
|
||||
<!-- here `row` is a row object generated from sheet_to_json -->
|
||||
<td>{{ row.Name }}</td>
|
||||
<td>{{ row.Index }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
```
|
||||
|
||||
### Nuxt Content 3 Demo
|
||||
|
||||
1) Create a stock app and install dependencies:
|
||||
|
||||
```bash
|
||||
npx -y nuxi init -t content --packageManager pnpm --no-gitInit sheetjs-nc3 -M ,
|
||||
cd sheetjs-nc3
|
||||
npx -y pnpm install
|
||||
```
|
||||
|
||||
2) Install the SheetJS library and start the server:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npx -y pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npx -y pnpm dev`}
|
||||
</CodeBlock>
|
||||
|
||||
When the build finishes, the terminal will display a URL like:
|
||||
|
||||
```
|
||||
> Local: http://localhost:3000/
|
||||
```
|
||||
|
||||
The server is listening on that URL. Open the link in a web browser.
|
||||
|
||||
3) Download https://docs.sheetjs.com/pres.xlsx and move to the root folder:
|
||||
|
||||
```bash
|
||||
curl -o pres.xlsx https://docs.sheetjs.com/pres.xlsx
|
||||
```
|
||||
|
||||
4) Replace `nuxt.config.ts` with the following codeblock:
|
||||
|
||||
```ts title="nuxt.config.ts"
|
||||
import { readFileSync } from 'fs';
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
export default defineNuxtConfig({
|
||||
vite: { // these options are passed to ViteJS
|
||||
assetsInclude: ['**/*.xlsx'], // xlsx file should be treated as assets
|
||||
|
||||
plugins: [
|
||||
{ // this plugin handles .xlsx
|
||||
name: "vite-sheet",
|
||||
transform(_code, id) {
|
||||
if(!id.match(/\.xlsx$/)) 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).replace(/\\/g, "\\\\")}')`;
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
modules: [
|
||||
'@nuxt/content',
|
||||
],
|
||||
devtools: { enabled: true },
|
||||
});
|
||||
```
|
||||
|
||||
5) Create a new file `app.vue` with the following contents:
|
||||
|
||||
```html title="app.vue (create new file)"
|
||||
<script setup>
|
||||
import data from '../../pres.xlsx'
|
||||
</script>
|
||||
<template>
|
||||
<table><thead><tr><th>Name</th><th>Index</th></tr></thead><tbody>
|
||||
<tr v-for="row in data" v-bind:key="row.Index">
|
||||
<td>{{ row.Name }}</td>
|
||||
<td>{{ row.Index }}</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
</template>
|
||||
```
|
||||
|
||||
6) Refresh the browser window. This page should now display an HTML table.
|
||||
|
||||
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
|
||||
npx -y pnpm run generate
|
||||
```
|
||||
|
||||
This will create a static site in `.output/public`, which can be served with:
|
||||
|
||||
@ -52,13 +52,14 @@ This demo was tested in the following environments:
|
||||
|
||||
| AstroJS | Template | Date |
|
||||
|:--------|:-----------------|:-----------|
|
||||
| `4.6.1` | Starlight 0.22.4 | 2025-01-07 |
|
||||
| `5.1.3` | Starlight 0.30.5 | 2025-01-07 |
|
||||
| `6.0.6` | Starlight 0.38.1 | 2026-03-22 |
|
||||
|
||||
In previous test runs, this demo successfully ran using older AstroJS versions:
|
||||
|
||||
| AstroJS | Template |
|
||||
|:--------|:-----------------|
|
||||
| `5.1.3` | Starlight 0.30.5 |
|
||||
| `4.6.1` | Starlight 0.22.4 |
|
||||
| `3.6.5` | Starlight 0.14.0 |
|
||||
|
||||
:::
|
||||
@ -345,7 +346,7 @@ AstroJS will place the generated site in the `dist` subfolder.
|
||||
9) Start a web server to host the static site:
|
||||
|
||||
```bash
|
||||
npx http-server dist
|
||||
npx -y http-server dist
|
||||
```
|
||||
|
||||
Open a web browser and access the displayed URL ( `http://localhost:8080` ).
|
||||
|
||||
@ -241,8 +241,8 @@ This demo was tested in the following environments:
|
||||
|:-----------|:--------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `0.76.8` | `darwin-arm` | 2025-03-26 |
|
||||
| iOS 18.3 | iPhone 16 Pro | `0.76.8` | `darwin-arm` | 2025-03-26 |
|
||||
| Android 35 | Pixel 9 | `0.76.5` | `win11-x64` | 2024-12-22 |
|
||||
| Android 35 | Pixel 9 | `0.76.5` | `linux-x64` | 2025-01-02 |
|
||||
| Android 35 | Pixel 9 Pro XL | `0.79.2` | `win11-x64` | 2025-06-08 |
|
||||
| Android 36 | Pixel 9 | `0.79.2` | `linux-x64` | 2025-07-06 |
|
||||
|
||||
:::
|
||||
|
||||
@ -259,12 +259,22 @@ Make sure you can run a basic test app on your phone/simulator before continuing
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
**Java JDK**
|
||||
|
||||
On the Steam Deck, JDK17 was installed using `pacman`:
|
||||
|
||||
```bash
|
||||
sudo pacman -Syu jdk17-openjdk
|
||||
```
|
||||
|
||||
Debian and Ubuntu require the `openjdk-17-jdk` package:
|
||||
|
||||
```bash
|
||||
sudo apt install openjdk-17-jdk
|
||||
```
|
||||
|
||||
**Android Studio for Linux**
|
||||
|
||||
[The Android Studio tarball](https://developer.android.com/studio) was
|
||||
downloaded and extracted. After extracting:
|
||||
|
||||
@ -276,6 +286,8 @@ cd ./android-studio/bin
|
||||
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)".
|
||||
|
||||
**Environment Variables for Linux**
|
||||
|
||||
When this demo was last tested, the following environment variables were used:
|
||||
|
||||
```bash
|
||||
@ -289,7 +301,7 @@ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
|
||||
1) Create project:
|
||||
|
||||
```bash
|
||||
npx -y @react-native-community/cli@15 init SheetJSRNFetch --version="0.76.8"
|
||||
npx -y @react-native-community/cli@18 init SheetJSRNFetch --version="0.79.2"
|
||||
```
|
||||
|
||||
On macOS, if prompted to install `CocoaPods`, press <kbd>Y</kbd>
|
||||
@ -330,12 +342,47 @@ npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm i -S https://cdn.sheetjs.com/react-native-tabeller-0.1.0/react-native-tabeller-0.1.0.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::note pass
|
||||
|
||||
In PowerShell, the command may fail with a parameter error:
|
||||
|
||||
```
|
||||
Invoke-WebRequest : A parameter cannot be found that matches parameter name 'LO'.
|
||||
```
|
||||
|
||||
`curl.exe` must be invoked directly:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
cd SheetJSRNFetch
|
||||
curl.exe -LO https://docs.sheetjs.com/logo.png
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm i -S https://cdn.sheetjs.com/react-native-tabeller-0.1.0/react-native-tabeller-0.1.0.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
3) Download and replace [`App.tsx`](pathname:///reactnative/App.tsx):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/reactnative/App.tsx
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
In PowerShell, the command may fail with a parameter error:
|
||||
|
||||
```
|
||||
Invoke-WebRequest : A parameter cannot be found that matches parameter name 'LO'.
|
||||
```
|
||||
|
||||
`curl.exe` must be invoked directly:
|
||||
|
||||
```bash
|
||||
curl.exe -LO https://docs.sheetjs.com/reactnative/App.tsx
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
**Android Testing**
|
||||
|
||||
4) Install or switch to Java 17[^7]
|
||||
@ -355,8 +402,8 @@ the interactive CLI tool:
|
||||
npx react-native start
|
||||
```
|
||||
|
||||
Once the dev server is ready, the terminal will display a few options. Press `a`
|
||||
to run on Android.
|
||||
Once the dev server is ready, the terminal will display a few options. Press
|
||||
<kbd>r</kbd> to relaod the app.
|
||||
|
||||
:::
|
||||
|
||||
@ -578,7 +625,7 @@ reconnect the device before trying again.
|
||||
|
||||
:::info pass
|
||||
|
||||
In some test runs, the app requested for local network access:
|
||||
In some test runs, the app requested for local network access:
|
||||
|
||||
> "SheetJSRNFetch" would like to find and connect to devices on your local network.
|
||||
|
||||
@ -1096,8 +1143,8 @@ This demo was tested in the following environments:
|
||||
|:-----------|:------------------|:---------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `0.76.5` | `darwin-arm` | 2025-01-05 |
|
||||
| iOS 18.2 | iPhone 16 Pro | `0.76.5` | `darwin-arm` | 2025-01-05 |
|
||||
| Android 35 | Pixel 9 | `0.76.5` | `win11-x64` | 2024-12-22 |
|
||||
| Android 35 | Pixel 9 | `0.76.5` | `linux-x64` | 2025-01-02 |
|
||||
| Android 35 | Pixel 9 Pro XL | `0.76.5` | `win11-x64` | 2025-06-08 |
|
||||
| Android 36 | Pixel 9 | `0.76.5` | `linux-x64` | 2025-07-06 |
|
||||
|
||||
:::
|
||||
|
||||
@ -1128,15 +1175,50 @@ On macOS, if prompted to install `CocoaPods`, press <kbd>Y</kbd>
|
||||
cd SheetJSRN
|
||||
curl -LO https://docs.sheetjs.com/logo.png
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm i -S react-native-table-component@1.2.2 react-native-document-picker@9.3.1`}
|
||||
npm i -S https://cdn.sheetjs.com/react-native-tabeller-0.1.0/react-native-tabeller-0.1.0.tgz react-native-document-picker@9.3.1`}
|
||||
</CodeBlock>
|
||||
|
||||
:::note pass
|
||||
|
||||
In PowerShell, the command may fail with a parameter error:
|
||||
|
||||
```
|
||||
Invoke-WebRequest : A parameter cannot be found that matches parameter name 'LO'.
|
||||
```
|
||||
|
||||
`curl.exe` must be invoked directly:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
cd SheetJSRN
|
||||
curl.exe -LO https://docs.sheetjs.com/logo.png
|
||||
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm i -S https://cdn.sheetjs.com/react-native-tabeller-0.1.0/react-native-tabeller-0.1.0.tgz react-native-document-picker@9.3.1`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
3) Download [`index.js`](pathname:///mobile/index.js) and replace:
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/mobile/index.js
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
In PowerShell, the command may fail with a parameter error:
|
||||
|
||||
```
|
||||
Invoke-WebRequest : A parameter cannot be found that matches parameter name 'LO'.
|
||||
```
|
||||
|
||||
`curl.exe` must be invoked directly:
|
||||
|
||||
```bash
|
||||
curl.exe -LO https://docs.sheetjs.com/mobile/index.js
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
4) Start the Android emulator:
|
||||
|
||||
```bash
|
||||
@ -1147,6 +1229,20 @@ The app should look like the following screenshot:
|
||||
|
||||

|
||||
|
||||
:::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
|
||||
<kbd>r</kbd> to relaod the app.
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
In some test runs on Windows, the build failed with an error:
|
||||
@ -1192,13 +1288,13 @@ Stop the dev server and close the React Native Metro NodeJS window.
|
||||
Install `react-native-blob-util` dependency:
|
||||
|
||||
```bash
|
||||
npm i -S react-native-blob-util@0.21.2
|
||||
npm i -S react-native-blob-util@0.22.2
|
||||
```
|
||||
|
||||
Add the highlighted lines to `index.js`:
|
||||
|
||||
```js title="index.js"
|
||||
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
|
||||
```js title="index.js (add highlighted lines)"
|
||||
import { Table, Row, Rows, TableWrapper } from 'react-native-tabeller';
|
||||
|
||||
// highlight-start
|
||||
import { read, write } from 'xlsx';
|
||||
@ -1246,7 +1342,7 @@ npm i -S react-native-file-access@3.1.1
|
||||
Add the highlighted lines to `index.js`:
|
||||
|
||||
```js title="index.js"
|
||||
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
|
||||
import { Table, Row, Rows, TableWrapper } from 'react-native-tabeller';
|
||||
|
||||
// highlight-start
|
||||
import { read, write } from 'xlsx';
|
||||
@ -1313,7 +1409,7 @@ These errors can be ignored.
|
||||
Add the highlighted lines to `index.js`:
|
||||
|
||||
```js title="index.js"
|
||||
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
|
||||
import { Table, Row, Rows, TableWrapper } from 'react-native-tabeller';
|
||||
|
||||
// highlight-start
|
||||
import { read, write } from 'xlsx';
|
||||
@ -1687,7 +1783,7 @@ The Numbers app will load the spreadsheet, confirming that the file is valid.
|
||||
[^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 is available in official releases starting from `0.72.0`.
|
||||
[^6]: See [the compatibility table](https://github.com/react-native-community/cli) in the CLI project repository to determine which version of `@react-native-community/cli` is required for a given `react-native` version.
|
||||
[^6]: See [the compatibility table](https://github.com/react-native-community/cli/blob/main/README.md#compatibility) in the CLI project repository to determine which version of `@react-native-community/cli` is required for a given `react-native` version.
|
||||
[^7]: 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)
|
||||
[^8]: See ["Running On Device"](https://reactnative.dev/docs/running-on-device) in the React Native documentation
|
||||
[^9]: See [`UIFileSharingEnabled`](https://developer.apple.com/documentation/bundleresources/information_property_list/uifilesharingenabled) in the Apple Developer Documentation.
|
||||
|
||||
@ -56,17 +56,17 @@ This demo was tested in the following environments:
|
||||
|
||||
| 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 |
|
||||
| Android 30 | NVIDIA Shield | `8.9.2` | 2025-05-06 |
|
||||
| iOS 15.1 | iPad Pro | `8.9.2` | 2025-05-06 |
|
||||
|
||||
**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 35 | Pixel 9 | `8.8.3` | `win11-x64` | 2024-12-21 |
|
||||
| Android 35 | Pixel 9 | `8.8.3` | `linux-x64` | 2025-01-02 |
|
||||
| Android 35 | Pixel 9 Pro XL | `8.9.2` | `darwin-x64` | 2025-05-06 |
|
||||
| iOS 18.4 | iPhone 16 Pro Max | `8.9.2` | `darwin-x64` | 2025-05-06 |
|
||||
| Android 35 | Pixel 9 | `8.9.2` | `win11-x64` | 2025-06-08 |
|
||||
| Android 36 | Pixel 9 | `8.9.2` | `linux-x64` | 2025-07-06 |
|
||||
|
||||
:::
|
||||
|
||||
@ -78,15 +78,15 @@ NativeScript 8.6.1 split the telemetry into two parts: "usage" and "error". Both
|
||||
must be disabled separately:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns usage-reporting disable
|
||||
npx -p nativescript ns error-reporting disable
|
||||
npx -y -p nativescript ns usage-reporting disable
|
||||
npx -y -p nativescript ns error-reporting disable
|
||||
```
|
||||
|
||||
To verify telemetry was disabled:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns usage-reporting status
|
||||
npx -p nativescript ns error-reporting status
|
||||
npx -y -p nativescript ns usage-reporting status
|
||||
npx -y -p nativescript ns error-reporting status
|
||||
```
|
||||
|
||||
:::
|
||||
@ -120,6 +120,22 @@ for accessing data and are subject to change in future platform versions.
|
||||
<details>
|
||||
<summary><b>Technical Details</b> (click to show)</summary>
|
||||
|
||||
**iOS**
|
||||
|
||||
The following key/value pairs must be added to `Info.plist`:
|
||||
|
||||
```xml title="App_Resources/iOS/Info.plist (add highlighted lines)"
|
||||
<dict>
|
||||
<!-- highlight-start -->
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<!-- highlight-end -->
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Android**
|
||||
|
||||
Android security has evolved over the years. In newer Android versions, the
|
||||
@ -265,8 +281,8 @@ const wb = read(ab);
|
||||
0) Disable telemetry:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns usage-reporting disable
|
||||
npx -p nativescript ns error-reporting disable
|
||||
npx -y -p nativescript ns usage-reporting disable
|
||||
npx -y -p nativescript ns error-reporting disable
|
||||
```
|
||||
|
||||
1) Follow the official Environment Setup instructions[^8].
|
||||
@ -274,14 +290,14 @@ npx -p nativescript ns error-reporting disable
|
||||
:::caution pass
|
||||
|
||||
In previous test runs, NativeScript did not support the latest Android API.
|
||||
The error message from `npx -p nativescript ns doctor android` clearly stated
|
||||
The error message from `npx -y -p nativescript ns doctor android` clearly stated
|
||||
supported versions:
|
||||
|
||||
<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>
|
||||
|
||||
If NativeScript does not properly supports the latest API level, a previous API
|
||||
If NativeScript does not properly support the latest API level, an older API
|
||||
version should be installed using Android Studio.
|
||||
|
||||
In a previous test run, the following packages were required:
|
||||
@ -290,14 +306,14 @@ In a previous test run, the following packages were required:
|
||||
- `Android SDK Build-Tools` Version `33.0.2`
|
||||
|
||||
It is recommended to install the SDK Platform and corresponding Android SDK
|
||||
Build-Tools for the latest supported API level.ß
|
||||
Build-Tools for the latest supported API level.
|
||||
|
||||
:::
|
||||
|
||||
2) Test the local system configuration for Android development:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns doctor android
|
||||
npx -y -p nativescript ns doctor android
|
||||
```
|
||||
|
||||
In the last macOS test, the following output was displayed:
|
||||
@ -316,7 +332,7 @@ In the last macOS test, the following output was displayed:
|
||||
<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.
|
||||
<span {...g}>✔</span> Component nativescript has 8.9.2 version and is up to date.
|
||||
</pre>
|
||||
|
||||
</details>
|
||||
@ -324,7 +340,7 @@ In the last macOS test, the following output was displayed:
|
||||
3) Test the local system configuration for iOS development (macOS only):
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns doctor ios
|
||||
npx -y -p nativescript ns doctor ios
|
||||
```
|
||||
|
||||
In the last macOS test, the following output was displayed:
|
||||
@ -343,9 +359,9 @@ In the last macOS test, the following output was displayed:
|
||||
<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> Xcode version 16.3.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.
|
||||
<span {...g}>✔</span> Component nativescript has 8.9.2 version and is up to date.
|
||||
</pre>
|
||||
|
||||
</details>
|
||||
@ -355,21 +371,21 @@ In the last macOS test, the following output was displayed:
|
||||
4) Create a skeleton NativeScript + Angular app:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns create SheetJSNS --ng
|
||||
npx -y -p nativescript ns create SheetJSNS --ng
|
||||
```
|
||||
|
||||
5) Launch the app in the android simulator to verify the app:
|
||||
5) Launch the app in the Android simulator to verify the app:
|
||||
|
||||
```bash
|
||||
cd SheetJSNS
|
||||
npx -p nativescript ns run android
|
||||
npx -y -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 pressing <kbd>CTRL</kbd>+<kbd>C</kbd>. On Windows, if
|
||||
prompted to `Terminate batch job`, type `y` and press Enter.
|
||||
prompted to `Terminate batch job`, type <kbd>Y</kbd> and press Enter.
|
||||
|
||||
:::note pass
|
||||
|
||||
@ -381,6 +397,23 @@ Emulator start failed with: No emulator image available for device identifier 'u
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
In the most recent test, the build failed with an exception:
|
||||
|
||||
```
|
||||
WARNING: A restricted method in java.lang.System has been called
|
||||
WARNING: java.lang.System::load has been called by net.rubygrapefruit.platform.internal.NativeLibraryLoader in an unnamed module (file:/Users/sheetjs/.gradle/wrapper/dists/gradle-8.7-bin/bhs2wmbdwecv87pi65oeuq5iu/gradle-8.7/lib/native-platform-0.22-milestone-25.jar)
|
||||
WARNING: Use --enable-native-access=ALL-UNNAMED to avoid a warning for callers in this module
|
||||
WARNING: Restricted methods will be blocked in a future release unless native access is enabled
|
||||
```
|
||||
|
||||
**The NativeScript Gradle version is incompatible with Java 24!**
|
||||
|
||||
It is strongly recommended to roll back to Java 21.
|
||||
|
||||
:::
|
||||
|
||||
### Add SheetJS
|
||||
|
||||
:::note pass
|
||||
@ -401,16 +434,15 @@ SheetJS version string and adds it to a `version` variable in the component:
|
||||
```ts title="src/app/item/items.component.ts (add highlighted lines)"
|
||||
// highlight-next-line
|
||||
import { version } from 'xlsx';
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
import { Component, NO_ERRORS_SCHEMA, inject } from '@angular/core'
|
||||
|
||||
// ...
|
||||
|
||||
export class ItemsComponent implements OnInit {
|
||||
items: Array<Item>
|
||||
export class ItemsComponent {
|
||||
// highlight-next-line
|
||||
version = `SheetJS - ${version}`;
|
||||
|
||||
constructor(private itemService: ItemService) {}
|
||||
itemService = inject(ItemService)
|
||||
page = inject(Page)
|
||||
// ...
|
||||
```
|
||||
|
||||
@ -428,7 +460,7 @@ in the title of the action bar:
|
||||
9) End the script and relaunch the app in the Android simulator:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
npx -y -p nativescript ns run android
|
||||
```
|
||||
|
||||
The title bar should show the version.
|
||||
@ -449,7 +481,7 @@ The title bar should show the version.
|
||||
<Button text="Export File" (tap)="export()" style="padding: 10px"></Button>
|
||||
</StackLayout>
|
||||
<!-- highlight-end -->
|
||||
<ListView [items]="items">
|
||||
<ListView [items]="itemService.items()">
|
||||
<!-- ... -->
|
||||
</ListView>
|
||||
<!-- highlight-next-line -->
|
||||
@ -458,15 +490,15 @@ The title bar should show the version.
|
||||
|
||||
11) Add the `import` and `export` methods in the component script:
|
||||
|
||||
```ts title="src/app/item/items.component.ts"
|
||||
```ts title="src/app/item/items.component.ts (add highlighted lines)"
|
||||
// highlight-start
|
||||
import { version, utils, read, write } from 'xlsx';
|
||||
import { Dialogs, getFileAccess } from '@nativescript/core';
|
||||
import { Folder, knownFolders, path } from '@nativescript/core/file-system';
|
||||
// highlight-end
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
|
||||
import { Item } from './item'
|
||||
import { Component, NO_ERRORS_SCHEMA, inject } from '@angular/core'
|
||||
import { NativeScriptCommonModule, NativeScriptRouterModule } from '@nativescript/angular'
|
||||
import { Page } from '@nativescript/core'
|
||||
import { ItemService } from './item.service'
|
||||
|
||||
// highlight-start
|
||||
@ -476,19 +508,12 @@ function get_url_for_filename(filename: string): string {
|
||||
}
|
||||
// highlight-end
|
||||
|
||||
@Component({
|
||||
selector: 'ns-items',
|
||||
templateUrl: './items.component.html',
|
||||
})
|
||||
export class ItemsComponent implements OnInit {
|
||||
items: Array<Item>
|
||||
version: string = `SheetJS - ${version}`;
|
||||
// ...
|
||||
|
||||
constructor(private itemService: ItemService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.items = this.itemService.getItems()
|
||||
}
|
||||
export class ItemsComponent {
|
||||
version = `SheetJS - ${version}`;
|
||||
itemService = inject(ItemService)
|
||||
page = inject(Page)
|
||||
|
||||
// highlight-start
|
||||
/* Import button */
|
||||
@ -499,13 +524,14 @@ export class ItemsComponent implements OnInit {
|
||||
async export() {
|
||||
}
|
||||
// highlight-end
|
||||
}
|
||||
|
||||
// ...
|
||||
```
|
||||
|
||||
12) End the script and relaunch the app in the Android simulator:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
npx -y -p nativescript ns run android
|
||||
```
|
||||
|
||||
Two buttons should appear just below the header:
|
||||
@ -534,7 +560,7 @@ Two buttons should appear just below the header:
|
||||
const ws = wb.Sheets[wsname];
|
||||
|
||||
/* update table */
|
||||
this.items = utils.sheet_to_json<Item>(ws);
|
||||
this.itemService.items.set(utils.sheet_to_json(ws));
|
||||
} catch(e) { await Dialogs.alert(e.message); }
|
||||
// highlight-end
|
||||
}
|
||||
@ -547,7 +573,7 @@ Two buttons should appear just below the header:
|
||||
|
||||
try {
|
||||
/* create worksheet from data */
|
||||
const ws = utils.json_to_sheet(this.items);
|
||||
const ws = utils.json_to_sheet(this.itemService.items());
|
||||
|
||||
/* create workbook from worksheet */
|
||||
const wb = utils.book_new();
|
||||
@ -569,7 +595,7 @@ Two buttons should appear just below the header:
|
||||
14) Launch the app in the Android Simulator:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
npx -y -p nativescript ns run android
|
||||
```
|
||||
|
||||
If the app does not automatically launch, manually open the `SheetJSNS` app.
|
||||
@ -585,7 +611,7 @@ adb root
|
||||
adb pull /data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls SheetJSNS.xls
|
||||
```
|
||||
|
||||
If the emulator cannot be rooted, the following command works in macOS:
|
||||
If the emulator cannot be rooted, the following workaround should be used:
|
||||
|
||||
```bash
|
||||
adb shell "run-as org.nativescript.SheetJSNS cat /data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls" > SheetJSNS.xls
|
||||
@ -611,8 +637,8 @@ $bytes = [Convert]::FromBase64String($b64)
|
||||
After the header row, insert a row and make the following assignments:
|
||||
|
||||
- Set cell `A2` to `0`
|
||||
- Set cell `B2` to `SheetJS` (type `'SheetJS` in the formula bar)
|
||||
- Set cell `C2` to `Library` (type `'Library` in the formula bar)
|
||||
- Set cell `B2` to `SheetJS` (type `'SheetJS` in the formula bar)
|
||||
- Set cell `C2` to `Library` (type `'Library` in the formula bar)
|
||||
|
||||
After making the changes, the worksheet should look like the following:
|
||||
|
||||
@ -620,8 +646,6 @@ After making the changes, the worksheet should look like the following:
|
||||
id | name | role
|
||||
# highlight-next-line
|
||||
0 | SheetJS | Library
|
||||
1 | Ter Stegen | Goalkeeper
|
||||
3 | Piqué | Defender
|
||||
...
|
||||
```
|
||||
|
||||
@ -631,7 +655,7 @@ id | name | role
|
||||
adb push SheetJSNS.xls /data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls
|
||||
```
|
||||
|
||||
If the emulator cannot be rooted, the following command works in macOS:
|
||||
If the emulator cannot be rooted, raw byte operations work in macOS and Linux:
|
||||
|
||||
```bash
|
||||
dd if=SheetJSNS.xls | adb shell "run-as org.nativescript.SheetJSNS dd of=/data/user/0/org.nativescript.SheetJSNS/files/SheetJSNS.xls"
|
||||
@ -671,7 +695,7 @@ Scroll down to ["Fetching Files"](#android-device) for Android device testing.
|
||||
20) Launch the app in the iOS Simulator:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run ios
|
||||
npx -y -p nativescript ns run ios
|
||||
```
|
||||
|
||||
21) Tap "Export File". A dialog will print where the file was written.
|
||||
@ -681,8 +705,8 @@ npx -p nativescript ns run ios
|
||||
After the header row, insert a row and make the following assignments:
|
||||
|
||||
- Set cell `A2` to `0`
|
||||
- Set cell `B2` to `SheetJS` (type `'SheetJS` in the formula bar)
|
||||
- Set cell `C2` to `Library` (type `'Library` in the formula bar)
|
||||
- Set cell `B2` to `SheetJS` (type `'SheetJS` in the formula bar)
|
||||
- Set cell `C2` to `Library` (type `'Library` in the formula bar)
|
||||
|
||||
After making the changes, the worksheet should look like the following:
|
||||
|
||||
@ -690,8 +714,6 @@ After making the changes, the worksheet should look like the following:
|
||||
id | name | role
|
||||
# highlight-next-line
|
||||
0 | SheetJS | Library
|
||||
1 | Ter Stegen | Goalkeeper
|
||||
3 | Piqué | Defender
|
||||
...
|
||||
```
|
||||
|
||||
@ -704,31 +726,21 @@ The first item in the list will change:
|
||||
|
||||
### Fetching Files
|
||||
|
||||
25) In `src/app/item/items.component.ts`, make `ngOnInit` asynchronous:
|
||||
|
||||
```ts title="src/app/item/items.component.ts (replace existing function)"
|
||||
async ngOnInit(): Promise<void> {
|
||||
this.items = await this.itemService.getItems()
|
||||
}
|
||||
```
|
||||
|
||||
26) Replace `item.service.ts` with the following:
|
||||
25) Replace `item.service.ts` with the following:
|
||||
|
||||
```ts title="src/app/item/item.service.ts"
|
||||
import { Injectable } from '@angular/core'
|
||||
|
||||
import { knownFolders, path, getFileAccess } from '@nativescript/core'
|
||||
import { getFile } from '@nativescript/core/http';
|
||||
import { read, utils } from 'xlsx';
|
||||
|
||||
import { Injectable, signal, effect } from '@angular/core'
|
||||
import { knownFolders, path, getFileAccess } from '@nativescript/core';
|
||||
import { getFile } from '@nativescript/core/http';
|
||||
import { Item } from './item'
|
||||
|
||||
interface IPresident { Name: string; Index: number };
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ItemService {
|
||||
private items: Array<Item>;
|
||||
|
||||
async getItems(): Promise<Array<Item>> {
|
||||
items = signal<Item[]>([]);
|
||||
constructor() { effect(() => { (async() => {
|
||||
/* fetch https://docs.sheetjs.com/pres.xlsx */
|
||||
const temp: string = path.join(knownFolders.temp().path, "pres.xlsx");
|
||||
const ab = await getFile("https://docs.sheetjs.com/pres.xlsx", temp)
|
||||
@ -736,32 +748,33 @@ export class ItemService {
|
||||
const wb = read(await getFileAccess().readBufferAsync(ab.path));
|
||||
/* translate the first worksheet to the required Item type */
|
||||
const data = utils.sheet_to_json<IPresident>(wb.Sheets[wb.SheetNames[0]]);
|
||||
return this.items = data.map((pres, id) => ({id, name: pres.Name, role: ""+pres.Index} as Item));
|
||||
}
|
||||
/* update state */
|
||||
this.items.set(data.map((pres, id) => ({id, name: pres.Name, role: ""+pres.Index} as Item)));
|
||||
})(); }); }
|
||||
|
||||
getItem(id: number): Item {
|
||||
return this.items.filter((item) => item.id === id)[0]
|
||||
return this.items().find((item) => item.id === id)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
27) End the script and relaunch the app in the Android simulator:
|
||||
26) End the script and relaunch the app in the Android simulator:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
npx -y -p nativescript ns run android
|
||||
```
|
||||
|
||||
The app should show Presidential data.
|
||||
|
||||
### Android Device
|
||||
|
||||
28) Connect an Android device using a USB cable.
|
||||
27) Connect an Android device using a USB cable.
|
||||
|
||||
If the device asks to allow USB debugging, tap "Allow".
|
||||
|
||||
29) Close any Android / iOS emulators.
|
||||
28) Close any Android / iOS emulators.
|
||||
|
||||
30) Enable "Legacy External Storage" in the Android app. The manifest is stored
|
||||
29) 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)"
|
||||
@ -776,13 +789,13 @@ at `App_Resources/Android/src/main/AndroidManifest.xml`:
|
||||
android:hardwareAccelerated="true">
|
||||
```
|
||||
|
||||
31) Install the `@nativescript-community/perms` dependency:
|
||||
30) Install the `@nativescript-community/perms` dependency:
|
||||
|
||||
```bash
|
||||
npm i --save @nativescript-community/perms
|
||||
```
|
||||
|
||||
32) Add the highlighted lines to `items.component.ts`:
|
||||
31) Add the highlighted lines to `items.component.ts`:
|
||||
|
||||
- Import `File` from NativeScript core and `request` from the new dependency:
|
||||
|
||||
@ -815,10 +828,10 @@ import { Component, OnInit } from '@angular/core'
|
||||
} catch(e) { await Dialogs.alert(e.message); }
|
||||
```
|
||||
|
||||
33) Build APK and run on device:
|
||||
32) Build APK and run on device:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run android
|
||||
npx -y -p nativescript ns run android
|
||||
```
|
||||
|
||||
If the Android emulators are closed and an Android device is connected, the last
|
||||
@ -839,22 +852,59 @@ file named `SheetJSNS.xls`.
|
||||
|
||||
### iOS Device
|
||||
|
||||
34) Connect an iOS device using a USB cable
|
||||
33) Connect an iOS device using a USB cable
|
||||
|
||||
35) Close any Android / iOS emulators.
|
||||
34) Close any Android / iOS emulators.
|
||||
|
||||
36) Enable developer code signing certificates:
|
||||
35) Enable developer code signing certificates:
|
||||
|
||||
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.
|
||||
the "Project Navigator" and select `SheetJSNS`. In the main view, select the
|
||||
`SheetJSNS` target. Click "Signing & Capabilities". Under "Signing", select a
|
||||
team in the dropdown menu.
|
||||
|
||||
:::caution pass
|
||||
|
||||
When this demo was last tested, Xcode repeatedly crashed.
|
||||
|
||||
The issue was resolved by cleaning the project:
|
||||
|
||||
```bash
|
||||
npx -y -p nativescript ns platform clean ios
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
36) Add the following key/value pairs to `Info.plist`:
|
||||
|
||||
```xml title="App_Resources/iOS/Info.plist (add highlighted lines)"
|
||||
<dict>
|
||||
<!-- highlight-start -->
|
||||
<key>UIFileSharingEnabled</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<!-- highlight-end -->
|
||||
```
|
||||
|
||||
37) Run on device:
|
||||
|
||||
```bash
|
||||
npx -p nativescript ns run ios
|
||||
npx -y -p nativescript ns run ios
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
If this is the first time testing an app on a device, the certificate must be
|
||||
trusted on the device:
|
||||
|
||||
Under "Settings" > "General" > "VPN & Device Management", there should be a
|
||||
"Apple Development" certificate in the "DEVELOPER APP" section. Select the
|
||||
certificate and confirm that "SheetJSNS" is listed under "APPS". Tap "Trust ..."
|
||||
and tap "Trust" in the popup.
|
||||
|
||||
:::
|
||||
|
||||
<details open>
|
||||
<summary><b>iOS Device Testing</b> (click to hide)</summary>
|
||||
|
||||
@ -863,8 +913,9 @@ 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`.
|
||||
Switch to the "Files" app and repeatedly tap "<". In the "Browse" window, tap
|
||||
"On My iPhone". There should be a new folder named "SheetJSNS". Tap the folder
|
||||
and look for the file named `SheetJSNS.xls`.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@ -53,8 +53,8 @@ This demo was tested in the following environments:
|
||||
|:-----------|:--------------------|:------------------|:-------------|:-----------|
|
||||
| Android 34 | Pixel 3a | `7.1.0` / `7.0.0` | `darwin-arm` | 2025-03-30 |
|
||||
| iOS 18.2 | iPhone 16 Pro Max | `7.1.0` / `7.0.0` | `darwin-arm` | 2025-03-30 |
|
||||
| Android 35 | Pixel 9 | `6.2.0` / `6.0.2` | `win11-x64` | 2024-12-21 |
|
||||
| Android 35 | Pixel 9 | `6.2.0` / `6.0.2` | `linux-x64` | 2025-01-02 |
|
||||
| Android 35 | Pixel 9 Pro XL | `7.3.0` / `7.1.1` | `win11-x64` | 2025-06-08 |
|
||||
| Android 36 | Pixel 9 | `7.4.1` / `7.1.2` | `linux-x64` | 2025-07-06 |
|
||||
|
||||
:::
|
||||
|
||||
@ -63,13 +63,13 @@ This demo was tested in the following environments:
|
||||
Before starting this demo, manually disable telemetry. On Linux and MacOS:
|
||||
|
||||
```bash
|
||||
npx @capacitor/cli telemetry off
|
||||
npx -y @capacitor/cli telemetry off
|
||||
```
|
||||
|
||||
To verify telemetry was disabled:
|
||||
|
||||
```bash
|
||||
npx @capacitor/cli telemetry
|
||||
npx -y @capacitor/cli telemetry
|
||||
```
|
||||
|
||||
:::
|
||||
@ -212,25 +212,29 @@ iOS development is only supported on macOS.
|
||||
|
||||
:::
|
||||
|
||||
<details>
|
||||
<details open>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
For Android development, CapacitorJS requires a Java version compatible with the
|
||||
expected Gradle version. When this demo was tested against CapacitorJS `6.2.0`,
|
||||
Java 20 was required to support Gradle `8.2.1`.
|
||||
expected Gradle version:
|
||||
|
||||
| CapacitorJS | Gradle | Java |
|
||||
|:------------|:---------|:-----|
|
||||
| `6.2.0` | `8.2.1` | 20 |
|
||||
| `7.4.1` | `8.11.1` | 21 |
|
||||
|
||||
</details>
|
||||
|
||||
1) Disable telemetry.
|
||||
|
||||
```bash
|
||||
npx @capacitor/cli telemetry off
|
||||
npx -y @capacitor/cli telemetry off
|
||||
```
|
||||
|
||||
Verify that telemetry is disabled by running
|
||||
|
||||
```bash
|
||||
npx @capacitor/cli telemetry
|
||||
npx -y @capacitor/cli telemetry
|
||||
```
|
||||
|
||||
(it should print `Telemetry is off`)
|
||||
@ -238,7 +242,7 @@ npx @capacitor/cli telemetry
|
||||
2) Create a new Svelte project:
|
||||
|
||||
```bash
|
||||
npm create vite@latest sheetjs-cap -- --template svelte
|
||||
npm create vite@latest sheetjs-cap -- --template svelte --no-rolldown --no-interactive
|
||||
cd sheetjs-cap
|
||||
```
|
||||
|
||||
@ -249,6 +253,22 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
npm i --save @capacitor/core @capacitor/cli @capacitor/filesystem`}
|
||||
</CodeBlock>
|
||||
|
||||
:::warning pass
|
||||
|
||||
When this demo was last tested, parts of the official project required ViteJS 6
|
||||
and other parts required ViteJS 7. The install failed.
|
||||
|
||||
**This is a bug in the Svelte integration!**
|
||||
|
||||
Until the bug is fixed, the `--force` option should be used:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz --force
|
||||
npm i --save @capacitor/core @capacitor/cli @capacitor/filesystem --force`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
4) Create CapacitorJS structure:
|
||||
|
||||
```bash
|
||||
@ -258,14 +278,14 @@ npm run build
|
||||
|
||||
:::note pass
|
||||
|
||||
If prompted to create an Ionic account, type `N` and press <kbd>Enter</kbd>.
|
||||
If prompted to create an Ionic account, Press <kbd>N</kbd> to opt out.
|
||||
|
||||
:::
|
||||
|
||||
5) Download [`src/App.svelte`](pathname:///cap/App.svelte) and replace:
|
||||
|
||||
```bash
|
||||
curl -o src/App.svelte -L https://docs.sheetjs.com/cap/App.svelte
|
||||
curl -o src/App.svelte https://docs.sheetjs.com/cap/App.svelte
|
||||
```
|
||||
|
||||
### Android
|
||||
@ -277,6 +297,22 @@ npm i --save @capacitor/android
|
||||
npx cap add android
|
||||
```
|
||||
|
||||
:::warning pass
|
||||
|
||||
When this demo was last tested, parts of the official project required ViteJS 6
|
||||
and other parts required ViteJS 7. The install failed.
|
||||
|
||||
**This is a bug in the Svelte integration!**
|
||||
|
||||
Until the bug is fixed, the `--force` option should be used:
|
||||
|
||||
```bash
|
||||
npm i --save @capacitor/android --force
|
||||
npx cap add android
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
|
||||
If the wrong Java version is installed, the last command will fail with a
|
||||
@ -530,7 +566,7 @@ error: Provisioning profile "iOS Team Provisioning Profile: com.sheetjs.cap" doe
|
||||
```
|
||||
|
||||
This error was resolved by manually selecting the device as the primary target
|
||||
in the Xcode workspace.
|
||||
in the Xcode workspace.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -48,18 +48,18 @@ This demo was tested in the following environments:
|
||||
|
||||
**Real Devices**
|
||||
|
||||
| OS | Device | Dart | Flutter | Date |
|
||||
|:-----------|:------------------|:--------|:---------|:-----------|
|
||||
| Android 34 | NVIDIA Shield | `3.7.2` | `3.29.2` | 2025-03-31 |
|
||||
| iOS 15.6 | iPhone 13 Pro Max | `3.7.2` | `3.29.2` | 2025-03-31 |
|
||||
| OS | Device | Dart | Flutter | Date |
|
||||
|:-----------|:------------------|:---------|:---------|:-----------|
|
||||
| Android 34 | NVIDIA Shield | `3.7.2` | `3.29.2` | 2025-03-31 |
|
||||
| iOS 26.3 | iPhone 13 Pro Max | `3.11.1` | `3.41.4` | 2026-03-10 |
|
||||
|
||||
**Simulators**
|
||||
|
||||
| OS | Device | Dart | Flutter | Dev Platform | Date |
|
||||
|:-----------|:------------------|:--------|:---------|:-------------|:-----------|
|
||||
| Android 35 | Pixel 9 Pro XL | `3.7.2` | `3.29.2` | `darwin-x64` | 2025-03-31 |
|
||||
| iOS 18.3 | iPhone 16 Pro Max | `3.7.2` | `3.29.2` | `darwin-x64` | 2025-03-31 |
|
||||
| Android 35 | Pixel 3a | `3.5.0` | `3.24.0` | `win11-x64` | 2024-08-10 |
|
||||
| OS | Device | Dart | Flutter | Dev Platform | Date |
|
||||
|:-----------|:------------------|:---------|:---------|:-------------|:-----------|
|
||||
| Android 36 | Pixel Tablet | `3.11.1` | `3.41.4` | `darwin-arm` | 2026-03-11 |
|
||||
| iOS 18.6 | iPhone 16 Pro Max | `3.11.1` | `3.41.4` | `darwin-arm` | 2026-03-11 |
|
||||
| Android 36 | Pixel 9 Pro XL | `3.7.2` | `3.29.3` | `win11-x64` | 2054-04-28 |
|
||||
|
||||
:::
|
||||
|
||||
@ -244,7 +244,7 @@ Run `flutter doctor` and confirm the following items are checked:
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
<pre>
|
||||
<span {...g}>[✓]</span> Android toolchain - develop for Android devices (Android SDK version 35.0.0)
|
||||
<span {...g}>[✓]</span> Android toolchain - develop for Android devices (Android SDK version 35.0.1)
|
||||
</pre>
|
||||
|
||||
</TabItem>
|
||||
@ -260,7 +260,7 @@ Run `flutter doctor` and confirm the following items are checked:
|
||||
On first run, there may be a warning with "Android toolchain":
|
||||
|
||||
```
|
||||
[!] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
|
||||
[!] Android toolchain - develop for Android devices (Android SDK version 35.0.1)
|
||||
! Some Android licenses not accepted. To resolve this, run: flutter doctor
|
||||
--android-licenses
|
||||
```
|
||||
@ -297,6 +297,21 @@ error: Android sdkmanager not found. Update to the latest Android SDK and ensure
|
||||
Android Studio does not install `Android SDK Command-Line Tools` by default. It
|
||||
must be installed manually.
|
||||
|
||||
---
|
||||
To enable Android SDK Command-Line Tools via Android Studio follow this:
|
||||
|
||||
Find SDK manager by searching it in *Search Everywhere*
|
||||

|
||||
|
||||
Select **SDK Tools** from the top tab in the middle panel, then check **Android SDK Command-line Tools (latest)** and
|
||||
click **OK**.
|
||||
|
||||

|
||||
|
||||
A dialog will appear asking to download and install the tools. Click **OK** to continue.
|
||||
|
||||
---
|
||||
|
||||
Assuming the command-line tools are installed
|
||||
|
||||
This was fixed by switching to Java 20, installing `Android SDK 33`, and rolling
|
||||
@ -386,9 +401,9 @@ Pixel_9_Pro_XL_API_35 • Pixel 9 Pro XL API 35 • Google • android
|
||||
There should be at least one `android` emulator:
|
||||
|
||||
```
|
||||
Id • Name • Manufacturer • Platform
|
||||
Id • Name • Manufacturer • Platform
|
||||
|
||||
Pixel_3a_API_35 • Pixel 3a API 35 • Google • android
|
||||
Pixel_9_Pro_XL • Pixel 9 Pro XL • Google • android
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@ -445,14 +460,43 @@ emulator -avd Pixel_9_Pro_XL_API_35
|
||||
|
||||
:::note pass
|
||||
|
||||
If `emulator` cannot be found, the folder must be added to the system path.
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="macos" label="macOS">
|
||||
|
||||
On macOS, `~/Library/Android/sdk/emulator/` is the typical location for the
|
||||
`emulator` binary. If it cannot be found, add the folder to `PATH`:
|
||||
`emulator` binary:
|
||||
|
||||
```bash
|
||||
export PATH="$PATH":~/Library/Android/sdk/emulator
|
||||
emulator -avd Pixel_9_Pro_XL_API_35
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
The Android SDK folder can be found in the SDK manager in Android Studio. It is
|
||||
typically `%LOCALAPPDATA%\Android\Sdk`.
|
||||
|
||||
If it is not assigned, create a User environment variable named `ANDROID_HOME`
|
||||
with the value set to the Android SDK folder.
|
||||
|
||||
---
|
||||
|
||||
There are three folders within the Android SDK folder that should be added to
|
||||
the User `PATH` environment variable. Each folder holds a different tool:
|
||||
|
||||
| Folder | Command-line Tool |
|
||||
|:------------------------------------------|:------------------|
|
||||
| `%ANDROID_HOME%\emulator` | `emulator` |
|
||||
| `%ANDROID_HOME%\cmdline-tools\latest\bin` | `avdmanager` |
|
||||
| `%ANDROID_HOME%\platform-tools` | `adb` |
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
:::
|
||||
|
||||
</details>
|
||||
@ -502,7 +546,7 @@ Once the app loads, stop the terminal process and close the simulator.
|
||||
5) Install Flutter / Dart dependencies:
|
||||
|
||||
```bash
|
||||
flutter pub add http csv flutter_js
|
||||
flutter pub add http csv flutter_js collection
|
||||
```
|
||||
|
||||
:::info pass
|
||||
@ -526,7 +570,7 @@ As stated, "Developer Mode" must be enabled:
|
||||
3) Reinstall dependencies:
|
||||
|
||||
```bash
|
||||
flutter pub add http csv flutter_js
|
||||
flutter pub add http csv flutter_js collection
|
||||
```
|
||||
|
||||
:::
|
||||
@ -645,6 +689,13 @@ flutter -v -d emulator-5554 run
|
||||
|
||||
</details>
|
||||
|
||||
:::caution pass
|
||||
|
||||
In some test runs on low-power devices, it took 20 seconds for the app to fetch
|
||||
and display data!
|
||||
|
||||
:::
|
||||
|
||||
:::info Troubleshooting
|
||||
|
||||
In some demo runs, the build failed with an Android SDK error:
|
||||
@ -822,7 +873,7 @@ The app may take 30 seconds to load the content.
|
||||
|
||||
### iOS Device
|
||||
|
||||
19) Follow the official "Deploy to physical iOS devices" instructions[^10]
|
||||
19) **Follow the official ["Deploy to physical iOS devices"](https://docs.flutter.dev/platform-integration/ios/setup#set-up-devices) instructions**
|
||||
|
||||
20) Connect the iOS device and verify that `flutter` can find the device:
|
||||
|
||||
@ -852,7 +903,7 @@ Tap "OK" to continue.
|
||||
|
||||
:::info pass
|
||||
|
||||
In some test runs, the app requested for local network access:
|
||||
In some test runs, the app requested for local network access:
|
||||
|
||||
> "Sheetjs Flutter" would like to find and connect to devices on your local network.
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@ import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
import Link from '@docusaurus/Link';
|
||||
|
||||
export const r = {style: {color:"red"}};
|
||||
export const g = {style: {color:"green"}};
|
||||
@ -176,7 +177,7 @@ The demo uses Lynx `<view/>` and `<text/>` elements to display tabular data:
|
||||
{/* Map through each cell in the current row */}
|
||||
{Array.isArray(row) && row.map((cell, cellIndex) => (
|
||||
{/* Cell with dynamic width based on content */}
|
||||
<view
|
||||
<view
|
||||
key={`cell-${rowIndex}-${cellIndex}`} className="Cell"
|
||||
style={{ width: `${widths[cellIndex]}px` }}>
|
||||
{/* Display cell content as text */}
|
||||
@ -257,7 +258,8 @@ curl -o ./src/App.tsx https://docs.sheetjs.com/lynx/App.tsx
|
||||
```bash
|
||||
curl -o ./src/App.css https://docs.sheetjs.com/lynx/App.css
|
||||
```
|
||||
<a name="step5"></a>
|
||||
|
||||
<Link id="step5"/>
|
||||
|
||||
5) Start the development server:
|
||||
|
||||
|
||||
@ -40,48 +40,54 @@ app to read and write workbooks. The app will look like the screenshots below:
|
||||
|
||||
## Integration Details
|
||||
|
||||
Electron uses a multi-process architecture, with the main process handling system level operations and I/O, and the renderer process handling UI and web content.
|
||||
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
|
||||
imported from the main or the renderer thread.
|
||||
|
||||
**Renderer Process Limitations**
|
||||
The SheetJS `readFile` and `writeFile` methods will use the Electron `fs` module
|
||||
where available.
|
||||
|
||||
The renderer process is sandboxed and cannot run any non-browser code.
|
||||
<details>
|
||||
<summary><b>Renderer Configuration</b> (click to show)</summary>
|
||||
|
||||
**Main Process Limitations**
|
||||
Electron 9 and later require the preference `nodeIntegration: true` in order to
|
||||
`require('xlsx')` in the renderer process.
|
||||
|
||||
The main process can run any NodeJS code, but it cannot access the DOM or any browser APIs.
|
||||
Electron 12 and later also require `worldSafeExecuteJavascript: true` and
|
||||
`contextIsolation: true`.
|
||||
|
||||
To allow communication between the main and renderer processes, Electron recommends building a [context bridge](https://www.electronjs.org/docs/latest/api/context-bridge) to expose low-level system calls and NodeJS APIs to the renderer process. Such as the [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) which we will be using here.
|
||||
</details>
|
||||
|
||||
Exposed APIs are available as `SheetJSDemoAPI` on the window object and proxied from the main process.
|
||||
:::caution pass
|
||||
|
||||
```js title="preload.js -- contextBridge API"
|
||||
const { contextBridge, ipcRenderer, shell } = require('electron');
|
||||
// import nodejs modules we wish to expose APIs from.
|
||||
const path = require('path');
|
||||
const XLSX = require('xlsx');
|
||||
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
|
||||
can be loaded from the renderer thread using a standard `SCRIPT` tag, but it is
|
||||
strongly discouraged.
|
||||
|
||||
// The contextBridge API allows us to expose APIs to the renderer process.
|
||||
// highlight-next-line
|
||||
contextBridge.exposeInMainWorld('SheetJSDemoAPI', {
|
||||
// request OS file dialogs from the main process
|
||||
openFile: (filters) => ipcRenderer.invoke('dialog:openFile', filters),
|
||||
saveFile: (filters) => ipcRenderer.invoke('dialog:saveFile', filters),
|
||||
message: (msg) => ipcRenderer.invoke('dialog:message', msg),
|
||||
// open external links in the default browser
|
||||
openExternal: (url) => shell.openExternal(url),
|
||||
// listen for file open events from the main process
|
||||
onFileOpened: (cb) => ipcRenderer.on('file-opened', (_e, fp) => cb(fp)),
|
||||
[Issue 3314](https://git.sheetjs.com/sheetjs/sheetjs/issues/3314) in the SheetJS
|
||||
CE issue tracker describes the required HTML configuration.
|
||||
|
||||
// You can use this to expose nodejs APIs to the renderer process.
|
||||
basename: (p) => path.basename(p),
|
||||
extname: (p) => path.extname(p),
|
||||
<details>
|
||||
<summary><b>HTML Configuration</b> (click to show)</summary>
|
||||
|
||||
// Here for example we are exposing the sheetjs package to the renderer process.
|
||||
// highlight-next-line
|
||||
xlsx: XLSX,
|
||||
});
|
||||
The following CSP directives should be specified in the `HEAD` block:
|
||||
|
||||
```html
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.sheetjs.com"
|
||||
/>
|
||||
<meta
|
||||
http-equiv="X-Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.sheetjs.com"
|
||||
/>
|
||||
```
|
||||
|
||||
Without these settings, newer Electron versions will not run the scripts.
|
||||
|
||||
</details>
|
||||
|
||||
:::
|
||||
|
||||
### Reading Files
|
||||
|
||||
Electron offers 3 different ways to read files, two of which use Web APIs.
|
||||
@ -98,7 +104,7 @@ For example, assuming a file input element on the page:
|
||||
|
||||
The event handler would process the event as if it were a web event:
|
||||
|
||||
```js title="index.js -- renderer process"
|
||||
```js
|
||||
async function handleFile(e) {
|
||||
const file = e.target.files[0];
|
||||
const data = await file.arrayBuffer();
|
||||
@ -112,9 +118,8 @@ document.getElementById("xlf").addEventListener("change", handleFile, false);
|
||||
|
||||
**Drag and Drop**
|
||||
|
||||
In the demo the [drag and drop snippet](/docs/solutions/input#example-user-submissions)
|
||||
applies to the entire window via the `document.body` element. However it can easily be
|
||||
applied to any element on the page.
|
||||
The [drag and drop snippet](/docs/solutions/input#example-user-submissions)
|
||||
applies to DIV elements on the page.
|
||||
|
||||
For example, assuming a DIV on the page:
|
||||
|
||||
@ -124,9 +129,7 @@ For example, assuming a DIV on the page:
|
||||
|
||||
The event handler would process the event as if it were a web event:
|
||||
|
||||
```js title="index.js -- renderer process"
|
||||
const XLSX = window.SheetJSDemoAPI.xlsx; // use xlsx package from bridge process
|
||||
|
||||
```js
|
||||
async function handleDrop(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
@ -145,105 +148,88 @@ document.getElementById("drop").addEventListener("drop", handleDrop, false);
|
||||
|
||||
[`XLSX.readFile`](/docs/api/parse-options) reads workbooks from the file system.
|
||||
`showOpenDialog` shows a Save As dialog and returns the selected file name.
|
||||
Unlike the Web APIs, the `showOpenDialog` flow can be initiated by app code:
|
||||
|
||||
We can now use the exposed APIs from our preload script above to show the open dialog and try to parse the workbook from within the renderer process.
|
||||
|
||||
```js title="index.js -- renderer process"
|
||||
// our exposed bridge APIs are available as SheetJSDemoAPI on the window object
|
||||
const openFile = window.SheetJSDemoAPI.openFile; // request the open file dialog from the main process
|
||||
// We can also access the SheetJS package from the exposed bridge APIs
|
||||
// highlight-next-line
|
||||
const XLSX = window.SheetJSDemoAPI.xlsx;
|
||||
```js
|
||||
/* from the renderer thread */
|
||||
const electron = require('@electron/remote');
|
||||
|
||||
/* this function will show the open dialog and try to parse the workbook */
|
||||
async function importFile() {
|
||||
/* show open file dialog */
|
||||
const result = await openFile([{
|
||||
/* show Save As dialog */
|
||||
const result = await electron.dialog.showOpenDialog({
|
||||
title: 'Select a file',
|
||||
filters: [{
|
||||
name: "Spreadsheets",
|
||||
extensions: ["xlsx", "xls", "xlsb", /* ... other formats ... */]
|
||||
}]);
|
||||
}]
|
||||
});
|
||||
/* result.filePaths is an array of selected files */
|
||||
if(result.filePaths.length == 0) throw new Error("No file was selected!");
|
||||
// highlight-next-line
|
||||
return XLSX.readFile(result.filePaths[0]);
|
||||
}
|
||||
```
|
||||
In order to interact with the file system, the `xlsx` package here depends on the Node.js. Which means we need to utilize the Bridge here and make it possible to call these methods from the renderer process. The appropriate IPC event can be found below.
|
||||
|
||||
```js title="main.js -- main process"
|
||||
const { ipcMain, dialog } = require('electron');
|
||||
:::note pass
|
||||
|
||||
ipcMain.handle('dialog:openFile', (_e, filters) =>
|
||||
dialog.showOpenDialog({ title: 'Select a file', filters, properties: ['openFile'] })
|
||||
);
|
||||
`showOpenDialog` originally returned an array of paths:
|
||||
|
||||
```js
|
||||
var dialog = require('electron').remote.dialog;
|
||||
|
||||
function importFile(workbook) {
|
||||
var result = dialog.showOpenDialog({ properties: ['openFile'] });
|
||||
return XLSX.readFile(result[0]);
|
||||
}
|
||||
```
|
||||
|
||||
This method was renamed to `showOpenDialogSync` in Electron 6.
|
||||
|
||||
:::
|
||||
|
||||
### Writing Files
|
||||
|
||||
[`XLSX.writeFile`](/docs/api/write-options) writes workbooks to the file system.
|
||||
`showSaveDialog` shows a Save As dialog and returns the selected file name:
|
||||
|
||||
The implementation for saving files looks very similar to the one above thanks to our bridge API.
|
||||
```js title="index.js -- renderer process"
|
||||
// our exposed bridge APIs are available as SheetJSDemoAPI on the window object
|
||||
const saveFile = window.SheetJSDemoAPI.saveFile; // request the save file dialog from the main process
|
||||
const XLSX = window.SheetJSDemoAPI.xlsx;
|
||||
```js
|
||||
/* from the renderer thread */
|
||||
const electron = require('@electron/remote');
|
||||
|
||||
/* this function will show the save dialog and try to write the workbook */
|
||||
async function exportFile(workbook) {
|
||||
const result = await saveFile([{
|
||||
/* show Save As dialog */
|
||||
const result = await electron.dialog.showSaveDialog({
|
||||
title: 'Save file as',
|
||||
filters: [{
|
||||
name: "Spreadsheets",
|
||||
extensions: ["xlsx", "xls", "xlsb", /* ... other formats ... */]
|
||||
}]);
|
||||
if(result.filePaths.length == 0) throw new Error("No file was selected!");
|
||||
XLSX.writeFile(workbook, result.filePaths[0]);
|
||||
}]
|
||||
});
|
||||
/* write file */
|
||||
// highlight-next-line
|
||||
XLSX.writeFile(workbook, result.filePath);
|
||||
}
|
||||
```
|
||||
And here is the implementation of the `saveFile` event listener in `main.js`:
|
||||
```js title="main.js -- main process"
|
||||
const { ipcMain, dialog } = require('electron');
|
||||
|
||||
ipcMain.handle('dialog:saveFile', (_e, filters) =>
|
||||
dialog.showSaveDialog({ title: 'Save file as', filters })
|
||||
);
|
||||
:::note pass
|
||||
|
||||
`showSaveDialog` originally returned the selected path:
|
||||
|
||||
```js
|
||||
var dialog = require('electron').remote.dialog;
|
||||
|
||||
function exportFile(workbook) {
|
||||
var result = dialog.showSaveDialog();
|
||||
XLSX.writeFile(workbook, result);
|
||||
}
|
||||
```
|
||||
|
||||
### Working with OS level file open events.
|
||||
This method was renamed to `showSaveDialogSync` in Electron 6.
|
||||
|
||||
Electron makes it possible to handle OS level file open events, such as the "open with" context menu or `open` CLI command.
|
||||
|
||||
The example below shows the configuration required to register your application as a handler supporting such events for all file extensions SheetJS supports.
|
||||
|
||||
:::caution
|
||||
|
||||
It is also possible to open files using the "open with" context menu without registering the application as a handler for the specified file types. This however, requires manually selecting the application binary as a target to open the file with.
|
||||
|
||||
**This action might not be supported by some file managers on Linux based systems.**
|
||||
:::
|
||||
|
||||
```json title="package.json"
|
||||
{
|
||||
// ...existing content
|
||||
"build": {
|
||||
"appId": "com.sheetjs.electron",
|
||||
"fileAssociations": [
|
||||
{
|
||||
"ext": [ // supported extensions to register with the OS.
|
||||
"xls","xlsx","xlsm","xlsb","xml","csv","txt","dif",
|
||||
"sylk","slk","prn","ods","fods","htm","html","numbers"
|
||||
],
|
||||
"name": "Spreadsheet / Delimited File",
|
||||
"description": "Spreadsheets and delimited text files opened by SheetJS-Electron",
|
||||
"role": "Editor"
|
||||
}
|
||||
],
|
||||
"mac": { "target": "dmg" },
|
||||
"win": { "target": "nsis" },
|
||||
"linux": { "target": "deb" }
|
||||
},
|
||||
}
|
||||
```
|
||||
This makes it possible to generate installers for MacOS, Windows and Linux which will automatically register the application as a handler for the specified file types avoiding manual registration processes that differ across operating systems.
|
||||
|
||||
## Complete Example
|
||||
|
||||
:::note Tested Deployments
|
||||
@ -252,18 +238,23 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Electron | Date |
|
||||
|:---------------|:-------------|:---------|:-----------|
|
||||
| macOS 15.3 | `darwin-x64` | `35.1.2` | 2025-03-31 |
|
||||
| macOS 15.4 | `darwin-arm` | `36.1.0` | 2025-05-03 |
|
||||
| Windows 11 | `win11-x64` | `36.1.0` | 2025-05-03 |
|
||||
| macOS 15.7.4 | `darwin-x64` | `40.8.0` | 2026-03-08 |
|
||||
| macOS 14.5 | `darwin-arm` | `35.1.2` | 2025-08-30 |
|
||||
| Windows 11 | `win11-x64` | `40.8.0` | 2026-05-14 |
|
||||
| Windows 11 | `win11-arm` | `33.2.1` | 2025-02-23 |
|
||||
| Linux (HoloOS) | `linux-x64` | `33.2.1` | 2025-01-02 |
|
||||
| Linux (Ubuntu) | `linux-x64` | `35.1.2` | 2025-07-06 |
|
||||
| Linux (Debian) | `linux-arm` | `33.2.1` | 2025-02-16 |
|
||||
|
||||
:::
|
||||
|
||||
The demo project is wired for `electron-forge` to build the standalone binary.
|
||||
This demo includes a drag-and-drop box as well as a file input box, mirroring
|
||||
the [SheetJS Data Preview Live Demo](https://oss.sheetjs.com/sheetjs/)
|
||||
|
||||
You can also use `electron-builder` to build a packaged installer binary.
|
||||
The core data in this demo is an editable HTML table. The readers build up the
|
||||
table using `sheet_to_html` (with `editable:true` option) and the writers scrape
|
||||
the table using `table_to_book`.
|
||||
|
||||
The demo project is wired for `electron-forge` to build the standalone binary.
|
||||
|
||||
1) Download the demo files:
|
||||
|
||||
@ -271,8 +262,6 @@ You can also use `electron-builder` to build a packaged installer binary.
|
||||
- [`main.js`](pathname:///electron/main.js) : main process script
|
||||
- [`index.html`](pathname:///electron/index.html) : window page
|
||||
- [`index.js`](pathname:///electron/index.js) : script loaded in render context
|
||||
- [`preload.js`](pathname:///electron/preload.js) : preload script (ContextBridge API worker)
|
||||
- [`styles.css`](pathname:///electron/styles.css) : stylesheet
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -290,8 +279,6 @@ curl -LO https://docs.sheetjs.com/electron/package.json
|
||||
curl -LO https://docs.sheetjs.com/electron/main.js
|
||||
curl -LO https://docs.sheetjs.com/electron/index.html
|
||||
curl -LO https://docs.sheetjs.com/electron/index.js
|
||||
curl -LO https://docs.sheetjs.com/electron/preload.js
|
||||
curl -LO https://docs.sheetjs.com/electron/styles.css
|
||||
```
|
||||
|
||||
:::note pass
|
||||
@ -309,8 +296,6 @@ curl.exe -LO https://docs.sheetjs.com/electron/package.json
|
||||
curl.exe -LO https://docs.sheetjs.com/electron/main.js
|
||||
curl.exe -LO https://docs.sheetjs.com/electron/index.html
|
||||
curl.exe -LO https://docs.sheetjs.com/electron/index.js
|
||||
curl.exe -LO https://docs.sheetjs.com/electron/preload.js
|
||||
curl.exe -LO https://docs.sheetjs.com/electron/styles.css
|
||||
```
|
||||
|
||||
:::
|
||||
@ -330,6 +315,28 @@ npx -y electron .
|
||||
|
||||
The app will run.
|
||||
|
||||
:::info pass
|
||||
|
||||
In some Linux deployments, the command will fail with a sandbox error:
|
||||
|
||||
```
|
||||
The SUID sandbox helper binary was found, but is not configured correctly. Rather than run without sandboxing I'm aborting now.
|
||||
```
|
||||
|
||||
The workaround is to temporarily disable the sandbox restriction:
|
||||
|
||||
```bash
|
||||
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
|
||||
```
|
||||
|
||||
After testing, the restriction can be re-enabled with a similar command:
|
||||
|
||||
```bash
|
||||
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=1
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
4) To build a standalone app, run the builder:
|
||||
|
||||
```bash
|
||||
@ -368,12 +375,12 @@ The program will run on ARM64 Windows.
|
||||
|
||||
#### Electron API
|
||||
|
||||
7) Click "Click here to select a file. With the file picker,
|
||||
7) Click "Click here to select a file from your computer". With the file picker,
|
||||
navigate to the Downloads folder and select `pres.numbers`.
|
||||
|
||||
The application should show a dropdown component for each worksheet contained in your file, clicking on it should display its data within a table.
|
||||
The application should show data in a table.
|
||||
|
||||
8) Click "Export" and click "Save" in the popup. By default, it will try
|
||||
8) Click "Export Data!" and click "Save" in the popup. By default, it will try
|
||||
to write to `Untitled.xls` in the Downloads folder.
|
||||
|
||||
:::note pass
|
||||
@ -387,51 +394,27 @@ If there is no default name, enter `Untitled.xls` and click "Save".
|
||||
The app will show a popup once the data is exported. Open the file in a
|
||||
spreadsheet editor and compare the data to the table shown in the application.
|
||||
|
||||
#### Open with menu
|
||||
#### Drag and Drop
|
||||
|
||||
9) Close the application, end the terminal process and re-launch (see step 6)
|
||||
|
||||
10) Open the Downloads folder in a file explorer or finder window.
|
||||
|
||||
11) Right-click the `pres.numbers` file and select "Open with".
|
||||
11) Click and drag the `pres.numbers` file from the Downloads folder to the
|
||||
bordered "Drop a spreadsheet file" box. The file data should be displayed.
|
||||
|
||||
12) Select your application binary by navigating to the folder where the application was built (see step 4).
|
||||
#### File Input Element
|
||||
|
||||
:::info
|
||||
On some Linux based systems, depending on the file manager in use selecting the binary directly may not be possible.
|
||||
:::
|
||||
12) Close the application, end the terminal process and re-launch (see step 6)
|
||||
|
||||
|
||||
The application should show a dropdown component for each worksheet contained in your file, clicking on it should display its data within a table.
|
||||
|
||||
#### Drag and Drop
|
||||
|
||||
13) Close the application, end the terminal process and re-launch (see step 6)
|
||||
|
||||
14) Open the Downloads folder in a file explorer or finder window.
|
||||
|
||||
15) Click and drag the `pres.numbers` file from the Downloads folder
|
||||
into the application window.
|
||||
|
||||
The application should show a dropdown component for each worksheet contained in your file, clicking on it should display its data within a table.
|
||||
|
||||
:::info
|
||||
On some Linux based systems, the experience can differ depending on the window manager / desktop environment in use.
|
||||
:::
|
||||
|
||||
#### File Picker Element
|
||||
|
||||
16) Close the application, end the terminal process and re-launch (see step 6)
|
||||
|
||||
17) Click "Choose File". With the file picker, navigate to the Downloads folder
|
||||
13) Click "Choose File". With the file picker, navigate to the Downloads folder
|
||||
and select `pres.numbers`.
|
||||
|
||||
The application should show a dropdown component for each worksheet contained in your file, clicking on it should display its data within a table.
|
||||
|
||||
|
||||
## Electron Breaking Changes
|
||||
|
||||
The first version of this demo used Electron `1.7.5`. The current demo includes
|
||||
the required changes for Electron `36.1.0`.
|
||||
the required changes for Electron `35.1.2`.
|
||||
|
||||
There are no Electron-specific workarounds in the library, but Electron broke
|
||||
backwards compatibility multiple times. A summary of changes is noted below.
|
||||
@ -459,8 +442,4 @@ Electron 14 and later must use `@electron/remote` instead of `remote`. An
|
||||
|
||||
:::
|
||||
|
||||
For demos built on top of Electron 36 and later we isolate the processes entirely and the demo no longer requires `@electron/remote`.
|
||||
However, `nodeIntegration: false` by default now means that the renderer process no longer has access to NodeJS APIs.
|
||||
To expose NodeJS APIs to the renderer process, we use the contextBridge API to expose APIs from the main process to the renderer process. [See more](https://www.electronjs.org/docs/latest/api/context-bridge). This has been best practice since Electron 25.
|
||||
|
||||
[^1]: See ["Makers"](https://www.electronforge.io/config/makers) in the Electron Forge documentation. On Linux, the demo generates `rpm` and `deb` distributables. On Arch Linux and the Steam Deck, `sudo pacman -Syu rpm-tools dpkg fakeroot` installed required packages. On Debian and Ubuntu, `sudo apt-get install rpm` sufficed.
|
||||
@ -119,14 +119,14 @@ input.click();
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | NW.js | Date | Notes |
|
||||
|:---------------|:-------------|:---------|:-----------|:---------------------|
|
||||
| macOS 15.3.2 | `darwin-x64` | `0.94.0` | 2025-03-31 | |
|
||||
| macOS 14.5 | `darwin-arm` | `0.94.0` | 2025-03-30 | |
|
||||
| Windows 11 | `win11-x64` | `0.94.0` | 2024-12-19 | |
|
||||
| Windows 11 | `win11-arm` | `0.94.0` | 2025-02-23 | |
|
||||
| Linux (HoloOS) | `linux-x64` | `0.89.0` | 2025-01-10 | |
|
||||
| Linux (Debian) | `linux-arm` | `0.60.0` | 2025-02-16 | Unofficial build[^1] |
|
||||
| OS and Version | Architecture | NW.js | Date | Notes |
|
||||
|:---------------|:-------------|:----------|:-----------|:---------------------|
|
||||
| macOS 15.7.4 | `darwin-x64` | `0.112.0` | 2026-06-13 | |
|
||||
| macOS 14.5 | `darwin-arm` | `0.94.0` | 2025-03-30 | |
|
||||
| Windows 11 | `win11-x64` | `0.111.3` | 2026-05-22 | |
|
||||
| Windows 11 | `win11-arm` | `0.94.0` | 2025-02-23 | |
|
||||
| Linux (Ubuntu) | `linux-x64` | `0.101.2` | 2025-07-06 | |
|
||||
| Linux (Debian) | `linux-arm` | `0.60.0` | 2025-02-16 | Unofficial build[^1] |
|
||||
|
||||
:::
|
||||
|
||||
@ -145,18 +145,27 @@ cd sheetjs-nwjs
|
||||
"author": "sheetjs",
|
||||
"version": "0.0.0",
|
||||
"main": "index.html",
|
||||
"nwbuild": {
|
||||
"app": {
|
||||
"icon": "favicon-196x196.png",
|
||||
"LSApplicationCategoryType": "public.app-category.utilities",
|
||||
"NSHumanReadableCopyright": "Copyright © SheetJS LLC"
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"nw": "0.94.0",
|
||||
"nw": "0.112.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz"
|
||||
}
|
||||
}`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Download [`index.html`](pathname:///nwjs/index.html) into the same folder.
|
||||
2) Download the following files into the same folder:
|
||||
- [`index.html`](pathname:///nwjs/index.html)
|
||||
- [`favicon-196x196.png`](https://sheetjs.com/favico/favicon-196x196.png)
|
||||
|
||||
:::caution pass
|
||||
|
||||
Right-click the link and select "Save Link As...". Left-clicking the link will
|
||||
Right-click each link and select "Save Link As...". Left-clicking a link will
|
||||
try to load the page in your browser. The goal is to save the file contents.
|
||||
|
||||
:::
|
||||
@ -165,8 +174,26 @@ In the terminal window, the download can be performed with:
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/nwjs/index.html
|
||||
curl -LO https://sheetjs.com/favico/favicon-196x196.png
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
In PowerShell, the command may fail with a parameter error:
|
||||
|
||||
```
|
||||
Invoke-WebRequest : A parameter cannot be found that matches parameter name 'L'.
|
||||
```
|
||||
|
||||
`curl.exe` must be invoked directly:
|
||||
|
||||
```bash
|
||||
curl.exe -LO https://docs.sheetjs.com/nwjs/index.html
|
||||
curl.exe -LO https://sheetjs.com/favico/favicon-196x196.png
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
3) Install dependencies:
|
||||
|
||||
```bash
|
||||
@ -208,18 +235,11 @@ Unfortunately `nw-builder` will not be able to build a standalone program.
|
||||
5) To build a standalone app, run the builder:
|
||||
|
||||
```bash
|
||||
npx -p nw-builder@4.11.6 nwbuild --mode=build --version=0.94.0 --glob=false --outDir=../out ./
|
||||
npx -p nw-builder@4.17.10 nwbuild --mode=build --version=0.111.3 --glob=false --outDir=../out ./
|
||||
```
|
||||
|
||||
This will generate the standalone app in the `..\out\` folder.
|
||||
|
||||
:::caution pass
|
||||
|
||||
There is a regression in `nw-builder` version `4.12.0`. In local `win11-x64`
|
||||
testing, version `4.11.6` correctly generated the standalone application.
|
||||
|
||||
:::
|
||||
|
||||
6) Launch the generated application:
|
||||
|
||||
| Architecture | Command |
|
||||
|
||||
@ -54,6 +54,21 @@ platform provides many native features out of the box.
|
||||
|
||||
:::
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Wails | Date |
|
||||
|:---------------|:-------------|:----------|:-----------|
|
||||
| macOS 15.7.4 | `darwin-x64` | `v2.12.0` | 2026-06-13 |
|
||||
| macOS 14.5 | `darwin-arm` | `v2.10.1` | 2025-03-30 |
|
||||
| Windows 11 | `win11-x64` | `v2.12.0` | 2026-05-26 |
|
||||
| Windows 11 | `win11-arm` | `v2.10` | 2025-02-23 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v2.10.2` | 2025-07-06 |
|
||||
| Linux (Debian) | `linux-arm` | `v2.10` | 2025-02-16 |
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
|
||||
@ -291,21 +306,6 @@ async function exportFile(table_element) {
|
||||
|
||||
## Complete Example
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Wails | Date |
|
||||
|:---------------|:-------------|:----------|:-----------|
|
||||
| macOS 15.3.2 | `darwin-x64` | `v2.10.1` | 2025-03-31 |
|
||||
| macOS 14.5 | `darwin-arm` | `v2.10.1` | 2025-03-30 |
|
||||
| Windows 11 | `win11-x64` | `v2.9.2` | 2024-12-21 |
|
||||
| Windows 11 | `win11-arm` | `v2.10` | 2025-02-23 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v2.9.2` | 2025-01-02 |
|
||||
| Linux (Debian) | `linux-arm` | `v2.10` | 2025-02-16 |
|
||||
|
||||
:::
|
||||
|
||||
0) Read the Wails "Getting Started" guide[^14] and install dependencies.
|
||||
|
||||
<details>
|
||||
@ -400,7 +400,12 @@ wails build
|
||||
|
||||
It will print the path to the generated program (typically in `build/bin/`).
|
||||
|
||||
5) Run the generated application.
|
||||
5) Run the generated application:
|
||||
|
||||
| Architecture | Command |
|
||||
|:-------------|:------------------------------------------|
|
||||
| `darwin-x64` | `open ./build/bin/sheetjs-wails.app` |
|
||||
| `win11-x64` | `.\build\bin\sheetjs-wails.exe` |
|
||||
|
||||
**Testing**
|
||||
|
||||
|
||||
@ -50,6 +50,21 @@ app to read and write workbooks. The app will look like the screenshots below:
|
||||
|
||||
</td></tr></tbody></table>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Tauri | Framework | Date |
|
||||
|:---------------|:-------------|:----------|:----------|:-----------|
|
||||
| macOS 15.7.4 | `darwin-x64` | `v1.6.0` | VueJS | 2026-06-13 |
|
||||
| macOS 14.5 | `darwin-arm` | `v1.6.0` | Kaioken | 2025-03-30 |
|
||||
| Windows 11 | `win11-x64` | `v1.6.0` | VueJS | 2025-05-27 |
|
||||
| Windows 11 | `win11-arm` | `v1.6.0` | VueJS | 2025-02-23 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v1.6.0` | VueJS | 2025-07-06 |
|
||||
| Linux (Debian) | `linux-arm` | `v1.6.0` | VueJS | 2025-05-27 |
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
|
||||
@ -347,21 +362,6 @@ function SheetJSExportKaioponent() {
|
||||
|
||||
## Complete Example
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Tauri | Date |
|
||||
|:---------------|:-------------|:----------|:-----------|
|
||||
| macOS 15.3.2 | `darwin-x64` | `v1.6.0` | 2025-03-31 |
|
||||
| macOS 14.5 | `darwin-arm` | `v1.6.0` | 2025-03-30 |
|
||||
| Windows 11 | `win11-x64` | `v1.6.0` | 2024-12-21 |
|
||||
| Windows 11 | `win11-arm` | `v1.6.0` | 2025-02-23 |
|
||||
| Linux (HoloOS) | `linux-x64` | `v1.6.0` | 2025-01-02 |
|
||||
| Linux (Debian) | `linux-arm` | `v1.6.0` | 2025-02-16 |
|
||||
|
||||
:::
|
||||
|
||||
0) Read Tauri "Getting Started" guide and install prerequisites.[^16]
|
||||
|
||||
<details>
|
||||
@ -376,7 +376,7 @@ At a high level, the following software is required for building Tauri apps:
|
||||
The platform configuration can be verified by running:
|
||||
|
||||
```bash
|
||||
npx @tauri-apps/cli info
|
||||
npx -y @tauri-apps/cli@1 info
|
||||
```
|
||||
|
||||
If required dependencies are installed, the output will show a checkmark next to
|
||||
@ -384,17 +384,17 @@ If required dependencies are installed, the output will show a checkmark next to
|
||||
|
||||
<pre>
|
||||
<span {...g}>[✔]</span> <span style={{...y.style,...B.style}}>Environment</span>
|
||||
{` `}<span {...c}>-</span> <span {...B}>OS</span>: Mac OS 14.5.0 arm64 (X64)
|
||||
{` `}<span {...c}>-</span> <span {...B}>OS</span>: Mac OS 15.7.4 X64
|
||||
{` `}<span {...g}>✔</span> <span {...B}>Xcode Command Line Tools</span>: installed
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustc</span>: 1.85.1 (4eb161250 2025-03-15)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>cargo</span>: 1.85.1 (d73d2caf9 2024-12-31)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustup</span>: 1.28.1 (f9edccde0 2025-03-05)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>Rust toolchain</span>: stable-aarch64-apple-darwin (default)
|
||||
{` `}<span {...c}>-</span> <span {...B}>node</span>: 20.18.0
|
||||
{` `}<span {...c}>-</span> <span {...B}>pnpm</span>: 9.12.3
|
||||
{` `}<span {...c}>-</span> <span {...B}>npm</span>: 10.8.2
|
||||
{` `}<span {...c}>-</span> <span {...B}>bun</span>: 1.2.7
|
||||
{` `}<span {...c}>-</span> <span {...B}>deno</span>: deno 2.2.6
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustc</span>: 1.96.0 (ac68faa20 2026-05-25)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>cargo</span>: 1.96.0 (30a34c682 2026-05-25)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>rustup</span>: 1.29.0 (28d1352db 2026-03-05)
|
||||
{` `}<span {...g}>✔</span> <span {...B}>Rust toolchain</span>: stable-x86_64-apple-darwin (default)
|
||||
{` `}<span {...c}>-</span> <span {...B}>node</span>: 24.13.0
|
||||
{` `}<span {...c}>-</span> <span {...B}>pnpm</span>: 11.6.0
|
||||
{` `}<span {...c}>-</span> <span {...B}>npm</span>: 11.6.2
|
||||
{` `}<span {...c}>-</span> <span {...B}>bun</span>: 1.3.14
|
||||
{` `}<span {...c}>-</span> <span {...B}>deno</span>: deno 1.46.3
|
||||
</pre>
|
||||
|
||||
:::caution pass
|
||||
@ -412,7 +412,7 @@ build step will correctly detect the platform architecture.
|
||||
<TabItem value="vuejs" label="VueJS">
|
||||
|
||||
```bash
|
||||
npm create tauri-app@3.x -- -m npm -t vue-ts SheetJSTauri -y
|
||||
npm create -y tauri-app@3.x -- -m npm -t vue-ts SheetJSTauri -y
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
@ -642,8 +642,9 @@ The following features should be manually verified:
|
||||
|
||||
- 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.
|
||||
- Clicking "Save Data" will show a save dialog. If there is no filename, type
|
||||
`SheetJSTauri.xlsb`. Click "Save". The app will write a file which can be
|
||||
opened in a spreadsheet editor.
|
||||
- Edit the file in a spreadsheet editor, then click "Load Data" and select the
|
||||
edited file. The table will refresh with new contents.
|
||||
|
||||
|
||||
@ -45,6 +45,24 @@ app to read and write workbooks. The app will look like the screenshots below:
|
||||
|
||||
</td></tr></tbody></table>
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Server | Client | Date |
|
||||
|:---------------|:-------------|:---------|:---------|:-----------|
|
||||
| macOS 15.7.4 | `darwin-x64` | `6.8.0` | `6.8.0` | 2026-06-13 |
|
||||
| macOS 14.5 | `darwin-arm` | `6.0.0` | `6.0.0` | 2025-03-30 |
|
||||
| Windows 11 | `win11-x64` | `6.7.0` | `6.7.0` | 2026-05-26 |
|
||||
| Windows 11 | `win11-arm` | `5.6.0` | `5.6.0` | 2025-02-23 |
|
||||
| Linux (HoloOS) | `linux-x64` | `6.1.0` | `6.1.0` | 2025-07-06 |
|
||||
| Linux (Debian) | `linux-arm` | `5.6.0` | `5.6.0` | 2025-02-16 |
|
||||
|
||||
NeutralinoJS on Windows on ARM generates X64 binaries that run using the X64
|
||||
compatibility layer. The binaries are not native ARM64 programs!
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
|
||||
@ -186,24 +204,6 @@ const save_button_callback = async() => {
|
||||
|
||||
## Complete Example
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | Server | Client | Date |
|
||||
|:---------------|:-------------|:---------|:---------|:-----------|
|
||||
| macOS 15.3.2 | `darwin-x64` | `6.0.0` | `6.0.0` | 2025-03-31 |
|
||||
| macOS 14.5 | `darwin-arm` | `6.0.0` | `6.0.0` | 2025-03-30 |
|
||||
| Windows 11 | `win11-x64` | `5.5.0` | `5.5.0` | 2024-12-20 |
|
||||
| Windows 11 | `win11-arm` | `5.6.0` | `5.6.0` | 2025-02-23 |
|
||||
| Linux (HoloOS) | `linux-x64` | `5.5.0` | `5.5.0` | 2025-01-02 |
|
||||
| Linux (Debian) | `linux-arm` | `5.6.0` | `5.6.0` | 2025-02-16 |
|
||||
|
||||
NeutralinoJS on Windows on ARM generates X64 binaries that run using the X64
|
||||
compatibility layer. The binaries are not native ARM64 programs!
|
||||
|
||||
:::
|
||||
|
||||
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.
|
||||
|
||||
@ -232,7 +232,7 @@ sudo pacman -Syu webkit2gtk
|
||||
1) Create a new NeutralinoJS app:
|
||||
|
||||
```bash
|
||||
npx @neutralinojs/neu create sheetjs-neu
|
||||
npx -y @neutralinojs/neu create sheetjs-neu
|
||||
cd sheetjs-neu
|
||||
```
|
||||
|
||||
@ -247,6 +247,22 @@ subdirectory in the `sheetjs-neu` folder:
|
||||
curl -L -o resources/js/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
|
||||
</CodeBlock>
|
||||
|
||||
:::note pass
|
||||
|
||||
In PowerShell, the command may fail with a parameter error:
|
||||
|
||||
```
|
||||
Invoke-WebRequest : A parameter cannot be found that matches parameter name 'L'.
|
||||
```
|
||||
|
||||
`curl.exe` must be invoked directly:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl.exe -L -o resources/js/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
3) Add the highlighted line to `neutralino.config.json` in `nativeAllowList`:
|
||||
|
||||
```json title="neutralino.config.json (add highlighted line)"
|
||||
@ -323,7 +339,7 @@ function showInfo() {
|
||||
7) Run the app:
|
||||
|
||||
```bash
|
||||
npx @neutralinojs/neu run
|
||||
npx -y @neutralinojs/neu run
|
||||
```
|
||||
|
||||
<p>The app should print <code>SheetJS Version {current}</code></p>
|
||||
@ -342,7 +358,7 @@ npx @neutralinojs/neu run
|
||||
9) Close the app. Run the app again:
|
||||
|
||||
```bash
|
||||
npx @neutralinojs/neu run
|
||||
npx -y @neutralinojs/neu run
|
||||
```
|
||||
|
||||
When the app loads, a table should show in the main screen.
|
||||
@ -381,7 +397,7 @@ async function exportData() {
|
||||
11) Close the app. Run the app again:
|
||||
|
||||
```bash
|
||||
npx @neutralinojs/neu run
|
||||
npx -y @neutralinojs/neu run
|
||||
```
|
||||
|
||||
When the app loads, click the "Import File" button and select a spreadsheet to
|
||||
@ -406,7 +422,7 @@ save as `SheetJSNeu` will not automatically add the `.xlsx` extension!
|
||||
12) Build production apps:
|
||||
|
||||
```bash
|
||||
npx @neutralinojs/neu build
|
||||
npx -y @neutralinojs/neu build
|
||||
```
|
||||
|
||||
Platform-specific programs will be created in the `dist` folder:
|
||||
|
||||
@ -46,12 +46,12 @@ This demo was tested in the following environments:
|
||||
|
||||
| OS and Version | Architecture | RN Platform | Date |
|
||||
|:---------------|:-------------|:------------|:-----------|
|
||||
| Windows 11 C++ | `win11-x64` | `v0.75.11` | 2024-12-22 |
|
||||
| Windows 11 C# | `win11-x64` | `v0.75.11` | 2024-12-22 |
|
||||
| Windows 11 C++ | `win11-x64` | `v0.78.8` | 2025-06-08 |
|
||||
| Windows 11 C# | `win11-x64` | `v0.78.8` | 2025-06-08 |
|
||||
| Windows 11 C++ | `win11-arm` | `v0.77.2` | 2025-02-23 |
|
||||
| Windows 11 C# | `win11-arm` | `v0.77.2` | 2025-02-23 |
|
||||
| MacOS 15.3.2 | `darwin-x64` | `v0.76.7` | 2025-03-31 |
|
||||
| MacOS 14.5 | `darwin-arm` | `v0.75.16` | 2024-12-22 |
|
||||
| MacOS 15.7.4 | `darwin-x64` | `v0.78.6` | 2026-06-13 |
|
||||
| MacOS 14.5 | `darwin-arm` | `v0.78.3` | 2025-06-14 |
|
||||
|
||||
:::
|
||||
|
||||
@ -432,12 +432,12 @@ not a requirement for this demo.
|
||||
|
||||
### Project Setup
|
||||
|
||||
1) Create a new project using React Native `0.77.1`:
|
||||
1) Create a new project using React Native `0.78.2`:
|
||||
|
||||
```bash
|
||||
npx -y @react-native-community/cli@16 init SheetJSWin --version="0.77.1"
|
||||
npx -y @react-native-community/cli@15 init SheetJSWin --version="0.78.2"
|
||||
cd SheetJSWin
|
||||
npm install --save react-native-windows@0.77.2
|
||||
npm install --save react-native-windows@0.78.8
|
||||
```
|
||||
|
||||
:::info pass
|
||||
@ -500,7 +500,7 @@ npx react-native run-windows --no-telemetry
|
||||
|
||||
When the demo was tested in Windows 11, the run step failed with the message:
|
||||
|
||||
> The Windows SDK version `10.0.19041.0` was not found
|
||||
> The Windows SDK version `10.0.22621.0` was not found
|
||||
|
||||
Specific Windows SDK versions can be installed through Visual Studio Installer.
|
||||
|
||||
@ -530,6 +530,18 @@ When this demo was last tested on Windows 11 ARM, the build failed.
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::info pass
|
||||
|
||||
In PowerShell, the command will fail with `msbuild` errors:
|
||||
|
||||
```
|
||||
× Could not find MSBuild with VCTools for Visual Studio 17.11.0 or later. Make sure all required components have been installed
|
||||
```
|
||||
|
||||
**The commands must be run in a "Native Tools Command Prompt"!**
|
||||
|
||||
:::
|
||||
|
||||
### Native Module
|
||||
|
||||
<Tabs groupId="rnwlang">
|
||||
@ -546,7 +558,7 @@ iwr -Uri https://docs.sheetjs.com/reactnative/DocumentPicker.cs -OutFile windows
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bash" label="WSL Bash">
|
||||
<TabItem value="bash" label="WSL Bash / Command Prompt">
|
||||
|
||||
```bash
|
||||
curl -Lo windows/SheetJSWin/DocumentPicker.cs https://docs.sheetjs.com/reactnative/DocumentPicker.cs
|
||||
@ -583,7 +595,7 @@ iwr -Uri https://docs.sheetjs.com/reactnative/DocumentPicker.h -OutFile windows/
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bash" label="WSL Bash">
|
||||
<TabItem value="bash" label="WSL Bash / Command Prompt">
|
||||
|
||||
```bash
|
||||
curl -Lo windows/SheetJSWin/DocumentPicker.h https://docs.sheetjs.com/reactnative/DocumentPicker.h
|
||||
@ -619,7 +631,7 @@ iwr -Uri https://docs.sheetjs.com/reactnative/rnw/App.tsx -OutFile App.tsx
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="bash" label="WSL Bash">
|
||||
<TabItem value="bash" label="WSL Bash / Command Prompt">
|
||||
|
||||
```bash
|
||||
rm App.js
|
||||
@ -680,10 +692,10 @@ select `pres.xlsx` . The app will refresh and display the data from the file.
|
||||
|
||||
### Project Setup
|
||||
|
||||
1) Create a new React Native project using React Native `0.76.8`:
|
||||
1) Create a new React Native project using React Native `0.78.3`:
|
||||
|
||||
```bash
|
||||
npx -y @react-native-community/cli init SheetJSmacOS --version 0.76.8
|
||||
npx -y @react-native-community/cli@15 init SheetJSmacOS --version 0.78.3
|
||||
cd SheetJSmacOS
|
||||
```
|
||||
|
||||
@ -861,13 +873,12 @@ Within the block, look for `buildPhases` and find the hex string for `Sources`:
|
||||
buildConfigurationList = 5142015A2437B4B40078DB4F /* Build configuration list for PBXNativeTarget "SheetJSmacOS-macOS" */;
|
||||
buildPhases = (
|
||||
1A938104A937498D81B3BD3B /* [CP] Check Pods Manifest.lock */,
|
||||
381D8A6F24576A6C00465D17 /* Start Packager */,
|
||||
// highlight-next-line
|
||||
514201452437B4B30078DB4F /* Sources */,
|
||||
514201462437B4B30078DB4F /* Frameworks */,
|
||||
514201472437B4B30078DB4F /* Resources */,
|
||||
381D8A6E24576A4E00465D17 /* Bundle React Native code and images */,
|
||||
3689826CA944E2EF44FCBC17 /* [CP] Copy Pods Resources */,
|
||||
B25E3632DA32DF17C623F9A1 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
```
|
||||
|
||||
@ -1011,9 +1022,9 @@ If there are no instances, the app path can be found in the `DerivedData` folder
|
||||
find ~/Library/Developer/Xcode/DerivedData -name SheetJSmacOS.app | grep Release
|
||||
```
|
||||
|
||||
:::caution pass
|
||||
:::info pass
|
||||
|
||||
During the last test, `xcodebuild` failed. Scrolling through the log reveals:
|
||||
In an older test run, `xcodebuild` failed. Scrolling through the log reveals:
|
||||
|
||||
```
|
||||
Welcome to Metro v0.80.12
|
||||
|
||||
@ -37,12 +37,12 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | NodeJS | Source | Date |
|
||||
|:-------------|:---------------|:----------|:----------|:-----------|
|
||||
| `darwin-x64` | `5.0.0-beta.4` | `14.15.3` | Pre-built | 2025-04-21 |
|
||||
| `darwin-arm` | `4.0.0-rc.6` | `22.14.0` | Compiled | 2025-04-03 |
|
||||
| `win11-x64` | `4.0.0-rc.6` | `14.15.3` | Pre-built | 2024-12-19 |
|
||||
| `win11-arm` | `4.0.0-rc.6` | `22.14.0` | Compiled | 2025-02-23 |
|
||||
| `linux-x64` | `5.0.0-beta.4` | `14.15.3` | Pre-built | 2025-04-21 |
|
||||
| `linux-arm` | `4.0.0-rc.6` | `22.13.0` | Compiled | 2025-02-15 |
|
||||
| `darwin-x64` | `5.0.0-beta.4` | `14.15.3` | Pre-built | 2026-01-21 |
|
||||
| `darwin-arm` | `5.0.0-beta.4` | `20.18.0` | Compiled | 2026-03-07 |
|
||||
| `win11-x64` | `5.0.0-beta.4` | `14.15.3` | Pre-built | 2026-03-08 |
|
||||
| `win11-arm` | `5.0.0-beta.4` | `22.14.0` | Compiled | 2026-05-05 |
|
||||
| `linux-x64` | `5.0.0-beta.4` | `14.15.3` | Pre-built | 2026-01-18 |
|
||||
| `linux-arm` | `5.0.0-beta.4` | `24.14.0` | Compiled | 2026-03-07 |
|
||||
|
||||
:::
|
||||
|
||||
@ -144,6 +144,16 @@ npx -y nexe xlsx-cli.js --build --make="-j8" --target=windows-arm64-22.14.0 --ve
|
||||
|
||||
Common error messages:
|
||||
|
||||
_MSB4126_
|
||||
|
||||
```
|
||||
error MSB4126: The specified solution configuration "Release|x64" is invalid.
|
||||
```
|
||||
|
||||
`nexe` will not detect the correct platform from PowerShell. To ensure the build
|
||||
targets ARM64, run from "ARM64 Native Tools Command Prompt".
|
||||
|
||||
|
||||
_"Python was not found"_
|
||||
|
||||
```
|
||||
|
||||
@ -37,12 +37,12 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | NodeJS | Date |
|
||||
|:-------------|:--------|:---------|:-----------|
|
||||
| `darwin-x64` | `5.8.1` | `18.5.0` | 2025-04-21 |
|
||||
| `darwin-arm` | `5.8.1` | `18.5.0` | 2025-02-13 |
|
||||
| `win11-x64` | `5.8.1` | `18.5.0` | 2024-12-19 |
|
||||
| `win11-arm` | `5.8.1` | `18.5.0` | 2025-02-23 |
|
||||
| `linux-x64` | `5.8.1` | `18.5.0` | 2025-04-21 |
|
||||
| `linux-arm` | `5.8.1` | `18.5.0` | 2025-02-15 |
|
||||
| `darwin-x64` | `5.8.1` | `18.5.0` | 2026-01-21 |
|
||||
| `darwin-arm` | `5.8.1` | `18.5.0` | 2026-03-07 |
|
||||
| `win11-x64` | `5.8.1` | `18.5.0` | 2026-03-08 |
|
||||
| `win11-arm` | `5.8.1` | `18.5.0` | 2026-05-05 |
|
||||
| `linux-x64` | `5.8.1` | `18.5.0` | 2026-01-18 |
|
||||
| `linux-arm` | `5.8.1` | `18.5.0` | 2026-03-07 |
|
||||
|
||||
:::
|
||||
|
||||
@ -78,7 +78,7 @@ When this demo was last tested, `pkg` failed with an error referencing `node20`:
|
||||
> Error! No available node version satisfies 'node20'
|
||||
```
|
||||
|
||||
**`pkg` does not support NodeJS 20 or 22!**
|
||||
**`pkg` does not support NodeJS 20 or 22 or 24!**
|
||||
|
||||
The local NodeJS version must be rolled back to version 18.
|
||||
|
||||
|
||||
@ -30,10 +30,10 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Version | NodeJS | Date |
|
||||
|:-------------|:--------|:----------|:-----------|
|
||||
| `darwin-x64` | `2.4.4` | `23.11.0` | 2025-04-21 |
|
||||
| `darwin-arm` | `2.4.4` | `22.14.0` | 2025-04-03 |
|
||||
| `win11-x64` | `2.4.4` | `16.20.2` | 2024-12-19 |
|
||||
| `linux-x64` | `2.4.4` | `23.11.0` | 2025-04-21 |
|
||||
| `darwin-x64` | `3.0.0` | `25.8.0` | 2026-03-08 |
|
||||
| `darwin-arm` | `3.0.0` | `23.11.0` | 2026-03-13 |
|
||||
| `win11-x64` | `3.0.0` | `22.22.2` | 2026-05-08 |
|
||||
| `linux-x64` | `3.0.0` | `25.8.0` | 2026-03-08 |
|
||||
| `linux-arm` | `2.4.4` | `23.8.0` | 2025-02-15 |
|
||||
|
||||
:::
|
||||
@ -91,7 +91,7 @@ yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epi
|
||||
<TabItem value="unix" label="Linux/MacOS">
|
||||
|
||||
```bash
|
||||
npx -y boxednode@2.4.4 -s xlsx-cli.js -t xlsx-cli
|
||||
npx -y boxednode@3.0.0 -s xlsx-cli.js -t xlsx-cli
|
||||
```
|
||||
|
||||
:::note pass
|
||||
@ -121,22 +121,22 @@ npx -y boxednode@2.4.4 -s xlsx-cli.js -t xlsx-cli -n 23.8.0
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
```bash
|
||||
npx -y boxednode@2.4.4 -s xlsx-cli.js -t xlsx-cli.exe -n 16.20.2
|
||||
```
|
||||
|
||||
:::info pass
|
||||
|
||||
The Windows builds require Visual Studio with "Desktop development with C++"
|
||||
workload, Python 3.11, and NASM[^2].
|
||||
Windows x64 builds require Visual Studio with the "Desktop development with C++"
|
||||
workload, Python 3.11.9, and NASM[^2].
|
||||
|
||||
**The build command must be run in "x64 Native Tools Command Prompt"**
|
||||
|
||||
:::
|
||||
|
||||
:::caution pass
|
||||
```bash
|
||||
npx -y boxednode@3.0.0 -s xlsx-cli.js -t xlsx-cli.exe -n 22.22.2
|
||||
```
|
||||
|
||||
When the demo was last tested, the build failed:
|
||||
:::caution Troubleshooting
|
||||
|
||||
In some test runs, the build failed:
|
||||
|
||||
```
|
||||
Not an executable Python program
|
||||
@ -158,22 +158,21 @@ Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or py
|
||||
|
||||
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:
|
||||
In some test runs, the build failed with error code `MSB8020`:
|
||||
|
||||
```
|
||||
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.
|
||||
error MSB8020: The build tools for Visual Studio 2019 (Platform Toolset = 'v143') cannot be found. To build using the v143 build tools, please install Visual Studio 2019 build tools.
|
||||
```
|
||||
|
||||
This error was fixed by installing the `v142` build tools through the Visual
|
||||
Studio installer.
|
||||
This error was fixed by installing the following components from Visual Studio:
|
||||
|
||||
:::
|
||||
- `C++/CLI support for v143 build tools`
|
||||
- `MSVC v143 - VS 2022 - C++ x64/x86 build tools`
|
||||
- `MSVC v143 - VS 2022 - C++ x64/x86 Spectre-mitigated libs`
|
||||
|
||||
:::caution pass
|
||||
---
|
||||
|
||||
In the most recent Windows test against NodeJS `20.8.0`, the build failed due
|
||||
to an issue in the OpenSSL dependency:
|
||||
@ -183,8 +182,8 @@ to an issue in the OpenSSL dependency:
|
||||
```
|
||||
|
||||
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.
|
||||
workaround is to select NodeJS `v22.22.2` using the `-n` flag. In previous test
|
||||
runs, the recommended version was `v16.20.2`.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -158,12 +158,12 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | NodeJS | Date |
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `22.14.0` | 2025-04-21 |
|
||||
| `darwin-arm` | `23.8.0` | 2025-02-16 |
|
||||
| `win11-x64` | `22.13.0` | 2025-01-19 |
|
||||
| `win11-arm` | `22.14.0` | 2025-02-23 |
|
||||
| `linux-x64` | `22.12.0` | 2025-01-02 |
|
||||
| `linux-arm` | `22.13.0` | 2025-02-16 |
|
||||
| `darwin-x64` | `24.13.0` | 2026-01-21 |
|
||||
| `darwin-arm` | `20.18.0` | 2026-03-13 |
|
||||
| `win11-x64` | `24.13.0` | 2026-03-08 |
|
||||
| `win11-arm` | `22.14.0` | 2026-05-05 |
|
||||
| `linux-x64` | `24.11.0` | 2026-03-08 |
|
||||
| `linux-arm` | `24.14.0` | 2026-03-07 |
|
||||
|
||||
:::
|
||||
|
||||
@ -289,7 +289,7 @@ codesign --remove-signature ./sheet2csv
|
||||
In PowerShell, the `Get-Command` command displays the location to `node.exe`:
|
||||
|
||||
```powershell
|
||||
PS C:\sheetjs-sea> get-command node
|
||||
PS C:\sheetjs-sea> Get-Command node
|
||||
|
||||
CommandType Name Version Source
|
||||
----------- ---- ------- ------
|
||||
@ -300,7 +300,7 @@ Application node.exe 20.12.0.0 C:
|
||||
Copy the program (listed in the "Source" column) to `sheet2csv.exe`:
|
||||
|
||||
```powershell
|
||||
copy "C:\Program Files\nodejs\node.exe" sheet2csv.exe
|
||||
copy "$((Get-Command node).Source)" sheet2csv.exe
|
||||
```
|
||||
|
||||
9) Remove the code signature.
|
||||
@ -433,6 +433,8 @@ If the Windows SDK is installed but the command fails, run the comand in the
|
||||
|
||||
:::
|
||||
|
||||
:::note pass
|
||||
|
||||
If the certificate is self-signed, there may be an error:
|
||||
|
||||
```
|
||||
@ -442,6 +444,8 @@ SignTool Error: A certificate chain processed, but terminated in a root
|
||||
|
||||
This error is expected.
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="linux-x64" label="Linux">
|
||||
|
||||
|
||||
@ -79,12 +79,12 @@ This demo was last tested in the following deployments:
|
||||
|
||||
| Architecture | BunJS | Date |
|
||||
|:-------------|:---------|:-----------|
|
||||
| `darwin-x64` | `1.2.10` | 2025-04-21 |
|
||||
| `darwin-arm` | `1.2.8` | 2025-04-03 |
|
||||
| `win11-x64` | `1.1.40` | 2024-12-19 |
|
||||
| `win11-arm` | `1.2.3` | 2025-02-23 |
|
||||
| `linux-x64` | `1.1.43` | 2025-01-10 |
|
||||
| `linux-arm` | `1.2.2` | 2025-02-16 |
|
||||
| `darwin-x64` | `1.3.6` | 2026-01-21 |
|
||||
| `darwin-arm` | `1.3.10` | 2026-03-07 |
|
||||
| `win11-x64` | `1.3.10` | 2026-03-08 |
|
||||
| `win11-arm` | `1.3.11` | 2026-05-05 |
|
||||
| `linux-x64` | `1.3.10` | 2026-03-08 |
|
||||
| `linux-arm` | `1.3.10` | 2026-03-07 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -102,12 +102,12 @@ This demo was last tested in the following deployments:
|
||||
|
||||
| Architecture | Deno | Date |
|
||||
|:-------------|:---------|:-----------|
|
||||
| `darwin-x64` | `2.2.11` | 2025-04-21 |
|
||||
| `darwin-arm` | `2.1.10` | 2025-02-13 |
|
||||
| `win11-x64` | `2.1.6` | 2025-01-19 |
|
||||
| `win11-arm` | `2.2.1` | 2025-02-23 |
|
||||
| `linux-x64` | `2.1.4` | 2025-01-02 |
|
||||
| `linux-arm` | `2.1.10` | 2025-02-15 |
|
||||
| `darwin-x64` | `2.6.5` | 2026-01-21 |
|
||||
| `darwin-arm` | `2.7.4` | 2026-03-07 |
|
||||
| `win11-x64` | `2.7.4` | 2026-03-08 |
|
||||
| `win11-arm` | `2.7.11` | 2026-05-05 |
|
||||
| `linux-x64` | `2.7.4` | 2026-03-08 |
|
||||
| `linux-arm` | `2.7.4` | 2026-03-07 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@ sidebar_label: txiki.js
|
||||
pagination_prev: demos/desktop/index
|
||||
pagination_next: demos/data/index
|
||||
sidebar_custom_props:
|
||||
summary: Compiled apps powered by QuickJS and txiki.js
|
||||
summary: Compiled apps powered by QuickJS and txiki.js
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
@ -88,14 +88,14 @@ console.log(csv);
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | TxikiJS | Date |
|
||||
|:-------------|:----------|:-----------|
|
||||
| `darwin-x64` | `24.12.0` | 2025-04-19 |
|
||||
| `darwin-arm` | `24.12.0` | 2025-04-19 |
|
||||
| `win11-x64` | `24.12.0` | 2025-04-19 |
|
||||
| `win11-arm` | `24.12.0` | 2025-04-19 |
|
||||
| `linux-x64` | `24.12.0` | 2025-04-19 |
|
||||
| `linux-arm` | `24.12.0` | 2025-04-19 |
|
||||
| Architecture | Version | Commit | Date |
|
||||
|:-------------|:----------|:----------|:-----------|
|
||||
| `darwin-x64` | `24.12.0` | `793dd9d` | 2026-01-21 |
|
||||
| `darwin-arm` | `24.12.0` | `793dd9d` | 2026-01-18 |
|
||||
| `win11-x64` | `26.4.0` | | 2026-05-26 |
|
||||
| `win11-arm` | `26.4.0` | | 2026-05-26 |
|
||||
| `linux-x64` | `24.12.0` | `65e5595` | 2026-01-18 |
|
||||
| `linux-arm` | `24.12.0` | `65e5595` | 2026-01-21 |
|
||||
|
||||
:::
|
||||
|
||||
@ -133,6 +133,40 @@ cp build/tjs ../
|
||||
cd ..
|
||||
```
|
||||
|
||||
:::caution pass
|
||||
|
||||
In some `linux-x64` test runs, the `make` step failed:
|
||||
|
||||
```
|
||||
make[5]: *** No rule to make target 'all-configured'. Stop.
|
||||
```
|
||||
|
||||
After re-running `make`, the `[ 0%]` line identifies the root cause:
|
||||
|
||||
```text
|
||||
// highlight-next-line
|
||||
[ 0%] Performing build step for 'libffi'
|
||||
[ 1%] Built target sqlite3
|
||||
[ 2%] Built target ffi-test
|
||||
...
|
||||
[ 61%] Built target sqlite-test
|
||||
MAKE x86_64-pc-linux-gnu : 0 * all-configured
|
||||
// highlight-next-line
|
||||
make[5]: *** No rule to make target 'all-configured'. Stop.
|
||||
```
|
||||
|
||||
If the root cause is `libffi`, it is possible to use the system `libffi`. The
|
||||
following commands should be run in the `txiki.js` folder:
|
||||
|
||||
```bash
|
||||
rm -rf build
|
||||
cmake -B build -DCMAKE_BUILD_TYPE=Release -DUSE_EXTERNAL_FFI=ON
|
||||
cmake --build build -j 8
|
||||
cp build/tjs ../
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win11-x64" label="Windows">
|
||||
|
||||
@ -147,11 +181,18 @@ mv txiki-windows-x86_64\* .
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
1) Download the test file https://docs.sheetjs.com/pres.numbers:
|
||||
1) Download the SheetJS Standalone script and test file. Move both files to the
|
||||
project directory:
|
||||
|
||||
```bash
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
|
||||
<li><a href="https://docs.sheetjs.com/pres.numbers">pres.numbers</a></li>
|
||||
</ul>
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
|
||||
</CodeBlock>
|
||||
|
||||
:::note pass
|
||||
|
||||
@ -163,9 +204,10 @@ Invoke-WebRequest : A parameter cannot be found that matches parameter name 'LO'
|
||||
|
||||
`curl.exe` must be invoked directly:
|
||||
|
||||
```bash
|
||||
<CodeBlock language="bash">{`\
|
||||
curl.exe -LO https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
curl.exe -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
@ -192,39 +234,13 @@ curl.exe -LO https://docs.sheetjs.com/txikijs/sheet2csv.js
|
||||
|
||||
:::
|
||||
|
||||
3) 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 -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
|
||||
</CodeBlock>
|
||||
|
||||
:::note pass
|
||||
|
||||
In PowerShell, the command may fail with a parameter error:
|
||||
|
||||
```
|
||||
Invoke-WebRequest : A parameter cannot be found that matches parameter name 'LO'.
|
||||
```
|
||||
|
||||
`curl.exe` must be invoked directly:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl.exe -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
|
||||
</CodeBlock>
|
||||
|
||||
:::
|
||||
|
||||
4) Bundle the script:
|
||||
3) Bundle the script:
|
||||
|
||||
```js
|
||||
npx -y esbuild sheet2csv.js --bundle --outfile=bundle.js --platform=neutral
|
||||
```
|
||||
|
||||
5) Compile and run `sheet2csv`:
|
||||
4) Compile and run `sheet2csv`:
|
||||
|
||||
```bash
|
||||
./tjs compile bundle.js sheet2csv
|
||||
|
||||
@ -8,7 +8,7 @@ sidebar_custom_props:
|
||||
---
|
||||
|
||||
<head>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.8.0/sql-wasm.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.13.0/sql-wasm.js"></script>
|
||||
</head>
|
||||
|
||||
import current from '/version.js';
|
||||
@ -39,11 +39,11 @@ This demo was tested in the following environments:
|
||||
|
||||
| Platform | Connector Library | Date |
|
||||
|:-----------------|:----------------------------|:-----------|
|
||||
| Chromium 131 | `sql.js` (`1.8.0`) | 2025-01-08 |
|
||||
| Konqueror 22 | `sql.js` (`1.8.0`) | 2025-04-23 |
|
||||
| NodeJS `20.18.0` | `better-sqlite3` (`11.7.2`) | 2025-01-08 |
|
||||
| BunJS `1.1.43` | (built-in) | 2025-01-08 |
|
||||
| Deno `2.1.4` | `sqlite` (`3.9.1`) | 2025-01-09 |
|
||||
| Chromium 143 | `sql.js` (`1.13.0`) | 2026-03-22 |
|
||||
| Konqueror 25 | `sql.js` (`1.13.0`) | 2026-03-22 |
|
||||
| NodeJS `20.18.0` | `better-sqlite3` (`12.6.2`) | 2026-03-22 |
|
||||
| BunJS `1.3.11` | (built-in) | 2026-03-22 |
|
||||
| Deno `2.7.4` | `sqlite` (`3.9.1`) | 2026-03-22 |
|
||||
|
||||
:::
|
||||
|
||||
@ -143,7 +143,7 @@ exported to a XLSX file.
|
||||
function SheetJSQLJS() { return (<button onClick={async() => {
|
||||
/* Load sql.js library */
|
||||
const config = {
|
||||
locateFile: filename => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.8.0/${filename}`
|
||||
locateFile: filename => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.13.0/${filename}`
|
||||
}
|
||||
const SQL = await initSqlJs(config);
|
||||
|
||||
@ -211,7 +211,7 @@ sqlite3 chinook.db ".read chinook.sql"
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm init -y
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz better-sqlite3@9.2.0`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz better-sqlite3@12.6.2`}
|
||||
</CodeBlock>
|
||||
|
||||
2) Download [`SheetJSQLiteNode.mjs`](pathname:///sqlite/SheetJSQLiteNode.mjs):
|
||||
@ -288,7 +288,8 @@ import * as XLSX from "https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs"
|
||||
var db = new DB("chinook.db");
|
||||
\n\
|
||||
/* get data from the \`Invoice\` table */
|
||||
var aoa = db.prepareQuery("SELECT * FROM 'Invoice' LIMIT 100000").all();
|
||||
var query = db.prepareQuery("SELECT * FROM 'Invoice' LIMIT 100000");
|
||||
var aoa = query.all();
|
||||
\n\
|
||||
/* create worksheet from the row objects */
|
||||
var data = [query.columns().map(x => x.name)].concat(aoa);
|
||||
|
||||
@ -25,10 +25,9 @@ This demo was tested in the following environments:
|
||||
|
||||
| Version | Database | Connector Module | Date |
|
||||
|:----------|:---------|:-----------------|:-----------|
|
||||
| `0.21.20` | SQLite | `sqlite3` | 2025-01-09 |
|
||||
| `2.4.2` | SQLite | `better-sqlite3` | 2025-01-09 |
|
||||
| `2.5.1` | SQLite | `better-sqlite3` | 2025-01-09 |
|
||||
| `3.1.0` | SQLite | `better-sqlite3` | 2025-01-09 |
|
||||
| `0.21.20` | SQLite | `sqlite3` | 2026-03-22 |
|
||||
| `2.5.1` | SQLite | `better-sqlite3` | 2026-03-22 |
|
||||
| `3.1.0` | SQLite | `better-sqlite3` | 2026-03-22 |
|
||||
|
||||
:::
|
||||
|
||||
@ -42,8 +41,8 @@ loaded in NodeJS scripts that use KnexJS.
|
||||
The KnexJS `select` method[^1] creates a `SELECT` query. The return value is a
|
||||
Promise that resolves to an array of objects.
|
||||
|
||||
The SheetJS `json_to_sheet` method[^2] can generate a worksheet object[^3] from
|
||||
the array of objects:
|
||||
The SheetJS [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input)
|
||||
method can generate a [worksheet object](/docs/csf/sheet) from the array:
|
||||
|
||||
```js
|
||||
const table_name = "Tabeller1"; // name of table
|
||||
@ -55,8 +54,9 @@ const aoo = await knex.select("*").from(table_name);
|
||||
const worksheet = XLSX.utils.json_to_sheet(aoo);
|
||||
```
|
||||
|
||||
A workbook object can be built from the worksheet using utility functions[^4].
|
||||
The workbook can be exported using the SheetJS `writeFile` method[^5]:
|
||||
Using [`book_new` and `book_append_sheet`](/docs/api/utilities/wb), a workbook
|
||||
object can be created. This workbook is typically exported to the filesystem
|
||||
with the [`writeFile`](/docs/api/write-options) method:
|
||||
|
||||
```js
|
||||
/* create a new workbook and add the worksheet */
|
||||
@ -69,10 +69,10 @@ XLSX.writeFile(wb, "SheetJSKnexJSExport.xlsx");
|
||||
|
||||
### Importing Data
|
||||
|
||||
The SheetJS `sheet_to_json` function[^6] takes a worksheet object and generates
|
||||
an array of objects.
|
||||
The SheetJS [`sheet_to_json` function](/docs/api/utilities/array#array-output)
|
||||
accepts a worksheet object and generates an array of objects.
|
||||
|
||||
The KnexJS `insert` method[^7] creates `INSERT` queries. The return value is a
|
||||
The KnexJS `insert` method[^2] creates `INSERT` queries. The return value is a
|
||||
Promise that resolves when the query is executed:
|
||||
|
||||
```js
|
||||
@ -87,8 +87,8 @@ await knex.insert(aoo).into(table_name);
|
||||
|
||||
### Creating a Table
|
||||
|
||||
The KnexJS Schema Builder supports creating tables with `createTable`[^8] and
|
||||
dropping tables with `dropTableIfExists`[^9].
|
||||
The KnexJS Schema Builder supports creating tables with `createTable`[^3] and
|
||||
dropping tables with `dropTableIfExists`[^4].
|
||||
|
||||
The array of objects can be scanned to determine column names and types.
|
||||
|
||||
@ -272,11 +272,6 @@ Older versions of KnexJS do not support the `better-sqlite3` module. The
|
||||
:::
|
||||
|
||||
[^1]: See [`select`](https://knexjs.org/guide/query-builder.html#select) in the KnexJS query builder documentation.
|
||||
[^2]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^3]: See ["Sheet Objects"](/docs/csf/sheet) in "SheetJS Data Model" for more details.
|
||||
[^4]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^5]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^6]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^7]: See [`insert`](https://knexjs.org/guide/query-builder.html#insert) in the KnexJS query builder documentation.
|
||||
[^8]: See [`createTable`](https://knexjs.org/guide/schema-builder.html#createtable) in the KnexJS Schema Builder documentation.
|
||||
[^9]: See [`dropTableIfExists`](https://knexjs.org/guide/schema-builder.html#droptableifexists) in the KnexJS Schema Builder documentation.
|
||||
[^2]: See [`insert`](https://knexjs.org/guide/query-builder.html#insert) in the KnexJS query builder documentation.
|
||||
[^3]: See [`createTable`](https://knexjs.org/guide/schema-builder.html#createtable) in the KnexJS Schema Builder documentation.
|
||||
[^4]: See [`dropTableIfExists`](https://knexjs.org/guide/schema-builder.html#droptableifexists) in the KnexJS Schema Builder documentation.
|
||||
|
||||
@ -36,12 +36,13 @@ This demo was tested in the following environments:
|
||||
|
||||
| Postgres | Connector Library | Date |
|
||||
|:---------|:------------------|:-----------|
|
||||
| `17.2` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `16.6` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `15.10` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `14.15` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `13.18` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `12.22` | `pg` (`8.13.1`) | 2025-01-03 |
|
||||
| `18.3` | `pg` (`8.20.0`) | 2026-03-22 |
|
||||
| `17.2` | `pg` (`8.20.0`) | 2026-03-22 |
|
||||
| `16.6` | `pg` (`8.20.0`) | 2026-03-22 |
|
||||
| `15.10` | `pg` (`8.20.0`) | 2026-03-22 |
|
||||
| `14.15` | `pg` (`8.20.0`) | 2026-03-22 |
|
||||
| `13.18` | `pg` (`8.20.0`) | 2026-03-22 |
|
||||
| `12.22` | `pg` (`8.20.0`) | 2026-03-22 |
|
||||
|
||||
:::
|
||||
|
||||
@ -58,8 +59,8 @@ other PostgreSQL libraries.
|
||||
`Client#query` returns a Promise that resolves to a result set. The `rows`
|
||||
property of the result is an array of objects.
|
||||
|
||||
The SheetJS `json_to_sheet` method[^2] can generate a worksheet object[^3] from
|
||||
the array of objects:
|
||||
The SheetJS [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input)
|
||||
method can generate a [worksheet object](/docs/csf/sheet) from the array:
|
||||
|
||||
```js
|
||||
const table_name = "Tabeller1"; // name of table
|
||||
@ -71,8 +72,8 @@ const res = await client.query(`SELECT * FROM ${table_name}`);
|
||||
const worksheet = XLSX.utils.json_to_sheet(res.rows);
|
||||
```
|
||||
|
||||
A workbook object can be built from the worksheet using utility functions[^4].
|
||||
The workbook can be exported using the SheetJS `writeFile` method[^5]:
|
||||
[Utility functions](/docs/api/utilities/wb) can build a SheetJS workbook object.
|
||||
The workbook can be exported using the [`writeFile`](/docs/api/write-options):
|
||||
|
||||
```js
|
||||
/* create a new workbook and add the worksheet */
|
||||
@ -85,8 +86,8 @@ XLSX.writeFile(wb, "SheetJSPGExport.xlsx");
|
||||
|
||||
### Importing Data
|
||||
|
||||
The SheetJS `sheet_to_json` function[^6] takes a worksheet object and generates
|
||||
an array of objects.
|
||||
The SheetJS [`sheet_to_json` function](/docs/api/utilities/array#array-output)
|
||||
accepts a worksheet object and generates an array of objects.
|
||||
|
||||
Queries must be manually generated from the objects. Assuming the field names
|
||||
in the object match the column headers, a loop can generate `INSERT` queries.
|
||||
@ -101,7 +102,7 @@ INSERT INTO table_name (?) VALUES (?);
|
||||
```
|
||||
|
||||
Queries are generated manually. To help prevent SQL injection vulnerabilities,
|
||||
the `pg-format`[^7] module escapes identifiers and fields.
|
||||
the `pg-format`[^2] module escapes identifiers and fields.
|
||||
|
||||
:::
|
||||
|
||||
@ -308,7 +309,7 @@ sudo -u postgres createuser -P $USER
|
||||
sudo -u postgres psql -c "ALTER USER $USER WITH SUPERUSER;"
|
||||
```
|
||||
|
||||
If running the optional user creation steps above, a PostgreSQL password will be required. [^8]
|
||||
If running the optional user creation steps above, a PostgreSQL password will be required. [^3]
|
||||
|
||||
Run the command to start a local database instance.
|
||||
|
||||
@ -538,10 +539,5 @@ psql SheetJSPG -c 'SELECT * FROM "Presidents";'
|
||||
|
||||
|
||||
[^1]: See [the official `pg` website](https://node-postgres.com/) for more info.
|
||||
[^2]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^3]: See ["Sheet Objects"](/docs/csf/sheet) in "SheetJS Data Model" for more details.
|
||||
[^4]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^5]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^6]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^7]: The [`pg-format`](https://npm.im/pg-format) package is available on the public NPM registry. Even though the project is marked as deprecated, the official [`pg` website still recommends `pg-format`](https://node-postgres.com/features/queries#parameterized-query:~:text=use%20pg%2Dformat%20package%20for%20handling%20escaping)
|
||||
[^8]: PostgreSQL on Linux uses [SCRAM authentication by default, which requires a password](https://www.postgresql.org/docs/current/auth-password.html)
|
||||
[^2]: The [`pg-format`](https://npm.im/pg-format) package is available on the public NPM registry. Even though the project is marked as deprecated, the official [`pg` website still recommends `pg-format`](https://node-postgres.com/features/queries#parameterized-query:~:text=use%20pg%2Dformat%20package%20for%20handling%20escaping)
|
||||
[^3]: PostgreSQL on Linux uses [SCRAM authentication by default, which requires a password](https://www.postgresql.org/docs/current/auth-password.html)
|
||||
@ -36,7 +36,8 @@ This demo was tested in the following environments:
|
||||
|
||||
| MariaDB | Connector Library | Date |
|
||||
|:---------|:--------------------|:-----------|
|
||||
| `11.6.2` | `mysql2` (`3.12.0`) | 2025-01-19 |
|
||||
| `11.8` | `mysql2` (`3.20.2`) | 2026-03-22 |
|
||||
| `10.6` | `mysql2` (`3.20.2`) | 2026-03-22 |
|
||||
|
||||
:::
|
||||
|
||||
@ -53,8 +54,8 @@ to other MariaDB and MySQL libraries.
|
||||
`Connection#execute` returns a Promise that resolves to a result array. The
|
||||
first entry of the result is an array of objects.
|
||||
|
||||
The SheetJS `json_to_sheet` method[^2] can generate a worksheet object[^3] from
|
||||
the array of objects:
|
||||
The SheetJS [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input)
|
||||
method can generate a [worksheet object](/docs/csf/sheet) from the array:
|
||||
|
||||
```js
|
||||
const mysql = require("mysql2/promise"), XLSX = require("xlsx");
|
||||
@ -72,8 +73,9 @@ const [rows, fields] = await conn.execute(`SELECT * FROM ${mysql.escapeId(table_
|
||||
const worksheet = XLSX.utils.json_to_sheet(rows);
|
||||
```
|
||||
|
||||
A workbook object can be built from the worksheet using utility functions[^4].
|
||||
The workbook can be exported using the SheetJS `writeFile` method[^5]:
|
||||
Using [`book_new` and `book_append_sheet`](/docs/api/utilities/wb), a workbook
|
||||
object can be created. This workbook is typically exported to the filesystem
|
||||
with the [`writeFile`](/docs/api/write-options) method:
|
||||
|
||||
```js
|
||||
/* create a new workbook and add the worksheet */
|
||||
@ -86,8 +88,8 @@ XLSX.writeFile(wb, "SheetJSMariaDBExport.xlsx");
|
||||
|
||||
### Importing Data
|
||||
|
||||
The SheetJS `sheet_to_json` function[^6] takes a worksheet object and generates
|
||||
an array of objects.
|
||||
The SheetJS [`sheet_to_json` function](/docs/api/utilities/array#array-output)
|
||||
accepts a worksheet object and generates an array of objects.
|
||||
|
||||
Queries must be manually generated from the objects. Assuming the field names
|
||||
in the object match the column headers, a loop can generate `INSERT` queries.
|
||||
@ -102,7 +104,7 @@ INSERT INTO table_name (?) VALUES (?);
|
||||
```
|
||||
|
||||
Queries are generated manually. To help prevent SQL injection vulnerabilities,
|
||||
the undocumented `escapeId` method [^7] escapes identifiers and fields.
|
||||
the undocumented `escapeId` method [^2] escapes identifiers and fields.
|
||||
|
||||
:::
|
||||
|
||||
@ -408,9 +410,4 @@ The output should be consistent with the following table:
|
||||
```
|
||||
|
||||
[^1]: See [the official `mysql2` website](https://sidorares.github.io/node-mysql2/docs) for more info.
|
||||
[^2]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^3]: See ["Sheet Objects"](/docs/csf/sheet) in "SheetJS Data Model" for more details.
|
||||
[^4]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^5]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^6]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^7]: The `mysql2` connector library `escapeId` method is not mentioned in the documentation but is present in the TypeScript definitions.
|
||||
[^2]: The `mysql2` connector library `escapeId` method is not mentioned in the documentation but is present in the TypeScript definitions.
|
||||
|
||||
@ -10,27 +10,35 @@ sidebar_custom_props:
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[MongoDB](https://mongodb.github.io/node-mongodb-native/) is a document-oriented
|
||||
database engine. [FerretDB](https://www.ferretdb.com/) is a truly open source
|
||||
implementation of the MongoDB wire protocol
|
||||
:::danger pass
|
||||
|
||||
**MongoDB is not open source!**
|
||||
|
||||
MongoDB uses the Server Side Public License (SSPL), which is not open source.
|
||||
|
||||
This demo has been tested with FerretDB and other servers that implement the
|
||||
MongoDB wire protocol.
|
||||
|
||||
:::
|
||||
|
||||
[FerretDB](https://docs.ferretdb.io) is an Apache 2.0-licensed document database
|
||||
that implements the MongoDB wire protocol using a PostgreSQL or SQLite backend.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses SheetJS to exchange data between spreadsheets and MongoDB. We'll
|
||||
explore how to use save tables from a MongoDB collection to spreadsheets and how
|
||||
to add data from spreadsheets into a collection.
|
||||
explore how to save tables from a database collection to spreadsheets and how to
|
||||
add data from spreadsheets into a collection.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Server | Connector Library | Date |
|
||||
|:--------------------|:---------------------|:-----------|
|
||||
| FerretDB `1.24.0` | `mongodb` (`6.12.0`) | 2025-01-03 |
|
||||
| MongoDB CE `8.0.4` | `mongodb` (`6.12.0`) | 2025-01-19 |
|
||||
| MongoDB CE `7.0.16` | `mongodb` (`6.12.0`) | 2025-01-19 |
|
||||
| MongoDB CE `6.0.20` | `mongodb` (`6.5.0`) | 2025-01-19 |
|
||||
| Server | Connector Library | Date |
|
||||
|:-------------------|:--------------------|:-----------|
|
||||
| FerretDB `1.24.0` | `mongodb` (`7.1.0`) | 2026-03-22 |
|
||||
| MongoDB CE `8.2.0` | `mongodb` (`7.1.0`) | 2026-03-22 |
|
||||
|
||||
:::
|
||||
|
||||
@ -45,8 +53,10 @@ a row in the table.
|
||||
#### Importing Data
|
||||
|
||||
Data stored in an array of objects can be added to MongoDB Collections using
|
||||
`Collection#insertMany`[^1]. The SheetJS `sheet_to_json` method[^2] can generate
|
||||
data from worksheets:
|
||||
`Collection#insertMany`[^1].
|
||||
|
||||
The SheetJS [`sheet_to_json` method](/docs/api/utilities/array#array-output) can
|
||||
generate data from worksheets:
|
||||
|
||||
```js
|
||||
/* import data from a worksheet to a collection */
|
||||
@ -54,15 +64,15 @@ const aoo = XLSX.utils.sheet_to_json(ws);
|
||||
await collection.insertMany(aoo, {ordered: true});
|
||||
```
|
||||
|
||||
Typically worksheet objects are extracted from workbook objects[^3] generated
|
||||
from the SheetJS `read` or `readFile` methods[^4].
|
||||
Typically worksheets are extracted from [workbook objects](/docs/csf/book) that
|
||||
are created by SheetJS [`read` or `readFile`](/docs/api/parse-options) methods.
|
||||
|
||||
#### Exporting Data
|
||||
|
||||
`Collection#find`[^5] can pull an array of objects from a MongoDB Collection.
|
||||
`Collection#find`[^2] can pull an array of objects from a MongoDB Collection.
|
||||
|
||||
The SheetJS `json_to_sheet` method[^6] can take the result and generate a
|
||||
worksheet object.
|
||||
The SheetJS [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input)
|
||||
method can take the result and generate a worksheet object.
|
||||
|
||||
:::info pass
|
||||
|
||||
@ -79,20 +89,18 @@ const aoo = await collection.find({}, {projection:{_id:0}}).toArray();
|
||||
const ws = utils.json_to_sheet(aoo);
|
||||
```
|
||||
|
||||
Using `book_new` and `book_append_sheet`[^7], a workbook object can be created.
|
||||
This workbook is typically exported to the filesystem with `writeFile`[^8].
|
||||
Using [`book_new` and `book_append_sheet`](/docs/api/utilities/wb), a workbook
|
||||
object can be created. This workbook is typically exported to the filesystem
|
||||
with the [`writeFile`](/docs/api/write-options) method.
|
||||
|
||||
## Complete Example
|
||||
|
||||
0) Install a MongoDB-compatible server. Options include MongoDB CE[^9] and
|
||||
FerretDB[^10]
|
||||
|
||||
1) Start a server on `localhost` (follow official instructions).
|
||||
1) Install and start a compatible database locally.
|
||||
|
||||
<details>
|
||||
<summary><b>MongoDB CE Setup</b> (click to show)</summary>
|
||||
<summary><b>MongoDB CE</b> (click to show)</summary>
|
||||
|
||||
For MongoDB 8.0 Community Edition, the macOS steps required `brew`:
|
||||
For MongoDB 8.2 Community Edition, the macOS steps required `brew`:
|
||||
|
||||
```bash
|
||||
brew tap mongodb/brew
|
||||
@ -116,7 +124,7 @@ $(brew --prefix)/opt/mongodb-community/bin/mongod --config $(brew --prefix)/etc/
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary><b>FerretDB Setup</b> (click to show)</summary>
|
||||
<summary><b>FerretDB</b> (click to show)</summary>
|
||||
|
||||
The official documentation recommends Docker, but it is strongly recommended to
|
||||
use [`colima`](https://github.com/abiosoft/colima) on MacOS:
|
||||
@ -188,7 +196,7 @@ docker run -d --rm --name ferretdb -p 27017:27017 -e FERRETDB_HANDLER=sqlite ghc
|
||||
mkdir sheetjs-mongo
|
||||
cd sheetjs-mongo
|
||||
npm init -y
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz mongodb@6.12.0`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz mongodb@7.1.0`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Save the following to `SheetJSMongoCRUD.mjs` (the key step is highlighted):
|
||||
@ -247,12 +255,6 @@ There should be no errors in the terminal. The script will generate the file
|
||||
`SheetJSMongoCRUD.xlsx`. That file can be opened in a spreadsheet editor.
|
||||
|
||||
[^1]: See [`insertMany`](https://mongodb.github.io/node-mongodb-native/5.7/classes/Collection.html#insertMany) in the MongoDB documentation.
|
||||
[^2]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^3]: See ["Workbook Object"](/docs/csf/book)
|
||||
[^4]: See [`read` and `readFile` in "Reading Files"](/docs/api/parse-options)
|
||||
[^5]: See [`find`](https://mongodb.github.io/node-mongodb-native/5.7/classes/Collection.html#find) in the MongoDB documentation.
|
||||
[^6]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^7]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^8]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^9]: See ["Install MongoDB Community Edition"](https://www.mongodb.com/docs/manual/administration/install-community/#std-label-install-mdb-community-edition) in the MongoDB documentation.
|
||||
[^10]: See ["SQLite Setup with Docker Compose"](https://docs.ferretdb.io/quickstart-guide/docker/#sqlite-setup-with-docker-compose) in the FerretDB documentation.
|
||||
[^2]: See [`find`](https://mongodb.github.io/node-mongodb-native/5.7/classes/Collection.html#find) in the MongoDB documentation.
|
||||
[^3]: See ["Install MongoDB Community Edition"](https://www.mongodb.com/docs/manual/administration/install-community/#std-label-install-mdb-community-edition) in the MongoDB documentation.
|
||||
[^4]: See ["SQLite Setup with Docker Compose"](https://docs.ferretdb.io/quickstart-guide/docker/#sqlite-setup-with-docker-compose) in the FerretDB documentation.
|
||||
@ -24,8 +24,9 @@ serialization protocol" (RESP).
|
||||
|
||||
:::
|
||||
|
||||
[KeyDB](https://docs.keydb.dev/) is a Redis-compatible in-memory data store. It
|
||||
is capable of storing sets, lists and other simple data structures.
|
||||
[KeyDB](https://docs.keydb.dev/) is a Redis-compatible in-memory data store
|
||||
licensed under BSD-3-Clause. It is capable of storing sets, lists and other
|
||||
simple data structures.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
@ -38,12 +39,12 @@ from XLSX files to a Redis database and to serialize a database to a workbook.
|
||||
|
||||
This demo was tested in the following environments:
|
||||
|
||||
| Server | Connector Module | Date |
|
||||
|:----------------|:------------------|:----------:|
|
||||
| KeyDB `6.3.4` | `redis` (`4.7.0`) | 2025-01-08 |
|
||||
| Redis `6.2.17` | `redis` (`4.7.0`) | 2025-01-08 |
|
||||
| Valkey `8.0.2` | `redis` (`4.7.0`) | 2025-01-08 |
|
||||
| Garnet `1.0.49` | `redis` (`4.7.0`) | 2025-01-08 |
|
||||
| Server | Connector Module | Date |
|
||||
|:---------------|:-------------------|:----------:|
|
||||
| KeyDB `6.3.4` | `redis` (`5.11.0`) | 2026-03-22 |
|
||||
| Redis `6.2.18` | `redis` (`5.11.0`) | 2026-03-22 |
|
||||
| Valkey `9.0.3` | `redis` (`5.11.0`) | 2026-03-22 |
|
||||
| Garnet `1.1.1` | `redis` (`5.11.0`) | 2026-03-22 |
|
||||
|
||||
:::
|
||||
|
||||
@ -249,12 +250,14 @@ this demo also requires NodeJS version 18 or later.
|
||||
|
||||
This demo was last tested on macOS.
|
||||
|
||||
---
|
||||
|
||||
_KeyDB_
|
||||
|
||||
KeyDB was installed with:
|
||||
KeyDB was installed from Homebrew:
|
||||
|
||||
```bash
|
||||
brew install keydb@6.3.4
|
||||
brew install keydb
|
||||
```
|
||||
|
||||
The following command started the server process:
|
||||
@ -263,6 +266,8 @@ The following command started the server process:
|
||||
keydb-server --protected-mode no
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
_Valkey_
|
||||
|
||||
Valkey was installed with:
|
||||
@ -278,7 +283,7 @@ This conflicts with the main `redis` package. `redis` must be unlinked:
|
||||
|
||||
```bash
|
||||
brew unlink redis
|
||||
brew link valkey
|
||||
brew link valkey || brew install valkey
|
||||
```
|
||||
|
||||
:::
|
||||
@ -286,9 +291,11 @@ brew link valkey
|
||||
The following command started the server process:
|
||||
|
||||
```bash
|
||||
redis-server $(brew config | grep HOMEBREW_PREFIX | awk '{print $2}')/etc/redis.conf
|
||||
redis-server $(brew --prefix)/etc/redis.conf
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
_Redis 6_
|
||||
|
||||
Redis 6 was installed with:
|
||||
@ -300,7 +307,7 @@ brew install redis@6.2
|
||||
The following command started the server process:
|
||||
|
||||
```bash
|
||||
redis-server $(brew config | grep HOMEBREW_PREFIX | awk '{print $2}')/etc/redis.conf
|
||||
redis-server $(brew --prefix)/etc/redis.conf
|
||||
```
|
||||
|
||||
:::caution pass
|
||||
@ -310,6 +317,8 @@ version of Redis.
|
||||
|
||||
:::
|
||||
|
||||
---
|
||||
|
||||
_Garnet_
|
||||
|
||||
After installing `dotnet` and .NET runtime, install the `garnet-server` tool:
|
||||
@ -335,7 +344,7 @@ curl -LO https://docs.sheetjs.com/nosql/SheetJSRedisTest.mjs
|
||||
2) Install dependencies:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz redis@4.6.13`}
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz redis@5.11.0`}
|
||||
</CodeBlock>
|
||||
|
||||
3) Run the test script:
|
||||
|
||||
@ -29,13 +29,13 @@ This demo was tested in the following environments:
|
||||
|
||||
| PouchDB | Date |
|
||||
|:--------|:----------:|
|
||||
| `9.0.0` | 2025-01-19 |
|
||||
| `8.0.1` | 2025-01-19 |
|
||||
| `7.3.1` | 2025-01-19 |
|
||||
| `6.4.3` | 2025-01-19 |
|
||||
| `5.4.5` | 2025-01-19 |
|
||||
| `4.0.3` | 2025-01-19 |
|
||||
| `3.6.0` | 2025-01-19 |
|
||||
| `9.0.0` | 2026-01-08 |
|
||||
| `8.0.1` | 2026-01-08 |
|
||||
| `7.3.1` | 2026-01-08 |
|
||||
| `6.4.3` | 2026-01-08 |
|
||||
| `5.4.5` | 2026-01-08 |
|
||||
| `4.0.3` | 2026-01-08 |
|
||||
| `3.6.0` | 2026-01-08 |
|
||||
|
||||
:::
|
||||
|
||||
@ -53,20 +53,18 @@ The `PouchDB` constructor returns a `Database` object.
|
||||
#### Importing Data
|
||||
|
||||
`Database#bulkDocs`[^2] is the standard approach for bulk data import. The method
|
||||
accepts "arrays of objects" that can be generated through the SheetJS
|
||||
`sheet_to_json`[^3] method.
|
||||
accepts "arrays of objects" that can be generated using the SheetJS
|
||||
[`sheet_to_json`](/docs/api/utilities/array#array-output) method.
|
||||
|
||||
If rows do not include the `_id` parameter, the database will automatically
|
||||
assign an ID per row. It is strongly recommended to generate the `_id` directly.
|
||||
|
||||
This method starts from a SheetJS workbook object[^4] and uses data from the
|
||||
first sheet. `read` and `readFile`[^5] can generate workbook objects from files.
|
||||
|
||||
```js
|
||||
async function push_first_sheet_to_pouchdb(db, wb, _id_) {
|
||||
/* get first worksheet */
|
||||
const ws = wb.Sheets[wb.SheetNames[0]];
|
||||
This method starts from a SheetJS [worksheet object](/docs/csf/sheet) and uses
|
||||
data from the first sheet. [`read` and `readFile`](/docs/api/parse-options) can
|
||||
generate workbook objects from files.
|
||||
|
||||
```js title="Extract data from a SheetJS worksheet and push to PouchDB"
|
||||
async function push_sheet_to_pouchdb(db, ws, _id_) {
|
||||
/* generate array of objects */
|
||||
const aoo = XLSX.utils.sheet_to_json(ws);
|
||||
|
||||
@ -86,14 +84,15 @@ Existing data can be erased with `Database#destroy`.
|
||||
|
||||
#### Exporting Data
|
||||
|
||||
`Database#allDocs`[^6] is the standard approach for bulk data export. Generated
|
||||
`Database#allDocs`[^3] is the standard approach for bulk data export. Generated
|
||||
row objects have additional `_id` and `_rev` keys that should be removed.
|
||||
|
||||
After removing the PouchDB internal fields, the SheetJS `json_to_sheet`[^7]
|
||||
method can generate a worksheet. Other utility functions[^8] can construct a
|
||||
workbook. The workbook can be exported with the SheetJS `writeFile`[^9] method:
|
||||
The SheetJS [`json_to_sheet`](/docs/api/utilities/array#array-of-objects-input)
|
||||
method can generate a worksheet. [API functions](/docs/api/utilities/wb) can
|
||||
generate a workbook object. The [`writeFile`](/docs/api/write-options) method
|
||||
will attempt to download the generated workbook:
|
||||
|
||||
```js
|
||||
```js title="Extract data from PouchDB and export to XLSX using SheetJS"
|
||||
function export_pouchdb_to_xlsx(db) {
|
||||
/* fetch all rows, including the underlying data */
|
||||
db.allDocs({include_docs: true}, function(err, doc) {
|
||||
@ -171,8 +170,8 @@ cd getting-started-todo-master
|
||||
<script src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>
|
||||
<button id="xport">Export!</button>
|
||||
<!-- highlight-end -->
|
||||
<section id="todoapp">`}
|
||||
</CodeBlock>
|
||||
<section id="todoapp">
|
||||
`}</CodeBlock>
|
||||
|
||||
3) Near the end of `index.html`, look for a script tag referencing a CDN:
|
||||
|
||||
@ -180,7 +179,7 @@ cd getting-started-todo-master
|
||||
<script src="//cdn.jsdelivr.net/pouchdb/3.2.0/pouchdb.min.js"></script>
|
||||
```
|
||||
|
||||
Upgrade PouchDB by changing the `src` attribute to the production build[^10]:
|
||||
Upgrade PouchDB by changing the `src` attribute to the production build[^4]:
|
||||
|
||||
```html title="index.html (replace line)"
|
||||
<script src="//cdn.jsdelivr.net/npm/pouchdb@8.0.1/dist/pouchdb.min.js"></script>
|
||||
@ -228,7 +227,7 @@ order of todo items in the export matches the list displayed in the webpage.
|
||||
5) Start a local web server:
|
||||
|
||||
```bash
|
||||
npx http-server .
|
||||
npx -y http-server .
|
||||
```
|
||||
|
||||
The command will display a URL (typically `http://localhost:8080`) which can be
|
||||
@ -255,11 +254,5 @@ export named "SheetJSPouch.xlsx"
|
||||
|
||||
[^1]: See ["Setting up PouchDB"](https://pouchdb.com/guides/setup-pouchdb.html) in the PouchDB documentation.
|
||||
[^2]: See ["Create/update a batch of documents"](https://pouchdb.com/api.html#batch_create) in the PouchDB API documentation
|
||||
[^3]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
|
||||
[^4]: See ["SheetJS Data Model"](/docs/csf)
|
||||
[^5]: See [`read` in "Reading Files"](/docs/api/parse-options)
|
||||
[^6]: See ["Fetch a batch of documents"](https://pouchdb.com/api.html#batch_fetch) in the PouchDB API documentation
|
||||
[^7]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
|
||||
[^8]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
|
||||
[^9]: See [`writeFile` in "Writing Files"](/docs/api/write-options)
|
||||
[^10]: The ["Quick Start" section of "Download"](https://pouchdb.com/download.html#file) in the PouchDB website describes the recommended CDN for PouchDB scripts.
|
||||
[^3]: See ["Fetch a batch of documents"](https://pouchdb.com/api.html#batch_fetch) in the PouchDB API documentation
|
||||
[^4]: The ["Quick Start" section of "Download"](https://pouchdb.com/download.html#file) in the PouchDB website describes the recommended CDN for PouchDB scripts.
|
||||
@ -291,7 +291,7 @@ following screenshot was taken in Chrome 126.0.6478.127:
|
||||
|
||||
This is a browser limitation and no pure JavaScript library can work around the
|
||||
issue. See [Issue #3145](https://git.sheetjs.com/sheetjs/sheetjs/issues/3145) in
|
||||
the SheetJS bug tracker for more details.
|
||||
the SheetJS CE bug tracker for more details.
|
||||
|
||||
:::
|
||||
|
||||
@ -466,15 +466,15 @@ This browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 131 | 2025-01-07 |
|
||||
| Chromium 142 | 2025-11-15 |
|
||||
|
||||
Some lesser-used browsers do not support File System Access API:
|
||||
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Safari 17.5 | 2025-01-07 |
|
||||
| Safari 26.1 | 2025-11-15 |
|
||||
| Konqueror 22 | 2025-04-23 |
|
||||
| Firefox 133 | 2025-01-07 |
|
||||
| Firefox 139 | 2025-06-20 |
|
||||
|
||||
:::
|
||||
|
||||
@ -836,4 +836,4 @@ Desktop and mobile apps have their own specific APIs covered in separate demos:
|
||||
[^1]: See ["Input Type" in "Reading Files"](/docs/api/parse-options#input-type)
|
||||
[^2]: See ["Supported Output Formats" type in "Writing Files"](/docs/api/write-options#supported-output-formats)
|
||||
[^3]: See ["Buffers and TypedArrays"](https://nodejs.org/api/buffer.html#buffers-and-typedarrays) in the NodeJS documentation.
|
||||
[^4]: See [issue 3145 in the SheetJS bug tracker](https://git.sheetjs.com/sheetjs/sheetjs/issues/3145#issuecomment-11074) for more details. Special thanks to `@sjoenH`!
|
||||
[^4]: See [issue 3145 in the SheetJS CE bug tracker](https://git.sheetjs.com/sheetjs/sheetjs/issues/3145#issuecomment-11074) for more details. Special thanks to `@sjoenH`!
|
||||
@ -159,13 +159,13 @@ This browser demo was tested in the following environments:
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Konqueror 22 | 2025-04-23 |
|
||||
| Chromium 118 | 2025-03-30 |
|
||||
| Chromium 118 | 2026-05-22 |
|
||||
|
||||
Browsers that do not support WebSQL will throw errors:
|
||||
|
||||
| Browser | Date | Error Message |
|
||||
|:-------------|:-----------|:------------------------------|
|
||||
| Chromium 133 | 2025-03-30 | `openDatabase is not defined` |
|
||||
| Chromium 147 | 2026-05-22 | `openDatabase is not defined` |
|
||||
| Safari 18.3 | 2025-03-30 | `Web SQL is deprecated` |
|
||||
| Firefox 136 | 2025-03-30 | `openDatabase is not defined` |
|
||||
|
||||
|
||||
@ -11,8 +11,10 @@ simple key-value stores that only support string values and keys.
|
||||
|
||||
This demo covers two common use patterns:
|
||||
|
||||
- "Row Objects" shows a simple convention for loading and storing row objects
|
||||
- "Simple Strings" discusses how to persist and recover a raw Storage
|
||||
- ["Row Objects"](#row-objects) shows a simple convention for loading and
|
||||
storing row objects.
|
||||
- ["Simple Strings"](#simple-strings) discusses how to persist and recover keys
|
||||
and string values.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
@ -20,8 +22,8 @@ Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 131 | 2024-12-23 |
|
||||
| Safari 18.2 | 2024-12-31 |
|
||||
| Chromium 136 | 2025-05-21 |
|
||||
| Safari 18.2 | 2025-05-21 |
|
||||
| Konqueror 22 | 2025-04-23 |
|
||||
|
||||
:::
|
||||
@ -49,10 +51,13 @@ strings using `JSON.stringify` and store using the row index as a key:
|
||||
|
||||
#### Importing Data
|
||||
|
||||
Starting from a worksheet, the SheetJS `sheet_to_json` method[^1] generates an
|
||||
array of row objects. `localStorage.setItem` will store data in Local Storage:
|
||||
`localStorage.setItem` will store data in Local Storage.
|
||||
|
||||
```js
|
||||
Starting from a worksheet, the SheetJS `sheet_to_json` method[^1] generates an
|
||||
array of row objects. Each object in the array can be saved in the Local Storage
|
||||
using the row index as the key.
|
||||
|
||||
```js title="Store a SheetJS worksheet in Local Storage"
|
||||
function sheet_to_localStorage(worksheet) {
|
||||
const aoo = XLSX.utils.sheet_to_json(worksheet);
|
||||
for(let i = 0; i < aoo.length; ++i) {
|
||||
@ -96,7 +101,7 @@ function localStorage_to_array_of_objects() {
|
||||
The SheetJS `json_to_sheet`[^2] method will create a new worksheet from the
|
||||
array of objects:
|
||||
|
||||
```js
|
||||
```js title="Generate a SheetJS worksheet from records in Local Storage "
|
||||
function localStorage_to_sheet() {
|
||||
const aoo = [];
|
||||
for(let i = 0; i < localStorage.length; ++i) {
|
||||
@ -118,8 +123,8 @@ After saving the exported file, the Local Storage can be inspected in the
|
||||
|
||||
:::caution pass
|
||||
|
||||
This example is for illustration purposes. If array of objects is available, it
|
||||
is strongly recommended to convert that array to a worksheet directly.
|
||||
This example is for illustration purposes. If an array of objects is available,
|
||||
it is strongly recommended to convert that array to a worksheet directly.
|
||||
|
||||
:::
|
||||
|
||||
@ -203,7 +208,7 @@ In modern browsers, `Object.entries` will generate an array of key/value pairs.
|
||||
The SheetJS `aoa_to_sheet`[^3] method will interpret that array as a worksheet
|
||||
with 2 columns (key and value):
|
||||
|
||||
```js
|
||||
```js title="Generate a SheetJS two-column worksheet from Local Storage"
|
||||
function localStorage_to_ws() {
|
||||
const aoa = Object.entries(localStorage);
|
||||
return XLSX.utils.aoa_to_sheet(aoa);
|
||||
@ -216,7 +221,7 @@ In the other direction, the worksheet is assumed to store keys in column A and
|
||||
values in column B. The SheetJS `sheet_to_json`[^1] method, with the option
|
||||
`header: 1`, will generate key/value pairs that can be assigned to a storage:
|
||||
|
||||
```js
|
||||
```js title="Store a SheetJS two-column worksheet in Local Storage"
|
||||
function ws_to_localStorage(ws) {
|
||||
const aoa = XLSX.utils.sheet_to_json(ws, { header: 1 });
|
||||
aoa.forEach(([key, val]) => localStorage.setItem(key, val));
|
||||
|
||||
@ -22,10 +22,10 @@ Each browser demo was tested in the following environments:
|
||||
|
||||
| Browser | Architecture | Date | Notes |
|
||||
|:-------------|:-------------|:-----------|:--------------------------------|
|
||||
| Chromium 133 | `darwin-arm` | 2025-04-23 | |
|
||||
| Safari 17.5 | `darwin-arm` | 2025-04-23 | `text/rtf` not supported |
|
||||
| Chromium 116 | `win11-arm` | 2025-04-23 | |
|
||||
| Edge 135 | `win11-arm` | 2025-04-23 | |
|
||||
| Chromium 146 | `darwin-arm` | 2026-05-16 | `text/rtf` did not work |
|
||||
| Safari 26.2 | `darwin-arm` | 2026-05-16 | `text/rtf` not supported |
|
||||
| Chromium 147 | `win11-arm` | 2026-05-26 | |
|
||||
| Edge 148 | `win11-arm` | 2026-05-26 | |
|
||||
| Chromium 135 | `linux-arm` | 2025-04-23 | |
|
||||
| Konqueror 22 | `linux-arm` | 2025-04-23 | `text/rtf`, files not supported |
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ sidebar_custom_props:
|
||||
|
||||
<head>
|
||||
<script type="text/javascript" src="https://unpkg.com/localforage@1.10.0/dist/localforage.min.js"></script>
|
||||
<script type="text/javascript" src="https://unpkg.com/dexie@4.0.10/dist/dexie.js"></script>
|
||||
<script type="text/javascript" src="https://unpkg.com/dexie@4.0.11/dist/dexie.js"></script>
|
||||
</head>
|
||||
|
||||
:::danger pass
|
||||
@ -43,8 +43,8 @@ This demo was last tested in the following environments:
|
||||
|
||||
| Browser | Date | `localForage` |
|
||||
|:-------------|:-----------|:--------------|
|
||||
| Chromium 131 | 2024-12-31 | `1.10.0` |
|
||||
| Safari 18.2 | 2024-12-31 | `1.10.0` |
|
||||
| Chromium 136 | 2025-05-21 | `1.10.0` |
|
||||
| Safari 18.2 | 2025-05-21 | `1.10.0` |
|
||||
| Konqueror 22 | 2025-04-23 | `1.10.0` |
|
||||
|
||||
:::
|
||||
@ -116,8 +116,8 @@ This demo was last tested in the following environments:
|
||||
|
||||
| Browser | Date | DexieJS |
|
||||
|:-------------|:-----------|:---------|
|
||||
| Chromium 131 | 2024-12-31 | `4.0.10` |
|
||||
| Safari 18.2 | 2024-12-31 | `4.0.10` |
|
||||
| Chromium 136 | 2025-05-21 | `4.0.11` |
|
||||
| Safari 18.2 | 2025-05-21 | `4.0.11` |
|
||||
| Konqueror 22 | 2025-04-23 | `4.0.10` |
|
||||
|
||||
:::
|
||||
|
||||
@ -33,7 +33,7 @@ This demo was tested in the following deployments:
|
||||
|
||||
| Lightning API | Date |
|
||||
|:--------------|:-----------|
|
||||
| `61.0` | 2024-10-06 |
|
||||
| `66.0` | 2026-05-05 |
|
||||
|
||||
:::
|
||||
|
||||
@ -43,7 +43,7 @@ The Salesforce developer tools embed telemetry. It can be disabled by setting
|
||||
the environment variable `SF_DISABLE_TELEMETRY` to `true` or running a command:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli config set disable-telemetry=true --global
|
||||
npx -y @salesforce/cli config set disable-telemetry=true --global
|
||||
```
|
||||
|
||||
:::
|
||||
@ -317,13 +317,13 @@ This demo was built on a "Developer Edition" account. At the time of writing, an
|
||||
2) Disable telemetry:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli config set disable-telemetry=true --global
|
||||
npx -y @salesforce/cli config set disable-telemetry=true --global
|
||||
```
|
||||
|
||||
3) Confirm the CLI tool works by checking version information:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli --version
|
||||
npx -y @salesforce/cli --version
|
||||
```
|
||||
|
||||
:::note pass
|
||||
@ -331,7 +331,7 @@ npx @salesforce/cli --version
|
||||
When the demo was last tested, the command printed
|
||||
|
||||
```
|
||||
@salesforce/cli/2.60.13 darwin-arm64 node-v20.18.0
|
||||
@salesforce/cli/2.129.8 darwin-arm64 node-v24.11.1
|
||||
```
|
||||
|
||||
:::
|
||||
@ -339,17 +339,39 @@ When the demo was last tested, the command printed
|
||||
4) Log into the org from the CLI tool:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli org login web
|
||||
npx -y @salesforce/cli org login web
|
||||
```
|
||||
|
||||
This will open a web browser. Sign in and authorize the application.
|
||||
|
||||
After authorizing the app, the terminal window will show a confirmation:
|
||||
|
||||
```
|
||||
Successfully authorized USERNAME with org ID ORGID
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
The "Developer Edition" account username is not the same as the email used to
|
||||
register for the free account!
|
||||
|
||||
The correct username can be found in the email authorization flow:
|
||||
|
||||
1) Access the mail Salesforce gateway at https://login.salesforce.com/
|
||||
|
||||
2) Click "Log In with Email" and enter the original email address and password.
|
||||
|
||||
3) Wait for a verification email from `noreply@salesforce.com`. The correct
|
||||
username will be included in the message body.
|
||||
|
||||
:::
|
||||
|
||||
### Create Project
|
||||
|
||||
5) Create the "SheetForce" sample project with the `project generate` command:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli project generate -n SheetForce
|
||||
npx -y @salesforce/cli template generate project -n SheetForce
|
||||
```
|
||||
|
||||
Enter the project directory:
|
||||
@ -361,7 +383,7 @@ cd SheetForce
|
||||
6) Create a LWC component with the `lightning generate component` command:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli lightning generate component --type lwc -n sheetComponent -d force-app/main/default/lwc
|
||||
npx -y @salesforce/cli template generate lightning component --type lwc -n sheetComponent -d force-app/main/default/lwc
|
||||
```
|
||||
|
||||
7) Replace `force-app\main\default\lwc\sheetComponent\sheetComponent.html` with
|
||||
@ -380,7 +402,7 @@ with the following XML:
|
||||
```xml title="force-app\main\default\lwc\sheetComponent\sheetComponent.js-meta.xml (replace highlighted lines)"
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
|
||||
<apiVersion>61.0</apiVersion>
|
||||
<apiVersion>66.0</apiVersion>
|
||||
<!-- highlight-start -->
|
||||
<isExposed>true</isExposed>
|
||||
<masterLabel>SheetForce</masterLabel>
|
||||
@ -398,7 +420,7 @@ with the following XML:
|
||||
Username. For example, if the Username was `SF@USER.NAME`, the command is:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli project deploy start -d force-app -o SF@USER.NAME
|
||||
npx -y @salesforce/cli project deploy start -d force-app -o SF@USER.NAME
|
||||
```
|
||||
|
||||
10) Find the new component:
|
||||
@ -412,7 +434,7 @@ A) In the Salesforce site, click on the gear icon in the top-right corner of the
|
||||
page and select "Setup" (Setup for current app).
|
||||
|
||||
B) Type "Custom Code" in the left sidebar search box. Expand "Custom Code",
|
||||
expand "Lightning Components" and click "Lightning Components".
|
||||
expand "Lightning Components" and click the inner "Lightning Components".
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -430,8 +452,8 @@ Click the link to open the page in Salesforce Classic.
|
||||
|
||||
A) Click the "Setup" link in the top-right corner of the page.
|
||||
|
||||
B) Type "Lightning" in the left sidebar search box. Expand "Develop", expand
|
||||
"Lightning Components" and click "Lightning Components".
|
||||
B) Type "Custom Code" in the left sidebar search box. In the section, expand
|
||||
"Lightning Components" and click the inner "Lightning Components".
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
@ -499,13 +521,26 @@ builder main view to add it to the page.
|
||||
|
||||
Click "Save".
|
||||
|
||||
:::note pass
|
||||
|
||||
In some test runs, there was a warning popup when "SheetForce" was selected.
|
||||
|
||||
> Select an insertion point for the component, either in an empty region, or
|
||||
> before or after another component.
|
||||
|
||||
Click "Add Component(s) Here" in the main panel. The button will be replaced
|
||||
with a blue bar. Click "SheetForce" once and it will be added to the page.
|
||||
|
||||
:::
|
||||
|
||||
13) Activate the page.
|
||||
|
||||
When the "Page Saved" modal is displayed, click "Activate".
|
||||
|
||||
The following options should be set:
|
||||
- Click "Change..." next to "Icon" and pick a memorable icon
|
||||
- Under "Lightning Experience" click "LightningBolt" then "Add page to app"
|
||||
- Under "Lightning Experience" select "LightningBolt" in the left column and
|
||||
click "Add page to app" in the right side
|
||||
|
||||
Click "Save" to activate the page.
|
||||
|
||||
@ -566,7 +601,7 @@ mv xlsx.full.min.js force-app/main/default/staticresources/sheetjs.js
|
||||
18) Deploy the project again with the same command from step 9:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli project deploy start -d force-app -o SF@USER.NAME
|
||||
npx -y @salesforce/cli project deploy start -d force-app -o SF@USER.NAME
|
||||
```
|
||||
|
||||
Replace `SF@USER.NAME` with the unique Username.
|
||||
@ -579,7 +614,8 @@ npx @salesforce/cli project deploy start -d force-app -o SF@USER.NAME
|
||||
A) In the Salesforce site, click on the gear icon in the top-right corner of the
|
||||
page and select "Setup" (Setup for current app).
|
||||
|
||||
B) Type "Static" in the left sidebar search box. Click "Static Resources"
|
||||
B) Type "Static" in the left sidebar search box. Click "Static Resources" in the
|
||||
"Custom Code" section.
|
||||
|
||||
:::caution pass
|
||||
|
||||
@ -642,7 +678,7 @@ This template references the `version` property.
|
||||
22) Deploy the project again with the same command from step 9:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli project deploy start -d force-app -o SF@USER.NAME
|
||||
npx -y @salesforce/cli project deploy start -d force-app -o SF@USER.NAME
|
||||
```
|
||||
|
||||
Replace `SF@USER.NAME` with the unique Username.
|
||||
@ -713,7 +749,7 @@ export default class SheetComponent extends LightningElement {
|
||||
26) Deploy the project again with the same command from step 9:
|
||||
|
||||
```bash
|
||||
npx @salesforce/cli project deploy start -d force-app -o SF@USER.NAME
|
||||
npx -y @salesforce/cli project deploy start -d force-app -o SF@USER.NAME
|
||||
```
|
||||
|
||||
Replace `SF@USER.NAME` with the unique Username.
|
||||
|
||||
@ -24,10 +24,10 @@ This demo was verified by NetSuite consultants in the following deployments:
|
||||
|
||||
| `@NScriptType` | `@NApiVersion` | Date |
|
||||
|:----------------|:---------------|:-----------|
|
||||
| ScheduledScript | 2.1 | 2024-12-06 |
|
||||
| Restlet | 2.1 | 2024-12-06 |
|
||||
| Suitelet | 2.1 | 2024-12-06 |
|
||||
| MapReduceScript | 2.1 | 2024-12-06 |
|
||||
| ScheduledScript | 2.1 | 2025-06-08 |
|
||||
| Restlet | 2.1 | 2025-06-08 |
|
||||
| Suitelet | 2.1 | 2025-06-08 |
|
||||
| MapReduceScript | 2.1 | 2025-06-08 |
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ will be available in the future.
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024-06-12.
|
||||
This demo was last tested on 2025-05-11.
|
||||
|
||||
:::
|
||||
|
||||
@ -59,7 +59,8 @@ Azure Functions Core Tools (`func`) telemetry is controlled through the
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="unix" label="Linux/MacOS">
|
||||
|
||||
Add the following line to `.profile`, `.bashrc` and `.zshrc`:
|
||||
Add the following line to `.profile`, `.bash_profile`, `.bashrc`, `.zprofile`,
|
||||
`.zshrc`, and any other configuration files:
|
||||
|
||||
```bash
|
||||
export FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT=1
|
||||
@ -131,7 +132,7 @@ Uploaded files can be pulled into `ArrayBuffer` objects.
|
||||
|
||||
This function returns a promise that resolves to an `ArrayBuffer` object:
|
||||
|
||||
```js
|
||||
```js title="Get raw data from an uploaded file"
|
||||
const { Blob } = require('buffer');
|
||||
|
||||
async function get_file_from_request(request, form_field_name) {
|
||||
@ -158,7 +159,7 @@ SheetJS workbook objects[^3] which can be processed with other API functions.
|
||||
For example, a handler can use `sheet_to_csv`[^4] to generate CSV text from
|
||||
user-submitted spreadsheets:
|
||||
|
||||
```js
|
||||
```js title="Function that reads uploaded workbooks and converts to CSV"
|
||||
const { Blob } = require('buffer');
|
||||
const { app } = require('@azure/functions');
|
||||
const XLSX = require('xlsx');
|
||||
@ -194,7 +195,7 @@ The following example generates a sample worksheet using the `aoa_to_sheet`[^6]
|
||||
method, generates a sample workbook using worksheet helper methods[^7], writes
|
||||
the workbook to XLSX format in a Buffer, and sends the Buffer in the response:
|
||||
|
||||
```js
|
||||
```js title="Function that exports data and initiates a download to XLSX"
|
||||
const { app } = require('@azure/functions');
|
||||
const XLSX = require('xlsx');
|
||||
|
||||
@ -299,10 +300,20 @@ Until the bugs are resolved, JavaScript should be preferred over TypeScript.
|
||||
npm start
|
||||
```
|
||||
|
||||
7) While the server is running, open a new terminal window and make a request:
|
||||
The process will display the functions and respective URLs:
|
||||
|
||||
```text title="Expected output"
|
||||
Functions:
|
||||
|
||||
SheetJSAzure: [GET,POST] http://localhost:7071/api/SheetJSAzure
|
||||
(access this URL)------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
```
|
||||
|
||||
7) While the server is running, open a new terminal window and make a GET
|
||||
request to the URL listed in the previous step:
|
||||
|
||||
```bash
|
||||
curl -L http://localhost:7071/api/SheetJSAzure
|
||||
curl http://localhost:7071/api/SheetJSAzure
|
||||
```
|
||||
|
||||
The terminal should display `Hello, world!`
|
||||
@ -333,7 +344,7 @@ npm start
|
||||
make a POST request to the dev server:
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
curl -X POST -F "upload=@pres.numbers" http://localhost:7071/api/SheetJSAzure
|
||||
```
|
||||
|
||||
@ -354,19 +365,20 @@ Open in Excel or another spreadsheet editor to confirm the file is valid.
|
||||
|
||||
15) Click "+ Create"
|
||||
|
||||
16) Select the following options:
|
||||
16) In the "Create Function App" screen, click "Consumption" and click "Select".
|
||||
|
||||
- "Select a hosting option": "Consumption"
|
||||
17) In the next screen, select the following options:
|
||||
|
||||
- Type a memorable "Function Name" ("sheetjsazure" when last tested)
|
||||
- Look for the "Function App name" input field and type a memorable function
|
||||
name. When this demo was last tested, the name "sheetjsazure" was chosen.
|
||||
|
||||
- "Operating System": "Windows"
|
||||
|
||||
- "Runtime stack": select `Node.js`
|
||||
|
||||
17) Click "Review + create", then click "Create" to create the function.
|
||||
18) Click "Review + create", then click "Create" to create the function.
|
||||
|
||||
The page will display a status message
|
||||
The page will redirect to a new page. It will display a status message:
|
||||
|
||||
> ... Deployment is in progress
|
||||
|
||||
@ -374,21 +386,19 @@ When the resources are configured, the status will change to
|
||||
|
||||
> Your deployment is complete
|
||||
|
||||
18) Click "Go to Resource".
|
||||
|
||||
19) Take note of the URL from the "Essentials" table.
|
||||
19) Click "Go to Resource".
|
||||
|
||||
#### Deploy to Azure
|
||||
|
||||
20) Sign into Azure:
|
||||
20) Sign into Azure from the command line:
|
||||
|
||||
```
|
||||
```bash
|
||||
az login
|
||||
```
|
||||
|
||||
The login flow resumes in the browser.
|
||||
|
||||
21) Deploy to Azure. Replace `FUNCTION_NAME` with the name from Step 16:
|
||||
21) Deploy to Azure. Replace `FUNCTION_NAME` with the name from Step 17:
|
||||
|
||||
```bash
|
||||
func azure functionapp publish FUNCTION_NAME
|
||||
@ -429,7 +439,7 @@ make a POST request to the production server. Replace `FUNCTION_URL` with the
|
||||
Invoke URL from Step 21:
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
curl -X POST -F "upload=@pres.numbers" FUNCTION_URL
|
||||
```
|
||||
|
||||
@ -546,9 +556,9 @@ requests and 2000 write requests per month.
|
||||
|
||||
- "Redundancy": select LRS (Locally-redundant storage)
|
||||
|
||||
5) Click "Review", then click "Create" to create the storage.
|
||||
5) Click "Review + create", then click "Create" to create the storage.
|
||||
|
||||
The page will display a status message
|
||||
The page will redirect to a new page. It will display a status message:
|
||||
|
||||
> ... Deployment is in progress
|
||||
|
||||
@ -596,11 +606,64 @@ npm init -y
|
||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @azure/storage-blob`}
|
||||
</CodeBlock>
|
||||
|
||||
14) Copy the [`SheetJSReadFromAzure.mjs` code block](#downloading-data) and save
|
||||
to `SheetJSReadFromAzure.mjs`.
|
||||
14) Save the following codeblock to `SheetJSReadFromAzure.mjs`:
|
||||
|
||||
15) Copy the [`SheetJSWriteToAzure.mjs` code block](#uploading-data) and save
|
||||
to `SheetJSWriteToAzure.mjs`.
|
||||
```js title="SheetJSReadFromAzure.mjs"
|
||||
import { BlobServiceClient } from "@azure/storage-blob";
|
||||
import { read, utils } from "xlsx";
|
||||
|
||||
/* replace these constants */
|
||||
// highlight-start
|
||||
const connStr = "<REPLACE WITH CONNECTION STRING>";
|
||||
const containerName = "<REPLACE WITH CONTAINER NAME>";
|
||||
// highlight-end
|
||||
|
||||
/* Blob name */
|
||||
const blobName = "SheetJSBloblobber.xlsx";
|
||||
|
||||
/* get a readable stream*/
|
||||
const blobServiceClient = BlobServiceClient.fromConnectionString(connStr);
|
||||
const containerClient = blobServiceClient.getContainerClient(containerName);
|
||||
const blobClient = containerClient.getBlobClient(blobName);
|
||||
const response = (await blobClient.download()).readableStreamBody;
|
||||
|
||||
/* collect data into a Buffer */
|
||||
const bufs = [];
|
||||
for await(const buf of response) bufs.push(buf);
|
||||
const downloaded = Buffer.concat(bufs);
|
||||
|
||||
/* parse downloaded buffer */
|
||||
const wb = read(downloaded);
|
||||
/* print first worksheet */
|
||||
console.log(utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
||||
```
|
||||
|
||||
15) Save the following codeblock to `SheetJSWriteToAzure.mjs`:
|
||||
|
||||
```js title="SheetJSWriteToAzure.mjs"
|
||||
import { BlobServiceClient } from "@azure/storage-blob";
|
||||
import { write, utils } from "xlsx";
|
||||
|
||||
/* replace these constants */
|
||||
// highlight-start
|
||||
const connStr = "<REPLACE WITH CONNECTION STRING>";
|
||||
const containerName = "<REPLACE WITH CONTAINER NAME>";
|
||||
// highlight-end
|
||||
|
||||
/* Blob name */
|
||||
const blobName = "SheetJSBloblobber.xlsx";
|
||||
|
||||
/* Create a simple workbook and write XLSX to buffer */
|
||||
const ws = utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
|
||||
const wb = utils.book_new(); utils.book_append_sheet(wb, ws, "Sheet1");
|
||||
const buf = write(wb, {type: "buffer", bookType: "xlsx"});
|
||||
|
||||
/* upload buffer */
|
||||
const blobServiceClient = BlobServiceClient.fromConnectionString(connStr);
|
||||
const containerClient = blobServiceClient.getContainerClient(containerName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
const uploadBlobResponse = await blockBlobClient.upload(buf, buf.length);
|
||||
```
|
||||
|
||||
16) Edit both `SheetJSReadFromAzure.mjs` and `SheetJSWriteToAzure.mjs`:
|
||||
|
||||
@ -616,7 +679,7 @@ the buffer to a file named `SheetJSBloblobber.xlsx` on Azure Blob Storage.
|
||||
|
||||
The read demo fetches `SheetJSBloblobber.xlsx` and displays the data.
|
||||
|
||||
```
|
||||
```text title="Data in SheetJSBloblobber.xlsx"
|
||||
| A | B | C | D | E | F | G |
|
||||
---+---|---|---|---|---|---|---|
|
||||
1 | S | h | e | e | t | J | S |
|
||||
@ -641,7 +704,7 @@ node SheetJSReadFromAzure.mjs
|
||||
|
||||
It will fetch the file created in the previous step and display CSV rows.
|
||||
|
||||
```
|
||||
```text title="Expected output"
|
||||
S,h,e,e,t,J,S
|
||||
5,4,3,3,7,9,5
|
||||
```
|
||||
|
||||
@ -8,7 +8,7 @@ pagination_next: demos/extensions/index
|
||||
import current from '/version.js';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[Deno Deploy](https://dash.deno.com/) offers distributed "Serverless Functions"
|
||||
[Deno Deploy](https://deno.com/deploy) offers distributed "Serverless Functions"
|
||||
powered by Deno.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
@ -22,7 +22,7 @@ types of spreadsheets to HTML tables and CSV rows.
|
||||
|
||||
:::caution pass
|
||||
|
||||
When the demo was last tested, Deno Deploy required a GitHub account.
|
||||
When the demo was last tested, Deno Deploy required a GitHub or Google account.
|
||||
|
||||
:::
|
||||
|
||||
@ -82,9 +82,9 @@ class SheetJSResource extends Drash.Resource {
|
||||
|
||||
## Demo
|
||||
|
||||
0) Create a new GitHub account or sign into an existing account.
|
||||
0) Create a new Github or Google account, or sign into an existing account.
|
||||
|
||||
1) Open the [main Deno Deploy portal](https://dash.deno.com/) in a browser.
|
||||
1) Open the [main Deno Deploy portal](https://console.deno.com/) in a browser.
|
||||
|
||||
2) If the account never signed into Deno Deploy, click "Continue with Github".
|
||||
|
||||
|
||||
@ -111,6 +111,7 @@ const jwt = new google.auth.JWT({
|
||||
key: creds.private_key,
|
||||
scopes: [
|
||||
'https://www.googleapis.com/auth/spreadsheets', // Google Sheets
|
||||
'https://www.googleapis.com/auth/drive', // Google Drive
|
||||
'https://www.googleapis.com/auth/drive.file', // Google Drive
|
||||
]
|
||||
});
|
||||
@ -495,7 +496,7 @@ At this point `wb` is a SheetJS workbook object[^10].
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024-06-08 using `googleapis` version `140.0.0`.
|
||||
This demo was last tested on 2025-05-14 using `googleapis` version `148.0.0`.
|
||||
The demo uses Sheets v4 and Drive v3 APIs.
|
||||
|
||||
:::
|
||||
@ -551,10 +552,10 @@ be a selection box. Click the `▼` icon to show the modal.
|
||||
|
||||
If the selection box is missing, expand the browser window.
|
||||
|
||||
3) Click "NEW PROJECT" in the top right corner of the modal.
|
||||
3) Click "New project" in the top right corner of the modal.
|
||||
|
||||
4) In the New Project screen, enter "SheetJS Test" in the Project name textbox
|
||||
and select "No organization" in the Location box. Click "CREATE".
|
||||
and select "No organization" in the Location box. Click "Create".
|
||||
|
||||
A notification will confirm that the project was created:
|
||||
|
||||
@ -569,14 +570,13 @@ The goal of this section is to enable Google Sheets API and Google Drive API.
|
||||
|
||||
:::
|
||||
|
||||
5) Open the Project Selector (`▼` icon) and select "SheetJS Test"
|
||||
5) Click "Select a project" and select "SheetJS Test" from the Recent tab.
|
||||
|
||||
6) In the search bar, type "Enabled" and select "Enabled APIs & services". This
|
||||
item will be in the "PRODUCTS & PAGES" part of the search results.
|
||||
6) In the search bar, type "Enabled" and select "Enabled APIs & services".
|
||||
|
||||
#### Enable Google Sheets API
|
||||
|
||||
7) Near the top of the page, click "+ ENABLE APIS AND SERVICES".
|
||||
7) Near the top of the page, click "+ Enable APIs and services".
|
||||
|
||||
8) In the search bar near the middle of the page (not the search bar at the top),
|
||||
type "Sheets" and press <kbd>Enter</kbd>.
|
||||
@ -585,11 +585,11 @@ In the results page, look for "Google Sheets API". Click the card
|
||||
|
||||
9) In the Product Details screen, click the blue "ENABLE" button.
|
||||
|
||||
10) Click the left arrow (`<-`) next to "API/Service details".
|
||||
10) Click the left arrow (`<-`) next to "API/Service Details".
|
||||
|
||||
#### Enable Google Drive API
|
||||
|
||||
11) Near the top of the page, click "+ ENABLE APIS AND SERVICES".
|
||||
11) Near the top of the page, click "+ Enable APIs and services".
|
||||
|
||||
12) In the search bar near the middle of the page (not the search bar at the top),
|
||||
type "Drive" and press <kbd>Enter</kbd>.
|
||||
@ -614,13 +614,13 @@ the top bar.
|
||||
15) Click the Project Selector (`:·` icon) and select "SheetJS Test".
|
||||
|
||||
16) In the search bar, type "Credentials" and select the "Credentials" item with
|
||||
subtitle "APIs & Services". This item will be in the "PRODUCTS & PAGES" group:
|
||||
subtitle "APIs & Services":
|
||||
|
||||

|
||||
|
||||
17) Click "+ CREATE CREDENTIALS". In the dropdown, select "Service Account"
|
||||
17) Click "+ Create credentials". In the dropdown, select "Service account"
|
||||
|
||||
18) Enter "SheetJService" for Service account name. Click "CREATE AND CONTINUE"
|
||||
18) Enter "SheetJService" for Service account name. Click "Create and continue".
|
||||
|
||||
:::note pass
|
||||
|
||||
@ -628,24 +628,24 @@ The Service account ID is generated automatically.
|
||||
|
||||
:::
|
||||
|
||||
19) In Step 2 "Grant this service account access to project", click CONTINUE
|
||||
19) In Step 2 "Grant this service account access to project", click Continue.
|
||||
|
||||
20) In Step 3 click "DONE". You will be taken back to the credentials screen
|
||||
20) In Step 3 click "Done". You will be taken back to the credentials screen
|
||||
|
||||
#### Create JSON Key
|
||||
|
||||
21) Look for "SheetJService" in the "Service Accounts" table and click the email
|
||||
address in the row.
|
||||
|
||||
22) Click "KEYS" in the horizontal bar near the top of the page.
|
||||
22) Click "Keys" in the horizontal bar near the top of the page.
|
||||
|
||||
23) Click "ADD KEY" and select "Create new key" in the dropdown.
|
||||
23) Click "Add key" and select "Create new key" in the dropdown.
|
||||
|
||||
24) In the popup, select the "JSON" radio button and click "CREATE".
|
||||
24) In the popup, select the "JSON" radio button and click "Create".
|
||||
|
||||
The page will download a JSON file. If prompted, allow the download.
|
||||
|
||||
25) Click "CLOSE"
|
||||
25) Click "Close"
|
||||
|
||||
### Create Document
|
||||
|
||||
@ -675,7 +675,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz googlea
|
||||
29) Download [`init.mjs`](pathname:///gsheet/init.mjs):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/gsheet/init.mjs
|
||||
curl -o init.mjs https://docs.sheetjs.com/gsheet/init.mjs
|
||||
```
|
||||
|
||||
Edit the marked lines near the top of the file:
|
||||
@ -713,11 +713,12 @@ Shared a-long-string-of-characters with YOUR_ACCOUNT@gmail.com
|
||||
The long string of characters after "Created Google Workbook" is the ID. Take
|
||||
note of this ID.
|
||||
|
||||
31) Sign into Google Sheets. A shared document "SheetJS Test" should be
|
||||
displayed in the table. It will be owned by the service account.
|
||||
31) Sign into Google Drive and select "Shared with me" from the left sidebar. A
|
||||
shared document "SheetJS Test" should be displayed in the table. It will be
|
||||
owned by the service account.
|
||||
|
||||
32) Open the shared document from step 31 and confirm that the document has two
|
||||
worksheets named "SheetJS1" and "SheetJS2".
|
||||
32) Click `⋮` next to "SheetJS Test" and select "Open with" > "Google Sheets".
|
||||
Confirm that the document has two worksheets named "SheetJS1" and "SheetJS2".
|
||||
|
||||
Confirm the worksheet data matches the following screenshots:
|
||||
|
||||
@ -786,13 +787,13 @@ NUMBERS file.
|
||||
34) Download the [test file `pres.numbers`](https://docs.sheetjs.com/pres.numbers):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/pres.numbers
|
||||
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
|
||||
```
|
||||
|
||||
35) Download [`load.mjs`](pathname:///gsheet/load.mjs):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/gsheet/load.mjs
|
||||
curl -o load.mjs https://docs.sheetjs.com/gsheet/load.mjs
|
||||
```
|
||||
|
||||
Edit the marked lines near the top of the file:
|
||||
@ -830,7 +831,7 @@ The goal of this section is to export the raw data from Google Sheets to XLSB.
|
||||
38) Download [`dump.mjs`](pathname:///gsheet/dump.mjs):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/gsheet/dump.mjs
|
||||
curl -o dump.mjs https://docs.sheetjs.com/gsheet/dump.mjs
|
||||
```
|
||||
|
||||
Edit the marked lines near the top of the file:
|
||||
@ -876,7 +877,7 @@ assign a grid of values
|
||||
43) Download [`raw.mjs`](pathname:///gsheet/raw.mjs):
|
||||
|
||||
```bash
|
||||
curl -LO https://docs.sheetjs.com/gsheet/raw.mjs
|
||||
curl -o raw.mjs https://docs.sheetjs.com/gsheet/raw.mjs
|
||||
```
|
||||
|
||||
Edit the marked lines near the top of the file:
|
||||
|
||||
@ -207,7 +207,7 @@ const wb = XLSX.readFile("SheetJSAirtableTest.xlsb");
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2025-04-21. In the most recent test, free accounts
|
||||
This demo was last tested on 2026-03-15. In the most recent test, free accounts
|
||||
included limited API access.
|
||||
|
||||
:::
|
||||
|
||||
@ -266,7 +266,7 @@ function SheetJSEnregistrez() {
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was last tested on 2024-05-27.
|
||||
This demo was last tested on 2025-05-14.
|
||||
|
||||
:::
|
||||
|
||||
|
||||
@ -23,9 +23,10 @@ tables with a content script and a background script.
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Platform | Date |
|
||||
|:-------------|:-----------|
|
||||
| Chromium 131 | 2025-01-02 |
|
||||
| Platform | Version | Date |
|
||||
|:-------------|:--------|:-----------|
|
||||
| Chromium 140 | V3 | 2025-09-13 |
|
||||
| Chromium 137 | V2 | 2025-09-13 |
|
||||
|
||||
:::
|
||||
|
||||
@ -33,8 +34,7 @@ This demo was tested in the following deployments:
|
||||
|
||||
This demo showcases Manifest V2 and Manifest V3 extensions.
|
||||
|
||||
Chrome Web Store will not accept new V2 extensions, but these can be sideloaded
|
||||
using the "Load unpacked" extension option in Developer mode.
|
||||
Chrome 138 and later no longer support Manifest V2 extensions.
|
||||
|
||||
**New Chrome and Chromium Extensions should use Manifest V3!**
|
||||
|
||||
|
||||
@ -40,8 +40,8 @@ This demo was tested in the following deployments:
|
||||
| OS and Version | Architecture | Excel | Date |
|
||||
|:---------------|:-------------|:-----------|:-----------|
|
||||
| macOS 15.3 | `darwin-x64` | 16.95.4 | 2025-04-17 |
|
||||
| macOS 14.5 | `darwin-arm` | 16.96.1 | 2025-04-24 |
|
||||
| Windows 11 | `win11-x64` | 365 (2501) | 2025-01-19 |
|
||||
| macOS 14.5 | `darwin-arm` | 16.106.3 | 2026-05-05 |
|
||||
| Windows 11 | `win11-x64` | 365 (2604) | 2026-06-05 |
|
||||
| Windows 11 | `win11-arm` | 365 (2503) | 2025-04-24 |
|
||||
|
||||
:::
|
||||
@ -129,12 +129,24 @@ export async function extern(url) {
|
||||
|
||||
## Complete Demo
|
||||
|
||||
0) Clear the functions cache. For the tested version of Excel for Windows:
|
||||
0) Clear the functions cache.
|
||||
|
||||
For the tested version of Excel for Windows:
|
||||
|
||||
- Open File Explorer
|
||||
- Select the address bar and enter `%LOCALAPPDATA%\Microsoft\Office\16.0\Wef`
|
||||
- Delete the `CustomFunctions` folder (if it exists) and empty Recycle Bin.
|
||||
|
||||
For the tested version of Excel for Mac:
|
||||
|
||||
- Open the Terminal app
|
||||
- Run the following command to open the `Wef` folder:
|
||||
|
||||
```bash
|
||||
open ~/Library/Containers/com.microsoft.Excel/Data/Library/Application\ Support/Microsoft/Office/16.0/Wef
|
||||
```
|
||||
- Delete the `CustomFunctions` folder (if it exists) and empty Trash.
|
||||
|
||||
:::caution pass
|
||||
|
||||
**This will delete all custom functions associated with the user account!**
|
||||
@ -241,6 +253,19 @@ npm run stop
|
||||
npm start
|
||||
```
|
||||
|
||||
:::note pass
|
||||
|
||||
In some test runs, the stop command failed with an error:
|
||||
|
||||
```
|
||||
Debugging is being stopped...
|
||||
Unable to kill process id 69420: Error: kill ESRCH
|
||||
```
|
||||
|
||||
The error can be ignored.
|
||||
|
||||
:::
|
||||
|
||||
### Integrating the SheetJS Library
|
||||
|
||||
10) Install the SheetJS library in the project:
|
||||
@ -299,12 +324,48 @@ npm run stop
|
||||
npm start
|
||||
```
|
||||
|
||||
4) Activate the Task Pane for the addin (click "Show Task Pane" in the ribbon).
|
||||
4) Activate the Task Pane for the addin (click "Show Task Pane" in the ribbon).
|
||||
|
||||
5) Hover near the top-right corner of the addin and click the `i` icon.
|
||||
|
||||
6) Click "Clear Web Cache" and wait a few moments.
|
||||
|
||||
---
|
||||
|
||||
If the previous steps fail, the `CustomFunctions` folders should be wiped:
|
||||
|
||||
7) Stop the development process:
|
||||
|
||||
```bash
|
||||
npm run stop
|
||||
```
|
||||
|
||||
8) Close the Excel app by right-clicking Excel in the Dock and selecting "Quit".
|
||||
|
||||
9) Stop the development process one more time:
|
||||
|
||||
```bash
|
||||
npm run stop
|
||||
```
|
||||
|
||||
10) Kill any errant `webpack` processes:
|
||||
|
||||
```bash
|
||||
pkill webpack
|
||||
```
|
||||
|
||||
11) Remove the `CustomFunctions` folder:
|
||||
|
||||
```bash
|
||||
rm -rf ~/Library/Containers/com.microsoft.Excel/Data/Library/Application\ Support/Microsoft/Office/16.0/Wef/CustomFunctions
|
||||
```
|
||||
|
||||
12) Restart the development process:
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
### Fetching Files from the Internet
|
||||
|
||||
@ -37,9 +37,9 @@ remote file, parses the contents, and writes data to the sheet:
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Clasp | Date |
|
||||
|:--------|:-----------|
|
||||
| `2.4.2` | 2024-12-31 |
|
||||
| Clasp | Date |
|
||||
|:--------------|:-----------|
|
||||
| `3.0.4-alpha` | 2025-05-21 |
|
||||
|
||||
:::
|
||||
|
||||
@ -112,7 +112,7 @@ the result of setting cell `A1` to the formula `=AOA()`:
|
||||
```js
|
||||
function AOA(url) {
|
||||
return [
|
||||
["Sheet", "JS"],
|
||||
["Sheet", "JS"],
|
||||
[ 72, 62]
|
||||
];
|
||||
}
|
||||
@ -153,6 +153,10 @@ The next page will include the following title:
|
||||
|
||||
3) At the bottom of the screen, click "Continue".
|
||||
|
||||
The next page will include the following title:
|
||||
|
||||
> clasp – The Apps Script CLI wants access to your Google Account
|
||||
|
||||
4) In the next screen, check every box that mentions "Google Apps Script". When
|
||||
the demo was last tested, the following were required:
|
||||
|
||||
@ -183,7 +187,8 @@ Authorization successful.
|
||||
|
||||

|
||||
|
||||
9) Click the gear icon (Project Settings) and copy the Script ID
|
||||
9) Click the gear icon (Project Settings) in the left sidebar. Scroll down to
|
||||
the "IDs" section and copy the Script ID.
|
||||
|
||||
### Cloning the Apps Script
|
||||
|
||||
|
||||
420
docz/docs/03-demos/32-extensions/05-vscode.md
Normal file
420
docz/docs/03-demos/32-extensions/05-vscode.md
Normal file
@ -0,0 +1,420 @@
|
||||
---
|
||||
title: Visualizing Data in VS Code
|
||||
sidebar_label: Visual Studio Code
|
||||
description: View Excel files directly in VS Code. Seamlessly browse spreadsheet data using SheetJS. Navigate between worksheets and pages of data with a responsive interface.
|
||||
pagination_prev: demos/cloud/index
|
||||
pagination_next: demos/bigdata/index
|
||||
sidebar_custom_props:
|
||||
summary: View Excel spreadsheets directly within Visual Studio Code
|
||||
---
|
||||
|
||||
import current from '/version.js';
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from '@theme/CodeBlock';
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
[Visual Studio Code](https://code.visualstudio.com) is a popular code editor
|
||||
that supports JavaScript extensions for customizing and enhancing functionality.
|
||||
|
||||
The ["Complete Example"](#complete-example) uses SheetJS in a VS Code extension
|
||||
to view Excel files directly within the editor. The extension leverages the VS
|
||||
Code "WebView API"[^1] and "Custom Editor API"[^2] to display spreadsheet data
|
||||
as HTML tables.
|
||||
|
||||
:::tip pass
|
||||
|
||||
"SheetJS Spreadsheet Viewer" is a sample extension based on this demo. It is
|
||||
available on [Open VSX](https://open-vsx.org/extension/asadbek/sheetjs-demo) and
|
||||
[VSCode Marketplace](https://marketplace.visualstudio.com/items?itemName=asadbek.sheetjs-demo)
|
||||
|
||||
[The source code](https://git.sheetjs.com/asadbek064/sheetjs-vscode-extension)
|
||||
is available on the SheetJS Git server. Feedback and contributions are welcome!
|
||||
|
||||
:::
|
||||
|
||||

|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Platform | Architecture | Date |
|
||||
|:--------------------------------------------------|:-------------|:-----------|
|
||||
| [VSCodium 1.109.51242](https://vscodium.com/) | `darwin-arm` | 2026-03-05 |
|
||||
| [VS Code 1.110.0](https://code.visualstudio.com/) | `win11-arm` | 2026-03-05 |
|
||||
| [Antigravity 1.19.6](https://antigravity.google/) | `linux-arm` | 2026-03-05 |
|
||||
|
||||
:::
|
||||
|
||||
:::danger Telemetry and Data Exfiltration
|
||||
|
||||
VSCode and many forks embed telemetry and send code to third-party servers.
|
||||
|
||||
For example, Antigravity includes AI features that are powered by Google Gemini
|
||||
and other cloud AI services. These features necessitate code exfiltration.
|
||||
|
||||
**[VSCodium](https://vscodium.com/) does not include AI features or telemetry!**
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
|
||||
imported from any script in the extension.
|
||||
|
||||
:::caution pass
|
||||
|
||||
The SheetJS NodeJS module must be installed as a development dependency. If the
|
||||
module is installed as a normal dependency, the `vsce`[^3] command-line tool
|
||||
will fail to package or publish the extension.
|
||||
|
||||
<Tabs groupId="pm">
|
||||
<TabItem value="npm" label="npm">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
npm rm --save xlsx
|
||||
npm i --save-dev https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="pnpm" label="pnpm">
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
pnpm rm xlsx
|
||||
pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="yarn" label="Yarn" default>
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
yarn remove xlsx
|
||||
yarn add -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
|
||||
</CodeBlock>
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
:::
|
||||
|
||||
The core extension APIs are available in the `vscode` package. A TypeScript
|
||||
extension typically uses "glob imports" to load SheetJS and VSCode features:
|
||||
|
||||
```ts title="Importing SheetJS and VSCode features"
|
||||
import * as vscode from 'vscode';
|
||||
import * as XLSX from 'xlsx';
|
||||
```
|
||||
|
||||
## Extension Architecture
|
||||
|
||||
VSCode Extensions for processing custom file types use the Custom Editor API[^2]
|
||||
for lifecycle events. This involves a number of moving parts:
|
||||
|
||||
1) "Custom Document" for managing file metadata
|
||||
|
||||
2) "Custom Editor Provider" for processing file data and generating previews
|
||||
|
||||
3) Registration during extension lifecycle events.
|
||||
|
||||
4) Advertisement of filetype support in extension metadata.
|
||||
|
||||
When a spreadsheet is opened, the extension will use SheetJS methods to parse
|
||||
the raw file and display the data in a HTML table.
|
||||
|
||||
### Custom Documents
|
||||
|
||||
Extensions must provide a class that implements `vscode.CustomDocument`[^4].
|
||||
|
||||
```ts title="Simple CustomDocument"
|
||||
class ExcelDocument implements vscode.CustomDocument {
|
||||
constructor(public readonly uri: vscode.Uri) { }
|
||||
dispose() { }
|
||||
}
|
||||
```
|
||||
|
||||
### Editor Provider
|
||||
|
||||
Extensions that read data should implement `vscode.CustomReadonlyEditorProvider`
|
||||
with a generic parameter for the custom document type.
|
||||
|
||||
The `openCustomDocument` method takes a `vscode.Uri` and is expected to return a
|
||||
new document:
|
||||
|
||||
```ts title="src/extension.ts (snippet)"
|
||||
class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<ExcelDocument> {
|
||||
async openCustomDocument(uri: vscode.Uri): Promise<ExcelDocument> {
|
||||
return new ExcelDocument(uri);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Reading Files
|
||||
|
||||
The `FileSystemProvider` API[^5], available at `vscode.workspace.fs`, exposes
|
||||
common filesystem operations including reading raw data from files and watching
|
||||
for changes.
|
||||
|
||||
The `resolveCustomEditor`[^6] method of the `CustomEditorProvider` will be
|
||||
called when a file is opened. The first argument is a `CustomDocument` whose
|
||||
`uri` property points to the location of the file.
|
||||
|
||||
`vscode.workspace.fs.readFile`[^5] returns a promise that resolves to a
|
||||
`Uint8Array` containing the raw binary data. This `Uint8Array` can be passed to
|
||||
the SheetJS [`read`](/docs/api/parse-options) method:
|
||||
|
||||
```ts title="src/extension.ts (snippet)"
|
||||
export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<ExcelDocument> {
|
||||
// ...
|
||||
async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<void> {
|
||||
// read the raw bytes from the file
|
||||
const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri);
|
||||
|
||||
// parse the file data
|
||||
const wb: XLSX.WorkBook = XLSX.read(data);
|
||||
|
||||
// At this point, `wb` is a SheetJS Workbook Object
|
||||
// ...
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Previewing Data
|
||||
|
||||
The `resolveCustomEditor`[^6] method of the `CustomEditorProvider` will be
|
||||
called when a file is opened. The second argument is a `WebviewPanel`[^7].
|
||||
|
||||
The `webview.html` nested property of the `WebviewPanel` controls the displayed
|
||||
HTML. Extensions can use SheetJS [API methods](/docs/api/).
|
||||
|
||||
The SheetJS [`sheet_to_html`](/docs/api/utilities/html#html-table-output) method
|
||||
generates a simple HTML table. The following snippet displays the data of the
|
||||
first worksheet:
|
||||
|
||||
```ts title="src/extension.ts (snippet)"
|
||||
export class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<ExcelDocument> {
|
||||
// ...
|
||||
async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<void> {
|
||||
// ...
|
||||
// continuing from "Reading Files", `wb` is a SheetJS Workbook Object
|
||||
const first_sheet = wb.Sheets[wb.SheetNames[0]];
|
||||
webviewPanel.webview.html = XLSX.utils.sheet_to_html(first_sheet);
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
### Registration
|
||||
|
||||
The exported `activate` method registers the editor provider. The first argument
|
||||
to `registerCustomEditorProvider` is expected to be a unique name that will be
|
||||
referenced later.
|
||||
|
||||
```ts title="src/extension.ts (snippet)"
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
const provider = vscode.window.registerCustomEditorProvider(
|
||||
'excelViewer.spreadsheet',
|
||||
new ExcelEditorProvider(),
|
||||
{ webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden
|
||||
);
|
||||
context.subscriptions.push(provider);
|
||||
}
|
||||
```
|
||||
|
||||
### Filetype Support
|
||||
|
||||
Extensions must announce custom editor file type support in `package.json`.
|
||||
The `selector` property[^8] is expected to include "Glob Pattterns"[^9].
|
||||
|
||||
The demo uses the following `package.json` snippet to announce support for `xls`
|
||||
and `xlsx` spreadsheets:
|
||||
|
||||
```json title="package.json (snippet)"
|
||||
"contributes": {
|
||||
"customEditors": [
|
||||
{
|
||||
// ... other properties including displayName
|
||||
// highlight-start
|
||||
// The viewType must match the first argument of `registerCustomEditorProvider`
|
||||
"viewType": "excelViewer.spreadsheet",
|
||||
"selector": [
|
||||
{ "filenamePattern": "*.xlsx" },
|
||||
{ "filenamePattern": "*.xls" }
|
||||
]
|
||||
// highlight-end
|
||||
}
|
||||
],
|
||||
// ...
|
||||
},
|
||||
```
|
||||
|
||||
### Usage Flow
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
actor User
|
||||
participant VSCode as VS Code
|
||||
participant Provider as ExcelEditorProvider
|
||||
participant SheetJS
|
||||
participant WebView
|
||||
|
||||
User->>VSCode: Open .xlsx file
|
||||
VSCode->>Provider: openCustomDocument(uri)
|
||||
Provider-->>VSCode: return ExcelDocument
|
||||
VSCode->>Provider: resolveCustomEditor(document, webviewPanel)
|
||||
Provider->>VSCode: workspace.fs.readFile(document.uri)
|
||||
VSCode-->>Provider: return file data
|
||||
Provider->>SheetJS: XLSX.read(data, options)
|
||||
SheetJS-->>Provider: return workbook
|
||||
Provider->>SheetJS: XLSX.utils.sheet_to_html(sheet)
|
||||
SheetJS-->>Provider: return HTML
|
||||
Provider->>WebView: set webview.html
|
||||
WebView-->>User: Display Excel data
|
||||
```
|
||||
|
||||
## Complete Example
|
||||
|
||||
:::caution pass
|
||||
|
||||
To avoid conflicts with existing extensions, it is strongly recommended to test
|
||||
with a different VSCode fork. For example, VSCode and Antigravity users should
|
||||
install and use VSCodium for extension development.
|
||||
|
||||
:::
|
||||
|
||||
1) Download the [`pres.xlsx`](https://docs.sheetjs.com/pres.xlsx) sample file.
|
||||
|
||||
2) Create a new VS Code extension
|
||||
|
||||
```bash
|
||||
npx --package yo --package generator-code -- yo code
|
||||
```
|
||||
|
||||
When prompted, enter the following options:
|
||||
|
||||
- `What type of extension do you want to create?`: Select `New Extension (TypeScript)` and press <kbd>Enter</kbd>
|
||||
- `What's the name of your extension?`: Type `sheetjs-demo` and press <kbd>Enter</kbd>
|
||||
- `What's the identifier of your extension?`: Press <kbd>Enter</kbd> (use the default `sheetjs-demo`)
|
||||
- `What's the description of your extension?`: Press <kbd>Enter</kbd> (leave blank)
|
||||
- `Initialize a git repository?`: Type `n` and press <kbd>Enter</kbd>
|
||||
- `Which bundler to use?`: Select `webpack` and press <kbd>Enter</kbd>
|
||||
- `Which package manager to use?`: Select `pnpm` and press <kbd>Enter</kbd>
|
||||
|
||||

|
||||
|
||||
3) Install the SheetJS library and start the dev server:
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
cd sheetjs-demo
|
||||
pnpm install -D https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
|
||||
pnpm run watch
|
||||
`}
|
||||
</CodeBlock>
|
||||
|
||||
4) Launch a new window with the VSCode fork and open the `sheetjs-demo` folder.
|
||||
|
||||
5) Save the following codeblock to `src/extension.ts`:
|
||||
|
||||
```ts title="src/extension.ts (replace contents)"
|
||||
import * as vscode from 'vscode';
|
||||
import * as XLSX from 'xlsx';
|
||||
|
||||
class ExcelDocument implements vscode.CustomDocument {
|
||||
constructor(public readonly uri: vscode.Uri) { }
|
||||
dispose() { }
|
||||
}
|
||||
|
||||
class ExcelEditorProvider implements vscode.CustomReadonlyEditorProvider<ExcelDocument> {
|
||||
// This is called when the first time an editor for a given resource is opened
|
||||
async openCustomDocument(uri: vscode.Uri): Promise<ExcelDocument> {
|
||||
return new ExcelDocument(uri);
|
||||
}
|
||||
|
||||
// This is called whenever the user opens a new editor
|
||||
async resolveCustomEditor(document: ExcelDocument, webviewPanel: vscode.WebviewPanel): Promise<void> {
|
||||
const data: Uint8Array = await vscode.workspace.fs.readFile(document.uri);
|
||||
|
||||
const options: XLSX.ParsingOptions = { cellStyles: true, cellDates: true };
|
||||
const wb: XLSX.WorkBook = XLSX.read(data, options);
|
||||
|
||||
const first_sheet = wb.Sheets[wb.SheetNames[0]];
|
||||
webviewPanel.webview.html = XLSX.utils.sheet_to_html(first_sheet);
|
||||
}
|
||||
}
|
||||
|
||||
export function activate(context: vscode.ExtensionContext) {
|
||||
const provider = vscode.window.registerCustomEditorProvider(
|
||||
'excelViewer.spreadsheet',
|
||||
new ExcelEditorProvider(),
|
||||
{ webviewOptions: { retainContextWhenHidden: true } } // keep webview state when hidden
|
||||
);
|
||||
context.subscriptions.push(provider);
|
||||
}
|
||||
export function deactivate() {}
|
||||
```
|
||||
|
||||
6) Add the highlighted lines to the `contributes` section of `package.json`:
|
||||
|
||||
```json title="package.json (add highlighted lines)"
|
||||
"contributes": {
|
||||
// highlight-start
|
||||
"customEditors": [
|
||||
{
|
||||
"viewType": "excelViewer.spreadsheet",
|
||||
"displayName": "SheetJS Demo",
|
||||
"selector": [
|
||||
{ "filenamePattern": "*.xlsx" },
|
||||
{ "filenamePattern": "*.xls" }
|
||||
]
|
||||
}
|
||||
],
|
||||
// highlight-end
|
||||
"commands": [
|
||||
{
|
||||
"command": "sheetjs-demo.helloWorld",
|
||||
"title": "Hello World"
|
||||
}
|
||||
]
|
||||
},
|
||||
```
|
||||
|
||||
7) In the editor, open the Command Palette (Help > "Show All Commands" from the
|
||||
menu), type `Debug: Start` and select `Debug: Start Debugging`.
|
||||
|
||||
This will compile and run the extension in a new Extension Development Host window.
|
||||
|
||||
8) Drag and drop the `pres.xlsx` test file into the new window. If drag and drop
|
||||
is not available, click "Open..." in the Welcome screen and select the file.
|
||||
|
||||
A new `pres.xlsx` tab will show the contents of the file.
|
||||
|
||||
:::info pass
|
||||
|
||||
When this demo was last tested, the default project assumed VSCode version
|
||||
1.109.0 or later. Antigravity 1.19.6 is aligned to VSCode 1.107.0. The default
|
||||
extension will not run in Antigravity.
|
||||
|
||||
This can be fixed by changing the `vscode` field in `package.json`. When this
|
||||
demo was last tested, it was safe to set a minimum version of `^1.100.0`:
|
||||
|
||||
```json title="package.json (change highlighted line)"
|
||||
"engines": {
|
||||
// highlight-next-line
|
||||
"vscode": "^1.100.0"
|
||||
}
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
[^1]: See [`Webview API`](https://code.visualstudio.com/api/extension-guides/webview) in the VSCode documentation for more details.
|
||||
[^2]: See [`Custom Editor API`](https://code.visualstudio.com/api/extension-guides/custom-editors) in the VSCode documentation for more details.
|
||||
[^3]: See [`vsce`](https://code.visualstudio.com/api/working-with-extensions/publishing-extension#vsce) in the VSCode documentation for more details.
|
||||
[^4]: See [`CustomDocument`](https://code.visualstudio.com/api/references/vscode-api#CustomDocument) in the VSCode API documentation for more details.
|
||||
[^5]: See [`FileSystemProvider`](https://code.visualstudio.com/api/references/vscode-api#FileSystemProvider) in the VSCode API documentation for more details.
|
||||
[^6]: See [`CustomEditorProvider<T>`](https://code.visualstudio.com/api/references/vscode-api#CustomEditorProvider<T>) in the VSCode API documentation for more details.
|
||||
[^7]: See [`WebviewPanel`](https://code.visualstudio.com/api/references/vscode-api#WebviewPanel) in the VSCode API documentation for more details.
|
||||
[^8]: See [`contributes.customEditors`](https://code.visualstudio.com/api/references/contribution-points#contributes.customEditors) in the VSCode API documentation for more details.
|
||||
[^9]: See ["Glob Patterns Reference"](https://code.visualstudio.com/docs/editor/glob-patterns) in the VSCode documentation for more details.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user