vanilla-builder 0.2.0 → 0.3.0
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/CHANGELOG.md +21 -0
- package/README.es.md +531 -154
- package/README.md +530 -155
- package/bin/builder.js +345 -63
- package/package.json +16 -3
- package/src/browsers.js +128 -0
- package/src/budgets.js +77 -0
- package/src/builder.js +367 -103
- package/src/config.js +106 -23
- package/src/deps.js +12 -7
- package/src/files.js +12 -7
- package/src/html.js +10 -3
- package/src/i18n.js +33 -0
- package/src/images.js +61 -0
- package/src/js.js +99 -42
- package/src/jsinfo.js +63 -4
- package/src/obfuscate.js +8 -4
- package/src/optional.js +7 -3
- package/src/output.js +37 -9
- package/src/plugins.js +126 -0
- package/src/pool.js +6 -4
- package/src/report.js +9 -3
- package/src/server.js +8 -4
- package/src/tersercore.js +2 -2
- package/src/verify.js +26 -6
- package/src/worker.js +5 -1
package/README.es.md
CHANGED
|
@@ -1,230 +1,607 @@
|
|
|
1
1
|
# vanilla-builder
|
|
2
2
|
|
|
3
|
-
[](https://github.com/MarioACo/vanilla-builder/actions/workflows/ci.yml) [](https://www.npmjs.com/package/vanilla-builder) [](LICENSE)
|
|
3
|
+
[](https://github.com/MarioACo/vanilla-builder/actions/workflows/ci.yml) [](https://www.npmjs.com/package/vanilla-builder) [](#requisitos) [](LICENSE)
|
|
4
4
|
|
|
5
5
|
[English](README.md) · **Español**
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
Detecta solo las dependencias de cada página, verifica la salida antes de publicarla y nunca borra lo que no creó.
|
|
7
|
+
**Compilación de producción para sitios hechos con HTML, CSS y JavaScript sin framework: sin configuración y sin perder nada.**
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
- **Sin pérdida**: cada archivo del proyecto termina con un destino conocido (procesado, empaquetado, copiado u omitido a propósito) y la salida se verifica antes de reemplazar `dist/`.
|
|
12
|
-
- **Rápido**: la ofuscación y terser van en hilos paralelos, y una caché persistente hace casi gratis recompilar lo que no cambió (sitio de prueba de 40 páginas ofuscado: 11–18 s en 0.1.0 → 7 s la primera vez, 1,8 s al recompilar). Ver [Velocidad](#velocidad).
|
|
13
|
-
- **Tú decides qué es una librería**: el código de terceros se detecta y nunca se ofusca; lo corriges desde el HTML, el propio archivo o `builder deps`. Ver [Dependencias](#dependencias-de-terceros-y-ofuscación).
|
|
14
|
-
- **TypeScript incluido**: `<script src="app.ts">` funciona tal cual; la salida es `.js`.
|
|
15
|
-
- **Ligero**: la instalación base son 8 paquetes (el grueso es el binario de esbuild). El ofuscador y terser se instalan solo si los usas.
|
|
16
|
-
- **Node 16 o superior** (probado en 16, 18, 20, 22 y 24, en Linux, Windows y macOS).
|
|
9
|
+
Apúntalo a una carpeta con archivos `.html`. Encuentra cada script, hoja de estilos, imagen y página que usan; los empaqueta y minifica; puede ofuscar tu JavaScript (sin tocar las librerías de terceros); comprueba el resultado, y solo entonces escribe `dist/`.
|
|
17
10
|
|
|
18
|
-
|
|
11
|
+
```text
|
|
12
|
+
mi-sitio/ mi-sitio/dist/
|
|
13
|
+
├── index.html ├── index.html ← minificado, rutas actualizadas
|
|
14
|
+
├── contacto.html ├── contacto.html
|
|
15
|
+
├── css/main.css (+ @imports) ├── css/main.css ← un solo archivo, minificado
|
|
16
|
+
├── js/app.js (+ imports) → ├── js/app.js ← empaquetado, minificado y, si quieres, ofuscado
|
|
17
|
+
├── js/vendor/jquery.min.js ├── js/vendor/jquery.min.js ← detectado como librería: nunca se ofusca
|
|
18
|
+
├── img/… ├── img/… ← copiado tal cual
|
|
19
|
+
└── .env └── (no se publica: los secretos se excluyen)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Contenido
|
|
23
|
+
|
|
24
|
+
- [Por qué vanilla-builder](#por-qué-vanilla-builder)
|
|
25
|
+
- [Comparación](#comparación)
|
|
26
|
+
- [Requisitos](#requisitos)
|
|
27
|
+
- [Inicio rápido](#inicio-rápido)
|
|
28
|
+
- [Tareas habituales](#tareas-habituales)
|
|
29
|
+
- [Cómo funciona](#cómo-funciona)
|
|
30
|
+
- [Librerías de terceros y ofuscación](#librerías-de-terceros-y-ofuscación)
|
|
31
|
+
- [TypeScript](#typescript)
|
|
32
|
+
- [Configuración](#configuración)
|
|
33
|
+
- [Plugins](#plugins)
|
|
34
|
+
- [GitHub Action](#github-action)
|
|
35
|
+
- [Referencia de la línea de comandos](#referencia-de-la-línea-de-comandos)
|
|
36
|
+
- [Garantías de seguridad](#garantías-de-seguridad)
|
|
37
|
+
- [Rendimiento](#rendimiento)
|
|
38
|
+
- [API de JavaScript](#api-de-javascript)
|
|
39
|
+
- [Solución de problemas](#solución-de-problemas)
|
|
40
|
+
- [Limitaciones conocidas](#limitaciones-conocidas)
|
|
41
|
+
- [Contribuir](#contribuir)
|
|
42
|
+
|
|
43
|
+
## Por qué vanilla-builder
|
|
44
|
+
|
|
45
|
+
Herramientas como Vite o webpack dan por hecho una aplicación con un punto de entrada y un grafo de módulos. Muchos sitios reales no son así: varias páginas HTML, etiquetas `<script>` clásicas que comparten variables globales, un `jquery.min.js` copiado a mano, un service worker con una lista de archivos. vanilla-builder está hecho para esos sitios.
|
|
46
|
+
|
|
47
|
+
- **Cero configuración.** Cada `.html` completo es un punto de entrada. No hay nada que declarar.
|
|
48
|
+
- **No se pierde nada.** Cada archivo del proyecto termina con un destino conocido (procesado, empaquetado, copiado o excluido a propósito) y puedes ver cuál. Lo que no se puede rastrear se publica igualmente.
|
|
49
|
+
- **Salida verificada.** La compilación se escribe en una carpeta temporal, se comprueba (cada referencia existe, cada JS es válido, cada archivo de origen tiene destino) y solo entonces reemplaza `dist/`. Una compilación fallida nunca te deja un `dist/` roto.
|
|
50
|
+
- **Seguro con scripts clásicos.** Solo une o minifica scripts cuando puede demostrar que las variables globales no cambian.
|
|
51
|
+
- **Ofuscación que respeta las librerías.** Tu código queda protegido; jQuery, Bootstrap y los paquetes de npm se detectan y se dejan como están. Puedes corregir la detección en una línea.
|
|
52
|
+
- **TypeScript sin configurar nada.** `<script src="app.ts">` funciona; la salida es `.js`.
|
|
53
|
+
- **Rápido.** Hilos en paralelo y caché persistente: recompilar un sitio de 40 páginas ofuscado tarda menos de 2 segundos ([cifras](#rendimiento)).
|
|
54
|
+
- **Lo necesario para producción, incluido.** Navegadores objetivo con `browserslist`, optimización de imágenes opcional, presupuestos de tamaño que hacen fallar la CI, plugins y una GitHub Action con un informe de tamaños en cada pull request.
|
|
55
|
+
|
|
56
|
+
## Comparación
|
|
57
|
+
|
|
58
|
+
Los mismos sitios de prueba compilados con la configuración por defecto de cada herramienta para un sitio de varias páginas, y abiertos en Chromium junto al original ([resultados completos y método](bench/compare/RESULTS.md); se reproduce con `cd bench/compare && npm install && node run.mjs`):
|
|
59
|
+
|
|
60
|
+
| Sitio de prueba | vanilla-builder | Parcel 2.16 | Vite 8.3 |
|
|
61
|
+
| --- | --- | --- | --- |
|
|
62
|
+
| Scripts clásicos que comparten globales, un worker, una librería copiada | ✅ idéntico | ❌ no compila (worker creado desde un texto) | ❌ 404: no publica los scripts clásicos |
|
|
63
|
+
| Módulos ES, import map, service worker, CSS module script | ✅ idéntico | ❌ no compila (service worker desde un texto) | ❌ no compila (atributo de import CSS) |
|
|
64
|
+
| Paquetes de npm desde módulos y scripts clásicos | ✅ idéntico | ✅ idéntico | ❌ 404: no publica los scripts clásicos |
|
|
65
|
+
|
|
66
|
+
Tiempo y tamaño sobre un sitio generado de 40 páginas (en frío, sin caché), contando solo salidas cuyas páginas funcionan:
|
|
67
|
+
|
|
68
|
+
| | Tiempo | Salida (gzip) |
|
|
69
|
+
| --- | ---: | ---: |
|
|
70
|
+
| vanilla-builder, publicando solo lo referenciado (`"unreferenced": "skip"`) | **1,2 s** | **64,8 KB** |
|
|
71
|
+
| vanilla-builder, por defecto (publica también lo no referenciado) | 1,2 s | 156,6 KB |
|
|
72
|
+
| Parcel | 2,1–2,9 s | 102,6 KB |
|
|
73
|
+
| Vite | 0,3 s | — (salida rota: 12 problemas en 3 páginas de muestra, como 404 de scripts clásicos) |
|
|
74
|
+
|
|
75
|
+
Estas herramientas apuntan a cosas distintas: Vite y Parcel brillan en aplicaciones con un punto de entrada y un grafo de módulos. vanilla-builder es para sitios que son una carpeta de páginas y tienen que seguir funcionando exactamente igual.
|
|
76
|
+
|
|
77
|
+
## Requisitos
|
|
78
|
+
|
|
79
|
+
- **Node.js 16 o superior.** Probado en Node 16, 18, 20, 22 y 24, en Linux, Windows y macOS.
|
|
80
|
+
- Opcionales, solo si los usas: [`javascript-obfuscator`](https://www.npmjs.com/package/javascript-obfuscator) para `--obfuscate`, [`terser`](https://www.npmjs.com/package/terser) para `--minifier terser`, [`browserslist`](https://www.npmjs.com/package/browserslist) para los navegadores objetivo y [`sharp`](https://www.npmjs.com/package/sharp) (Node 20+) para `--images`.
|
|
81
|
+
|
|
82
|
+
En Node 16 y 17, npm muestra el aviso `EBADENGINE` porque esbuild declara Node 18+. Es solo un aviso: toda la batería de pruebas pasa con Node 16.
|
|
83
|
+
|
|
84
|
+
## Inicio rápido
|
|
85
|
+
|
|
86
|
+
**1. Instálalo en tu proyecto:**
|
|
19
87
|
|
|
20
88
|
```bash
|
|
21
|
-
npm install --save-dev vanilla-builder
|
|
22
|
-
npm install --save-dev javascript-obfuscator # solo si vas a ofuscar
|
|
23
|
-
npm install --save-dev terser # solo si quieres la compresión máxima
|
|
89
|
+
npm install --save-dev vanilla-builder
|
|
24
90
|
```
|
|
25
91
|
|
|
26
|
-
|
|
27
|
-
> toda la batería de pruebas (incluidas las de navegador) pasa compilando con Node 16.
|
|
92
|
+
**2. Compila:**
|
|
28
93
|
|
|
29
|
-
|
|
94
|
+
```bash
|
|
95
|
+
npx builder build
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
El resultado queda en `dist/`. La terminal muestra una tabla con cada archivo de salida y su tamaño antes, después, con gzip y con brotli, y confirma la verificación:
|
|
99
|
+
|
|
100
|
+
```text
|
|
101
|
+
✔ 3 html · 8 js · 1 css · 1 json · 4 svg · 1 text (0.21 s)
|
|
102
|
+
✔ Verificación: 18 archivos escritos, 17 referencias comprobadas, 8 JS válidos, 0 errores
|
|
103
|
+
✔ Cobertura: 21/21 archivos de origen con destino conocido
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**3. Prueba el resultado en el navegador:**
|
|
30
107
|
|
|
31
108
|
```bash
|
|
32
|
-
builder
|
|
33
|
-
builder build mi-sitio --obfuscate # además ofusca tu JavaScript (nivel medium)
|
|
34
|
-
builder analyze mi-sitio # muestra qué pasará con cada archivo, sin escribir nada
|
|
35
|
-
builder deps mi-sitio # qué JS son librerías (no se ofuscan) y cuáles son tuyos
|
|
36
|
-
builder init mi-sitio # crea builder.config.json con lo detectado
|
|
37
|
-
builder dev mi-sitio # compila, vigila cambios y sirve dist/ con recarga automática
|
|
38
|
-
builder serve mi-sitio # sirve dist/ para probarlo
|
|
109
|
+
npx builder serve # http://127.0.0.1:5173
|
|
39
110
|
```
|
|
40
111
|
|
|
41
|
-
|
|
112
|
+
Si quieres, añade scripts a tu `package.json`:
|
|
42
113
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
114
|
+
```json
|
|
115
|
+
{
|
|
116
|
+
"scripts": {
|
|
117
|
+
"dev": "builder dev",
|
|
118
|
+
"build": "builder build"
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
> Los comandos aceptan una carpeta: `npx builder build mi-sitio` compila `mi-sitio/` en `mi-sitio/dist/`. Sin carpeta, se usa la actual.
|
|
124
|
+
>
|
|
125
|
+
> Los mensajes salen en español si tu sistema está en español, y si no en inglés (elige con `--lang es|en` o `BUILDER_LANG`). Los campos de `--json` van siempre en inglés.
|
|
126
|
+
|
|
127
|
+
¿Prefieres empezar por algo que ya funciona? Mira los [ejemplos](examples/): un sitio clásico de varias páginas, una app en TypeScript y una app ofuscada con presupuestos de tamaño.
|
|
128
|
+
|
|
129
|
+
## Tareas habituales
|
|
130
|
+
|
|
131
|
+
### Desarrollar con recarga automática
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
npx builder dev # compila, vigila cambios, sirve dist/ y recarga el navegador
|
|
135
|
+
npx builder dev --port 3000 --open
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Cuando solo cambia CSS, las hojas de estilos se reemplazan sin recargar la página, así que conservas su estado.
|
|
139
|
+
|
|
140
|
+
### Publicar un sitio estático (Netlify, GitHub Pages, S3, nginx…)
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npx builder build --hash --compress
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
- `--hash` renombra JS y CSS a `nombre-<hash>.js` para que puedas cachearlos para siempre; las referencias del HTML se actualizan.
|
|
147
|
+
- `--compress` escribe además `.gz` y `.br` junto a cada archivo, para servidores que sirven archivos precomprimidos (`gzip_static`, `brotli_static` de nginx).
|
|
148
|
+
|
|
149
|
+
Si el sitio se sirve desde una subcarpeta (`https://ejemplo.com/tienda/`), añade `--base /tienda/` para que las rutas absolutas (`/js/app.js`) funcionen.
|
|
150
|
+
|
|
151
|
+
### Proteger tu JavaScript
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
npm install --save-dev javascript-obfuscator
|
|
155
|
+
npx builder build --obfuscate # nivel medium (recomendado)
|
|
156
|
+
npx builder build --obfuscate high
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Las librerías de terceros se detectan y no se ofuscan. Comprueba qué se detectó con `npx builder deps`; ver [Librerías de terceros](#librerías-de-terceros-y-ofuscación).
|
|
160
|
+
|
|
161
|
+
### Dejar el JavaScript lo más pequeño posible
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
npm install --save-dev terser
|
|
165
|
+
npx builder build --minifier terser --drop-console
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Dar soporte a navegadores antiguos
|
|
169
|
+
|
|
170
|
+
Declara tus navegadores de la forma estándar y Builder los usa para CSS y JavaScript: añade los prefijos que falten (`-webkit-backdrop-filter`), aplana el CSS anidado y reescribe la sintaxis de JavaScript más nueva.
|
|
171
|
+
|
|
172
|
+
```json
|
|
173
|
+
// package.json
|
|
174
|
+
{ "browserslist": ["> 0.5%", "last 2 versions", "not dead"] }
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm install --save-dev browserslist
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
También sirve un archivo `.browserslistrc`, o `--browsers "<consulta>"`. Sin navegadores declarados, tu código conserva su propio nivel de sintaxis.
|
|
182
|
+
|
|
183
|
+
### Optimizar imágenes
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
npm install --save-dev sharp
|
|
187
|
+
npx builder build --images # PNG sin pérdida, JPEG/WebP con calidad 80
|
|
188
|
+
npx builder build --image-quality 70
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Los PNG se recomprimen sin pérdida y se comprueban píxel a píxel. Los JPEG y WebP se recodifican con la calidad elegida (con pérdida; visualmente equivalente con el valor por defecto), conservando la orientación EXIF y el perfil de color. Los nombres no cambian, y una imagen solo se reemplaza si el resultado es más pequeño.
|
|
192
|
+
|
|
193
|
+
### Controlar el tamaño
|
|
194
|
+
|
|
195
|
+
```json
|
|
196
|
+
{
|
|
197
|
+
"budgets": {
|
|
198
|
+
"js/**/*.js": "50 KB",
|
|
199
|
+
"css/app.css": "20 KB gzip",
|
|
200
|
+
"total": "1 MB brotli"
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
```
|
|
87
204
|
|
|
88
|
-
|
|
205
|
+
Si un archivo (o el total) supera su presupuesto, la compilación falla antes de tocar `dist/` y lista lo que se pasó. En CI también puedes usar `--budget "total=1MB gzip"`.
|
|
89
206
|
|
|
90
|
-
|
|
207
|
+
### Ver qué pasará antes de compilar
|
|
91
208
|
|
|
92
|
-
|
|
209
|
+
```bash
|
|
210
|
+
npx builder analyze
|
|
211
|
+
```
|
|
93
212
|
|
|
94
|
-
|
|
95
|
-
- Nombres de librerías conocidas (`jquery-3.7.1.min.js`, `bootstrap.bundle.js`…) y versiones compiladas (`.min.js`, `.umd.js`).
|
|
96
|
-
- Archivos que se llaman como un paquete de las `dependencies` de tu `package.json` (`js/chart.umd.js` si dependes de `chart.js`).
|
|
97
|
-
- Envoltorios UMD/AMD (el formato en que se publican las librerías), cabeceras de licencia con versión (`/*! Foo v1.2.0 */`) y código ya minificado.
|
|
98
|
-
- Los paquetes de npm que importa tu código de módulos se separan en `assets/vendor/` (sin ofuscar y con su estado compartido intacto).
|
|
213
|
+
Lista cada archivo con lo que pasará con él, las librerías y workers detectados, las referencias rotas que ya existen en tu código y los archivos excluidos. No escribe nada.
|
|
99
214
|
|
|
100
|
-
|
|
215
|
+
### Usarlo en CI
|
|
101
216
|
|
|
102
217
|
```bash
|
|
103
|
-
builder
|
|
218
|
+
npx builder build --json > build-report.json
|
|
104
219
|
```
|
|
105
220
|
|
|
106
|
-
|
|
221
|
+
- Código de salida `0` si todo va bien y distinto de cero si la compilación o la verificación fallan; en ese caso `dist/` no se toca y el JSON trae `"ok": false` con el error.
|
|
222
|
+
- El JSON incluye salidas, tamaños, avisos, dependencias detectadas y el tiempo de cada fase (`perf.phases`).
|
|
223
|
+
- Para reutilizar la caché entre ejecuciones, apunta `BUILDER_CACHE_DIR` a una carpeta que tu CI guarde.
|
|
224
|
+
- En GitHub, la [GitHub Action](#github-action) hace todo esto y añade un informe de tamaños a cada ejecución y pull request.
|
|
225
|
+
|
|
226
|
+
## Cómo funciona
|
|
227
|
+
|
|
228
|
+
1. **Descubrir.** Se analiza cada página HTML completa. Desde ella, Builder sigue los scripts (clásicos y módulos, inline e import maps), las hojas de estilos (`@import`, `url()`, `image-set()`), imágenes y `srcset`, vídeo y audio, iconos, manifiestos, `og:image`, iframes, enlaces a otras páginas, `import()` dinámicos, `new URL('./x', import.meta.url)`, workers, service workers, `importScripts()` y rutas escritas como texto en tu código (como una lista de precache).
|
|
229
|
+
2. **Procesar.**
|
|
230
|
+
- Los módulos ES se empaquetan con [esbuild](https://esbuild.github.io/) (con división en chunks). Se mantiene el nivel de sintaxis de tu propio código: no se transpila nada salvo que lo pidas con `--target`.
|
|
231
|
+
- Los scripts clásicos consecutivos se unen solo cuando es seguro, y después se minifican.
|
|
232
|
+
- El CSS se empaqueta y minifica; el HTML se minifica con un minificador conservador que deja intactos `<pre>`, `<textarea>` y las plantillas.
|
|
233
|
+
- Al JSON solo se le quitan espacios. Todo lo demás (imágenes, fuentes, datos) se copia.
|
|
234
|
+
3. **Proteger (opcional).** Se ofusca tu JavaScript; las librerías no.
|
|
235
|
+
4. **Verificar.** En una carpeta temporal: cada referencia existe, cada JS es válido, los tamaños coinciden y cada archivo de origen tiene destino.
|
|
236
|
+
5. **Publicar.** La carpeta temporal reemplaza a `dist/`.
|
|
237
|
+
|
|
238
|
+
Los archivos que nada referencia también se minifican y se publican en su ruta original (`unreferenced: "process"`), así que un `fetch(variable)` o una plantilla del servidor que cargue un archivo siguen funcionando.
|
|
239
|
+
|
|
240
|
+
## Librerías de terceros y ofuscación
|
|
241
|
+
|
|
242
|
+
Ofuscar jQuery, Bootstrap o un paquete de npm no protege nada tuyo, los hace más lentos y puede incumplir su licencia. Al ofuscar, esto se trata como librería y no se toca:
|
|
243
|
+
|
|
244
|
+
| Señal | Ejemplo |
|
|
245
|
+
| --- | --- |
|
|
246
|
+
| Está en una carpeta de librerías | `vendor/`, `node_modules/`, `third-party/`, `external/`… |
|
|
247
|
+
| Nombre de librería conocida | `jquery-3.7.1.min.js`, `bootstrap.bundle.js`, `chart.umd.js` |
|
|
248
|
+
| Ya viene compilado | `.min.js`, `.umd.js`, o código ya minificado |
|
|
249
|
+
| Se llama como un paquete del que dependes | `js/swiper.js` si `package.json` tiene `swiper` en `dependencies` |
|
|
250
|
+
| Envoltorio de librería | UMD/AMD (`typeof define === "function" && define.amd`) |
|
|
251
|
+
| Cabecera de licencia con versión | `/*! Foo v1.2.0 */` |
|
|
252
|
+
|
|
253
|
+
Los paquetes de npm que importan tus módulos (`import confetti from 'canvas-confetti'`) se empaquetan desde `node_modules`. Al ofuscar, se separan en archivos aparte en `assets/vendor/`, sin ofuscar y compartidos entre páginas.
|
|
254
|
+
|
|
255
|
+
### Comprobar y corregir la detección
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
npx builder deps
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
```text
|
|
262
|
+
Librerías de terceros (no se ofuscan) (3)
|
|
263
|
+
• js/vendor/jquery.min.js — está en vendor/
|
|
264
|
+
• js/chart.js — se llama como el paquete "chart.js" de tu package.json
|
|
265
|
+
• js/slider.js — envoltorio UMD/AMD (formato de librería publicada)
|
|
266
|
+
|
|
267
|
+
Tu código (se ofusca con --obfuscate) (1)
|
|
268
|
+
• js/app.js
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Con `--json` obtienes `{ "dependencies": [{ "rel", "reason" }], "own": [] }`.
|
|
272
|
+
|
|
273
|
+
Si algo está mal clasificado, corrígelo donde te resulte más cómodo:
|
|
274
|
+
|
|
275
|
+
#### En el HTML
|
|
107
276
|
|
|
108
277
|
```html
|
|
109
|
-
|
|
110
|
-
<script src="js/
|
|
111
|
-
<script src="js/app.min.js" data-builder="own"></script>
|
|
278
|
+
<script src="js/mi-lib.js" data-builder="dependency"></script> <!-- librería: no ofuscar -->
|
|
279
|
+
<script src="js/app.min.js" data-builder="own"></script> <!-- mi código: ofuscar -->
|
|
112
280
|
```
|
|
113
281
|
|
|
282
|
+
#### Al principio del archivo
|
|
283
|
+
|
|
114
284
|
```js
|
|
115
|
-
/*
|
|
116
|
-
/* @builder-dependency */ // o: /* @builder-own */
|
|
285
|
+
/* @builder-dependency */ // o /* @builder-own */
|
|
117
286
|
```
|
|
118
287
|
|
|
288
|
+
#### Desde la terminal
|
|
289
|
+
|
|
290
|
+
Escribe `builder.config.json` por ti y conserva el resto de tu configuración:
|
|
291
|
+
|
|
119
292
|
```bash
|
|
120
|
-
|
|
121
|
-
builder deps
|
|
122
|
-
builder deps
|
|
123
|
-
builder deps reset js/app.min.js # volver a la detección automática
|
|
293
|
+
npx builder deps add "js/libs/**" # son librerías
|
|
294
|
+
npx builder deps own js/app.min.js # es mi código
|
|
295
|
+
npx builder deps reset js/app.min.js # volver a la detección automática
|
|
124
296
|
```
|
|
125
297
|
|
|
126
|
-
|
|
298
|
+
#### En la configuración
|
|
127
299
|
|
|
128
300
|
```json
|
|
129
301
|
{
|
|
130
|
-
"obfuscate": "high",
|
|
131
302
|
"dependencies": {
|
|
132
303
|
"include": ["js/mi-libreria.js"],
|
|
133
|
-
"exclude": ["js/app.min.js"]
|
|
134
|
-
"obfuscate": false
|
|
304
|
+
"exclude": ["js/app.min.js"]
|
|
135
305
|
}
|
|
136
306
|
}
|
|
137
307
|
```
|
|
138
308
|
|
|
139
|
-
|
|
309
|
+
Prioridad: configuración › marcas en el HTML o en el archivo › detección automática. Para ofuscarlo todo, librerías incluidas, usa `--obfuscate-deps` (`"dependencies": { "obfuscate": true }`).
|
|
140
310
|
|
|
141
|
-
Niveles
|
|
311
|
+
### Niveles de ofuscación
|
|
312
|
+
|
|
313
|
+
| Nivel | Para qué |
|
|
314
|
+
| --- | --- |
|
|
315
|
+
| `low` | Renombrado y ocultación de textos. Casi sin coste en ejecución. |
|
|
316
|
+
| `medium` | **Recomendado.** Añade aplanado del flujo de control, código muerto y textos codificados. |
|
|
317
|
+
| `high` | Transformaciones más fuertes; código más grande y más lento. |
|
|
318
|
+
| `max` | Todo, más protección contra el formateo. El más pesado. |
|
|
319
|
+
|
|
320
|
+
Cada archivo ofuscado se comprueba: las variables globales de los scripts clásicos y los imports/exports de los módulos deben seguir iguales; si no, ese archivo se publica sin ofuscar y con un aviso. Las opciones que cambian el comportamiento (`debugProtection`, `disableConsoleOutput`, `renameGlobals`) nunca se activan solas; pásalas a propósito: `"obfuscate": { "preset": "high", "debugProtection": true }`. Los comentarios de licencia (`/*! … */`, `@license`) se conservan.
|
|
142
321
|
|
|
143
322
|
## TypeScript
|
|
144
323
|
|
|
145
|
-
|
|
324
|
+
Referencia archivos `.ts` desde tu HTML —o el nombre `.js`, como recomienda TypeScript— y compila. No hace falta instalar nada más.
|
|
146
325
|
|
|
147
326
|
```html
|
|
148
327
|
<script type="module" src="js/main.ts"></script>
|
|
149
328
|
```
|
|
150
329
|
|
|
151
|
-
-
|
|
152
|
-
- La salida es `.js` (`.mjs
|
|
153
|
-
-
|
|
154
|
-
-
|
|
155
|
-
|
|
156
|
-
## Velocidad
|
|
157
|
-
|
|
158
|
-
Medido con `npm run bench` (un sitio generado con 40 páginas, 240 módulos, 120 scripts clásicos, 30 CSS y 200 imágenes; mediana de 3 ejecuciones en un i7-11700F, Node 24, Windows):
|
|
330
|
+
- Los `.ts`, `.mts` y `.cts` se transpilan con esbuild usando tu `tsconfig.json`. Se quitan los tipos; el nivel de sintaxis se mantiene.
|
|
331
|
+
- La salida es `.js` (`.mjs`, `.cjs`) y el HTML se actualiza para apuntar a ella.
|
|
332
|
+
- Siguen funcionando: `import './util'`, `import './util.ts'`, `import './util.js'` (cuando el archivo es `util.ts`), `import './componentes'` (carpeta con `index.ts`) y `new URL('./worker.ts', import.meta.url)`.
|
|
333
|
+
- Los `.d.ts` y `*.test.ts` no se publican.
|
|
334
|
+
- No se comprueban tipos. Para eso, ejecuta `tsc --noEmit` en tu editor o en CI.
|
|
159
335
|
|
|
160
|
-
|
|
161
|
-
| --- | ---: | ---: | ---: |
|
|
162
|
-
| Por defecto | 3,7 s | 1,9 s | 1,4 s |
|
|
163
|
-
| `--obfuscate` | 11,5–17,9 s | 7,0 s | 1,8 s |
|
|
164
|
-
| `--hash --compress` | 2,6–3,8 s | 2,1 s | 1,1 s |
|
|
165
|
-
| `--minifier terser` | 5,6–6,0 s | 3,7 s | 1,6 s |
|
|
166
|
-
|
|
167
|
-
Cómo:
|
|
168
|
-
|
|
169
|
-
- **Hilos**: la ofuscación, terser y la comprobación final de sintaxis van en hilos de trabajo (`workers: "auto"` ≈ núcleos físicos, máximo 8). El hilo principal también trabaja, y los hilos solo arrancan cuando hay suficiente trabajo en cola para compensar su arranque, así que un proyecto pequeño nunca va más lento.
|
|
170
|
-
- **Caché persistente**: los resultados se guardan por contenido en `node_modules/.cache/vanilla-builder` (o en el temporal del sistema). Misma entrada + mismas opciones + mismas versiones = misma salida, byte a byte; las pruebas lo comprueban. Con `BUILDER_CACHE_DIR` puedes conservarla entre ejecuciones de CI. `--no-cache` o `"cache": false` la desactivan.
|
|
171
|
-
- **En paralelo y en orden**: los archivos independientes se procesan a la vez, pero se registran en el orden original, así que la salida no depende de los tiempos.
|
|
172
|
-
- `--json` incluye `perf.phases` (milisegundos por fase) para ver dónde se va el tiempo en tu proyecto.
|
|
336
|
+
## Configuración
|
|
173
337
|
|
|
174
|
-
|
|
338
|
+
Todo funciona sin configuración. Para cambiar valores por defecto, crea `builder.config.json` en la carpeta del proyecto (`npx builder init` crea uno a partir de tu proyecto). Cada opción también se puede pasar por la línea de comandos, que tiene prioridad. Las opciones mal escritas se rechazan con una sugerencia.
|
|
175
339
|
|
|
176
340
|
```json
|
|
177
341
|
{
|
|
178
342
|
"outDir": "dist",
|
|
179
|
-
"
|
|
180
|
-
"
|
|
181
|
-
"
|
|
182
|
-
"
|
|
183
|
-
"
|
|
184
|
-
"dependencies": { "detect": true, "obfuscate": false, "include": [], "exclude": [] },
|
|
185
|
-
"hash": false,
|
|
186
|
-
"sourcemap": false,
|
|
187
|
-
"compress": false,
|
|
188
|
-
"cache": true,
|
|
189
|
-
"workers": "auto",
|
|
190
|
-
"base": "/",
|
|
191
|
-
"sri": "auto",
|
|
192
|
-
"html": { "minify": true, "removeComments": true, "collapseWhitespace": "auto" },
|
|
193
|
-
"css": { "minify": true, "bundle": true, "target": "esnext" },
|
|
194
|
-
"js": { "minify": true, "bundle": true, "target": "auto", "minifier": "esbuild", "mergeClassic": "auto", "drop": [], "legalComments": "eof", "chunkDir": "assets" }
|
|
343
|
+
"obfuscate": "medium",
|
|
344
|
+
"hash": true,
|
|
345
|
+
"compress": true,
|
|
346
|
+
"ignore": ["borradores/**"],
|
|
347
|
+
"js": { "drop": ["console", "debugger"] }
|
|
195
348
|
}
|
|
196
349
|
```
|
|
197
350
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
351
|
+
También se acepta `builder.config.mjs`, que puede exportar un objeto o una función (síncrona o asíncrona) que lo devuelva.
|
|
352
|
+
|
|
353
|
+
### Todas las opciones
|
|
354
|
+
|
|
355
|
+
| Opción | Por defecto | Descripción |
|
|
356
|
+
| --- | --- | --- |
|
|
357
|
+
| `root` | `"."` | Carpeta del proyecto, relativa al archivo de configuración. |
|
|
358
|
+
| `outDir` | `"dist"` | Carpeta de salida. Builder se niega a vaciar una carpeta que no creó. |
|
|
359
|
+
| `entries` | `"auto"` | `"auto"` usa cada página HTML completa. O una lista de archivos/patrones `.html`, `.js` o `.css`. |
|
|
360
|
+
| `include` | `[]` | Patrones que siempre se publican, aunque nada los referencie (ej. `"datos/**"`). |
|
|
361
|
+
| `ignore` | `[]` | Patrones que nunca se publican (ej. `"borradores/**"`). |
|
|
362
|
+
| `defaultIgnore` | `true` | Excluye secretos (`.env*`, `*.pem`, `*.key`), `node_modules`, `package.json`, lockfiles, configuración de herramientas, tests y `.d.ts`. |
|
|
363
|
+
| `unreferenced` | `"process"` | Archivos que nada referencia: `"process"` (minificar y publicar), `"copy"` (publicar tal cual) o `"skip"`. |
|
|
364
|
+
| `base` | `"/"` | Ruta pública base del sitio, para URLs absolutas (`"/tienda/"`). |
|
|
365
|
+
| `hash` | `false` | Hash del contenido en los nombres de JS/CSS (`assets/app-3f9a1c2b.js`). |
|
|
366
|
+
| `sourcemap` | `false` | `true` (archivos `.map` enlazados), `"hidden"` (sin comentario en el código) o `"inline"`. |
|
|
367
|
+
| `compress` | `false` | `true` (gzip y brotli), `"gzip"` o `"brotli"`: copias precomprimidas junto a cada archivo. |
|
|
368
|
+
| `sri` | `"auto"` | Subresource Integrity. `"auto"` recalcula los atributos `integrity` existentes; `true` además los añade a cada script y hoja de estilos local; `false` los quita. |
|
|
369
|
+
| `verify` | `true` | Verificar la salida antes de publicarla. No se recomienda desactivarlo. |
|
|
370
|
+
| `clean` | `true` | Reemplazar `outDir` por completo. Con `false`, los archivos nuevos se copian encima de los existentes. |
|
|
371
|
+
| `cache` | `true` | Reutilizar resultados de compilaciones anteriores. |
|
|
372
|
+
| `workers` | `"auto"` | Hilos para ofuscación y terser: `"auto"`, un número, o `0` para ninguno. |
|
|
373
|
+
| `browsers` | `"auto"` | Navegadores objetivo: `"auto"` lee `.browserslistrc` o `browserslist` en `package.json`; o una consulta (`"> 0.5%, not dead"`); o `false`. Se aplica a `css.target` y `js.target` cuando tienen su valor por defecto. Necesita `browserslist`. |
|
|
374
|
+
| `images` | `false` | `true` o `{ "quality": 1-100 }`: optimiza PNG (sin pérdida), JPEG y WebP. Necesita `sharp`. |
|
|
375
|
+
| `budgets` | `false` | Límites de tamaño por patrón de salida o `"total"`: `{ "js/*.js": "50 KB", "total": "1 MB gzip" }`. Pasarse = compilación fallida. |
|
|
376
|
+
| `plugins` | `[]` | Ver [Plugins](#plugins). |
|
|
377
|
+
| `obfuscate` | `false` | `false`, `true` (= `"medium"`), `"low"`, `"medium"`, `"high"`, `"max"`, o un objeto con [opciones de javascript-obfuscator](https://github.com/javascript-obfuscator/javascript-obfuscator#javascript-obfuscator-options) y un `preset` opcional. |
|
|
378
|
+
| `dependencies.detect` | `true` | Detectar librerías de terceros automáticamente. |
|
|
379
|
+
| `dependencies.include` | `[]` | Patrones que son librerías (no se ofuscan). |
|
|
380
|
+
| `dependencies.exclude` | `[]` | Patrones que son tu código (se ofuscan aunque parezcan librería). |
|
|
381
|
+
| `dependencies.obfuscate` | `false` | Ofuscar también las librerías. |
|
|
382
|
+
| `html.minify` | `true` | Minificar el HTML. |
|
|
383
|
+
| `html.removeComments` | `true` | Quitar comentarios HTML. Se conservan los que tienen significado: `<!--! … -->`, condicionales de IE, SSI y ESI. |
|
|
384
|
+
| `html.collapseWhitespace` | `"auto"` | Colapsar espacios entre etiquetas. `"auto"` lo desactiva si tu CSS usa `white-space: pre`. |
|
|
385
|
+
| `css.minify` | `true` | Minificar el CSS. |
|
|
386
|
+
| `css.bundle` | `true` | Incluir los archivos de los `@import`. |
|
|
387
|
+
| `css.target` | `"esnext"` | Nivel de sintaxis CSS, ej. `["chrome90", "safari15"]`. |
|
|
388
|
+
| `js.minify` | `true` | Minificar el JavaScript. |
|
|
389
|
+
| `js.bundle` | `true` | Empaquetar los módulos ES. Con `false`, cada módulo se minifica en su sitio. |
|
|
390
|
+
| `js.target` | `"auto"` | `"auto"` mantiene el nivel de sintaxis de tu código; o `"es2018"`, `["chrome90", "safari15"]`… |
|
|
391
|
+
| `js.minifier` | `"esbuild"` | `"terser"` añade una segunda pasada de compresión, más fuerte. |
|
|
392
|
+
| `js.mergeClassic` | `"auto"` | Unir etiquetas `<script>` clásicas consecutivas cuando es seguro (se desactiva con source maps). |
|
|
393
|
+
| `js.drop` | `[]` | Quitar `"console"` y/o `"debugger"`. |
|
|
394
|
+
| `js.keepNames` | `false` | Conservar los nombres de funciones y clases (`fn.name`). |
|
|
395
|
+
| `js.define` | `{}` | Sustituir identificadores globales al compilar, ej. `{ "DEBUG": "false" }`. |
|
|
396
|
+
| `js.legalComments` | `"eof"` | Dónde van los comentarios de licencia: `"eof"`, `"inline"` o `"none"`. |
|
|
397
|
+
| `js.chunkDir` | `"assets"` | Carpeta para chunks compartidos, archivos con hash y paquetes vendor. |
|
|
398
|
+
| `json.minify` | `true` | Quitar espacios de `.json` y `.webmanifest` (los valores nunca se reescriben). |
|
|
399
|
+
|
|
400
|
+
## Plugins
|
|
401
|
+
|
|
402
|
+
Para lo que Builder no hace por su cuenta. Un plugin es un objeto con ganchos; decláralo en `builder.config.mjs`:
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
// builder.config.mjs
|
|
406
|
+
export default {
|
|
407
|
+
plugins: [
|
|
408
|
+
{
|
|
409
|
+
name: 'version',
|
|
410
|
+
filter: /\.(html|js)$/, // opcional: qué archivos ve transform()
|
|
411
|
+
transform: ({ path, code }) => code.replaceAll('__VERSION__', '1.4.0'),
|
|
412
|
+
buildStart: ({ config, mode }) => {}, // antes de leer nada
|
|
413
|
+
buildEnd: ({ result, outDir }) => {}, // después de escribir dist/ (solo build)
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
};
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
- `transform` recibe el **código fuente** de cada HTML, CSS, JS y TS y devuelve el código nuevo (o nada para dejarlo igual). Se ejecuta antes de procesar, así que el hash, el SRI y la verificación final ven el resultado del plugin.
|
|
420
|
+
- En `builder.config.json` se nombra un paquete instalado: `"plugins": ["mi-plugin", ["otro-plugin", { "opcion": 1 }]]`. El paquete exporta el objeto plugin, o una función que recibe las opciones y lo devuelve.
|
|
421
|
+
- Si un plugin lanza un error, la compilación se detiene con un mensaje que nombra el plugin y el archivo.
|
|
422
|
+
|
|
423
|
+
## GitHub Action
|
|
424
|
+
|
|
425
|
+
```yaml
|
|
426
|
+
# .github/workflows/build.yml
|
|
427
|
+
on: [push, pull_request]
|
|
428
|
+
permissions:
|
|
429
|
+
contents: read
|
|
430
|
+
pull-requests: write # solo para comment: true
|
|
431
|
+
jobs:
|
|
432
|
+
build:
|
|
433
|
+
runs-on: ubuntu-latest
|
|
434
|
+
steps:
|
|
435
|
+
- uses: actions/checkout@v4
|
|
436
|
+
- uses: MarioACo/vanilla-builder@v0.3.0
|
|
437
|
+
with:
|
|
438
|
+
args: --hash --compress # cualquier opción de build
|
|
439
|
+
comment: true # informe de tamaños en los pull requests
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
Compila con una caché que se conserva entre ejecuciones, escribe un resumen de tamaños en la página de la ejecución, comenta en los pull requests (actualizando el mismo comentario en cada push) y hace fallar el trabajo si fallan la compilación, la verificación o un presupuesto. Entradas: `directory`, `args`, `version` (si el proyecto no instala vanilla-builder), `node-version`, `cache`, `comment`. Salidas: `total-size`, `total-gzip`, `report` (ruta del informe JSON).
|
|
202
443
|
|
|
203
|
-
##
|
|
444
|
+
## Referencia de la línea de comandos
|
|
445
|
+
|
|
446
|
+
```text
|
|
447
|
+
builder <comando> [carpeta] [opciones]
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
| Comando | Descripción |
|
|
451
|
+
| --- | --- |
|
|
452
|
+
| `build` | Compila el proyecto en `dist/`. |
|
|
453
|
+
| `dev` | Compila, vigila cambios, sirve `dist/` y recarga el navegador. |
|
|
454
|
+
| `serve` | Sirve el `dist/` existente. |
|
|
455
|
+
| `analyze` | Muestra qué pasaría con cada archivo. No escribe nada. |
|
|
456
|
+
| `deps` | Lista qué archivos JavaScript son librerías y cuáles son tuyos. |
|
|
457
|
+
| `deps add\|own\|reset <patrón…>` | Marca archivos como librería, como tu código, o vuelve a lo automático. Con `--dir <carpeta>` para otro proyecto. |
|
|
458
|
+
| `init` | Crea `builder.config.json` a partir de lo detectado (`--force` para sobrescribir). |
|
|
459
|
+
| `help`, `--version` | Ayuda y versión. |
|
|
460
|
+
|
|
461
|
+
### Opciones de build
|
|
462
|
+
|
|
463
|
+
| Opción | Descripción |
|
|
464
|
+
| --- | --- |
|
|
465
|
+
| `--out <carpeta>` | Carpeta de salida (por defecto `dist`). |
|
|
466
|
+
| `--config <archivo>` | Archivo de configuración (por defecto `builder.config.json`). |
|
|
467
|
+
| `--entry <archivo>` | Punto de entrada explícito. Repetible. |
|
|
468
|
+
| `--include <patrón>` / `--ignore <patrón>` | Publicar siempre / no publicar nunca. Repetibles. |
|
|
469
|
+
| `--obfuscate [nivel]` | Ofuscar tu JavaScript: `low`, `medium` (por defecto), `high`, `max`. |
|
|
470
|
+
| `--dep <patrón>` / `--not-dep <patrón>` | Marcar como librería / como tu código. Repetibles. |
|
|
471
|
+
| `--obfuscate-deps` | Ofuscar también las librerías. |
|
|
472
|
+
| `--minifier terser` | Pasada extra de compresión con terser. |
|
|
473
|
+
| `--compress [gzip\|brotli]` | Escribir archivos `.gz`/`.br` precomprimidos (ambos por defecto). |
|
|
474
|
+
| `--hash` | Hash del contenido en los nombres de JS/CSS. |
|
|
475
|
+
| `--sourcemap [linked\|hidden\|inline]` | Generar source maps. |
|
|
476
|
+
| `--target <target>` | Nivel de JavaScript de salida, ej. `es2018`. |
|
|
477
|
+
| `--drop-console` | Quitar `console.*` y `debugger`. |
|
|
478
|
+
| `--no-minify` | No minificar (útil para investigar un problema). |
|
|
479
|
+
| `--no-merge` | No unir scripts clásicos. |
|
|
480
|
+
| `--unreferenced <modo>` | `process`, `copy` o `skip`. |
|
|
481
|
+
| `--base <ruta>` | Ruta pública base, ej. `/tienda/`. |
|
|
482
|
+
| `--workers <n\|auto>` | Número de hilos (`0` = ninguno). |
|
|
483
|
+
| `--browsers <consulta>` / `--no-browsers` | Navegadores objetivo (consulta de browserslist) / ignorar los del proyecto. |
|
|
484
|
+
| `--images`, `--image-quality <1-100>` | Optimizar imágenes (necesita `sharp`). |
|
|
485
|
+
| `--budget <patrón=tamaño>` | Presupuesto de tamaño, ej. `"total=1MB gzip"`. Repetible; sustituye a los de la configuración. |
|
|
486
|
+
| `--lang <en\|es>` | Idioma de los mensajes. |
|
|
487
|
+
| `--no-cache` | Ignorar la caché. |
|
|
488
|
+
| `--no-verify` | Saltarse la verificación final (no recomendado). |
|
|
489
|
+
| `--force` | Permitir vaciar una carpeta de salida que no creó Builder. |
|
|
490
|
+
| `--keep-failed` | Conservar la carpeta temporal si la verificación falla, para revisarla. |
|
|
491
|
+
| `--json` | Resultado legible por máquinas. |
|
|
492
|
+
| `--verbose` / `--quiet` | Más detalle (notas, archivos copiados y excluidos) / solo errores. |
|
|
493
|
+
|
|
494
|
+
`dev` y `serve` aceptan además `--port <n>` (por defecto `5173`), `--host <host>` (por defecto `127.0.0.1`) y `--open`. Las opciones desconocidas se rechazan con una sugerencia (`--obfusacte` → ¿quisiste decir `--obfuscate`?).
|
|
495
|
+
|
|
496
|
+
## Garantías de seguridad
|
|
497
|
+
|
|
498
|
+
| Riesgo habitual de una herramienta de compilación | Qué hace vanilla-builder |
|
|
499
|
+
| --- | --- |
|
|
500
|
+
| Unir scripts clásicos rompe las globales compartidas | Solo une scripts consecutivos con el mismo `defer` y modo estricto, sin `document.currentScript` ni `let`/`const` en conflicto, con un separador seguro. |
|
|
501
|
+
| La minificación renombra o añade globales | Compara las globales antes y después; si cambian, usa una minificación más segura o deja el original. |
|
|
502
|
+
| La ofuscación rompe un módulo | Compara imports, exports y atributos de import tras ofuscar; si no coinciden, ese archivo se publica sin ofuscar. |
|
|
503
|
+
| Minificar el HTML cambia el texto | Comparación estructural de elementos, atributos y texto; `<pre>`, `<textarea>` y plantillas intactos. |
|
|
504
|
+
| Atributos `integrity` obsoletos bloquean scripts | Se recalculan siempre que cambia el contenido. |
|
|
505
|
+
| Codificaciones antiguas o BOM se corrompen | Los bytes del HTML se conservan; JS y CSS se emiten con escapes ASCII. |
|
|
506
|
+
| Los números del JSON pierden precisión | Solo se quitan espacios fuera de las cadenas. |
|
|
507
|
+
| Borrar la carpeta equivocada | Nunca vacía una carpeta que no creó (marcada con `.builder-manifest.json`), ni la del proyecto, ni tu carpeta de usuario, ni la raíz de una unidad. |
|
|
508
|
+
| Una compilación fallida deja el sitio roto | La salida se escribe y verifica en una carpeta temporal antes de reemplazar `dist/`. |
|
|
509
|
+
| Publicar secretos | `.env*`, claves, `node_modules`, `package.json` y configuración de herramientas se excluyen por defecto. |
|
|
510
|
+
|
|
511
|
+
Cada versión se prueba abriendo sitios de ejemplo —original y compilado— en un Chromium real y exigiendo el mismo comportamiento, sin errores de consola ni 404, en cinco variantes (por defecto, ofuscación alta + hash, ofuscación máxima, terser + precompresión, sin minificar), compilando con Node 16 y con el Node actual.
|
|
512
|
+
|
|
513
|
+
## Rendimiento
|
|
514
|
+
|
|
515
|
+
Medido con `npm run bench` sobre un sitio generado con 40 páginas, 240 módulos, 120 scripts clásicos, 30 CSS y 200 imágenes (mediana de 3 ejecuciones; Intel i7-11700F, Node 24, Windows):
|
|
516
|
+
|
|
517
|
+
| Compilación | Primera vez | Recompilar (caché) | v0.1.0 |
|
|
518
|
+
| --- | ---: | ---: | ---: |
|
|
519
|
+
| Por defecto | 1,9 s | 1,4 s | 3,7 s |
|
|
520
|
+
| `--obfuscate` | 7,0 s | 1,8 s | 11,5–17,9 s |
|
|
521
|
+
| `--hash --compress` | 2,1 s | 1,1 s | 2,6–3,8 s |
|
|
522
|
+
| `--minifier terser` | 3,7 s | 1,6 s | 5,6–6,0 s |
|
|
523
|
+
|
|
524
|
+
- **Hilos.** La ofuscación, terser y la comprobación final de sintaxis van en hilos de trabajo (`"auto"` ≈ núcleos físicos, hasta 8). Los hilos solo arrancan cuando hay trabajo suficiente para compensar su arranque, así que un proyecto pequeño no va más lento.
|
|
525
|
+
- **Caché persistente.** Los resultados lentos se guardan por contenido en `node_modules/.cache/vanilla-builder` (o en el temporal del sistema). La misma entrada, opciones y versiones dan la misma salida byte a byte; las pruebas lo comprueban. Cambia la ubicación con `BUILDER_CACHE_DIR`; desactívala con `--no-cache`.
|
|
526
|
+
- **Determinista.** Los archivos independientes se procesan en paralelo pero se registran en su orden original, así que la salida nunca depende de los tiempos.
|
|
527
|
+
- Para ver dónde se va el tiempo en tu proyecto, mira `perf.phases` en `--json`.
|
|
528
|
+
|
|
529
|
+
## API de JavaScript
|
|
204
530
|
|
|
205
531
|
```js
|
|
206
532
|
import { build, analyze } from 'vanilla-builder';
|
|
207
533
|
|
|
208
|
-
const result = await build({
|
|
209
|
-
|
|
534
|
+
const result = await build({
|
|
535
|
+
dir: 'mi-sitio', // carpeta del proyecto (por defecto, la actual)
|
|
536
|
+
overrides: { obfuscate: 'high' }, // misma forma que builder.config.json
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
console.log(result.report.totals); // { before, size, gzip, brotli, files }
|
|
540
|
+
console.log(result.warnings); // string[]
|
|
541
|
+
console.log(result.dependencies); // [{ rel, reason }]
|
|
210
542
|
```
|
|
211
543
|
|
|
212
|
-
|
|
544
|
+
- `build(opciones)` compila y escribe `outDir`. Opciones: `dir`, `config` (ruta a un archivo de configuración), `overrides`, `force`, `keepFailed`, `log` (función que recibe los mensajes de progreso).
|
|
545
|
+
- `analyze(opciones)` devuelve el mismo resultado sin escribir nada.
|
|
546
|
+
- Los errores se lanzan como `BuildError` (exportado), con una lista `details`.
|
|
547
|
+
- `startServer({ dir, port, host })` sirve una carpeta, como `builder serve`.
|
|
213
548
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
549
|
+
## Solución de problemas
|
|
550
|
+
|
|
551
|
+
### `La carpeta de salida … ya tiene archivos y no la creó Builder`
|
|
552
|
+
|
|
553
|
+
Builder nunca vacía una carpeta que no creó. Elige otra con `--out`, vacíala tú o usa `--force` si estás seguro.
|
|
554
|
+
|
|
555
|
+
### `Falta el paquete opcional "javascript-obfuscator"` (o `terser`, `browserslist`, `sharp`)
|
|
220
556
|
|
|
221
|
-
|
|
557
|
+
Instálalo en tu proyecto, por ejemplo `npm install --save-dev javascript-obfuscator`. Son opcionales para que la instalación base sea pequeña.
|
|
222
558
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
559
|
+
### `hay navegadores objetivo en package.json (browserslist), pero falta el paquete "browserslist"`
|
|
560
|
+
|
|
561
|
+
Tu proyecto declara navegadores (quizá para otra herramienta) pero `browserslist` no está instalado, así que Builder deja tu código como está. Instálalo (`npm install --save-dev browserslist`) para usarlos, o pon `"browsers": false` para quitar el aviso.
|
|
562
|
+
|
|
563
|
+
### Falta un archivo en `dist/`
|
|
564
|
+
|
|
565
|
+
Ejecuta `npx builder analyze --verbose`. Lista cada archivo con su destino, y cada archivo excluido con el motivo. Los que se excluyen por defecto (secretos, configuración, tests) se pueden publicar igualmente con `--include "<patrón>"`.
|
|
566
|
+
|
|
567
|
+
### Se ofuscó una librería, o no se ofuscó mi código
|
|
568
|
+
|
|
569
|
+
Ejecuta `npx builder deps` para ver el motivo de cada archivo y corrígelo con `data-builder`, un comentario `@builder-*` o `npx builder deps add|own` ([detalles](#comprobar-y-corregir-la-detección)).
|
|
570
|
+
|
|
571
|
+
### `Dos resultados distintos quieren escribirse en …`
|
|
572
|
+
|
|
573
|
+
Dos salidas acabarían en la misma ruta. Suele pasar si una carpeta de tu proyecto se llama igual que `js.chunkDir` (`assets` por defecto), o si el mismo módulo se usa con import maps distintos. Cambia `js.chunkDir` a otro nombre.
|
|
574
|
+
|
|
575
|
+
### `"base" debe empezar con "/"` al usar Git Bash en Windows
|
|
576
|
+
|
|
577
|
+
Git Bash convierte los argumentos que parecen rutas de Unix, así que `--base /tienda/` llega como `C:/Program Files/Git/tienda/`. Pon `"base": "/tienda/"` en `builder.config.json`, o ejecuta `MSYS_NO_PATHCONV=1 npx builder build --base /tienda/`. PowerShell y cmd no tienen este problema.
|
|
578
|
+
|
|
579
|
+
### Algo se comporta distinto tras compilar
|
|
580
|
+
|
|
581
|
+
Compila con `--no-minify` para descartar la minificación, o sin `--obfuscate` para descartar la ofuscación. Si encuentras una diferencia, [abre un issue](https://github.com/MarioACo/vanilla-builder/issues) con el ejemplo más pequeño que puedas compartir.
|
|
582
|
+
|
|
583
|
+
## Limitaciones conocidas
|
|
584
|
+
|
|
585
|
+
- Ningún ofuscador hace el código imposible de leer; solo lo hace mucho más caro de entender.
|
|
586
|
+
- Con `hash`, JS y CSS cambian de nombre. Si tu código pide alguno con una ruta escrita como texto, también se publica la ruta original y recibes un aviso.
|
|
587
|
+
- Colapsar espacios del HTML cambia `textContent`, pero no lo que se ve. Para conservar el texto byte a byte: `"html": { "collapseWhitespace": false }`.
|
|
588
|
+
- Un `import()` con ruta totalmente calculada hace que ese grupo de módulos se minifique archivo por archivo en vez de empaquetarse, para que las rutas sigan funcionando.
|
|
589
|
+
- TypeScript: no se comprueban tipos, no hay `.tsx`/JSX, y los source maps apuntan al JavaScript ya sin tipos.
|
|
590
|
+
- `--images` recodifica JPEG y WebP con pérdida (PNG es sin pérdida). No se generan formatos modernos (WebP/AVIF a partir de JPEG), porque habría que cambiar tu HTML.
|
|
591
|
+
|
|
592
|
+
## Contribuir
|
|
593
|
+
|
|
594
|
+
Los issues y pull requests son bienvenidos.
|
|
595
|
+
|
|
596
|
+
```bash
|
|
597
|
+
git clone https://github.com/MarioACo/vanilla-builder.git
|
|
598
|
+
cd vanilla-builder
|
|
599
|
+
npm install
|
|
600
|
+
npm test # pruebas unitarias y de integración (Node 18+; en Node 16: npm run test:node16)
|
|
601
|
+
npm run test:browser # sitios originales frente a compilados en Chromium (usa Chrome/Edge o BUILDER_CHROMIUM)
|
|
602
|
+
npm run bench # rendimiento sobre un sitio generado
|
|
603
|
+
cd bench/compare && npm install && node run.mjs # comparación con Parcel y Vite
|
|
604
|
+
```
|
|
228
605
|
|
|
229
606
|
## Licencia
|
|
230
607
|
|