typograph-editor-documentation
    Preparing search index...

    Editor → CDN: how the deploy works

    This documents how editor builds reach the CDN. There is no beta / pre-release channel — we develop backwards-compatible and ship through the normal master → latest flow, so every consumer can point at one stable URL.

    Three things, three places:

    1. The editor — this repo. src/editor.ts is the entry point.
    2. The canvas — a separate git repo (typograph-canvas), used as a pinned dependency. Its TypeScript gets bundled into editor.js at build time.
    3. The colour engine (scripts/jsColorEngineWeb.js) — a standalone, global-scope script (a WASM/webpack build that defines window.jsColorEngine). It is not part of the esbuild bundle (see "The colour engine" below).
    4. The CDN — a Cloudflare R2 bucket (typograph-cdn) served at https://cdn.typograph.nl/. Files land in folders like editor/latest/ and editor/1.2.0/.

    Each deploy syncs the dist/ folder into one version folder:

    typograph-cdn (bucket)  →  https://cdn.typograph.nl/

    └── editor/
    ├── latest/ ← current master build (what everyone uses)
    │ ├── editor.js
    │ ├── editor.min.js
    │ ├── scripts/
    │ │ └── jsColorEngineWeb.jsthe colour engine, shipped alongside
    │ ├── stylesheets/ ← style.css (+ its ../images/ refs resolve here)
    │ ├── images/ ← UI icons, cursors, colour-picker assets
    │ └── manifest.json
    └── 1.2.0/ ← a tagged release, frozen forever
    └── ...same files...

    Everything the browser loads at runtime — the bundle, the colour engine, the CSS, and the icons — ships together on every merge. A change to a stylesheet or an icon goes live through the same master → latest deploy as a code change; there is never a manual build or upload step.

    The canvas colour wrapper (typograph-canvas/scripts/colorengine.js) calls a bare globalnew jsColorEngine.Profile(). That global is provided by scripts/jsColorEngineWeb.js, a self-contained script that must be loaded on the page before the editor module runs. esbuild bundles the canvas TypeScript into editor.js, but it does not pull in this global-scope engine file — nothing imports it, and it is a webpack IIFE that assigns a top-level var jsColorEngine which would become module-scoped (and thus invisible to the wrapper) if inlined into the ESM bundle.

    So the engine travels to the CDN as its own file next to editor.js:

    • In CI, npm run build:engine (part of build:all) copies scripts/jsColorEngineWeb.js into dist/, so aws s3 sync dist/ uploads it automatically.
    • Locally, the widgets-cdn nginx serves /editor/<version>/jsColorEngineWeb.js straight from scripts/ (the watch container only rebuilds dist/editor.js, so the source file is the reliable place to serve from in dev).

    Same URL in both environments; only the on-disk source differs.

    A host page (portal-ui via EDITOR_CDN_URL, the demo, a customer page) loads two tags, engine first:

    <!-- classic script: runs synchronously, defines window.jsColorEngine -->
    <script src="https://cdn.typograph.nl/editor/latest/scripts/jsColorEngineWeb.js"></script>
    <!-- module script: deferred, so the global is guaranteed to exist when it runs -->
    <script type="module" src="https://cdn.typograph.nl/editor/latest/editor.js"></script>

    Point the CSS <link> at the CDN copy too (…/editor/latest/stylesheets/style.css); its own ../images/… references resolve relative to that file, so the colour-picker/CSS icons load from the CDN automatically.

    Asset base URL. Icons/cursors referenced from JavaScript (e.g. url(images/ui/openhand.svg)) are resolved through assetUrl() in src/assets.ts, which builds new URL(path, import.meta.url). Because import.meta.url is the editor bundle's own URL, these assets load from wherever editor.js is served — the CDN — regardless of which host page embeds the editor. No host configuration is required. Only editor-owned images/ assets go through assetUrl; host/backend paths (php/…, userdata/…) and the user's uploaded images stay relative to the host page on purpose.

    npm run build:all runs, in order: editor.js (esbuild bundle) → editor.min.jsbuild:assets (copy the colour engine into dist/scripts/, and stylesheets/ + images/ into dist/) → docs.

    Language assets (hyphenation patterns, spell-check dictionaries) are not built or deployed here. They are served from https://cdn.typograph.nl/languages, which the canvas library defaults to, and are generated in typograph-canvas via npm run copy:lang-assets. See PLAN-Language_assets.md in that repo.

    The canvas version baked into the bundle is pinned in package.json:

    "typograph-canvas": "git+ssh://git@bitbucket.org/get-interactive/typograph-canvas.git#<commit-sha>"
    

    npm install checks out exactly that canvas commit every time — predictable builds, same philosophy as composer.lock in the PHP services. To adopt newer canvas code, bump the SHA after the #, commit, and push.

    bitbucket-pipelines.yml is a lookup table keyed on what was pushed:

    You push... Pipeline that runs Result on CDN
    any feature branch default nothing — build only, as a smoke test
    master build → deploy → docs editor/latest/ updated
    a tag like v1.3.0 build → deploy → docs editor/1.3.0/ created, latest/stable markers set

    Feature branches build but never deploy, so an experiment can never overwrite the CDN. Work becomes live only by merging to master — which is exactly why every change must stay backwards-compatible with existing consumers of editor/latest/.

    Credentials: the deploy step declares deployment: staging, reusing the CF_ACCOUNT_ID and AWS keys already stored in Bitbucket.

    You change editor code:

    commitmerge to masterBitbucket builds & deploys automatically
    → ~2 min later, cdn.typograph.nl/editor/latest/editor.js is the new build

    Someone changes canvas / colour-engine code:

    The editor keeps building the pinned canvas commit until you bump it:

    1. Note the new canvas commit SHA (git log in the canvas repo).
    2. Edit package.json: replace the SHA after the #.
    3. Commit → merge → the pipeline builds with the new canvas baked in.

    If the change touches scripts/jsColorEngineWeb.js itself, just commit the new file here — build:engine picks it up on the next deploy.

    Checking what's live:

    https://cdn.typograph.nl/editor/latest/manifest.json records the exact commit, branch, and build date currently deployed. If the browser serves an old bundle, that is Cloudflare/browser caching — hard-refresh; the manifest is the truth.