Building a Vue 3–Powered Frappe App: Zero-Config Install, Full Control
Integrating a Vue frontend into a Frappe app can be powerful — but it’s easy to get tangled in folders, build tools, and asset serving. In our changelog_claudion app, we set out to make it complete
Integrating a Vue frontend into a Frappe app can be powerful — but it’s easy to get tangled in folders, build tools, and asset serving. In our changelog_claudion
app, we set out to:
- ✅ Mount a Vue 3 interface inside Frappe Desk
- ✅ Use native asset serving via Frappe’s
public/js/
structure - ✅ Avoid forcing contributors to use Node/Vite
- ✅ Make the app installable via
bench get-app
with no extra setup - ✅ Still keep the code modular, maintainable, and Vue-authentic
Here’s how we did it.
Goals
We wanted to push raw .vue
and .js
files to GitHub — just like POS Awesome does — and let Frappe serve them directly. But we also wanted to use Vue 3 syntax, components, and modern tooling like Vite… without splitting folders or requiring external build environments.
The final solution: Vue 3 + Vite compiled inside the Frappe app, all in one folder. No src/
, no dist/
, just clean output into public/js/changelog_claudion/
.
Final Folder Structure
changelog_claudion/└── public/└── js/└── changelog_claudion/├── changelog_app.js # Vue 3 entry point (compiled)├── Home.vue # Root component (raw)├── format.js # Utility JS├── bus.js # Event bus (optional)├── package.json # Vite project setup├── vite.config.js # Local build config└── components/└── ItemCard.vue # Reusable Vue component
Build Setup: Vue 3 + Vite Inside the App
Instead of keeping the Vue build system in a separate src
folder, we placed everything inside the Frappe app’s public directory:
cd public/js/changelog_claudion/npm init -ynpm install vue@3 vite @vitejs/plugin-vue
vite.config.js
:
import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import path from 'path'export default defineConfig({plugins: [vue()],build: {lib: {entry: path.resolve(__dirname, 'changelog_app.js'),name: 'ChangelogApp',fileName: 'changelog_app'},outDir: '.', // Overwrite in-placerollupOptions: {external: ['vue'] // Provided via CDN}}})
package.json
:
{"name": "changelog-ui","version": "1.0.0","scripts": {"build": "vite build"},"dependencies": {"vue": "^3.4.21"},"devDependencies": {"@vitejs/plugin-vue": "^4.5.1","vite": "^4.5.0"}}
To compile:
npm run build
Frappe Integration
add to hooks.py
app_include_js = ["public/js/changelog_claudion/changelog_app.js","https://unpkg.com/vue@3.4.21/dist/vue.global.prod.js"]
Desk Page Setup:
- Name:
changelog
- Module:
changelog_claudion
- Triggered by:
frappe.pages['changelog'].on_page_load
📄 changelog_app.js
:
import { createApp } from 'vue'import Home from './Home.vue'frappe.pages['changelog'].on_page_load = function(wrapper) {const el = document.createElement('div')el.id = 'changelog-app'wrapper.appendChild(el)createApp(Home).mount('#changelog-app')}
Asset Serving & Debugging
Frappe rewrites assets from:
public/js/changelog_claudion/changelog_app.js
to
/assets/changelog_claudion/js/changelog_claudion/changelog_app.js
So make sure:
- You reference
public/js/...
inhooks.py
, not/public/
- You run
bench build
to register assets - You verify the served path manually:
https://your-site.com/assets/changelog_claudion/js/changelog_claudion/changelog_app.js
Outcome
Now the app installs cleanly via:
bench get-app https://github.com/your-org/changelog_claudion.gitbench install-app changelog_claudion
…and the Vue UI is immediately available under:
/app/changelog
No build steps required. Contributors can edit .vue
files directly inside the public folder and run npm run build
to regenerate changelog_app.js
.
💡 Why This Works
FeatureBenefit | |
Raw .vue in repo | Easy for contributors to edit, no tooling required |
Vue 3 + Vite | Modern syntax, modular, fast |
In-place build | Keeps everything in one folder |
Frappe-native assets | Served via /assets/... without config |
GitHub ready | Fully pushable, installable via bench get-app |
Final Thoughts
This setup combines the best of POS Awesome’s simplicity with Vue 3’s modern tooling — all inside a Frappe-compatible layout. It's lean, redistributable, and perfect for open-source collaboration. If you're building apps for the Frappe community, this pattern might be your new baseline.
No comments yet. Login to start a new discussion Start a new discussion