Skip to content

Commit 162e616

Browse files
authored
feat: add importMetaUrl to DevframeDefinition for dependency resolution (#261)
1 parent fb4886c commit 162e616

41 files changed

Lines changed: 197 additions & 65 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/guide/client-assets.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,13 @@ import pkg from '../package.json' with { type: 'json' }
4646
const distDir: RemoteAssets = {
4747
package: '@acme/my-tool-assets',
4848
version: pkg.version,
49-
resolveFrom: import.meta.url,
5049
}
5150

5251
export default defineDevframe({
5352
id: 'my-tool',
5453
version: pkg.version,
5554
packageName: pkg.name,
55+
importMetaUrl: import.meta.url,
5656
cli: { distDir },
5757
setup(ctx) {
5858
//
@@ -62,11 +62,13 @@ export default defineDevframe({
6262

6363
The UI mounts as usual — the first request for each file is streamed from a CDN and written to a local cache; subsequent requests are served from disk.
6464

65+
The definition's [`importMetaUrl`](./devframe-definition#resolving-against-the-plugins-own-dependencies) supplies the resolution base, so a remote source needs only its `package` and `version`. A per-source `resolveFrom` overrides that base for one source, and an explicit `resolveFrom: null` opts a source out of the installed-copy lookup entirely.
66+
6567
### How assets resolve
6668

6769
For each request the source resolves in order:
6870

69-
1. **Locally installed package** — resolved from `resolveFrom` (`import.meta.url`). If `@acme/my-tool-assets` is installed next to your tool, it's served directly with no network. This is the offline path.
71+
1. **Locally installed package** — resolved from `resolveFrom`, which defaults to the definition's `importMetaUrl`. If `@acme/my-tool-assets` is installed next to your tool, it's served directly with no network. This is the offline path.
7072
2. **On-disk cache** — files already fetched, under the project's storage directory.
7173
3. **CDN back-proxy**[jsDelivr](https://www.jsdelivr.com/) by default, mirroring npm. Each file streams to the browser and is cached on the way past.
7274

@@ -78,7 +80,7 @@ Exact-version URLs are immutable, so a cached file never goes stale.
7880
|-------|---------|
7981
| `package` | npm package holding the built assets. |
8082
| `version` | Exact version to serve — usually your tool's own `pkg.version`. |
81-
| `resolveFrom` | `import.meta.url` of the declaring module; enables the zero-network path from a locally installed copy. Omit to skip straight to cache + CDN. |
83+
| `resolveFrom` | Resolution base for the zero-network path from a locally installed copy. Defaults to the definition's `importMetaUrl`; set it to override that for one source, or to `null` to skip straight to cache + CDN. |
8284
| `path` | Subpath inside the package the assets live under. Defaults to `dist`. |
8385
| `provider` | `'jsdelivr'` (default), `'unpkg'`, or a custom provider for an internal mirror. |
8486
| `offline` | `true` serves only from a local install or the cache — never the network. |
@@ -109,7 +111,6 @@ A custom provider supplies the file URL, and optionally a file listing (used for
109111
const distDir: RemoteAssets = {
110112
package: '@acme/my-tool-assets',
111113
version: pkg.version,
112-
resolveFrom: import.meta.url,
113114
provider: {
114115
fileUrl: (name, version, file) =>
115116
`https://npm.internal.acme.com/${name}@${version}/${file}`,
@@ -119,7 +120,7 @@ const distDir: RemoteAssets = {
119120

120121
### Publishing the assets
121122

122-
The assets package is an ordinary npm package that ships the built UI under `path` (default `dist`) and exposes its `package.json` so `resolveFrom` can locate it:
123+
The assets package is an ordinary npm package that ships the built UI under `path` (default `dist`) and exposes its `package.json` so the resolver can locate it:
123124

124125
```json
125126
{

docs/guide/devframe-definition.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export default defineDevframe({
1717
name: 'My Devframe',
1818
version: '1.0.0',
1919
packageName: 'my-devframe',
20+
importMetaUrl: import.meta.url,
2021
homepage: 'https://github.com/me/my-devframe',
2122
description: 'A one-line summary of what the tool does.',
2223
icon: 'ph:gauge-duotone',
@@ -45,6 +46,7 @@ export default defineDevframe({
4546
| `name` | `string` | **Required.** Display name shown in the dock and agent manifests. |
4647
| `version` | `string` | **Required.** Semver of the tool, surfaced in hub UIs and diagnostics. |
4748
| `packageName` | `string` | **Required.** npm package name the devframe ships in (e.g. `@scope/my-tool`). |
49+
| `importMetaUrl` | `string` | **Recommended.** Always pass `import.meta.url`. The resolution base for the tool's own dependency graph: it becomes the default `resolveFrom` for any [remote assets](./client-assets) the devframe hosts, and the base the host resolves declared [services](./services#wire-services) from — so a plugin ships an assets or service package as its own dependency instead of asking users to install it. See [Resolving against the plugin's own dependencies](#resolving-against-the-plugins-own-dependencies). |
4850
| `homepage` | `string` | **Required.** Project homepage or documentation URL. |
4951
| `description` | `string` | **Required.** One-line summary of what the tool does. |
5052
| `icon` | `string \| { light, dark }` | Optional Iconify name or URL; supports light/dark pairs. |
@@ -67,6 +69,7 @@ export default defineDevframe({
6769
name: 'My Devframe', // display label
6870
version: pkg.version,
6971
packageName: pkg.name,
72+
importMetaUrl: import.meta.url,
7073
homepage: pkg.homepage,
7174
description: pkg.description,
7275
setup(ctx) { /**/ },
@@ -75,6 +78,36 @@ export default defineDevframe({
7578

7679
The default import with a `with { type: 'json' }` attribute resolves under both bundlers and Node's native TypeScript execution. Bundlers also support the destructured `import { version } from '../package.json'` form when the devframe is always bundled before it runs.
7780

81+
### Resolving against the plugin's own dependencies
82+
83+
A devframe often ships companion packages — a separate `--assets` package holding its built SPA, or a service package it consumes. `importMetaUrl` lets the host resolve those against the plugin's **own** installed dependencies rather than the consuming app's, so the plugin declares them as its dependencies and users install nothing extra.
84+
85+
```ts
86+
import pkg from '../package.json' with { type: 'json' }
87+
88+
export default defineDevframe({
89+
id: 'my-devframe',
90+
name: 'My Devframe',
91+
version: pkg.version,
92+
packageName: pkg.name,
93+
importMetaUrl: import.meta.url,
94+
homepage: pkg.homepage,
95+
description: pkg.description,
96+
cli: {
97+
// Served from the locally installed `my-devframe--assets` — resolved via
98+
// `importMetaUrl`, so it works under pnpm's strict layout with zero network.
99+
distDir: { package: `${pkg.name}--assets`, version: pkg.version },
100+
},
101+
services: [
102+
// Imported from `my-devframe`'s own dependency graph.
103+
{ package: '@scope/my-service', version: pkg.version },
104+
],
105+
setup(ctx) { /**/ },
106+
})
107+
```
108+
109+
For a remote assets source, `importMetaUrl` is the default `resolveFrom`; a per-source `resolveFrom` still wins, and an explicit `resolveFrom: null` opts out of the installed-copy lookup. See [Client Assets](./client-assets) and [Cross-Plugin Services](./services#wire-services) for the full resolution order.
110+
78111
### Runtime flags
79112

80113
The `ctx.mode` field is either `'dev'` or `'build'`. Use it to gate work that should only run in one runtime:

docs/guide/services.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,15 @@ Two declaration merges make it fully typed for consumers: the fully-qualified RP
103103

104104
### Installing
105105

106-
A host with the factory at hand installs explicitly; a plugin declares what it consumes on its definition and the adapter resolves the package **against the plugin's own dependencies**:
106+
A host with the factory at hand installs explicitly; a plugin declares what it consumes on its definition and the adapter resolves the package **against the plugin's own dependencies** — the base for that resolution is the definition's [`importMetaUrl`](./devframe-definition#resolving-against-the-plugins-own-dependencies), so a plugin ships a service package as its own dependency and users install nothing extra:
107107

108108
```ts
109109
// host side (e.g. inside initHub's configure)
110110
ctx.services.install(createShikiService({ themes }))
111111

112112
// plugin side — declarative
113113
defineDevframe({
114+
importMetaUrl: import.meta.url, // resolution base for the declared packages
114115
services: [
115116
{ package: '@devframes/service-open' },
116117
{ package: '@devframes/service-shiki', version: '^1', options: { langs: ['vue'] } },

examples/files-inspector/src/devframe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export default defineDevframe({
1111
name: 'Files Inspector',
1212
version: pkg.version,
1313
packageName: pkg.name,
14+
importMetaUrl: import.meta.url,
1415
homepage: pkg.homepage,
1516
description: pkg.description,
1617
icon: 'ph:folder-open-duotone',

examples/hub-next/src/client/devframe/demo-devframe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export default defineDevframe({
1313
name: 'Next Demo Tool',
1414
version: pkg.version,
1515
packageName: pkg.name,
16+
importMetaUrl: import.meta.url,
1617
homepage: pkg.homepage,
1718
description: 'A tiny demo devframe mounted into the Next.js hub via its `devframes` list.',
1819
icon: 'ph:rocket-duotone',

examples/hub-next/src/client/devframe/tabbed-devframe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default defineDevframe({
1919
name: 'Next Tabbed Tool',
2020
version: pkg.version,
2121
packageName: pkg.name,
22+
importMetaUrl: import.meta.url,
2223
homepage: pkg.homepage,
2324
description: 'A multi-view SPA hosted as shared-iframe hub docks with soft navigation.',
2425
icon: 'ph:squares-four-duotone',

examples/hub-vite/src/devframe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default defineDevframe({
1919
name: 'Demo Tool',
2020
version: pkg.version,
2121
packageName: pkg.name,
22+
importMetaUrl: import.meta.url,
2223
homepage: pkg.homepage,
2324
description: 'A tiny demo devframe that plugs into the hub via its `devframes` list.',
2425
icon: 'ph:rocket-duotone',

examples/hub-vite/src/tabbed-tool.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export default defineDevframe({
1919
name: 'Tabbed Tool',
2020
version: pkg.version,
2121
packageName: pkg.name,
22+
importMetaUrl: import.meta.url,
2223
homepage: pkg.homepage,
2324
description: 'A multi-view SPA hosted as shared-iframe hub docks with soft navigation.',
2425
icon: 'ph:squares-four-duotone',

examples/next-runtime-snapshot/src/devframe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default defineDevframe({
1515
name: 'Next Runtime Snapshot',
1616
version: pkg.version,
1717
packageName: pkg.name,
18+
importMetaUrl: import.meta.url,
1819
homepage: pkg.homepage,
1920
description: pkg.description,
2021
icon: 'ph:gauge-duotone',

examples/streaming-chat/src/devframe.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export default defineDevframe({
1515
name: 'Streaming Chat',
1616
version: pkg.version,
1717
packageName: pkg.name,
18+
importMetaUrl: import.meta.url,
1819
homepage: pkg.homepage,
1920
description: pkg.description,
2021
icon: 'ph:chat-circle-dots-duotone',

0 commit comments

Comments
 (0)