Develop and publish
The developer loop for a Feeef theme — edit, preview a draft on the real shop, then publish a release and decide when customers see it.
This is the loop I use after the folder exists. The first-time scaffold is Create a template. This page is what happens every day after that: develop against a draft, then publish a release.
Helium drafts use {slug}.h.feeef.store; Lithium drafts use {slug}.feeef.store.
For Helium, review the runtime and
hydration contract alongside this release workflow.
Two documents live on the store. They are easy to mix up, and mixing them up is how a half-finished hero reaches a customer.
| Draft | Live | |
|---|---|---|
| Command | npm run dev | npm run publish -- --apply |
| Field | metadata.templatePreview | metadata.templateData |
| Who sees it | You, with the preview cookie | Customers |
npm run dev never writes the live document. Publish uploads a listing and a release.
Customers see that release only when something installs it. From the CLI, that install
is --apply.
Develop
Edit pages/, shared/, library/, locales/, and schema.ts. Then:
npm run check # validate, write nothing
npm test # smoke: render every App()
npm run dev # watch, rebuild, upload the draft, open ?preview=check is the fast one. Smoke catches a component that throws while rendering. Neither
replaces clicking the draft: home, a product, checkout. The products and prices are the
store's real catalog.
The preview URL sets an httpOnly feeef_preview cookie for 24 hours, so the next pages
stay on the draft. Leave with the banner, /?preview=0, or by stopping the CLI. Stopping
the CLI clears the draft blob.
The CLI and shop must read the same API. The CLI defaults to alpha; for a production store select the production API and sign in again:
feeef config set apiUrl https://api.feeef.org/v1
feeef signinA few authoring facts I keep relearning:
schema.tspagesdefines the editor page list. A new folder underpages/also needs an entry there, or the editor will not offer the page.feeef template add pageupdatesfeeef.template.jsononly. It does not editschema.ts.propsis merchant content.codeandpropsSchemasit besideprops, not inside it.library/components/is the drag-drop catalog. A library file is not on a page until someone inserts it.- Hand-editing
dist/data.jsonis wasted work. The next build overwrites it.
The blank product page is already a slotted order form. Field visibility and order are props on those nodes. The worked example is on the create guide.
Publish
feeef template publish builds again, then uploads. You do not have to run npm run build
first. npm run publish is the same command, and npm needs -- before CLI flags:
npm run publish -- --no-applyWhat one publish writes:
| Target | What lands there |
|---|---|
template_components | shared/, library/, and each unique page-level custom body |
store_templates | The listing: title, policy, price, head schema and data |
store_template_releases | An immutable semver snapshot and the changelog |
store_template_locales | dist/locales/*.json |
Page-level customs are uploaded too, then the document stored on the listing points at
them with type: "reference". That is why a missing slotsSchema on a shell makes the
shop render an empty slot: the registry never receives the holes.
Locales are stripped out of the template document and stored as their own rows. The shop
still speaks Arabic and English. The strings just do not ride inside templateData.
When customers see it
| Invocation | Listing and release | Live shop |
|---|---|---|
npm run publish | Updated | Asks. Enter means no. |
npm run publish -- --apply | Updated | Installed. Customers see it. |
npm run publish -- --no-apply | Updated | Unchanged |
npm run publish -- --yes | Updated, no questions | Unchanged |
npm run publish -- --yes --apply | Updated, no questions | Installed |
--yes means "do not ask me." It does not mean "install." I have published a changelog
while the draft was still wrong, so the install stays a separate flag.
If your installed CLI still highlights yes on that question, update @feeef.dev/cli.
Older builds treated Enter as install.
Who can see the listing
| Flag | Policy |
|---|---|
| (none) | private. Your store. Not in the public browse. |
--public | Anyone can find it. Free unless you set --price. |
--unlisted | Reachable with the link, not listed in browse. |
--price 5000 | One-time price in DZD. 0 is free. The platform takes a cut on a sale. |
--version 1.2.0 | Release semver. Omit it and the CLI bumps the patch. |
--changelog "RTL on the form" | Shown to merchants on Update. |
--title "My theme" | Listing title. Default is the manifest name or the folder name. |
# private release, live on your store
npm run publish -- --apply
# free public listing, do not touch the live shop yet
npm run publish -- --public --no-apply
# paid public listing and install
feeef template publish --public --price 5000 --version 1.0.0 \
--changelog "First release" --applyA public or paid release can die in the security scan. The scan reads the custom function bodies. When it fails, that release does not exist. Fix the component the error names. The listing update may already have happened; the release is the part that stopped.
Paid themes cannot be unpacked with feeef template init --from. Merchants buy and
install them from the app. Free public themes can be unpacked, and their library
references are inlined so the folder stands alone.
After it is live
The merchant editor can still change props, slots, and layout children on the
installed document. Your next npm run publish -- --apply installs the new release
over that document. Say so in the changelog when the update will move blocks they
rearranged.
Cover, screenshots, category, and the long description are listing fields. Publish
sends title, policy, price, schema, and data. The rest is a later edit on the listing,
from the merchant app or PATCH /store_templates/:id. Details are in
Marketplace.
A demo link can preview a release without installing it:
https://{slug}.feeef.store/?templateId={listingId}&templateRelease={releaseId}Exit with /?templateRelease=0. That is a different cookie from draft preview.
When something looks wrong
| What you see | What it usually is |
|---|---|
| Preview matches the old shop | CLI apiUrl is not the API the shop reads, or the preview cookie is gone |
npm run publish and customers already have it | You passed --apply, or an older CLI treated Enter as yes |
| New page exists on disk and not in the editor | schema.ts pages was not updated |
| A slot on a published shell is empty | The component row was saved without slotsSchema |
| Public publish dies after "Publishing release" | securityScan rejected a custom function |
| Inspector has no fields | propsSchema is missing or nested under props |
Command reference: CLI. First scaffold: Create a template. The same loop, as a note: Develop on a draft.