V3 vanilla-JS apps
Vanilla JS is the lowest-friction V3 target because there is no framework to load and no syntax the browser can’t parse. Most of the work is just respecting the V3 bootstrap contract and the routing lint.
Loading the framework
Nothing to load. Still call Fliplet().then(...) before touching Fliplet APIs — the runtime needs to finish registering globals.
Features that need a build step
Vanilla JS is the cheapest option precisely because nothing here needs a build step. Two things to still be careful of:
- No bare ESM imports across source files.
import { helper } from './helpers'fails because there is no bundler to resolve the specifier. Load shared code either as a single uploaded source file evaluated viaFliplet.Media.getContents, or as a registered dependency viaFliplet.require.lazy. - Top-level
awaitacross files won’t work for the same reason — no module graph.
Modern browser syntax (optional chaining, nullish coalescing, destructuring, async/await inside functions) is fine. The target is a current Chromium.
Wiring to Fliplet.Router
Navigation is platform-conditional: the History API on web, the hash on native (Cordova file:// blocks pushState path changes). Branch on Fliplet.Router.isNative():
if (Fliplet.Router.isNative()) {
location.hash = path; // native — fires 'hashchange'
} else {
history.pushState({}, '', Fliplet.Router.getBasePath() + path);
window.dispatchEvent(new PopStateEvent('popstate')); // web — fires 'popstate'
}
Read the current route from location.hash on native, or by stripping Fliplet.Router.getBasePath() from location.pathname on web. Listen for hashchange on native and popstate on web — match the listener to the navigation mechanism. Route resolution (access check + screen-source fetch) goes through Fliplet.Router.resolveRoute(path) — see V3 routing.
Binding Fliplet.Media.authenticate
Authenticated URLs resolve asynchronously. Compute the URL, then assign it to the DOM element:
const url = await Fliplet.Media.authenticate(rawUrl);
imgEl.src = url;
Don’t compute the URL at module load and hope it’s ready — the element will have src="" (or the unauthenticated URL) for long enough to render broken.
Common errors
Symptom in get_preview_logs('errors') |
Cause | Fix |
|---|---|---|
ReferenceError: Fliplet is not defined |
Code ran before Fliplet().then(...) resolved |
Move initialization inside the Fliplet().then(...) callback |
SyntaxError: Cannot use import statement outside a module |
ESM import in an uploaded source file |
Load the dependency via Fliplet.require.lazy or inline the helper |
| Image/font renders broken then disappears | Raw media URL used without Fliplet.Media.authenticate |
Wrap the URL and assign after the promise resolves |
DO / DON’T
- DO branch navigation on
Fliplet.Router.isNative()—location.hash = pathon native,history.pushState(state, '', Fliplet.Router.getBasePath() + path)on web. - DO dispatch
popstateafterpushStateon web so listeners re-render; on native thehashchangeevent fires on its own. - DO listen for
hashchangeon native andpopstateon web — match the listener to the navigation mechanism. - DON’T read or write
window.location.hashon web — the routing lint flags it unless you branch onFliplet.Router.isNative()(hash is the required native branch). - DON’T use
href="#/..."literals for internal links — render real paths and intercept clicks, letting the platform pick the URL shape. - DON’T
importacross uploaded source files — resolve shared code viaFliplet.require.lazyor a single boot file.