@fluid-app/fluid-cli-theme-dev 0.1.25 → 0.1.26
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.
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: template-stylesheet-to-asset-migration
|
|
3
|
+
description: |
|
|
4
|
+
Migrates per-template `styles.css` files in a local Fluid theme repo to theme-level
|
|
5
|
+
assets (`assets/*.css`) referenced explicitly from each template's `index.liquid`. Use
|
|
6
|
+
when a `fluid theme push` warned that `styles.css` files were skipped because their
|
|
7
|
+
remote template is `stylesheet_tag_injected`, when a `fluid theme push` failed with 422
|
|
8
|
+
because the backing company has `STYLESHEET_STRICT_INPUT` on, or when the user is
|
|
9
|
+
proactively bringing an older theme repo onto the new asset-based stylesheet shape.
|
|
10
|
+
The skill walks the repo one template at a time — moves the CSS bytes, chooses inline
|
|
11
|
+
vs external emission based on size, updates `index.liquid`, and pushes. Never pushes
|
|
12
|
+
without explicit approval.
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Template Stylesheet → Theme-Level Asset Migration
|
|
16
|
+
|
|
17
|
+
## Why this migration exists
|
|
18
|
+
|
|
19
|
+
Fluid used to inject each template's `stylesheet` column into the rendered HTML as an inline `<style>` block on every request. That bloated HTML, defeated browser and CDN caching, and made stylesheets impossible to author independently of Liquid. The new model:
|
|
20
|
+
|
|
21
|
+
- Each template's CSS lives in a **theme-level `FileResource`** — a real asset under `assets/` in the theme repo, cacheable, editable independently.
|
|
22
|
+
- The template's `index.liquid` **explicitly references** the asset via a Liquid tag:
|
|
23
|
+
|
|
24
|
+
```liquid
|
|
25
|
+
{{ 'template-<themeable_type>-<name>.css' | asset_url | stylesheet_tag }}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
- Once a template has been migrated (backend marker `stylesheet_tag_injected: true`), the CLI **skips** any local `<themeable_type>/<name>/styles.css` on push and prints a warning listing the skipped files. Under the `STYLESHEET_STRICT_INPUT` company feature flag, the API also rejects the field with 422 for any caller that still sends it.
|
|
29
|
+
|
|
30
|
+
The migration is one-way: legacy `styles.css` → asset. Once the flag flips on for a company, legacy `styles.css` pushes just fail.
|
|
31
|
+
|
|
32
|
+
## When to use this skill
|
|
33
|
+
|
|
34
|
+
- `fluid theme push` printed a "Skipped N per-template styles.css file(s)…" warning — the remote templates are already migrated and the local files are dead weight.
|
|
35
|
+
- `fluid theme push` returned 422 with "The `stylesheet` field is no longer accepted" — the company has `STYLESHEET_STRICT_INPUT` on and the remote template hasn't been migrated locally yet.
|
|
36
|
+
- The user is bringing a theme repo from before the migration and wants to prep it for the new shape.
|
|
37
|
+
- The user is packaging a `.zip` for import and the target company is flagged.
|
|
38
|
+
|
|
39
|
+
**Do not use** when the theme is entirely made of `layouts/`, `locales/`, `config/`, or `mysite/` templates — those never had per-template stylesheets. Only `<themeable_type>/<name>/styles.css` files are in scope.
|
|
40
|
+
|
|
41
|
+
## Boundaries
|
|
42
|
+
|
|
43
|
+
- Every mutation is a **local file edit**. This skill never pushes, never calls the API, never asks whether to push. When the sweep finishes, hand the repo back to the user.
|
|
44
|
+
- Preserve the CSS bytes exactly (byte-for-byte) — this migration is a **reshape**, not a rewrite. Refactoring CSS is a separate concern.
|
|
45
|
+
- Don't touch mysite templates. Their render path is different and they still use the column.
|
|
46
|
+
|
|
47
|
+
## Workflow
|
|
48
|
+
|
|
49
|
+
Work one template at a time. For each `<themeable_type>/<name>/styles.css` under the theme root:
|
|
50
|
+
|
|
51
|
+
1. **Read** the two files that make up the migration source:
|
|
52
|
+
- `<themeable_type>/<name>/index.liquid` — needs the Liquid reference prepended.
|
|
53
|
+
- `<themeable_type>/<name>/styles.css` — the CSS bytes to move.
|
|
54
|
+
2. **Decide** how to reference the CSS (inline vs external — see the "Choosing emission" section).
|
|
55
|
+
3. **Move** the CSS bytes into `assets/` under a deterministic name.
|
|
56
|
+
4. **Update** `index.liquid` — insert the Liquid tag at the **top** of the file (see "Placement" below).
|
|
57
|
+
5. **Delete** the old `<themeable_type>/<name>/styles.css`.
|
|
58
|
+
6. **Validate** with `fluid theme lint --json` — parse the JSON, fix what it flags, re-run until clean.
|
|
59
|
+
7. **Preview** — if a local dev server is running (`fluid theme dev`), reload the corresponding page and visually confirm the stylesheet still applies.
|
|
60
|
+
|
|
61
|
+
Sweep through every `<themeable_type>/<name>/styles.css` in the repo. When they're all migrated, hand back to the user. Pushing / verifying / deploying is out of scope for this skill — it only reshapes the local files.
|
|
62
|
+
|
|
63
|
+
## Filename convention
|
|
64
|
+
|
|
65
|
+
Local files have no template ids — those exist only on the remote. Pick a short kebab-case name that mirrors the template's folder path so the intent is obvious to whoever reads the theme next:
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
template-<themeable_type>-<name>.css
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
- `<themeable_type>`: singular type folder name — `product`, `sections`, `page`, etc.
|
|
72
|
+
- `<name>`: template folder name — `default`, `hero`, whatever the folder is called under the type folder.
|
|
73
|
+
|
|
74
|
+
Any short, unambiguous filename works. The reference in `index.liquid` is the only pointer, so it can be renamed later without breaking anything else. Just make sure two different templates don't collide on the same asset name.
|
|
75
|
+
|
|
76
|
+
## Choosing emission — external vs inline
|
|
77
|
+
|
|
78
|
+
The backend's own auto-migration used a **2 KB threshold**:
|
|
79
|
+
|
|
80
|
+
- **≤ 2 KB CSS** → inline via `inline_asset_content` (renders as `<style>…</style>` at request time). Keeps critical single-component CSS fast without an extra HTTP round trip.
|
|
81
|
+
- **> 2 KB CSS** → external via `asset_url | stylesheet_tag` (renders as `<link rel="stylesheet" href="…">`). Cacheable by browser and CDN.
|
|
82
|
+
|
|
83
|
+
Use the same threshold for consistency with existing migrated templates. Check the size with `wc -c < path/to/styles.css` (bytes).
|
|
84
|
+
|
|
85
|
+
### External `<link>` (default for larger CSS)
|
|
86
|
+
|
|
87
|
+
```liquid
|
|
88
|
+
{{ 'template-product-default.css' | asset_url | stylesheet_tag }}
|
|
89
|
+
|
|
90
|
+
<div class="product">
|
|
91
|
+
<!-- template body -->
|
|
92
|
+
</div>
|
|
93
|
+
|
|
94
|
+
{% schema %}
|
|
95
|
+
{ "name": "Product" }
|
|
96
|
+
{% endschema %}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Inline `<style>` (small critical CSS)
|
|
100
|
+
|
|
101
|
+
```liquid
|
|
102
|
+
{{ 'template-product-default.css' | inline_asset_content }}
|
|
103
|
+
|
|
104
|
+
<div class="product">
|
|
105
|
+
<!-- template body -->
|
|
106
|
+
</div>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Both filters are Shopify-compat. `inline_asset_content` fetches the FR content at render time and wraps it in `<style>` — the CSS bytes are **not** baked into `content`, so a later CSS edit still flows through the normal asset update path.
|
|
110
|
+
|
|
111
|
+
## Placement
|
|
112
|
+
|
|
113
|
+
Prepend the tag at the **top** of `index.liquid`. Never append at the end.
|
|
114
|
+
|
|
115
|
+
- Templates that end with a `{% schema %}` block don't render anything after `{% endschema %}`, so appending would put the tag in dead space.
|
|
116
|
+
- Prepending is uniform whether or not the template has a schema block.
|
|
117
|
+
- Cascade impact is intentional: inline `<style>` blocks or later template-body CSS override the theme-level stylesheet on equal specificity — which is what theme authors typically expect.
|
|
118
|
+
|
|
119
|
+
## Worked example
|
|
120
|
+
|
|
121
|
+
Starting state — `product/default/`:
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
product/default/
|
|
125
|
+
├── index.liquid ← <h1>Product</h1>… (no stylesheet reference yet)
|
|
126
|
+
├── styles.css ← 780 bytes of CSS
|
|
127
|
+
└── variables.json
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`wc -c` says 780 bytes → below the 2 KB threshold → inline.
|
|
131
|
+
|
|
132
|
+
**Step 1 — move the file:**
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
mv product/default/styles.css assets/template-product-default.css
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Step 2 — edit `product/default/index.liquid`, prepend the tag:**
|
|
139
|
+
|
|
140
|
+
```liquid
|
|
141
|
+
{{ 'template-product-default.css' | inline_asset_content }}
|
|
142
|
+
<h1>Product</h1>
|
|
143
|
+
<!-- rest of body -->
|
|
144
|
+
{% schema %}
|
|
145
|
+
{ "name": "Product" }
|
|
146
|
+
{% endschema %}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Step 3 — lint:**
|
|
150
|
+
|
|
151
|
+
```
|
|
152
|
+
fluid theme lint --json
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Parse the JSON, fix any issues, re-run until clean.
|
|
156
|
+
|
|
157
|
+
**Step 4 — dev-server sanity check:**
|
|
158
|
+
|
|
159
|
+
If `fluid theme dev` is running, refresh the product page in the browser. Confirm the stylesheet is emitted (either as inline `<style>` or `<link>` per your emission choice) and the layout looks the same.
|
|
160
|
+
|
|
161
|
+
Move on to the next `<themeable_type>/<name>/styles.css`.
|
|
162
|
+
|
|
163
|
+
## Skip conditions
|
|
164
|
+
|
|
165
|
+
Skip these templates entirely:
|
|
166
|
+
|
|
167
|
+
- **`mysite/*/styles.css`** — mysite render path is separate; column stays as-is.
|
|
168
|
+
- **`layouts/*.liquid`**, **`locales/*.json`**, **`config/*.json`** — never had per-template CSS.
|
|
169
|
+
- **Templates whose local `index.liquid` already contains `asset_url | stylesheet_tag` or `inline_asset_content`** — they've already been migrated once. The `<themeable_type>/<name>/styles.css` file that lingers next to them is a leftover, **but do not delete it blindly**: a theme author who missed the memo may have edited it after the migration and now has real work sitting in that file. Read the local `styles.css` and the corresponding `assets/template-*.css` (the filename referenced by the injected Liquid tag). If they're byte-identical, delete the leftover — no data at risk. If they differ, stop, show the user the diff, and ask what to keep — merging into the asset, discarding the leftover, or replacing the asset. Never silently discard bytes.
|
|
170
|
+
|
|
171
|
+
## What good looks like after the migration
|
|
172
|
+
|
|
173
|
+
Run `find . -path ./assets -prune -o -name styles.css -print` — the only match should be the theme-root `styles.css` (the theme-level "custom" stylesheet). No per-template `styles.css` files remain.
|
|
174
|
+
|
|
175
|
+
Run `ls assets/template-*.css` — every template that used to have CSS is now represented as an asset.
|
|
176
|
+
|
|
177
|
+
Every migrated template's `index.liquid` starts with a `{{ 'template-*.css' | ... }}` expression.
|
|
178
|
+
|
|
179
|
+
`fluid theme lint --json` is clean.
|
|
180
|
+
|
|
181
|
+
`fluid theme push` reports no "Skipped … styles.css" warning and no 422.
|
|
182
|
+
|
|
183
|
+
## Anti-patterns
|
|
184
|
+
|
|
185
|
+
- **Appending the tag at the end of `index.liquid`.** Dead space after `{% schema %}`. Always prepend.
|
|
186
|
+
- **Refactoring the CSS while migrating.** Two changes at once — hard to review, easy to break. Do the byte-for-byte move first, refactor later in its own commit.
|
|
187
|
+
- **Skipping the lint step.** The validator catches missing assets, dangling Liquid expressions, and other easy misses.
|
|
188
|
+
- **Pushing from within this skill.** Not this skill's job. Hand the reshaped repo back to the user; they decide when to push.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluid-app/fluid-cli-theme-dev",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "Fluid CLI plugin for theme developer workflows — dev server, push, pull, init",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"open": "^10.0.0",
|
|
28
28
|
"ora": "^8.0.0",
|
|
29
29
|
"prompts": "^2.4.2",
|
|
30
|
-
"@fluid-app/fluid-cli": "0.1.
|
|
30
|
+
"@fluid-app/fluid-cli": "0.1.12"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@swc/core": "^1.15.18",
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"tsdown": "^0.21.0",
|
|
40
40
|
"typescript": "^5",
|
|
41
41
|
"@fluid-app/api-client-core": "0.1.0",
|
|
42
|
+
"@fluid-app/typescript-config": "0.0.0",
|
|
42
43
|
"@fluid-app/theme-schema": "0.1.0",
|
|
43
|
-
"@fluid-app/themes-api-client": "0.1.0"
|
|
44
|
-
"@fluid-app/typescript-config": "0.0.0"
|
|
44
|
+
"@fluid-app/themes-api-client": "0.1.0"
|
|
45
45
|
},
|
|
46
46
|
"engines": {
|
|
47
47
|
"node": ">=18.0.0"
|