Skip to content

fix(editor): keep manifold-3d out of consumer bundler graphs - #735

Open
Aymericr wants to merge 1 commit into
mainfrom
fix/manifold-out-of-bundler-graph
Open

fix(editor): keep manifold-3d out of consumer bundler graphs#735
Aymericr wants to merge 1 commit into
mainfrom
fix/manifold-out-of-bundler-graph

Conversation

@Aymericr

@Aymericr Aymericr commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes #715. External webpack consumers of @pascal-app/editor fail at build time because manifold-3d's emscripten glue awaits import('node:module') behind a Node-only check — the branch never executes in a browser, but webpack refuses to build a graph that can reach it. export-manager.tsx statically imports the manifold worker wrapper and ExportManager renders unconditionally from the editor root, so the poison was in every consumer's graph whether or not they used print export.

The fix keeps the worker chunk bundler-built but removes every traceable manifold-3d specifier from it:

  • print-shell-compiler-manifold-core.ts keeps only a type import from manifold-3d; the runtime factory loads through an import() no bundler follows (webpackIgnore + @vite-ignore), trying the bare specifier first (bun tests, dev servers, bundlers that inlined it anyway) and falling back to a version-pinned jsDelivr copy for bundled browser builds. Emscripten locates manifold.wasm relative to the glue's own URL, so the CDN path self-resolves the wasm.
  • New configureManifoldRuntime({ moduleUrl, wasmUrl }) (exported from the package entry) lets offline or CSP-restricted hosts point both URLs at self-hosted assets before the first print export.
  • The worker protocol carries the runtime options; the in-process test runner path is unchanged (compileManifoldMeshData's second parameter went from wasmUrl?: string to runtime?: ManifoldRuntimeOptions; no caller passed it).
  • A failed load (offline, blocked CDN) no longer poisons later compile attempts — the cached module promise resets on rejection.

How to test

  1. bun test packages/editor/src/lib/print-golden-house.test.ts packages/editor/src/lib/print-shell-compiler-baseline.test.ts — the in-process runner now reaches manifold through the bare-specifier branch of the untraced import.
  2. In the app: Settings → Export 3D print files still produces a preflight + artifact (worker path, bare specifier resolved by the bundler dev server or CDN fallback).
  3. External repro from @pascal-app/editor beta.5 pulls node:module into external browser builds through Manifold print export #715: bundle a Next 15/webpack app that imports @pascal-app/editor — the build no longer errors on node:module; the worker chunk contains no manifold-3d module.

Screenshots / screen recording

N/A — non-visual packaging/loading change.

Checklist

  • I've tested this locally with bun dev
  • My code follows the existing code style (run bun check to verify)
  • I've updated relevant documentation (if applicable)
  • This PR targets the main branch

Note

Medium Risk
Print export now depends on runtime dynamic loading (CDN fallback or host-configured URLs); misconfiguration or network blocks could break Manifold compilation without affecting unrelated editor features.

Overview
Fixes #715 by stopping webpack/Next apps that import @pascal-app/editor from failing on manifold-3d’s unreachable node:module import in the emscripten glue.

print-shell-compiler-manifold-core.ts now uses a type-only manifold-3d import and loads the runtime factory via a dynamic import() annotated with webpackIgnore / @vite-ignore, so consumer bundlers no longer trace manifold-3d. Resolution tries the bare manifold-3d specifier first, then a version-pinned jsDelivr glue URL; WASM follows the glue URL unless overridden. Failed loads clear the cached module promise so a later export can retry.

Hosts with CSP or offline constraints can call the new public configureManifoldRuntime({ moduleUrl, wasmUrl }) (re-exported from the package entry) before the first print export. The worker request carries those options; compileManifoldMeshData takes optional ManifoldRuntimeOptions instead of a lone wasmUrl.

Reviewed by Cursor Bugbot for commit 58edd0c. Bugbot is set up for automated code reviews on this repo. Configure here.

manifold-3d's emscripten glue awaits import('node:module') behind a Node
check; the branch never executes in a browser, but webpack refuses to
build any graph that can reach it. export-manager.tsx statically imports
the manifold worker wrapper and ExportManager renders unconditionally
from the editor root, so every external webpack consumer of
@pascal-app/editor failed at build time (#715).

The worker chunk is still built by the consumer's bundler, but it no
longer contains a traceable manifold-3d specifier. The glue is loaded at
runtime through an import() no bundler follows: bare specifier first
(bun tests, dev servers, bundlers that inlined it anyway), then a
version-pinned jsDelivr copy for bundled browser builds — emscripten
locates manifold.wasm relative to the glue's own URL, so the CDN path
self-resolves. configureManifoldRuntime(options) lets offline or
CSP-restricted hosts point both URLs at self-hosted assets.

A failed load no longer poisons later attempts: the cached module
promise resets on rejection.

Fixes #715

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Aymericr

Copy link
Copy Markdown
Contributor Author

Empirical check of the pattern with webpack 5.110.2, isolated repro (worker created via new Worker(new URL(...)), manifold-3d@3.5.1 resolvable on the resolve path so webpack would follow it if it could):

Still waiting on @smokie40 to validate the branch against their real Next/webpack integration before merging (per #715).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant