znode-plugin 0.1.6 → 0.1.8
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 +114 -5
- package/lib/znode-package.mjs +1444 -1083
- package/package.json +6 -1
package/README.md
CHANGED
|
@@ -217,9 +217,113 @@ export default function setup(host: IBrowserHost): IBrowserPlugin {
|
|
|
217
217
|
}
|
|
218
218
|
```
|
|
219
219
|
|
|
220
|
-
**
|
|
221
|
-
|
|
222
|
-
|
|
220
|
+
**Which slots are there?** Ask the store you are linked to; the list is read from its source, so it is always current:
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
npx znode slot list # every slot
|
|
224
|
+
npx znode slots product # only the ones matching "product"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
```
|
|
228
|
+
Slot Side Hands over Store component Eject In this package
|
|
229
|
+
------------------ ------- ---------- ---------------- ---------------- ---------------
|
|
230
|
+
product.basicInfo browser yes ProductBasicInfo ProductBasicInfo yes
|
|
231
|
+
product.card browser yes ProductCard ProductCard
|
|
232
|
+
product.layout browser no ProductBasicInfo -
|
|
233
|
+
layout.root server yes app/layout - yes
|
|
234
|
+
...
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
- **Side**: `browser` slots go in `src/browser.tsx` (`slots`), `server` slots in `src/server.tsx` (`serverSlots`).
|
|
238
|
+
- **Hands over**: `yes` = your component gets the store's rendering as `children` (keep, wrap or replace it); `no` = it
|
|
239
|
+
adds or lays out (e.g. `product.layout` moves the store's parts into your structure).
|
|
240
|
+
- **Eject**: the store component you can copy into your package (next section). **In this package**: you already fill it.
|
|
241
|
+
|
|
242
|
+
### Take over a whole store component (eject)
|
|
243
|
+
|
|
244
|
+
When a slot is not enough and you want to change the component itself (its markup, its logic), copy it into your
|
|
245
|
+
package. The store then renders your copy in its place; everything else stays the store's.
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
npx znode eject ProductBasicInfo # or by its slot: npx znode eject product.basicInfo
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
It copies the store's file to `src/components/ProductBasicInfo.tsx` (imports turned into the store's `@znode/...`
|
|
252
|
+
aliases), registers it in `src/browser.tsx` under its slot, and prints any npm package the copy needs
|
|
253
|
+
(`npm install zustand@4.5.5`). Edit the copy, then `npm run build` and `npm run dev`. The copy is yours: store fixes to
|
|
254
|
+
the component no longer reach it, so compare it with the store's file after a store upgrade. `npx znode eject` with no
|
|
255
|
+
name lists what can be ejected.
|
|
256
|
+
|
|
257
|
+
**The component has no slot yet?** `eject` offers to create one in the **base store** (the store you linked), then ejects:
|
|
258
|
+
|
|
259
|
+
```
|
|
260
|
+
$ npx znode eject ProductDetailsPage
|
|
261
|
+
ProductDetailsPage has no slot yet, so it cannot be ejected.
|
|
262
|
+
Create a slot for ProductDetailsPage in the base store now? [y/N] y
|
|
263
|
+
Slot name (area.name) [product.detailsPage]: product.details
|
|
264
|
+
creating slot "product.details" around ProductDetailsPage (packages/base-components/src/...) ...
|
|
265
|
+
ejected ProductDetailsPage -> src/components/ProductDetailsPage.tsx
|
|
266
|
+
registered "product.details": EjectedProductDetailsPage in src/browser.tsx
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Creating a slot edits the base store's **source** (a `Runtime<Component>` wrapper in
|
|
270
|
+
`packages/extensions/src/slots/RuntimeCreatedSlots.tsx`, the component's export wrapped with `withRuntimeWrapper`, the
|
|
271
|
+
slot added to the store's slot list and docs). It never touches `.next` and commits nothing. Before the store renders
|
|
272
|
+
your copy: review the diff in the store repo (`git diff`), commit it there through the store's own flow (it changes base
|
|
273
|
+
components, so it is reviewed like any base change), and rebuild / restart the webstore.
|
|
274
|
+
|
|
275
|
+
- In a script or CI (no questions): `npx znode eject ProductDetailsPage --slot product.details`.
|
|
276
|
+
- Only the slot, no copy: `npx znode create-slot ProductDetailsPage product.details`; add `--dry-run` first to see
|
|
277
|
+
exactly which store files and lines it would change, without writing anything.
|
|
278
|
+
- A server **component** inside base-components cannot get a slot (a browser slot is filled in the browser): it refuses
|
|
279
|
+
an `async` component or one that imports `server-only` / `next/headers` / `fs`, and says to use a client component it
|
|
280
|
+
renders instead, e.g. `ProductDetails` is a server component, so take over `ProductBasicInfo` or `ProductDetailsPage`.
|
|
281
|
+
|
|
282
|
+
### Take over a whole store page
|
|
283
|
+
|
|
284
|
+
A store **page** (a route, `apps/webstore/src/app/**/page.tsx`) runs on the server, so it gets a **server slot** around
|
|
285
|
+
its content. Use the page's component name (its `export default function <Name>`):
|
|
286
|
+
|
|
287
|
+
```
|
|
288
|
+
$ npx znode eject ForgotPasswordPage
|
|
289
|
+
ForgotPasswordPage has no slot yet, so it cannot be ejected.
|
|
290
|
+
Create a slot for ForgotPasswordPage in the base store now? [y/N] y
|
|
291
|
+
Slot name (area.name) [forgotPassword.page]:
|
|
292
|
+
creating slot "forgotPassword.page" around ForgotPasswordPage (apps/webstore/src/app/[locale]/forgot-password/page.tsx) ...
|
|
293
|
+
ejected ForgotPasswordPage (server slot "forgotPassword.page") -> src/server/pages/ForgotPasswordPage.tsx
|
|
294
|
+
registered "forgotPassword.page": EjectedForgotPasswordPage in src/server.tsx (serverSlots)
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
In the store, the page's content is wrapped (inside its `NextIntlClientProvider`, so the page's texts still reach it):
|
|
298
|
+
|
|
299
|
+
```tsx
|
|
300
|
+
<NextIntlClientProvider messages={...}>
|
|
301
|
+
<RuntimeServerSlot name="forgotPassword.page">
|
|
302
|
+
<ForgotPassword />
|
|
303
|
+
</RuntimeServerSlot>
|
|
304
|
+
</NextIntlClientProvider>
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
In your package you get a server component to build the page in. `children` is the store's page content:
|
|
308
|
+
|
|
309
|
+
```tsx
|
|
310
|
+
// src/server/pages/ForgotPasswordPage.tsx
|
|
311
|
+
export async function ForgotPasswordPage(props: { children?: ReactNode }, context: IServerSlotContext) {
|
|
312
|
+
return (
|
|
313
|
+
<div className="my-forgot-page">
|
|
314
|
+
<h1>Reset your password</h1>
|
|
315
|
+
<aside>Help text, images, data fetched here (async is fine)</aside>
|
|
316
|
+
{props.children /* the store's form; leave it out to render a page of your own */}
|
|
317
|
+
</div>
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
- It is not a copy of the route: the route's server code (agents, `getResourceMessages`, data) stays the store's. Your
|
|
323
|
+
component runs on the server only (async, no hooks): put interactive parts in a browser slot, e.g. change the form
|
|
324
|
+
itself with `npx znode eject ForgotPassword` (slot `account.forgotPassword`).
|
|
325
|
+
- A page that already has a server slot (`login.page`, `layout.root`) is ejected straight away (`npx znode eject LoginPage`).
|
|
326
|
+
- Only the slot: `npx znode create-slot ForgotPasswordPage forgotPassword.page` (`--dry-run` to preview).
|
|
223
327
|
|
|
224
328
|
### Add a page-builder widget
|
|
225
329
|
|
|
@@ -291,9 +395,10 @@ Run them with `npm run <name>` inside a project (the scripts call `znode … .`)
|
|
|
291
395
|
| `npm run link-store -- <store repo>` | `znode link-store <repo> .` | connect the store's types |
|
|
292
396
|
| | `npx znode install <zip> [pluginsDir]` | install a released zip into a store's plugin folder |
|
|
293
397
|
| | `npx znode create <theme\|plugin\|widget\|content> <name>` | a minimal starter of another kind |
|
|
398
|
+
| | `npx znode slot list [<filter>] [--json]` | every slot the linked store renders, read from its source: browser or server side, whether it hands over what the store renders there (children: keep, wrap or replace it) or only adds / lays out, the store component it is around, what `eject` can copy into it, and whether this package already fills it. `npx znode slots` is the same; a filter matches slot or component names (`npx znode slots product`) |
|
|
294
399
|
| | `npx znode eject` | list the store components a package can take over (each has a slot that hands the component over) |
|
|
295
|
-
| | `npx znode
|
|
296
|
-
| | `npx znode eject <Name> [--force]` | `<Name>` is the component or its slot (`ProductBasicInfo` or `product.basicInfo`). Copy the store's component into `src/components/<Name>.tsx` (imports turned into store aliases, runtime wrapper removed) and register it in `src/browser.tsx` under its slot; prints any npm package the copy needs. The copy is yours: store fixes no longer reach it |
|
|
400
|
+
| | `npx znode create-slot <Component> <area.name> [--dry-run] [--file <store file>]` | create a slot around a store component that has none, in the **base store's source** (the linked store, not the theme, never `.next`): a `Runtime<Component>` wrapper in `packages/extensions/src/slots/RuntimeCreatedSlots.tsx`, the component's export wrapped with `withRuntimeWrapper`, the slot added to the store's slot list and docs, the module registry regenerated. Refuses server components inside base-components (`async`, server-only imports): a browser slot is filled in the browser. For a **route page** (`<Component>` is its `export default function`, e.g. `ForgotPasswordPage`) it puts a **server slot** (`<RuntimeServerSlot>`) around the page's content instead, filled in `src/server.tsx` (`serverSlots`). Nothing is committed: review the diff in the store, commit it there, rebuild the webstore, then `npx znode eject <Component>`. `create slot` (with a space) works too; `add-slot` (0.1.6) still works |
|
|
401
|
+
| | `npx znode eject <Name> [--force] [--slot <area.name>] [--yes]` | `<Name>` is the component or its slot (`ProductBasicInfo` or `product.basicInfo`). Copy the store's component into `src/components/<Name>.tsx` (imports turned into store aliases, runtime wrapper removed) and register it in `src/browser.tsx` under its slot; prints any npm package the copy needs. The copy is yours: store fixes no longer reach it. **No slot yet?** It asks whether to create one in the base store and for its name (suggested from the component, e.g. `ProductDetailsPage` → `product.detailsPage`), does what `create-slot` does, then ejects. `--slot <area.name>` creates it without asking (for scripts / CI); `--yes` skips the confirm only |
|
|
297
402
|
|
|
298
403
|
The plugin folder is taken from: the command's argument, else the `RUNTIME_PLUGINS_DIR` environment variable, else
|
|
299
404
|
`znode.local.json`.
|
|
@@ -371,6 +476,10 @@ folder after an upgrade; delete them by hand if you need the space.
|
|
|
371
476
|
| `installed …` but still no change | the package went to another plugin folder than the running webstore reads: compare `znode.local.json` with the webstore's `RUNTIME_PLUGINS_DIR` (`apps/webstore/.env.local` or `.env`) |
|
|
372
477
|
| `MISSING_MESSAGE` for your label | put browser labels under a namespace the page sends, e.g. `Common` |
|
|
373
478
|
| Theme shows for you but not shoppers | expected: enable it in `plugins.json` (step 7) |
|
|
479
|
+
| `<Name> cannot be ejected` | run it in a terminal and answer `y` to create the slot, or `npx znode eject <Name> --slot <area.name>`; `npx znode slot list` shows what exists |
|
|
480
|
+
| `<Name> is an async server component` | a component inside base-components cannot get a slot: eject a client component it renders instead, or the route page it is on (`npx znode eject <Name>Page`) |
|
|
481
|
+
| `no <Name> found` | use the component's name, or for a page its `export default function <Name>` (e.g. `ForgotPasswordPage`, not the URL); `npx znode slot list` shows what exists |
|
|
482
|
+
| Ejected / new slot but the store still shows its own | the slot was created in the store's source: commit it there and rebuild / restart the webstore; check `npx znode slot list` shows it with **In this package** `yes` |
|
|
374
483
|
|
|
375
484
|
---
|
|
376
485
|
|