[Workflow] Customizing Frappe UI such as Frappe CRM & HR from custom App

Like many in community, we too faced challenges while trying to customize Frappe UI-based applications. Sometimes, client needs some customisations that are critical. Am sharing the workflow we are following for the same, for feedback and for others benefit.

The Challenge
While Frappe’s Desk based application and modules are highly customizable using client scripts, server scripts etc… Frappe UI based apps built using Vue.js (e.g., CRM, Gameplan), etc are almost impossible to customise out of the box. Overriding or extending these apps without modifying the core can be tricky.

  • The Vue.js frontend code of most frappe-ui apps resides inside the frontend folder outside of app scope and most apps don’t use frappe bundler.
  • Customising components directly in the app is not a scalable or maintainable approach, as updates to the core app can overwrite your changes.
  • We wanted a cleaner way to extend functionality without touching the core app, much like we do with hooks in frappe.

The below workflow allow you to override a single component for example same as you would do in frappe website. Simply copy the component from the original app and put it in your app.

Please see the detailed workflow and solution in this post:

Github - example code overriding Frappe CRM

Files of interest:

  1. ./frontend/vite.config.js
  2. `./frontend/package.json
  3. `./frontend/custom-build.js

Below script does most of the heavylifting:

const fs = require('fs-extra');
const path = require('path');
const { execSync } = require('child_process');


const crmAppPath = path.resolve(__dirname, '../../crm/frontend');
const overrideSrcPath = path.resolve(__dirname, './src');
const overrideFilesPath = path.resolve(__dirname, './src_override');

console.log('Starting  :  Copying original src.');
fs.copySync(path.join(crmAppPath, 'src'), overrideSrcPath);
console.log('Completed :  Copying original src.');

console.log('Starting  :  Overriding src.');
fs.copySync(overrideFilesPath, overrideSrcPath);
console.log('Completed :  Overriding src.');

execSync('yarn install', { stdio: 'inherit' });

Note: If you are using Frappe Cloud, please be advised this has not been tested in FC and you may need to build before pushing to FC.

Looking forward to hear how others have tackled this and feedback!

10 Likes