Web assets that belong together (a library with its CSS, fonts and images, or a whole SPA build) are best uploaded as one zip managed file: the coach runtime serves the zip's entries as if they were a folder, so relative references inside the files keep working.
- Build the folder locally: mylib/js/lib.js, mylib/css/lib.css, mylib/fonts/…, mylib/img/…; zip it without the top-level folder if you want short paths (zip -r mylib.zip js css fonts img).
- Toolkit / app > Files > Web files > upload mylib.zip.
- Reference entries in a coach view's Included Scripts: mylib.zip/js/lib.js, mylib.zip/css/lib.css - the picker lets you browse into the zip.
- Inside lib.css, url(../fonts/font.woff2) resolves inside the zip; inside JavaScript, compute the base from the script's own URL when you need it:
// find where the zip is served (works on every release / CP4BA prefix) from a script that is inside the zip
var scripts = document.getElementsByTagName("script"), base = "";
for (var i = 0; i < scripts.length; i++) if (/mylib\.zip\/js\/lib\.js/.test(scripts[i].src)) base = scripts[i].src.replace(/js\/lib\.js.*$/, "");
var img = document.createElement("img"); img.src = base + "img/logo.png";Advantages: one upload per version, atomic updates, no 60 single files in the library, relative paths intact; the entries are cached by the browser with the snapshot id in the URL, so a new snapshot invalidates them. Limits: the zip is loaded into memory when first requested - keep it under a few MB (no full node_modules), and do not put server files (jars) into web zips - those go to Server files. To update a single file you still re-upload the whole zip (keep the source folder in Git and script the packaging).
References