fortiplugin-bundle-adapter 0.0.3 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -20
- package/package.json +19 -4
package/README.md
CHANGED
|
@@ -19,9 +19,9 @@ Your plugin entry ends up like this (conceptually):
|
|
|
19
19
|
|
|
20
20
|
```ts
|
|
21
21
|
export default function factory(deps) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
// deps.imports["react"], deps.imports["@host/ui"], ...
|
|
23
|
+
// plugin module code (rewritten)
|
|
24
|
+
return DefaultExport;
|
|
25
25
|
}
|
|
26
26
|
```
|
|
27
27
|
|
|
@@ -128,6 +128,152 @@ and the plugin still gets the “default” value.
|
|
|
128
128
|
|
|
129
129
|
---
|
|
130
130
|
|
|
131
|
+
## Runtime helpers (createFactory + resolver)
|
|
132
|
+
|
|
133
|
+
Calling `factory({ imports })` directly works, but FortiPlugin hosts usually want a reusable runtime utility that:
|
|
134
|
+
|
|
135
|
+
* imports the plugin entry by URL/path
|
|
136
|
+
* resolves the correct export (`default` or named)
|
|
137
|
+
* detects whether the export is a **prep factory** or a **component**
|
|
138
|
+
* injects host dependencies (`react`, `react/jsx-runtime`, optional `@host/*`, optional `@inertiajs/*`)
|
|
139
|
+
* merges props correctly (**host props win**)
|
|
140
|
+
|
|
141
|
+
This package provides two runtime helpers for that.
|
|
142
|
+
|
|
143
|
+
### `createFactory(file, env, opts?, hostProps?)`
|
|
144
|
+
|
|
145
|
+
`createFactory()` dynamically imports the `file` and returns a callable renderer:
|
|
146
|
+
|
|
147
|
+
* `render(props)` → returns a React element
|
|
148
|
+
* `props` passed to `render()` are **defaults**
|
|
149
|
+
* `hostProps` are **priority** (override collisions)
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import React from "react";
|
|
153
|
+
import * as JsxRuntime from "react/jsx-runtime";
|
|
154
|
+
|
|
155
|
+
import { createFactory } from "fortiplugin-bundle-adapter/runtime/create-factory";
|
|
156
|
+
|
|
157
|
+
const render = await createFactory(
|
|
158
|
+
"/build/plugins/foo.entry.mjs",
|
|
159
|
+
{
|
|
160
|
+
react: React,
|
|
161
|
+
jsxRuntime: JsxRuntime,
|
|
162
|
+
|
|
163
|
+
// optional: already-available host modules
|
|
164
|
+
imports: {
|
|
165
|
+
// "@host/ui": HostUI,
|
|
166
|
+
// "@inertiajs/core": InertiaCore,
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
// optional: dev-mode host bundles by CORS-safe URL
|
|
170
|
+
hostUrls: {
|
|
171
|
+
// "@host/ui": "https://host.example.com/forti/dev/exports/ui.mjs",
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
exportName: "default",
|
|
176
|
+
mode: "auto",
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
accountId: 123, // PRIORITY host props
|
|
180
|
+
}
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
// render() props are defaults; host props override collisions
|
|
184
|
+
const element = render({ title: "Dashboard" });
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### `createPluginResolver({ env, options, hostProps })`
|
|
188
|
+
|
|
189
|
+
In real hosts, you don’t want to pass `env` everywhere. Instead, create a resolver once and reuse it.
|
|
190
|
+
|
|
191
|
+
A resolver bundles your defaults (React/JSX runtime, import map, dev URLs, base host props) and exposes:
|
|
192
|
+
|
|
193
|
+
* `resolver.resolve(file, overrides?)` → returns a prepared renderer (same shape as `createFactory`)
|
|
194
|
+
* `resolver.with(overrides)` → creates a new resolver layered on top (great for “with inertia”, “with ui”, etc.)
|
|
195
|
+
* `resolver.Embed` → a React component bound to the resolver (you only pass `file` + props)
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import React from "react";
|
|
199
|
+
import * as JsxRuntime from "react/jsx-runtime";
|
|
200
|
+
|
|
201
|
+
import { createPluginResolver } from "fortiplugin-bundle-adapter/runtime/create-resolver";
|
|
202
|
+
|
|
203
|
+
export const resolvePlugin = createPluginResolver({
|
|
204
|
+
env: {
|
|
205
|
+
react: React,
|
|
206
|
+
jsxRuntime: JsxRuntime,
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
// base PRIORITY props applied to every plugin render
|
|
210
|
+
hostProps: {
|
|
211
|
+
// accountId, permissions, pluginMeta, etc.
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
#### Add optional deps once (Inertia / Host UI)
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
import * as InertiaCore from "@inertiajs/core";
|
|
220
|
+
import * as HostUI from "./host-ui";
|
|
221
|
+
|
|
222
|
+
export const resolvePluginWithInertia = resolvePlugin.with({
|
|
223
|
+
env: {
|
|
224
|
+
imports: {
|
|
225
|
+
"@inertiajs/core": InertiaCore,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
export const resolvePluginWithUI = resolvePluginWithInertia.with({
|
|
231
|
+
env: {
|
|
232
|
+
imports: {
|
|
233
|
+
"@host/ui": HostUI,
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### Dev-mode: load host bundles by URL
|
|
240
|
+
|
|
241
|
+
```ts
|
|
242
|
+
export const resolvePluginDev = resolvePlugin.with({
|
|
243
|
+
env: {
|
|
244
|
+
hostUrls: {
|
|
245
|
+
"@host/ui": "https://host.example.com/forti/dev/exports/ui.mjs",
|
|
246
|
+
},
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
#### Use the resolver everywhere
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
const render = await resolvePluginWithUI.resolve("/build/plugins/foo.entry.mjs", {
|
|
255
|
+
hostProps: { accountId: 123 }, // per-call PRIORITY props
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// defaults + host override
|
|
259
|
+
const element = render({ title: "Dashboard" });
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
#### Use the bound React component
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
const Embed = resolvePluginWithUI.Embed;
|
|
266
|
+
|
|
267
|
+
<Embed
|
|
268
|
+
file="/build/plugins/foo.entry.mjs"
|
|
269
|
+
props={{ title: "Dashboard" }}
|
|
270
|
+
hostProps={{ accountId: 123 }}
|
|
271
|
+
fallback={<div>Loading…</div>}
|
|
272
|
+
/>;
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
131
277
|
## Configuration
|
|
132
278
|
|
|
133
279
|
### `injectedIds?: string[]`
|
|
@@ -327,24 +473,24 @@ const outFile = resolve(process.cwd(), process.argv[3] ?? "tests/fixture-output.
|
|
|
327
473
|
const input = readFileSync(inputFile, "utf-8");
|
|
328
474
|
|
|
329
475
|
const result = transformSync(input, {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
476
|
+
filename: inputFile,
|
|
477
|
+
sourceType: "module",
|
|
478
|
+
plugins: [
|
|
479
|
+
[
|
|
480
|
+
fortiPrepTransform,
|
|
481
|
+
{
|
|
482
|
+
injectedIds: ["react", "react/jsx-runtime"],
|
|
483
|
+
injectedPrefixes: ["@inertiajs/", "@host/"],
|
|
484
|
+
runtimeKey: "imports",
|
|
485
|
+
depsParam: "deps",
|
|
486
|
+
},
|
|
487
|
+
],
|
|
341
488
|
],
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
},
|
|
489
|
+
generatorOpts: {
|
|
490
|
+
compact: false,
|
|
491
|
+
comments: true,
|
|
492
|
+
retainLines: false,
|
|
493
|
+
},
|
|
348
494
|
});
|
|
349
495
|
|
|
350
496
|
if (!result?.code) throw new Error("No output produced");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fortiplugin-bundle-adapter",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist"
|
|
@@ -22,22 +22,37 @@
|
|
|
22
22
|
"typecheck": "tsc -p tsconfig.json",
|
|
23
23
|
"test:transform": "node tests/run-transform.mjs",
|
|
24
24
|
"prepublishOnly": "npm run build",
|
|
25
|
-
"
|
|
25
|
+
"postpublish": "npm version patch && git push origin --follow-tags"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@babel/core": "^7.28.5",
|
|
29
29
|
"@babel/types": "^7.28.5"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
|
-
"
|
|
32
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
33
|
+
"rollup": "^4.0.0",
|
|
34
|
+
"vite": "^5.0.0 || ^6.0.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"vite": {
|
|
38
|
+
"optional": true
|
|
39
|
+
},
|
|
40
|
+
"rollup": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
43
|
+
"react": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
33
46
|
},
|
|
34
47
|
"devDependencies": {
|
|
35
48
|
"@types/babel__core": "^7.20.5",
|
|
36
49
|
"@types/node": "^25.0.3",
|
|
50
|
+
"@types/react": "^19.2.7",
|
|
37
51
|
"react": "^19.2.3",
|
|
38
52
|
"rollup": "^4.55.1",
|
|
39
53
|
"tsup": "^8.5.1",
|
|
40
|
-
"typescript": "^5.9.3"
|
|
54
|
+
"typescript": "^5.9.3",
|
|
55
|
+
"vite": "^6"
|
|
41
56
|
},
|
|
42
57
|
"repository": {
|
|
43
58
|
"type": "git",
|