From 434c367f32db1885c76d3a28c684275d14c193c8 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Thu, 6 Aug 2026 10:04:51 +0200 Subject: [PATCH 1/3] Auto-detect playground dependency subpaths (playground 0.3.12) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump @studiometa/playground to 0.3.12 and replace the hand-rolled `packageDeps` loop with the preset's `subpaths: true` option. It reads each workspace package's `package.json` `exports` map and builds every subpath as an entry of ONE code-split tsdown build, so modules shared between entries — a component class referenced by the barrel, its own `@studiometa/ui/` subpath and the `./manifest` lazy imports — are emitted once as a shared chunk and referenced by every entry. That gives a single runtime instance and removes the singleton/identity hazard of bundling each subpath separately. The playground now resolves every ui / ui-mapbox / ui-autoload subpath from local source with same-origin declarations, so any `@studiometa/ui/` import works in the editor while developing new components. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_014FQxYGj2RqgcP8BkubpiNu --- package-lock.json | 8 ++--- packages/playground/meta.config.js | 55 ++++++------------------------ packages/playground/package.json | 2 +- 3 files changed, 16 insertions(+), 49 deletions(-) diff --git a/package-lock.json b/package-lock.json index 846e5bd0..c2f2cfb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23673,7 +23673,7 @@ "name": "@studiometa/ui-playground", "version": "1.10.0-beta.3", "dependencies": { - "@studiometa/playground": "^0.3.11" + "@studiometa/playground": "^0.3.12" }, "devDependencies": { "@mapbox/mapbox-gl-geocoder": "^5.1.0", @@ -23686,9 +23686,9 @@ } }, "packages/playground/node_modules/@studiometa/playground": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@studiometa/playground/-/playground-0.3.11.tgz", - "integrity": "sha512-z2qLYbuW1TpRR/Pbi3WY3tXJXyydcGvqZ+eu2/PAPJI6EZxoU5+0V9mQ6bMGox7IrBqosZf9QDNGBdzclDm4xQ==", + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@studiometa/playground/-/playground-0.3.12.tgz", + "integrity": "sha512-4c2JUPxGBvpDvVVlcCHLrh/zZSi7sqygMljUqE5MsoVGMiwSsFPjgGZVgRyVUUtIlejUvnOLPIq5Tszo41foxw==", "license": "MIT", "dependencies": { "@studiometa/js-toolkit": "^3.4.3", diff --git a/packages/playground/meta.config.js b/packages/playground/meta.config.js index 40fda9e3..8ee7d9df 100644 --- a/packages/playground/meta.config.js +++ b/packages/playground/meta.config.js @@ -1,40 +1,6 @@ -import { readFileSync } from 'node:fs'; import { resolve } from 'node:path'; import { playgroundPreset as playground, defineWebpackConfig } from '@studiometa/playground/preset'; -/** - * Build playground dependency configs for a workspace package from its `package.json` `exports` - * map, so its barrel and subpaths bundle from LOCAL source (tsdown) instead of being hardcoded. - * This is what lets the `@studiometa/ui-autoload` side-effect entries (`./ui`, `./ui-mapbox`) and the - * per-package `manifest` modules they pull resolve from the working tree while developing new components. - * - * `relDir` is relative to this config (e.g. `'../ui'`). `include`, when given, restricts the SUBpaths - * to that list (the barrel `.` is always emitted). It exists for `@studiometa/ui`, whose ~190 - * component subpaths are NOT needed here — the manifest lazy-loads them as relative chunks of its own - * bundle — and each would otherwise be a separate tsdown build. Generic all-subpath bundling in one - * multi-entry build belongs upstream in @studiometa/playground; this per-package loop is the starter. - */ -function packageDeps(specifier, relDir, { include } = {}) { - const { exports = {} } = JSON.parse(readFileSync(resolve(`${relDir}/package.json`), 'utf8')); - const source = `${relDir}/**/*.ts`; - const seen = new Set(); - const deps = []; - for (const [key, target] of Object.entries(exports)) { - if (key === './package.json' || key.includes('*') || typeof target !== 'string') continue; - if (key.endsWith('.js') && key !== '.') continue; // skip the `.js` alias of a subpath - const subpath = key === '.' ? '' : key.slice(1); // '.' → barrel, './manifest' → '/manifest' - if (include && key !== '.' && !include.includes(subpath)) continue; - if (seen.has(subpath)) continue; - seen.add(subpath); - deps.push({ - specifier: `${specifier}${subpath}`, - source, - entry: `${relDir}/${target.replace(/^\.\//, '')}`, - }); - } - return deps; -} - export default defineWebpackConfig({ presets: [ playground({ @@ -76,16 +42,17 @@ export default defineWebpackConfig({ { specifier: '@mapbox/mapbox-gl-geocoder', esmSh: { bundle: true } }, '@studiometa/js-toolkit', '@studiometa/js-toolkit/utils', - // Workspace packages bundled from local source, derived from each package's `exports` map. - // ui / ui-mapbox contribute their barrel + `./manifest`; ui-autoload its barrel + the - // `./ui`/`./ui-mapbox` side-effect entries — the subpaths the autoload lazy-import chain - // needs. The manifests code-split (their `load: () => import(...)` calls), which requires - // `@studiometa/playground` >= 0.3.11 (its `PlaygroundDependenciesPlugin` preserves per-chunk - // filenames instead of flattening them to `index.js`). ui's ~190 component subpaths are NOT - // listed: the manifest bundle lazy-loads them as its own chunks, so no separate entry is needed. - ...packageDeps('@studiometa/ui', '../ui', { include: ['/manifest'] }), - ...packageDeps('@studiometa/ui-mapbox', '../ui-mapbox', { include: ['/manifest'] }), - ...packageDeps('@studiometa/ui-autoload', '../ui-autoload', { include: ['/ui', '/ui-mapbox'] }), + // Workspace packages bundled from local source so the playground reflects the working tree. + // `subpaths: true` reads each package's `package.json` `exports` map and builds every subpath + // as an entry of ONE code-split tsdown build (@studiometa/playground >= 0.3.12): modules shared + // between entries — component classes referenced by both the barrel and the `./manifest` lazy + // imports, or by a direct `@studiometa/ui/` import — are emitted once as a shared + // chunk and referenced by every entry, so there is a single runtime instance (no singleton / + // identity hazard). ui exposes its barrel + `./manifest` + every component subpath; + // ui-autoload exposes its barrel + the `./ui`/`./ui-mapbox` side-effect entries. + { specifier: '@studiometa/ui', source: '../ui/**/*.ts', subpaths: true }, + { specifier: '@studiometa/ui-mapbox', source: '../ui-mapbox/**/*.ts', subpaths: true }, + { specifier: '@studiometa/ui-autoload', source: '../ui-autoload/**/*.ts', subpaths: true }, ], defaults: { html: `{% html_element 'span' with { class: 'dark:text-white font-bold border-b-2 border-current' } %} diff --git a/packages/playground/package.json b/packages/playground/package.json index 0b6577d7..fa472f27 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -9,7 +9,7 @@ "build": "meta build" }, "dependencies": { - "@studiometa/playground": "^0.3.11" + "@studiometa/playground": "^0.3.12" }, "devDependencies": { "@mapbox/mapbox-gl-geocoder": "^5.1.0", From ef914b8d8e51f2c5f6510f7a820d88ed72645e49 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Thu, 6 Aug 2026 10:29:10 +0200 Subject: [PATCH 2/3] Bump @studiometa/playground to 0.3.13 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 0.3.13 rewrites relative `.js` imports to `.d.ts` inside the emitted declaration chunks of self-hosted dependencies. rolldown-plugin-dts wrote cross-chunk type imports with a `.js` extension, but declaration chunks are content-hashed independently from the JS chunks, so `./X-.js` never existed for types (only `./X-.d.ts` did) — the editor LSP fetched the dead URL and type resolution broke for every code-split subpath. Verified in the playground build: all 145 cross-chunk `.d.ts` imports now point at existing `.d.ts` files (0 dead `.js` type-imports), while the JS shared-chunk singleton is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_014FQxYGj2RqgcP8BkubpiNu --- package-lock.json | 8 ++++---- packages/playground/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c2f2cfb4..ed270619 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23673,7 +23673,7 @@ "name": "@studiometa/ui-playground", "version": "1.10.0-beta.3", "dependencies": { - "@studiometa/playground": "^0.3.12" + "@studiometa/playground": "^0.3.13" }, "devDependencies": { "@mapbox/mapbox-gl-geocoder": "^5.1.0", @@ -23686,9 +23686,9 @@ } }, "packages/playground/node_modules/@studiometa/playground": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@studiometa/playground/-/playground-0.3.12.tgz", - "integrity": "sha512-4c2JUPxGBvpDvVVlcCHLrh/zZSi7sqygMljUqE5MsoVGMiwSsFPjgGZVgRyVUUtIlejUvnOLPIq5Tszo41foxw==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@studiometa/playground/-/playground-0.3.13.tgz", + "integrity": "sha512-VLNwlf4icGYQ87LeOTQQhGs+p4W/TzwvbJl5FiHYQeVqDHfUdMylKT/nVffGrW/aK2BdFUyQPZMDeEeLBZq7mA==", "license": "MIT", "dependencies": { "@studiometa/js-toolkit": "^3.4.3", diff --git a/packages/playground/package.json b/packages/playground/package.json index fa472f27..000da92c 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -9,7 +9,7 @@ "build": "meta build" }, "dependencies": { - "@studiometa/playground": "^0.3.12" + "@studiometa/playground": "^0.3.13" }, "devDependencies": { "@mapbox/mapbox-gl-geocoder": "^5.1.0", From 70585878296089f4e335e5607e6cb18ac9b14357 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Thu, 6 Aug 2026 10:49:31 +0200 Subject: [PATCH 3/3] Bump playground js-toolkit dev dependency to 3.8.2 Align the playground's `@studiometa/js-toolkit` dev dependency with the latest patch release so the local tsdown builds of the workspace packages resolve the same version consumers get from esm.sh. Playground build verified green. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_014FQxYGj2RqgcP8BkubpiNu --- package-lock.json | 12 +++++++++++- packages/playground/package.json | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index ed270619..e80c8dd4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23678,13 +23678,23 @@ "devDependencies": { "@mapbox/mapbox-gl-geocoder": "^5.1.0", "@motionone/easing": "^10.18.0", - "@studiometa/js-toolkit": "3.8.0", + "@studiometa/js-toolkit": "3.8.2", "deepmerge": "^4.3.1", "mapbox-gl": "^3.13.0", "morphdom": "^2.7.8", "tsdown": "^0.21.5" } }, + "packages/playground/node_modules/@studiometa/js-toolkit": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@studiometa/js-toolkit/-/js-toolkit-3.8.2.tgz", + "integrity": "sha512-qbQ2b6j1cN5GVC+sh62fiHzHc3PzGAP8YZVi/KLYExmd5mJj8AIBSSG8OE8JbPpTKKqF7rqnRIn6o/VzM+02Ww==", + "license": "MIT", + "dependencies": { + "@motionone/easing": "^10.18.0", + "deepmerge": "^4.3.1" + } + }, "packages/playground/node_modules/@studiometa/playground": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@studiometa/playground/-/playground-0.3.13.tgz", diff --git a/packages/playground/package.json b/packages/playground/package.json index 000da92c..5777573d 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -14,7 +14,7 @@ "devDependencies": { "@mapbox/mapbox-gl-geocoder": "^5.1.0", "@motionone/easing": "^10.18.0", - "@studiometa/js-toolkit": "3.8.0", + "@studiometa/js-toolkit": "3.8.2", "deepmerge": "^4.3.1", "mapbox-gl": "^3.13.0", "morphdom": "^2.7.8",