add --minify and --obfuscate flags to elc JS pipeline
Adds two post-processing flags that produce production-ready browser JS in a single elc invocation, replacing extract-js.py in the web product pipeline: elc --target=js --bundle --minify source.el > output.min.js elc --target=js --bundle --obfuscate source.el > output.obf.js --minify shells out to terser (passes=2, no drop_console, drop_debugger). --obfuscate shells out to javascript-obfuscator with the same options as the old extract-js.py script. --obfuscate implies --minify. Tool discovery: checks ./node_modules/.bin/, ../node_modules/.bin/ (monorepo), then falls back to npx. Both flags require --target=js; passing either without it exits 1 with a clear error. Both tools receive a reserved-names list of globals referenced from HTML onclick= attributes (neuronDemoToggle, signInWith, NEURON_CFG, etc.) so they are not mangled. Implementation adds stdout_to_file(path)/stdout_restore() builtins to the C runtime so codegen's println-streamed output can be captured to a temp file before being piped through the external tools. Temp files use /tmp/elc-<pid>-<timestamp>.js naming and are cleaned up on success and failure. Rebuilds dist/platform/elc and dist/platform/elc.c. Self-hosting verified.
This commit is contained in:
@@ -240,6 +240,93 @@ The argv parser scans for a `--target=<lang>` token; remaining positional args a
|
||||
|
||||
---
|
||||
|
||||
## 8a. Production output — `--minify` and `--obfuscate`
|
||||
|
||||
Two post-processing flags produce production-ready browser JS in a single compiler invocation, replacing any external post-processing scripts.
|
||||
|
||||
### Usage
|
||||
|
||||
```
|
||||
elc --target=js --bundle --minify source.el > output.min.js
|
||||
elc --target=js --bundle --obfuscate source.el > output.obf.js
|
||||
elc --target=js --bundle --minify --obfuscate source.el > output.final.js
|
||||
```
|
||||
|
||||
Both flags require `--target=js`. Passing either without `--target=js` prints an error and exits with code 1.
|
||||
|
||||
`--obfuscate` implies `--minify` — obfuscating unminified code produces no benefit and only increases output size.
|
||||
|
||||
### Pipeline order
|
||||
|
||||
```
|
||||
generate JS -> (if --bundle, wrap in IIFE) -> (if --minify, run terser) -> (if --obfuscate, run javascript-obfuscator) -> output
|
||||
```
|
||||
|
||||
### Tool discovery
|
||||
|
||||
The compiler looks for each tool in this order:
|
||||
|
||||
1. `<src_dir>/node_modules/.bin/<tool>` — local install next to source file
|
||||
2. `<src_dir>/../node_modules/.bin/<tool>` — one level up (monorepo layout)
|
||||
3. `npx --yes <tool>` — fall back to npx (uses globally cached package or downloads on first use)
|
||||
|
||||
If no path resolves and npx is not on `PATH`, the compiler prints a clear error and exits non-zero:
|
||||
|
||||
```
|
||||
el-compiler: error: terser not found. Run 'npm install terser' in your project directory.
|
||||
el-compiler: error: javascript-obfuscator not found. Run 'npm install javascript-obfuscator' in your project directory.
|
||||
```
|
||||
|
||||
### Minification (terser)
|
||||
|
||||
Command issued internally:
|
||||
|
||||
```
|
||||
terser <tmpfile> --compress passes=2,drop_console=false,drop_debugger=true \
|
||||
--mangle 'reserved=[<reserved>]' --output <tmpfile.min>
|
||||
```
|
||||
|
||||
### Obfuscation (javascript-obfuscator)
|
||||
|
||||
Command issued internally (runs after minification):
|
||||
|
||||
```
|
||||
javascript-obfuscator <input> --output <output>
|
||||
--compact true
|
||||
--simplify true
|
||||
--string-array true
|
||||
--string-array-encoding base64
|
||||
--string-array-threshold 0.75
|
||||
--identifier-names-generator hexadecimal
|
||||
--rename-globals false
|
||||
--self-defending false
|
||||
--reserved-names <reserved>
|
||||
```
|
||||
|
||||
### Reserved names
|
||||
|
||||
These identifiers are protected from renaming by both tools. They are referenced directly from HTML `onclick=` attributes and other global-scope callsites:
|
||||
|
||||
```
|
||||
neuronDemoToggle, neuronDemoSend, neuronDemoReset,
|
||||
signInWith, signInWithEmail, signUpWithEmail, sendMagicLink,
|
||||
signOut, resetPassword, sendResetEmail, updatePassword,
|
||||
showSignIn, showSignUp, hideReset,
|
||||
setSort, addFamilyMember, removeFamilyMember, copyForPlatform, entHeadcountChange,
|
||||
NEURON_CFG
|
||||
```
|
||||
|
||||
### Temp files
|
||||
|
||||
The compiler uses `/tmp/elc-<pid>-<timestamp>.js` naming for temp files. All temp files are cleaned up on both success and failure paths.
|
||||
|
||||
### Implementation notes
|
||||
|
||||
- The compiler adds `stdout_to_file(path)` / `stdout_restore()` builtins to the C runtime (`el_runtime.c`) to capture codegen output (which is streamed via `println`) into a temp file before passing it to the external tools.
|
||||
- `--minify` and `--obfuscate` error messages are printed after stdout is restored, so they always reach the terminal regardless of output redirection.
|
||||
|
||||
---
|
||||
|
||||
## 9. The path to compiling el-ui/runtime through this backend
|
||||
|
||||
This is the real-world test. `el-ui/runtime/src/` is currently 5 hand-written `.js` files. The path to authoring them in El:
|
||||
|
||||
Reference in New Issue
Block a user