Skip to content

Commit b9f70b0

Browse files
committed
feat: publish xlsx import export as separate wasm
1 parent 4905f60 commit b9f70b0

File tree

15 files changed

+234
-292
lines changed

15 files changed

+234
-292
lines changed

.github/workflows/rust-build-test.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ jobs:
1818

1919
- name: Install wasm-pack
2020
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
21+
22+
- name: Install wasm-bindgen-cli
23+
run: cargo install -f wasm-bindgen-cli --version 0.2.100
24+
25+
- name: Add wasm32 target
26+
run: rustup target add wasm32-unknown-unknown
2127

2228
- name: Build
2329
run: cargo build --release --verbose

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
target/*
22
**/node_modules/**
33
.DS_Store
4+
bindings/wasm/pkg/

Cargo.lock

Lines changed: 23 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
.PHONY: lint
22
lint:
33
cargo fmt -- --check
4-
cargo clippy --all-targets --all-features -- -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic -D warnings
4+
cargo clippy --workspace --exclude wasm --all-targets --all-features -- -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic -D warnings
5+
cd bindings/wasm/ && cargo clippy --target wasm32-unknown-unknown -- -W clippy::unwrap_used -W clippy::expect_used -W clippy::panic -D warnings
56
cd webapp/IronCalc/ && npm install && npm run check
67
cd webapp/app.ironcalc.com/frontend/ && npm install && npm run check
78

@@ -15,7 +16,12 @@ tests: lint
1516
make remove-artifacts
1617
# Regretabbly we need to build the wasm twice, once for the nodejs tests
1718
# and a second one for the vitest.
18-
cd bindings/wasm/ && wasm-pack build --target nodejs && node tests/test.mjs && make
19+
cd bindings/wasm/ && \
20+
wasm-pack build --target nodejs --out-name ironcalc && \
21+
cargo build --release --target wasm32-unknown-unknown --bin xlsx_wasm && \
22+
wasm-bindgen --target nodejs --typescript --out-dir pkg --out-name xlsx ../../target/wasm32-unknown-unknown/release/xlsx_wasm.wasm && \
23+
node tests/test.mjs && \
24+
make
1925
cd webapp/IronCalc/ && npm run test
2026
cd bindings/python && ./run_tests.sh && ./run_examples.sh
2127

bindings/wasm/Cargo.toml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,19 @@ repository = "https://github.com/ironcalc/ironcalc"
88
edition = "2021"
99

1010
[lib]
11+
name = "ironcalc_wasm"
1112
crate-type = ["cdylib"]
1213

14+
[[bin]]
15+
name = "xlsx_wasm"
16+
path = "src/xlsx.rs"
17+
1318
[dependencies]
14-
# Uses `../ironcalc/base` when used locally, and uses
15-
# the inicated version from crates.io when published.
16-
# https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#multiple-locations
1719
ironcalc = { path = "../../xlsx", version = "0.5.0" }
1820
ironcalc_base = { path = "../../base", version = "0.5", features = ["use_regex_lite"] }
1921
serde = { version = "1.0", features = ["derive"] }
20-
wasm-bindgen = "0.2.92"
21-
serde-wasm-bindgen = "0.4"
22+
wasm-bindgen = "0.2.100"
23+
serde-wasm-bindgen = "0.6"
2224

2325
[dev-dependencies]
24-
wasm-bindgen-test = "0.3.38"
26+
wasm-bindgen-test = "0.3.38"

bindings/wasm/Makefile

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
# ---------------------------------------------------------------------------
2+
# Build strategy
3+
# ---------------------------------------------------------------------------
4+
# We need two separate WASM bundles in the same NPM package:
5+
# 1) Core engine → @ironcalc/wasm (small, always shipped)
6+
# 2) XLSX helpers → @ironcalc/wasm/xlsx (large, optional)
7+
#
8+
# The natural way would be two wasm-pack invocations – one default lib and one
9+
# wasm-pack build --bin xlsx_wasm …
10+
# Unfortunately, on the stable Rust tool-chain wasm-pack's `--bin` flag relies
11+
# on Cargo's unstable `--out-dir`/`--artifact-dir` feature and therefore fails.
12+
#
13+
# Until that becomes stable (or we switch to a nightly tool-chain), we compile
14+
# the second binary with plain `cargo build` and then run `wasm-bindgen`
15+
# ourselves. As soon as the flag is stabilised we can collapse back to the
16+
# two simple wasm-pack commands shown above and delete the hand-rolled steps.
17+
# ---------------------------------------------------------------------------
118
# In some platforms, python is called python3
219
PYTHON := $(shell command -v python 2>/dev/null || command -v python3 2>/dev/null)
320

@@ -6,15 +23,35 @@ ifeq ($(PYTHON),)
623
$(error No python found. Please install python.)
724
endif
825

26+
TEMP_DIR := pkg_xlsx
27+
928
all:
10-
wasm-pack build --target web --scope ironcalc --release
29+
wasm-pack build --target web --scope ironcalc --out-dir pkg --out-name ironcalc --release
30+
31+
# Build XLSX helper separately (cargo + wasm-bindgen)
32+
cargo build --release --target wasm32-unknown-unknown --bin xlsx_wasm
33+
wasm-bindgen --target web --typescript --out-dir $(TEMP_DIR) --out-name xlsx ../../target/wasm32-unknown-unknown/release/xlsx_wasm.wasm
34+
35+
# Move generated files into main pkg directory
36+
mv $(TEMP_DIR)/xlsx_bg.wasm pkg/xlsx_bg.wasm
37+
mv $(TEMP_DIR)/xlsx.js pkg/xlsx.js
38+
mv $(TEMP_DIR)/xlsx.d.ts pkg/xlsx.d.ts
39+
1140
cp README.pkg.md pkg/README.md
1241
npx tsc types.ts --target esnext --module esnext
1342
$(PYTHON) fix_types.py
1443
rm -f types.js
44+
rm -rf $(TEMP_DIR)
1545

1646
tests:
17-
wasm-pack build --target nodejs && node tests/test.mjs
47+
wasm-pack build --target nodejs --out-dir pkg --out-name ironcalc
48+
cargo build --release --target wasm32-unknown-unknown --bin xlsx_wasm
49+
wasm-bindgen --target nodejs --typescript --out-dir $(TEMP_DIR) --out-name xlsx ../../target/wasm32-unknown-unknown/release/xlsx_wasm.wasm
50+
mv $(TEMP_DIR)/xlsx_bg.wasm pkg/xlsx_bg.wasm || true
51+
mv $(TEMP_DIR)/xlsx.js pkg/xlsx.js || true
52+
mv $(TEMP_DIR)/xlsx.d.ts pkg/xlsx.d.ts || true
53+
rm -rf $(TEMP_DIR)
54+
node tests/test.mjs
1855

1956
lint:
2057
cargo check

bindings/wasm/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# IronCalc Web bindings
22

3-
This package contains web bindings for IronCalc. It exposes the engine and helper functions to import or export workbooks as XLSX or IronCalc (icalc) byte arrays. The built-in XLSX support focuses on core spreadsheet features like cell values, formulas, and styling.
3+
This crate is used to build the web bindings for IronCalc.
4+
Note that it does not contain the xlsx writer and reader, only the engine.
45

56
https://www.npmjs.com/package/@ironcalc/wasm?activeTab=readme
67

bindings/wasm/README.pkg.md

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# IronCalc Web bindings
22

3-
This package contains web bindings for IronCalc. It exposes the engine and helper functions to import or export workbooks as XLSX or IronCalc (icalc) byte arrays. The built-in XLSX support focuses on core spreadsheet features like cell values, formulas, and styling.
4-
3+
This crate is used to build the web bindings for IronCalc.
54

65
## Usage
76

@@ -15,8 +14,11 @@ And then in your TypeScript
1514

1615
```TypeScript
1716
import init, { Model } from "@ironcalc/wasm";
17+
import initXLSX, { toXLSXBytes, fromXLSXBytes } from "@ironcalc/wasm/xlsx";
18+
1819

1920
await init();
21+
await initXLSX();
2022

2123
function compute() {
2224
const model = new Model('en', 'UTC');
@@ -30,23 +32,15 @@ function compute() {
3032
}
3133

3234
compute();
33-
```
34-
35-
### Importing and exporting bytes
36-
37-
The `Model` class provides helpers to load or save workbooks as raw byte arrays.
3835

39-
```ts
4036
// create a new workbook and export as XLSX bytes
4137
const model = new Model('Workbook1', 'en', 'UTC');
4238
model.setUserInput(0, 1, 1, '42');
43-
const xlsxBytes = model.saveToXlsx();
39+
const xlsxBytes = toXLSXBytes(model.toBytes());
4440

4541
// load from those bytes
46-
const roundTripped = Model.fromXlsxBytes(xlsxBytes, 'Workbook1', 'en', 'UTC');
42+
const roundTrippedBytes = fromXLSXBytes(xlsxBytes, 'Workbook1', 'en', 'UTC');
43+
const roundTripped = Model.fromBytes(roundTrippedBytes);
4744

48-
// same helpers exist for IronCalc's internal format
49-
const icalcBytes = model.saveToIcalc();
50-
const restored = Model.fromIcalcBytes(icalcBytes);
5145
```
5246

0 commit comments

Comments
 (0)