Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions .docker/sdkjs.bake.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ ARG BUILD_ROOT
#### BASE ####
FROM ubuntu:24.04 AS web-base
RUN apt-get update && \
apt-get install -y ca-certificates curl gnupg openjdk-21-jdk wget zip brotli bzip2 && \
apt-get install -y ca-certificates curl gnupg wget zip brotli bzip2 && \
curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y nodejs && \
npm install -g @yao-pkg/pkg grunt-cli && \
npm install -g @yao-pkg/pkg && \
rm -rf /var/lib/apt/lists/*

#### SDKJS ####
Expand All @@ -26,11 +26,11 @@ FROM web-base AS sdkjs-base

ARG PRODUCT_VERSION

COPY sdkjs/build/package*.json /app/build/
COPY sdkjs/build/package*.json sdkjs/build/npm-shrinkwrap.json /app/build/

RUN --mount=type=cache,target=/root/.npm \
cd app/build && \
npm install
npm ci

COPY sdkjs/ /app
COPY sdkjs-forms/ /sdkjs-forms
Expand All @@ -47,11 +47,12 @@ FROM web-base AS sdkjs-base
COPY --from=core-wasm ${BUILD_ROOT}/libfont/ /app/common/libfont/

FROM sdkjs-base AS sdkjs-desktop
ARG TARGETARCH
ENV SDK_ADDONS=/sdkjs-forms
ENV SDK_PLATFORM=desktop
RUN cd app/build && \
CC_PLATFORM=$(if [ "$TARGETARCH" = "arm64" ]; then echo "java"; else echo "native,java"; fi) grunt --addon=sdkjs-forms --desktop=true
npm run build

FROM sdkjs-base AS sdkjs
ARG TARGETARCH
ENV SDK_ADDONS=/sdkjs-forms
RUN cd app/build && \
CC_PLATFORM=$(if [ "$TARGETARCH" = "arm64" ]; then echo "java"; else echo "native,java"; fi) grunt --addon=sdkjs-forms
npm run build
16 changes: 16 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Build outputs — generated, not source
deploy/
develop/
build/node_modules/

# Vendor / third-party libraries — not our code
vendor/
common/zlib/
common/libfont/

# Generated / compiled PDF engine files (28k+ lines, not hand-written)
pdf/src/engine/drawingfile_ie.js
pdf/build/

# Test fixtures that are not JS source
tests/
69 changes: 63 additions & 6 deletions .github/workflows/check-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,18 @@ name: Check sdkjs
on:
push:
branches:
- main
- fork
- develop
- 'release/**'
- 'hotfix/**'
pull_request:
branches:
- main
- fork
- develop
- 'release/**'
- 'hotfix/**'
jobs:
code-style:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -62,10 +69,17 @@ jobs:

- name: Build develop SDK
working-directory: sdkjs
env:
# sdkjs-forms is checked out as a sibling of sdkjs/, so relative to
# sdkjs/build/ (where npm --prefix cds to run the script) it's two
# levels up. Without this, the forms/oform tests fail with
# "AscOForm is not defined" / "CreateTextForm is not a function"
# because the addon is checked out but never merged into the build.
SDK_ADDONS: ../../sdkjs-forms
run: |
npm install grunt-cli node-qunit-puppeteer
npm install --prefix build
node node_modules/grunt-cli/bin/grunt --gruntfile build/Gruntfile.js develop --addon=sdkjs-forms
npm install node-qunit-puppeteer
npm ci --prefix build
npm run --prefix build develop

- name: Run unit tests
working-directory: sdkjs
Expand Down Expand Up @@ -102,9 +116,52 @@ jobs:
with:
node-version: 20

- name: Run build-tooling unit tests
run: |
cd sdkjs
npm ci --prefix build
npm test --prefix build

- name: Run build sdkjs
run: |
cd sdkjs
npm install grunt-cli
npm install --prefix build
node node_modules/grunt-cli/bin/grunt --gruntfile build/Gruntfile.js
# npm ci here too (not just in "Run build-tooling unit tests"): this job
# runs on a runner where steps share a workspace but a fresh checkout
# may still land without node_modules installed. npm ci is fast on a
# warm cache, so this is cheap insurance against "webpack: not found".
npm ci --prefix build
npm run --prefix build build

- name: Install QUnit runner dependencies
run: |
sudo apt-get update
sudo apt-get install -y libatk1.0-0 libcups2 libatk-bridge2.0-0 libdrm2 libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libnss3 libgbm1 libasound2t64
cd sdkjs
npm install node-qunit-puppeteer

# The "unit-tests" job above runs the QUnit suite against raw source files
# (COMPILED unset) — it never touches the webpack output, so a regression in the
# actual bundle (wrong concatenation order, a helper-dedup bug, a stripped-directive
# bug, etc.) can pass CI entirely undetected. Re-point develop/sdkjs/*/scripts.js at
# the just-built sdk-all-min.js (COMPILED=1) and run a smoke test against that, so
# the built artifact itself is exercised at least once.
#
# tests/common/api/api.js only exercises AscCommon.* (editor-agnostic bootstrap
# APIs), never AscWord/AscCommonExcel/etc., so it's safe to reuse verbatim per
# module — api-cell.html/api-slide.html/api-visio.html point the same test file
# at cell/slide/visio's own scripts.js. This is deliberately NOT extended to
# suites touching module-specific APIs (tests/word/api, tests/*/shortcuts,
# tests/cell/js-api, ...): COMPILED=1's generated scripts.js references ONLY
# sdk-all-min.js, never sdk-all.js (mirrors the original Gruntfile's
# writeScripts() exactly — not a webpack-migration change), and
# AscWord/AscCommonExcel/etc. live in sdk-all.js, so those suites fail under
# COMPILED=1 with "AscWord is not defined" — a pre-existing limitation of
# developer-compiled mode, not something this step should be asserting on.
- name: Run QUnit against the built bundle (COMPILED=1)
run: |
cd sdkjs
COMPILED=1 npm run --prefix build develop
node node_modules/node-qunit-puppeteer/cli.js tests/common/api/api.html 30000 "--no-sandbox"
node node_modules/node-qunit-puppeteer/cli.js tests/common/api/api-cell.html 30000 "--no-sandbox"
node node_modules/node-qunit-puppeteer/cli.js tests/common/api/api-slide.html 30000 "--no-sandbox"
node node_modules/node-qunit-puppeteer/cli.js tests/common/api/api-visio.html 30000 "--no-sandbox"
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.idea/
build/node_modules
build/.webpack-cache
build/deserializer/cache
build/$weak$.js
build/maps
Expand Down
58 changes: 33 additions & 25 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ bundles (`sdk-all.js` / `sdk-all-min.js`) that the sibling **web-apps** repo loa
| `slide/` | Presentation editor + themes/textures. |
| `pdf/` | PDF editor; `src/` is the implementation, `build/` a compiled wrapper, `test/` a harness. |
| `visio/` | Diagram editor with its own VSDX serialization (`model/`). |
| `build/` | Grunt build: `Gruntfile.js`, `package.json`, `license.header`. Run grunt from **here**. |
| `build/` | Webpack build: `webpack.*.mjs`, `scripts/`, `package.json`, `license.header`. Run npm from **here**. See `build/DEVELOPER-GUIDE.md` for the full workflow. |
| `configs/` | `<editor>.json` file-lists that drive the build (load order); `externs.json` for Closure. |
| `tests/` | QUnit suites per editor + `code-style/check.py` (the lint gate). |
| `vendor/` | Third-party libs (jQuery, XRegExp, etc.). Excluded from lint/build minification. |
Expand All @@ -36,34 +36,38 @@ bundles (`sdk-all.js` / `sdk-all-min.js`) that the sibling **web-apps** repo loa

