Skip to content
Back to skills

Ps Css Build

BSecurity

Sets up a modern CSS build pipeline for a PrestaShop child theme: source partials in _dev/css/, lightningcss bundle+minify to a single generated assets/css/custom.css, pnpm 11 with supply-chain hardening, pre-commit hook with zero-dependency Node fallback, and agent/team documentation. Replaces runtime @import chains and manual ?v= cache-bust versioning. Use when scaffolding CSS architecture for a new PS child theme, when a theme has multiple @import'ed CSS partials loaded at runtime, when th...

  • 3 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 23, 2026
developmentgophpbashnodegitapisecuritydocumentation

Works with

  • terminal
  • cli
  • api

Security analysis

B81/100
  • highPerforms destructive filesystem operations
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 23, 2026

npx -y skills add educlopez/mallard --skill ps-css-build --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ps Css Build?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ps Css Build
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/educlopez-ps-css-build/badge)](https://www.skillsdirectory.com/skills/educlopez-ps-css-build)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ps-css-build
description: >
  Sets up a modern CSS build pipeline for a PrestaShop child theme: source
  partials in _dev/css/, lightningcss bundle+minify to a single generated
  assets/css/custom.css, pnpm 11 with supply-chain hardening, pre-commit hook
  with zero-dependency Node fallback, and agent/team documentation. Replaces
  runtime @import chains and manual ?v= cache-bust versioning. Use when
  scaffolding CSS architecture for a new PS child theme, when a theme has
  multiple @import'ed CSS partials loaded at runtime, when the user mentions
  manual CSS version bumps, CSS cache busting problems, "el CSS no se
  actualiza", or wants the Milagros-style CSS build on another project.
version: "0.1.0"
metadata:
  author: Eduardo Calvo
---

# PS CSS Build — pipeline para child themes

Montado y probado en `milagros-colombia-b2b-v9.1` (PS 9.1, child de Panda).
Sustituye: `@import` runtime (N requests encadenados) + bumps manuales `?v=N`
+ hacks tipo `_bust={$smarty.now}` (que anulan caché por completo).

## Resultado final

```
themes/{child}/
├── _dev/
│   ├── README.md            # doc del sistema (plantilla abajo)
│   └── css/
│       ├── custom.css       # entry point: @import de los parciales (SIN ?v=)
│       ├── tokens.css       # :root design tokens
│       ├── base.css
│       ├── components.css
│       ├── utilities.css
│       └── pages/*.css
├── scripts/bundle-css.js    # fallback cero-deps para el hook
├── assets/css/custom.css    # GENERADO — único CSS servido
├── package.json             # pnpm + scripts css/watch
├── pnpm-workspace.yaml      # supply-chain hardening
├── pnpm-lock.yaml
└── .gitignore               # node_modules/
.githooks/pre-commit         # raíz del repo
.gitattributes               # dist marcado generated
```

PS core auto-registra `assets/css/custom.css` como `theme-custom` — mantener
ese path/nombre exacto = cero cambios PHP, tema padre intacto.

## Paso 1 — Mover fuentes

```bash
cd themes/{child}
mkdir -p _dev/css
git mv assets/css/*.css _dev/css/        # parciales + custom.css
git mv assets/css/pages _dev/css/pages   # si existe
```

Limpiar el entry point `_dev/css/custom.css`:
- Quitar todos los `?v=N` de los imports: `sed -i '' -E "s/\.css\?v=[0-9]+'/.css'/g" _dev/css/custom.css`
- **CRÍTICO**: buscar `@import` con URL remota (Google Fonts) en TODOS los
  parciales: `grep -rn "@import url('http" _dev/css/`. lightningcss NO bundlea
  remotas — panic con error críptico `ResolverError NotFound`. Moverlas como
  `<link rel="preconnect">` + `<link rel="stylesheet">` al override
  `templates/_partials/stylesheets.tpl` (mejor perf además: descarga paralela).
- Revisar `url()` relativos en parciales (`grep -rn "url(" _dev/css/ | grep -v @import`).
  Rutas absolutas (`/img/...`) OK; relativas pueden romper al cambiar de nivel.

## Paso 2 — package.json + pnpm hardened

`themes/{child}/package.json`:

```json
{
  "name": "{child}-theme",
  "private": true,
  "packageManager": "pnpm@11.1.2",
  "scripts": {
    "css": "lightningcss --bundle --minify --targets 'defaults' _dev/css/custom.css -o assets/css/custom.css",
    "watch": "chokidar '_dev/css/**/*.css' -c 'pnpm run --silent css' --initial"
  },
  "devDependencies": {
    "chokidar-cli": "^3.0.0",
    "lightningcss-cli": "^1.30.2"
  }
}
```

Pin de versión pnpm **exacta** (la instalada: `pnpm --version`), no `11.x.x`.

`themes/{child}/pnpm-workspace.yaml` (ver skills `supply-chain-security` y
`gitlab-security-setup` para el detalle):

```yaml
allowBuilds:
  lightningcss-cli: true   # único postinstall permitido

minimumReleaseAge: 4320 # 72h quarantine (estándar Cinetic)

blockExoticSubdeps: true # bloquea transitivas git/tarball (pnpm 10.26+)

overrides:
  form-data: ">=4.0.4"
  axios: ">=1.15.2"
  lodash: ">=4.18.0"
  picomatch: ">=4.0.4"
  qs: ">=6.14.2"
```

`themes/{child}/.gitignore`: `node_modules/`

```bash
pnpm install --dir themes/{child}
pnpm --dir themes/{child} run css     # genera el dist
```

**Gotcha**: pnpm 11 bloqueará el postinstall de lightningcss-cli en el primer
install y escribirá un placeholder `allowBuilds: lightningcss-cli: set this to
true or false` en pnpm-workspace.yaml — editarlo a `true` y re-instalar.

**Test real**: `rm -rf node_modules && pnpm install --frozen-lockfile` —
la caché caliente NO aplica las políticas.

## Flujo de desarrollo diario (documentar al usuario)

Mientras se edita CSS, el watcher debe estar corriendo en una terminal:

```bash
pnpm --dir themes/{child} run watch
```

- Guardas un parcial en `_dev/css/` → chokidar dispara lightningcss → dist
  regenerado en ~10ms → recarga del browser y listo.
- `--initial` hace un build al arrancar, así que el dist nunca queda stale
  al empezar la sesión.
- Sin watch corriendo, los cambios en `_dev/css/` NO se ven en el browser
  (el browser carga el dist generado, no los fuentes). Síntoma típico:
  "cambié el CSS y no sale" → watch no estaba corriendo → build puntual:
  `pnpm --dir themes/{child} run css`.
- Combina con la skill `ps-watch` (BrowserSync) para recarga automática del
  browser además del rebuild: chokidar regenera el dist y BrowserSync detecta
  el cambio en `assets/css/` y recarga. Watch + BrowserSync = guardar y ver.

## Paso 3 — Limpiar el tpl

Revisar `templates/_partials/stylesheets.tpl` del child: si tiene hacks de
cache-bust (`?_bust={$smarty.now}`, timestamps), quitarlos — anulan caché en
cada pageview. Si el override solo existía para eso, dejarlo igual que el
padre + el bloque de fonts:

```smarty
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family={...}&display=swap">

{foreach $stylesheets.external as $stylesheet}
  <link rel="stylesheet" href="{$stylesheet.uri}" media="{$stylesheet.media}">
{/foreach}
...resto igual que el padre (Panda añade $sttheme.custom_css al final)...
```

Cache-busting de producción: el dist commiteado cambia de contenido → ETag
nuevo → revalidación. Si nginx sirve `.css` con `expires` largo, opciones:
`Cache-Control: no-cache` para el dir del tema (304s baratos), o activar
CCC "Smart cache CSS" en BO Rendimiento (ahora funciona porque el CSS es
plano — con @imports runtime se rompía).

## Paso 4 — Hook pre-commit con fallback cero-deps

`.githooks/pre-commit` (raíz, ejecutable `chmod +x`):

```sh
#!/bin/sh
# Rebuild theme CSS bundle when staged changes touch _dev/css sources.
# Works for everyone: pnpm if installed, zero-dep Node.js bundler otherwise.

THEME="themes/{child}"

if git diff --cached --quiet -- "$THEME/_dev/css"; then
  exit 0
fi

echo "pre-commit: _dev/css changed — rebuilding custom.css..."

if [ -d "$THEME/node_modules" ]; then
  pnpm --dir "$THEME" run --silent css || exit 1
  echo "pre-commit: rebuilt OK (minified)"
else
  node "$THEME/scripts/bundle-css.js" || exit 1
  echo "pre-commit: rebuilt OK (unminified — run 'pnpm install --dir $THEME' for minified)"
fi

git add "$THEME/assets/css/custom.css"
```

`themes/{child}/scripts/bundle-css.js` — bundler Node sin dependencias
(resuelve @imports recursivo, salta remotas). Copiarlo de
`milagros-colombia-b2b-v9.1/themes/milagros/scripts/bundle-css.js` ajustando
nada (usa rutas relativas a `__dirname`).

Activación (por clone, git no auto-activa hooks por diseño):

```bash
git config core.hooksPath .githooks
```

`.gitattributes` (raíz):

```
themes/{child}/assets/css/custom.css linguist-generated=true -diff
```

## Paso 5 — Documentación (obligatorio, es la red de seguridad real)

El hook NO se activa solo en clones nuevos. La protección para compañeros/
agentes que no conocen el sistema es documentación:

1. **CLAUDE.md del proyecto** — sección "CSS del tema hijo — REGLA OBLIGATORIA":
   dist generado (jamás editarlo), fuentes en `_dev/css/`, comando rebuild,
   activación del hook, sin `?v=`, remotas como `<link>`, no tocar hardening
   pnpm. Copiar la sección de `milagros-colombia-b2b-v9.1/CLAUDE.md`.
2. **`themes/{child}/_dev/README.md`** — doc completa: diagrama del flujo,
   setup por clone, watch, cómo funciona el hook (2 caminos), supply chain,
   tabla troubleshooting. Copiar de
   `milagros-colombia-b2b-v9.1/themes/milagros/_dev/README.md`.

## Paso 6 — Verificar

1. `pnpm --dir themes/{child} run css` → dist generado, comparar tamaño razonable
2. Cascade: `tail -c 300 assets/css/custom.css` — los overrides del entry deben
   estar al FINAL (lightningcss respeta orden de imports)
3. Hook ambos caminos: stage un parcial → `.githooks/pre-commit` → exit 0 y
   dist staged; repetir con `node_modules` renombrado (camino fallback)
4. En Lando con agent-browser: página renderiza, `<link>` custom.css sin
   query hacks, tokens aplicados (`getComputedStyle` de una variable), fuente OK
5. `rm -rf node_modules && pnpm install --frozen-lockfile && pnpm run css`

## Limitación conocida (aceptada)

Si alguien clona, NO activa el hook y commitea cambios de `_dev/css/`, el dist
queda desactualizado y "su cambio no sale". Mitigación: documentación (Paso 5)
+ el que integre con agente lo detecta por CLAUDE.md. Opciones descartadas en
Milagros por complejidad/deps: Husky, package.json raíz con prepare, build en
deploy, job CI de sincronía (válida si el proyecto ya tiene runners — ver
`gitlab-security-setup`).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.