V3 Vue apps
Vue 3 is the best-supported multi-screen framework in V3 because a runtime-compiler build exists — meaning template strings compile in the browser without a toolchain. The traps below come from using the wrong Vue build, or reaching for features that assume Vite/webpack.
Loading the framework
Add vue via add_dependencies with lazy: true, then:
await Fliplet.require.lazy('vue');
const Vue = window.Vue;
Fliplet.require.lazy(name) resolves once the UMD bundle has executed; the module itself lands on window (window.Vue, window.VueRouter). Read it off window after the await — assigning the awaited value directly gives you the URL string, not the module.
Pick the runtime-compiler build (usually vue.global.js), not the runtime-only build. The runtime-only build (vue.runtime.global.js) does not include the template compiler — any component that uses template: '...' strings will fail to render. The runtime-only build only works if every component is authored as a pre-compiled render function, which is impractical without a bundler.
For Vue Router, the separate dependency:
await Fliplet.require.lazy('vue-router');
const VueRouter = window.VueRouter;
Features that need a build step
| Feature | Why it fails | Do this instead |
|---|---|---|
.vue single-file components |
There is no loader resolving them at runtime | Use plain component objects with template: strings, or add vue3-sfc-loader as a dependency if the app genuinely needs SFCs. Pick one approach per app and stay consistent. |
<script setup> |
Requires SFC compilation | Use the Options API or explicit setup() function on component objects. |
<style scoped> |
Requires SFC compilation | Scope manually by wrapping each component’s CSS in a root class selector. |
Bare ESM imports (import Vue from 'vue') |
No bundler resolves the specifier | Use Fliplet.require.lazy('vue'). |
TypeScript (.ts, .tsx) |
No transpiler | Plain JavaScript. |
Wiring to Fliplet.Router
Full contract is in V3 routing. Vue-specific note: pass the base path into createWebHistory:
const router = VueRouter.createRouter({
history: VueRouter.createWebHistory(Fliplet.Router.getBasePath()),
routes: [...]
});
createWebHashHistory is rejected by the boot-HTML lint (rule create-web-hash-history).
Build routes from Fliplet.Router.getRouteManifest() — do not hardcode. In each route’s resolver, call Fliplet.Router.resolveRoute(path). The content field in its result IS the screen’s source — already fetched for you via Fliplet.Media.getContents. Return it from your loader and render it in your component; don’t fetch the file again.
Binding Fliplet.Media.authenticate
Authenticated URLs resolve asynchronously — bind through reactivity, not at module load:
// inside a component
data() { return { logoSrc: '' }; },
async mounted() {
this.logoSrc = await Fliplet.Media.authenticate(rawUrl);
}
Then <img :src="logoSrc">. Using src="" directly, or computing the authenticated URL at module scope, leaves the image broken until the template re-renders.
Common errors
Symptom in get_preview_logs('errors') |
Cause | Fix |
|---|---|---|
[Vue warn]: Component is missing template or render function |
Runtime-only Vue build loaded; template: strings silently ignored |
Switch to the runtime-compiler build (vue.global.js) |
Uncaught SyntaxError: Unexpected token '<' inside a component file |
.vue SFC uploaded without vue3-sfc-loader |
Either convert the component to a plain object with template: string, or add vue3-sfc-loader |
| Blank screen, no errors | Component returned from Fliplet.Media.getContents wasn’t registered before router resolved |
Register the component inside the route resolver, not at module load |
DO / DON’T
- DO use
Fliplet.require.lazy('vue')and the runtime-compiler build. - DO build the router from
Fliplet.Router.getRouteManifest()+getBasePath(). - DO bind authenticated media URLs into reactive
data()fields. - DON’T use
createWebHashHistory— rejected by lint. - DON’T author
.vueSFCs withoutvue3-sfc-loaderloaded. - DON’T
importanything — useFliplet.require.lazy.