For Docker dev environment setup (running the full server stack), see [/DocumentServer/AGENTS.md](../DocumentServer/AGENTS.md).

Requires **Node.js** and, for the full compile, **Java** (the build uses Google Closure
Compiler, pinned to `google-closure-compiler@20240317`). There is **no root `package.json`**;
all build deps live in `build/`.
Requires **Node.js** only — the build now runs on Webpack + Terser (no Java, no Google
Closure Compiler). There is **no root `package.json`**; all build deps live in `build/`.
See `build/DEVELOPER-GUIDE.md` for the full workflow (watch mode, source maps, cache).

```bash
# Full SDK build (release; ADVANCED minification). Run from build/.
cd build && npm install -g grunt-cli && npm ci && grunt
# Full SDK build (release; all 4 modules in parallel, ~50s cold / ~2-3s warm). Run from build/.
cd build && npm ci && npm run build
# Outputs: ../deploy/sdkjs/{word,cell,slide,visio}/sdk-all-min.js + sdk-all.js
```

```bash
# Debug/dev loop — NO recompile, NO Java needed. Run from build/.
grunt develop # writes ../develop/sdkjs/<editor>/scripts.js listing the
# individual source files, so editors/tests load unminified sources
grunt develop --compiled # same manifest, but pointing at the compiled bundles
# Debug/dev loop — no bundling. Run from build/.
npm run develop # writes ../develop/sdkjs/<editor>/scripts.js listing the
# individual source files, so editors/tests load unminified sources
COMPILED=1 npm run develop # same manifest, but pointing at the compiled bundles
```

Day-to-day inner loop: edit a source file → `grunt develop` → reload the editor/test page.
You only need the full `grunt` (Closure) build to produce release/min bundles.
Day-to-day inner loop: edit a source file → `npm run develop` → reload the editor/test page.
You only need the full `npm run build` (webpack) to produce release/min bundles, or
`npm run watch:word` (etc.) for an auto-rebuilding dev bundle.

