:simple vs :advanced Optimization for ClojureScript Backup Integrity
0 reputation · 09 Aug 2022, 07:19 UTC
0 reputation · 09 Aug 2022, 07:19 UTC
When a ClojureScript project is compiled for backup purposes, the selected optimization level determines how much of the original source structure is preserved in the resulting JavaScript.
Without source‑maps, a :advanced build may be difficult to decompile accurately, whereas a :simple build can be inspected more directly. Mixing modules compiled with different levels can lead to inconsistent symbol resolution during restoration.
When restoring from a backup that contains both :simple and :advanced compiled artifacts, how can one reliably verify that the recovered data matches the original semantics without source‑maps? Is there a documented strategy to fall back on decompilation or other techniques in such mixed‑level scenarios?
When a backup contains both :simple and :advanced compiled artifacts and no source‑maps, the only reliable way to confirm that the restored runtime behaves the same as the original is to use deterministic, data‑centric validation rather than decompilation. In practice this means:
Advanced builds rename symbols, inline functions, and remove dead code. Without source‑maps the mapping from runtime identifiers back to source names is lost, and property names used in interop may have been mangled. Even a perfect decompiler will produce code that is syntactically correct but semantically different from the original if externs were omitted or if the code relied on dynamic property access.
const data = serializeBackup();
const hash = crypto.createHash('sha256').update(JSON.stringify(data)).digest('hex');
console.log('Baseline hash:', hash);
:advanced builds, verify that any externally exposed property names (e.g., API keys, event names) match expected strings. If externs were omitted, missing properties will surface as runtime errors.
There is no official ClojureScript or Closure Compiler document that prescribes a decompilation‑based validation workflow for mixed optimization levels. The community consensus is to rely on deterministic tests and checksum comparison, as described above.
Does the backup archive include the original ClojureScript source files (or a copy of the shadow-cljs.edn / project.clj configuration)? If so, you could compare the source hash against the runtime hash to detect any inadvertent changes introduced by the compiler. If not, the checksum‑based approach remains the only practical method.
Use comments to ask for clarification. Post a solution as an answer.
33,775 reputation · 09 Aug 2022, 14:59 UTC
The mixed-level restore problem is mostly preventable at backup time: ClojureScript emits a source map for :advanced builds when :source-map true is set (long-standing compiler behavior — confirm the exact flag for your ClojureScript version), and that .js.map file is what maps mangled symbols back to the original names.
A durable backup set therefore includes:
.js.map files for every :advanced artifact,:advanced preserves interop property names only where externs cover them, andproject.clj, shadow-cljs.edn, or a deps.edn alias), so the artifact can be rebuilt and compared rather than decompiled.For archives already missing maps, a cheap partial check before the hash-based validation described above: string literals survive :advanced compilation unchanged, so grepping the bundle for known literals (version strings, error messages) can at least confirm which build and externs set produced the artifact — enough to rule out a mismatched-externs restore before deeper work begins.