vanilla-builder 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.es.md +162 -0
- package/README.md +163 -2
- package/bin/builder.js +367 -0
- package/package.json +79 -4
- package/src/builder.js +1202 -0
- package/src/config.js +190 -0
- package/src/css.js +166 -0
- package/src/deps.js +140 -0
- package/src/files.js +152 -0
- package/src/html.js +446 -0
- package/src/index.js +22 -0
- package/src/js.js +592 -0
- package/src/jsinfo.js +290 -0
- package/src/obfuscate.js +160 -0
- package/src/optional.js +38 -0
- package/src/output.js +100 -0
- package/src/report.js +79 -0
- package/src/server.js +124 -0
- package/src/sourcemap.js +77 -0
- package/src/urls.js +105 -0
- package/src/util.js +151 -0
- package/src/verify.js +148 -0
- package/src/watch.js +60 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/).
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-11-08
|
|
6
|
+
|
|
7
|
+
First public release.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `builder build | analyze | init | dev | serve` CLI and `build()` / `analyze()` API.
|
|
12
|
+
- Dependency discovery from every HTML page: classic and module scripts, import maps, CSS `@import`/`url()`/`image-set()`, media, icons, manifest, workers, service workers, dynamic `import()` and `new URL(..., import.meta.url)`.
|
|
13
|
+
- Lossless pipeline: every file gets a known fate, output is built in a temp folder, verified and only then swapped into `dist/`.
|
|
14
|
+
- Conservative HTML minifier on parse5 with structural verification.
|
|
15
|
+
- JS/CSS bundling and minification with esbuild, optional terser pass, safe merging of classic scripts.
|
|
16
|
+
- Optional obfuscation (`low`, `medium`, `high`, `max`) with javascript-obfuscator; third-party libraries are detected and left untouched unless requested.
|
|
17
|
+
- Content hashing, source maps, SRI recomputation, gzip/brotli precompression, `--json` output for CI.
|
|
18
|
+
- Projects opened through a symlink or junction (e.g. macOS `/tmp`) now build; the root is resolved to its real path.
|
|
19
|
+
- MIT license, CI on Node 16–24 (Linux, Windows, macOS) and browser equivalence tests in Chrome.
|
|
20
|
+
|
|
21
|
+
[0.1.0]: https://github.com/MarioACo/vanilla-builder/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MarioACo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.es.md
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# vanilla-builder
|
|
2
|
+
|
|
3
|
+
[](https://github.com/MarioACo/vanilla-builder/actions/workflows/ci.yml) [](https://www.npmjs.com/package/vanilla-builder) [](LICENSE)
|
|
4
|
+
|
|
5
|
+
[English](README.md) · **Español**
|
|
6
|
+
|
|
7
|
+
Empaqueta, minifica y ofusca proyectos web **vanilla** (HTML, CSS y JavaScript sin framework) **sin perder nada**.
|
|
8
|
+
Detecta solo las dependencias de cada página, verifica la salida antes de publicarla y nunca borra lo que no creó.
|
|
9
|
+
|
|
10
|
+
- **Cero configuración**: apúntalo a una carpeta con `.html` y listo.
|
|
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
|
+
- **Ligero**: 57 KB propios; la instalación base son 8 paquetes (el grueso es el binario de esbuild). El ofuscador y terser se instalan solo si los usas.
|
|
13
|
+
- **Node 16 o superior** (probado en 16, 18, 20, 22 y 24).
|
|
14
|
+
|
|
15
|
+
## Instalación
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install --save-dev vanilla-builder # o: npm link desde esta carpeta
|
|
19
|
+
npm install --save-dev javascript-obfuscator # solo si vas a ofuscar
|
|
20
|
+
npm install --save-dev terser # solo si quieres la compresión máxima
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
> En Node 16 y 17, npm muestra un aviso `EBADENGINE` porque esbuild declara Node 18+. Es solo un aviso:
|
|
24
|
+
> toda la batería de pruebas (incluidas las de navegador) pasa compilando con Node 16.
|
|
25
|
+
|
|
26
|
+
## Uso
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
builder build mi-sitio # compila en mi-sitio/dist
|
|
30
|
+
builder build mi-sitio --obfuscate # además ofusca tu JavaScript (nivel medium)
|
|
31
|
+
builder analyze mi-sitio # muestra qué pasará con cada archivo, sin escribir nada
|
|
32
|
+
builder init mi-sitio # crea builder.config.json con lo detectado
|
|
33
|
+
builder dev mi-sitio # compila, vigila cambios y sirve dist/ con recarga automática
|
|
34
|
+
builder serve mi-sitio # sirve dist/ para probarlo
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Opciones frecuentes de `build` (todas tienen equivalente en la configuración):
|
|
38
|
+
|
|
39
|
+
| Opción | Qué hace |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `--obfuscate [low\|medium\|high\|max]` | Ofusca tu JS. Las librerías de terceros se detectan y no se tocan. |
|
|
42
|
+
| `--dep <patrón>` / `--not-dep <patrón>` | Marca a mano una dependencia / corrige una detección. |
|
|
43
|
+
| `--obfuscate-deps` | Ofusca también las dependencias. |
|
|
44
|
+
| `--minifier terser` | Segunda pasada de compresión con terser (JS aún más pequeño). |
|
|
45
|
+
| `--compress [gzip\|brotli]` | Genera además `.gz` y `.br` para servidores que sirven precomprimido. |
|
|
46
|
+
| `--hash` | Nombres con hash en JS/CSS para caché a largo plazo. |
|
|
47
|
+
| `--sourcemap [linked\|hidden\|inline]` | Source maps. |
|
|
48
|
+
| `--target es2018` | Transpila a un nivel concreto (por defecto: el del propio código). |
|
|
49
|
+
| `--drop-console` | Quita `console.*` y `debugger`. |
|
|
50
|
+
| `--entry`, `--include`, `--ignore` | Entradas explícitas, archivos forzados y excluidos (repetibles). |
|
|
51
|
+
| `--json` | Resultado en JSON para CI (código de salida 1 si algo falla). |
|
|
52
|
+
|
|
53
|
+
## Qué detecta solo
|
|
54
|
+
|
|
55
|
+
Partiendo de cada `.html`, Builder sigue:
|
|
56
|
+
|
|
57
|
+
- `<script src>` clásicos y `type="module"`, scripts inline e **import maps**.
|
|
58
|
+
- `<link rel="stylesheet">`, `@import` y `url()` del CSS (también `image-set()`), `<style>` y atributos `style`.
|
|
59
|
+
- Imágenes, `srcset`, vídeo, audio, iconos, manifest, `og:image`, `<iframe>`, `<object>`, SVG `<use>`…
|
|
60
|
+
- Enlaces a otras páginas, `import()` dinámicos, `new URL('./x', import.meta.url)`.
|
|
61
|
+
- Workers, service workers e `importScripts()`.
|
|
62
|
+
- Rutas escritas como texto en el JS (por ejemplo la lista de precache de un service worker): esos archivos se publican también en su ruta original.
|
|
63
|
+
|
|
64
|
+
Lo que no se puede seguir (un `fetch(variable)`, una plantilla del servidor…) **no se pierde**: la estructura de carpetas se conserva y todo lo no referenciado se publica igualmente (`unreferenced: "process"`).
|
|
65
|
+
|
|
66
|
+
## Garantías
|
|
67
|
+
|
|
68
|
+
| Riesgo típico de un builder | Cómo lo evita Builder |
|
|
69
|
+
| --- | --- |
|
|
70
|
+
| Unir scripts clásicos rompe variables globales | Solo une scripts consecutivos, con el mismo `defer`/modo estricto, sin `document.currentScript`, sin redeclarar `let/const` y con separador seguro (`;`). |
|
|
71
|
+
| La minificación crea globales nuevas o renombra las tuyas | Compara las globales antes y después; si cambian, usa una minificación más conservadora o deja el original. |
|
|
72
|
+
| El ofuscador rompe exportaciones o atributos `with { type }` | Verifica exportaciones, importaciones y atributos tras ofuscar; si no cuadran, no ofusca ese archivo. |
|
|
73
|
+
| esbuild borra en silencio `with { type: 'css' }` | Se fuerza la conservación de los atributos de import. |
|
|
74
|
+
| La minificación HTML cambia el texto | Minificador propio sobre parse5 y comprobación estructural (elementos, atributos y texto). `<pre>`, `<textarea>` y plantillas quedan intactos; si el CSS usa `white-space: pre`, no colapsa espacios. |
|
|
75
|
+
| `integrity` (SRI) obsoleto bloquea scripts | Se recalcula al cambiar el contenido. |
|
|
76
|
+
| Codificaciones antiguas o BOM | Se conservan los bytes (HTML) o se emite JS/CSS con escapes ASCII. |
|
|
77
|
+
| JSON reformateado pierde precisión | Solo se quitan espacios fuera de las cadenas: `2.0` y números enormes quedan igual. |
|
|
78
|
+
| Borrar `dist/` equivocado | Nunca vacía una carpeta que no creó (marca `.builder-manifest.json`), ni la del proyecto, ni la raíz. |
|
|
79
|
+
| Compilación fallida a medias | Se escribe en una carpeta temporal, se verifica y solo entonces reemplaza `dist/`. |
|
|
80
|
+
| Publicar secretos | `.env*`, claves `.pem/.key`, `node_modules`, `package.json` y configuración de herramientas quedan fuera por defecto. |
|
|
81
|
+
|
|
82
|
+
La batería de pruebas abre cada sitio de ejemplo **original y compilado en Chromium** y exige resultados idénticos, sin errores ni 404, con 5 variantes (por defecto, ofuscación alta + hash, ofuscación max, terser + precompresión, sin minificar).
|
|
83
|
+
|
|
84
|
+
## Dependencias de terceros y ofuscación
|
|
85
|
+
|
|
86
|
+
Ofuscar jQuery, Bootstrap o un paquete de npm no protege nada tuyo, los hace más lentos y puede incumplir su licencia. Por eso, al ofuscar:
|
|
87
|
+
|
|
88
|
+
- Se detectan como dependencia los archivos en `vendor/`, `node_modules/`, `third-party/`…, los nombres de librerías conocidas (`jquery-3.7.1.min.js`, `bootstrap.bundle.js`…), los `.min.js`/`.umd.js`, el código ya minificado y las cabeceras de licencia con versión (`/*! Foo v1.2.0 */`).
|
|
89
|
+
- 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).
|
|
90
|
+
- `builder analyze` lista qué detectó y por qué.
|
|
91
|
+
|
|
92
|
+
Para corregirlo a mano:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"obfuscate": "high",
|
|
97
|
+
"dependencies": {
|
|
98
|
+
"include": ["js/mi-libreria.js"],
|
|
99
|
+
"exclude": ["js/app.min.js"],
|
|
100
|
+
"obfuscate": false
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`include` marca dependencias que no se detectaron; `exclude` indica que un archivo es tuyo y sí debe ofuscarse; `obfuscate: true` ofusca todo.
|
|
106
|
+
|
|
107
|
+
Niveles: `low` (casi sin coste), `medium` (recomendado), `high` y `max` (además se defiende de ser formateado o modificado; más pesado y lento). Las opciones que cambian el comportamiento (`debugProtection`, `disableConsoleOutput`, `renameGlobals`) nunca se activan solas; puedes pasarlas con un objeto: `"obfuscate": { "preset": "high", "debugProtection": true }`. Tus comentarios de licencia (`/*! … */`, `@license`) se conservan.
|
|
108
|
+
|
|
109
|
+
## Configuración (`builder.config.json`)
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"outDir": "dist",
|
|
114
|
+
"entries": "auto",
|
|
115
|
+
"include": [],
|
|
116
|
+
"ignore": [],
|
|
117
|
+
"unreferenced": "process",
|
|
118
|
+
"obfuscate": false,
|
|
119
|
+
"dependencies": { "detect": true, "obfuscate": false, "include": [], "exclude": [] },
|
|
120
|
+
"hash": false,
|
|
121
|
+
"sourcemap": false,
|
|
122
|
+
"compress": false,
|
|
123
|
+
"base": "/",
|
|
124
|
+
"sri": "auto",
|
|
125
|
+
"html": { "minify": true, "removeComments": true, "collapseWhitespace": "auto" },
|
|
126
|
+
"css": { "minify": true, "bundle": true, "target": "esnext" },
|
|
127
|
+
"js": { "minify": true, "bundle": true, "target": "auto", "minifier": "esbuild", "mergeClassic": "auto", "drop": [], "legalComments": "eof", "chunkDir": "assets" }
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
- `entries`: `"auto"` toma todos los HTML completos; también admite una lista de `.html`, `.js` o `.css`.
|
|
132
|
+
- `unreferenced`: qué hacer con lo que nada referencia: `process` (minificar y publicar), `copy` o `skip`.
|
|
133
|
+
- `js.target: "auto"` usa el nivel de sintaxis de tu propio código: no transpila ni introduce sintaxis más nueva que la que ya usas.
|
|
134
|
+
- También se acepta `builder.config.mjs` (exporta un objeto o una función). Las opciones mal escritas dan error con sugerencia.
|
|
135
|
+
|
|
136
|
+
## API
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
import { build, analyze } from 'vanilla-builder';
|
|
140
|
+
|
|
141
|
+
const result = await build({ dir: 'mi-sitio', overrides: { obfuscate: 'high' } });
|
|
142
|
+
console.log(result.report.totals, result.warnings);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Desarrollo
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npm test # unitarias + integración (Node 18+; en Node 16: npm run test:node16)
|
|
149
|
+
npm run test:browser # equivalencia real en Chromium (busca Chrome/Edge o usa BUILDER_CHROMIUM)
|
|
150
|
+
BUILDER_NODE=/ruta/node16 npm run test:browser # compila con otro Node y verifica en el navegador
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Límites conocidos
|
|
154
|
+
|
|
155
|
+
- Ningún ofuscador hace el código imposible de leer: solo lo encarece mucho.
|
|
156
|
+
- Con `hash: true`, los JS/CSS cambian de nombre; si tu código los pide por texto, Builder publica también la ruta original y lo avisa.
|
|
157
|
+
- Colapsar espacios en HTML cambia `textContent` (no lo que se ve). Para conservarlo byte a byte: `"html": { "collapseWhitespace": false }`.
|
|
158
|
+
- `import()` con rutas calculadas sin prefijo fijo hace que ese grupo de módulos se minifique archivo por archivo en su sitio (sin empaquetar), para no romper rutas.
|
|
159
|
+
|
|
160
|
+
## Licencia
|
|
161
|
+
|
|
162
|
+
[MIT](LICENSE) © MarioACo
|
package/README.md
CHANGED
|
@@ -1,3 +1,164 @@
|
|
|
1
|
-
#
|
|
1
|
+
# vanilla-builder
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/MarioACo/vanilla-builder/actions/workflows/ci.yml) [](https://www.npmjs.com/package/vanilla-builder) [](LICENSE)
|
|
4
|
+
|
|
5
|
+
**English** · [Español](README.es.md)
|
|
6
|
+
|
|
7
|
+
Bundle, minify and obfuscate **vanilla** web projects (HTML, CSS and JavaScript, no framework) **without losing anything**.
|
|
8
|
+
It follows the real dependencies of every page, verifies the output before publishing it and never deletes what it did not create.
|
|
9
|
+
|
|
10
|
+
- **Zero config**: point it at a folder with `.html` files and you are done.
|
|
11
|
+
- **Lossless**: every project file ends up with a known fate (processed, bundled, copied or deliberately skipped), and the output is verified before it replaces `dist/`.
|
|
12
|
+
- **Lightweight**: 57 KB of its own code; the base install is 8 packages (most of it is the esbuild binary). The obfuscator and terser are only installed if you use them.
|
|
13
|
+
- **Node 16 or newer** (tested on 16, 18, 20, 22 and 24).
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install --save-dev vanilla-builder
|
|
19
|
+
npm install --save-dev javascript-obfuscator # only if you obfuscate
|
|
20
|
+
npm install --save-dev terser # only if you want maximum compression
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
> On Node 16 and 17 npm prints an `EBADENGINE` warning because esbuild declares Node 18+. It is only a warning:
|
|
24
|
+
> the whole test suite (browser tests included) passes when building with Node 16.
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx builder build my-site # builds into my-site/dist
|
|
30
|
+
npx builder build my-site --obfuscate # also obfuscates your JavaScript (medium level)
|
|
31
|
+
npx builder analyze my-site # shows what will happen to each file, writes nothing
|
|
32
|
+
npx builder init my-site # creates builder.config.json from what it detected
|
|
33
|
+
npx builder dev my-site # builds, watches and serves dist/ with live reload
|
|
34
|
+
npx builder serve my-site # serves dist/ to try it out
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Common `build` options (all of them have a config equivalent):
|
|
38
|
+
|
|
39
|
+
| Option | What it does |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `--obfuscate [low\|medium\|high\|max]` | Obfuscates your JS. Third-party libraries are detected and left untouched. |
|
|
42
|
+
| `--dep <pattern>` / `--not-dep <pattern>` | Manually mark a dependency / correct a detection. |
|
|
43
|
+
| `--obfuscate-deps` | Obfuscate dependencies too. |
|
|
44
|
+
| `--minifier terser` | Second compression pass with terser (even smaller JS). |
|
|
45
|
+
| `--compress [gzip\|brotli]` | Also emits `.gz` and `.br` files for servers that serve precompressed assets. |
|
|
46
|
+
| `--hash` | Hashed JS/CSS file names for long-term caching. |
|
|
47
|
+
| `--sourcemap [linked\|hidden\|inline]` | Source maps. |
|
|
48
|
+
| `--target es2018` | Transpile to a specific level (default: whatever your own code already uses). |
|
|
49
|
+
| `--drop-console` | Removes `console.*` and `debugger`. |
|
|
50
|
+
| `--entry`, `--include`, `--ignore` | Explicit entries, forced files and exclusions (repeatable). |
|
|
51
|
+
| `--json` | JSON output for CI (exit code 1 if anything fails). |
|
|
52
|
+
|
|
53
|
+
Run `npx builder help` for the full list.
|
|
54
|
+
|
|
55
|
+
## What it detects on its own
|
|
56
|
+
|
|
57
|
+
Starting from each `.html` file, it follows:
|
|
58
|
+
|
|
59
|
+
- Classic and `type="module"` `<script src>`, inline scripts and **import maps**.
|
|
60
|
+
- `<link rel="stylesheet">`, CSS `@import` and `url()` (including `image-set()`), `<style>` and `style` attributes.
|
|
61
|
+
- Images, `srcset`, video, audio, icons, manifest, `og:image`, `<iframe>`, `<object>`, SVG `<use>`…
|
|
62
|
+
- Links to other pages, dynamic `import()`, `new URL('./x', import.meta.url)`.
|
|
63
|
+
- Workers, service workers and `importScripts()`.
|
|
64
|
+
- Paths written as strings in JS (for example a service worker precache list): those files are also published at their original path.
|
|
65
|
+
|
|
66
|
+
What cannot be followed (a `fetch(variable)`, a server template…) **is not lost**: the folder structure is preserved and everything unreferenced is still published (`unreferenced: "process"`).
|
|
67
|
+
|
|
68
|
+
## Guarantees
|
|
69
|
+
|
|
70
|
+
| Typical bundler risk | How vanilla-builder avoids it |
|
|
71
|
+
| --- | --- |
|
|
72
|
+
| Concatenating classic scripts breaks globals | Only merges consecutive scripts with the same `defer`/strict mode, no `document.currentScript`, no `let/const` redeclarations, and a safe `;` separator. |
|
|
73
|
+
| Minification creates new globals or renames yours | Compares globals before and after; if they differ it falls back to a more conservative minification or keeps the original. |
|
|
74
|
+
| The obfuscator breaks exports or `with { type }` attributes | Checks exports, imports and attributes after obfuscating; if they do not match, that file is not obfuscated. |
|
|
75
|
+
| esbuild silently drops `with { type: 'css' }` | Import attributes are forcibly preserved. |
|
|
76
|
+
| HTML minification changes the text | Own minifier on top of parse5 plus a structural check (elements, attributes and text). `<pre>`, `<textarea>` and templates stay intact; if the CSS uses `white-space: pre`, whitespace is not collapsed. |
|
|
77
|
+
| Stale `integrity` (SRI) blocks scripts | Recomputed whenever the content changes. |
|
|
78
|
+
| Legacy encodings or BOM | Bytes are preserved (HTML) or JS/CSS is emitted with ASCII escapes. |
|
|
79
|
+
| Reformatted JSON loses precision | Only whitespace outside strings is removed: `2.0` and huge numbers stay the same. |
|
|
80
|
+
| Wiping the wrong `dist/` | Never empties a folder it did not create (marked with `.builder-manifest.json`), nor the project folder, nor the root. |
|
|
81
|
+
| Half-finished build | Writes into a temp folder, verifies it, and only then replaces `dist/`. |
|
|
82
|
+
| Publishing secrets | `.env*`, `.pem/.key` keys, `node_modules`, `package.json` and tool configs are excluded by default. |
|
|
83
|
+
|
|
84
|
+
The test suite opens every example site **original and built in Chromium** and requires identical results, with no errors and no 404s, across 5 variants (default, high obfuscation + hash, max obfuscation, terser + precompression, unminified).
|
|
85
|
+
|
|
86
|
+
## Third-party dependencies and obfuscation
|
|
87
|
+
|
|
88
|
+
Obfuscating jQuery, Bootstrap or an npm package protects nothing of yours, makes them slower and may violate their license. So when obfuscating:
|
|
89
|
+
|
|
90
|
+
- Files in `vendor/`, `node_modules/`, `third-party/`…, well-known library names (`jquery-3.7.1.min.js`, `bootstrap.bundle.js`…), `.min.js`/`.umd.js` files, already-minified code and license headers with a version (`/*! Foo v1.2.0 */`) are detected as dependencies.
|
|
91
|
+
- npm packages imported by your module code are split into `assets/vendor/` (not obfuscated, with their shared state intact).
|
|
92
|
+
- `builder analyze` lists what it detected and why.
|
|
93
|
+
|
|
94
|
+
To correct it by hand:
|
|
95
|
+
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"obfuscate": "high",
|
|
99
|
+
"dependencies": {
|
|
100
|
+
"include": ["js/my-library.js"],
|
|
101
|
+
"exclude": ["js/app.min.js"],
|
|
102
|
+
"obfuscate": false
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`include` marks dependencies that were not detected; `exclude` says a file is yours and should be obfuscated; `obfuscate: true` obfuscates everything.
|
|
108
|
+
|
|
109
|
+
Levels: `low` (almost free), `medium` (recommended), `high` and `max` (also defends against being reformatted or tampered with; heavier and slower). Options that change behavior (`debugProtection`, `disableConsoleOutput`, `renameGlobals`) are never turned on automatically; pass them with an object: `"obfuscate": { "preset": "high", "debugProtection": true }`. Your license comments (`/*! … */`, `@license`) are kept.
|
|
110
|
+
|
|
111
|
+
## Configuration (`builder.config.json`)
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"outDir": "dist",
|
|
116
|
+
"entries": "auto",
|
|
117
|
+
"include": [],
|
|
118
|
+
"ignore": [],
|
|
119
|
+
"unreferenced": "process",
|
|
120
|
+
"obfuscate": false,
|
|
121
|
+
"dependencies": { "detect": true, "obfuscate": false, "include": [], "exclude": [] },
|
|
122
|
+
"hash": false,
|
|
123
|
+
"sourcemap": false,
|
|
124
|
+
"compress": false,
|
|
125
|
+
"base": "/",
|
|
126
|
+
"sri": "auto",
|
|
127
|
+
"html": { "minify": true, "removeComments": true, "collapseWhitespace": "auto" },
|
|
128
|
+
"css": { "minify": true, "bundle": true, "target": "esnext" },
|
|
129
|
+
"js": { "minify": true, "bundle": true, "target": "auto", "minifier": "esbuild", "mergeClassic": "auto", "drop": [], "legalComments": "eof", "chunkDir": "assets" }
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- `entries`: `"auto"` takes every complete HTML file; it also accepts a list of `.html`, `.js` or `.css` files.
|
|
134
|
+
- `unreferenced`: what to do with files nothing references: `process` (minify and publish), `copy` or `skip`.
|
|
135
|
+
- `js.target: "auto"` uses the syntax level of your own code: it neither transpiles nor introduces newer syntax than you already use.
|
|
136
|
+
- `builder.config.mjs` is also accepted (export an object or a function). Misspelled options raise an error with a suggestion.
|
|
137
|
+
|
|
138
|
+
## API
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
import { build, analyze } from 'vanilla-builder';
|
|
142
|
+
|
|
143
|
+
const result = await build({ dir: 'my-site', overrides: { obfuscate: 'high' } });
|
|
144
|
+
console.log(result.report.totals, result.warnings);
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Development
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npm test # unit + integration (Node 18+; on Node 16: npm run test:node16)
|
|
151
|
+
npm run test:browser # real equivalence in Chromium (finds Chrome/Edge or uses BUILDER_CHROMIUM)
|
|
152
|
+
BUILDER_NODE=/path/to/node16 npm run test:browser # build with another Node and verify in the browser
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Known limits
|
|
156
|
+
|
|
157
|
+
- No obfuscator makes code impossible to read: it only makes it much more expensive.
|
|
158
|
+
- With `hash: true`, JS/CSS files are renamed; if your code requests them by string, the original path is also published and you get a warning.
|
|
159
|
+
- Collapsing HTML whitespace changes `textContent` (not what you see). To keep it byte for byte: `"html": { "collapseWhitespace": false }`.
|
|
160
|
+
- `import()` with computed paths and no fixed prefix makes that group of modules minify file by file in place (without bundling), so paths do not break.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
[MIT](LICENSE) © MarioACo
|