Other flags: `--desktop=true` (desktop-only files), `--mobile=true`, `--map` (source maps),
`--level=WHITESPACE_ONLY` (faster, readable output), `--addon=sdkjs-forms` (merges an external
addon repo's `configs/`).
Config is via **environment variables**, not CLI flags: `SDK_PLATFORM=desktop` or `mobile`
(desktop/mobile-only files), `SDK_SOURCE_MAPS=1` (source maps on a production build),
`SDK_ADDONS=../../sdkjs-forms` (`path.delimiter`-separated list; merges external addon repos'
`configs/`), `NODE_ENV=development` (readable, unminified output). There is no `--level` /
`ADVANCED` vs `WHITESPACE_ONLY` distinction anymore — minification is always Terser with
`mangle: false` (see Gotchas below).

**`make` is NOT the SDK build.** The Makefile's default target also builds the sibling
`../web-apps` repo and requires it to be checked out next to sdkjs; it is the integration
build. Use `grunt` in `build/` for SDK-only work. (The Makefile's `SDKJS_FILES` is also stale —
it lists only `word/sdk-all.js` though grunt builds all editors.)
build. Use `npm run build` in `build/` for SDK-only work. (The Makefile's `SDKJS_FILES` is also
stale — it lists only `word/sdk-all.js` though the build produces all editors.)

### Adding a source file

Expand All @@ -81,9 +85,9 @@ QUnit suites run headless via `node-qunit-puppeteer`, **from the repo root**:

```bash
# one-time setup (from repo root)
npm install grunt-cli node-qunit-puppeteer
npm install --prefix build
node node_modules/grunt-cli/bin/grunt --gruntfile build/Gruntfile.js develop
npm install node-qunit-puppeteer
npm ci --prefix build
npm run --prefix build develop

# run a single suite
node node_modules/node-qunit-puppeteer/cli.js tests/word/api/api.html 30000 "--no-sandbox"
Expand All @@ -98,7 +102,7 @@ CI-guarded by this workflow.

Heaviest coverage is in `tests/cell/spreadsheet-calculation/` (formula engine) and
`tests/word/`. Suites depend on the generated `develop/sdkjs/*/scripts.js`, so run
`grunt develop` first.
`npm run develop` (in `build/`) first.

## Code style — the build-breakers

Expand Down Expand Up @@ -192,11 +196,15 @@ Each editor dir has the same set of API files:

- The editor instance lives in both `Asc.editor` and `window.editor` (desktop compat) — code
often checks both.
- External callers must use bracket access (`window['Asc']['asc_docs_api']`); dot access on
public names gets mangled by Closure ADVANCED minification.
- `make` pulls in `../web-apps`; for SDK-only work use `grunt` in `build/`.
- External callers must use bracket access (`window['Asc']['asc_docs_api']`); public names are
still published both ways (`window['Name'].Sym = window.Name.Sym = Sym`) as a defensive
convention, but the current webpack build runs Terser with `mangle: false` — property/name
mangling is not actually applied. Keep using bracket access anyway; don't rely on this as
license to switch to dot-access-only code.
- `make` pulls in `../web-apps`; for SDK-only work use `npm run build` in `build/`.
- Use `npm ci` (not `npm install`) in `build/` to respect the committed `npm-shrinkwrap.json`.
- The full `grunt` build needs Java; `grunt develop` does not.
- No Java/Closure Compiler dependency anymore — `npm run build` and `npm run develop` both only
need Node.js.

## Where future findings live

Expand Down
17 changes: 15 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
GRUNT = grunt
GRUNT_FLAGS = --no-color -v
GRUNT_FLAGS = --no-color -v
SDK_PLATFORM ?=

OUTPUT_DIR = deploy
OUTPUT = $(OUTPUT_DIR)
Expand All @@ -24,6 +25,17 @@ GRUNT_ENV += BUILD_NUMBER=$(BUILD_NUMBER)
GRUNT_ENV += APP_COPYRIGHT="$(APP_COPYRIGHT)"
GRUNT_ENV += PUBLISHER_URL="$(PUBLISHER_URL)"

# sdkjs's own build/ was migrated from Grunt to webpack (web-apps' build below is
# unaffected — it still uses Grunt). The new pipeline reads the same
# PRODUCT_VERSION/BUILD_NUMBER/APP_COPYRIGHT/PUBLISHER_URL via env vars, plus
# SDK_PLATFORM instead of a --desktop=true CLI flag, and it errors out on any
# stray CLI argument — so it must be invoked with no flags at all (no GRUNT_FLAGS).
# Recursive (=), not simple (:=): SDK_PLATFORM must expand at recipe-run time so
# the `desktop:` target-specific override below is picked up, not the empty
# top-level default in effect at parse time.
SDKJS_ENV = $(GRUNT_ENV)
SDKJS_ENV += SDK_PLATFORM=$(SDK_PLATFORM)

WEBAPPS_DIR := web-apps

WEBAPPS = $(OUTPUT)/$(WEBAPPS_DIR)
Expand All @@ -49,9 +61,10 @@ $(WEBAPPS_FILES): $(NODE_MODULES) $(SDKJS_FILES)

$(SDKJS_FILES): $(NODE_MODULES)
cd build && \
$(GRUNT_ENV) $(GRUNT) $(GRUNT_FLAGS)
$(SDKJS_ENV) npm run build

desktop: GRUNT_FLAGS += --desktop=true
desktop: SDK_PLATFORM = desktop
desktop: all

clean:
Expand Down
Loading
Loading