> Use when configuring frontend asset bundling, migrating from build.json (v14) to esbuild (v15+), or troubleshooting SCSS/CSS compilation. Prevents build failures from mixing v14 and v15 build systems and misconfigured asset pipelines. Covers esbuild configuration (v15+), build.json (v14), asset bundling, SCSS compilation, bundle.js setup, bench build flags.
npx skills add https://github.com/Impertio-Studio/Frappe_Claude_Skill_Package --skill frappe-ops-frontend-build
Complete reference for Frappe's frontend asset bundling pipeline, from build configuration to production optimization.
Versions: v14 (build.json) / v15+ (esbuild)
| Task | Command |
|------|---------|
| Build all apps | bench build |
| Build specific app | bench build --app myapp |
| Build multiple apps | bench build --apps frappe,erpnext |
| Production build (minified) | bench build --production |
| Force rebuild | bench build --force |
| Watch mode (auto-rebuild) | bench watch |
| Hard link assets | bench build --hard-link |
Which build system?
├── Frappe v14?
│ └── build.json — Concatenation-based bundling
├── Frappe v15+?
│ └── esbuild — ES module bundling with *.bundle.* convention
└── Migrating v14 → v15?
└── Replace build.json with *.bundle.* files in public/
The v15+ build system uses esbuild for fast ES module bundling. It automatically discovers bundle entry points by scanning the public/ directory for files matching *.bundle.{js|ts|css|scss|sass|less|styl}.
How it works:
bench build scans each app's public/ directory recursively*.bundle.* are treated as entry pointsassets/dist/[app]/js/ or assets/dist/[app]/css/main.bundle.HASH.jsSupported file types:
.js — ES6 modules with import/export.ts — TypeScript.vue — Vue single-file components.css — Standard CSS.scss / .sass — SASS/SCSS stylesheets.less — Less stylesheets.styl — Stylus stylesheetsThe v14 system uses build.json in the app root to define concatenation rules.
{
"js/myapp.min.js": [
"public/js/file1.js",
"public/js/file2.js"
],
"css/myapp.min.css": [
"public/css/style1.css",
"public/css/style2.css"
]
}
NEVER use build.json in v15+ — it is ignored by the esbuild pipeline.
Place files in your app's public/ directory with the .bundle. naming convention:
myapp/
└── public/
├── js/
│ └── myapp.bundle.js # → dist/myapp/js/myapp.bundle.HASH.js
├── css/
│ └── myapp.bundle.scss # → dist/myapp/css/myapp.bundle.HASH.css
└── components/
└── widget.bundle.js # → dist/myapp/js/widget.bundle.HASH.js
// myapp/public/js/myapp.bundle.js
import { createApp } from "vue";
import MyComponent from "./components/MyComponent.vue";
// ES6 imports are resolved by esbuild
import "../css/myapp.bundle.scss";
// npm packages (installed via yarn) can be imported directly
import dayjs from "dayjs";
createApp(MyComponent).mount("#myapp-root");
| Input | Output |
|-------|--------|
| public/js/main.bundle.js | assets/dist/[app]/js/main.bundle.[hash].js |
| public/css/style.bundle.scss | assets/dist/[app]/css/style.bundle.[hash].css |
| public/deep/nested/file.bundle.ts | assets/dist/[app]/js/file.bundle.[hash].js |
# hooks.py — loads in /app (Desk)
app_include_js = "myapp.bundle.js"
app_include_css = "myapp.bundle.css"
# Multiple files
app_include_js = ["myapp.bundle.js", "extra.bundle.js"]
app_include_css = ["myapp.bundle.css", "extra.bundle.css"]
# hooks.py — loads on web pages (portal)
web_include_js = "myapp-web.bundle.js"
web_include_css = "myapp-web.bundle.css"
# hooks.py — loads on specific Desk pages
page_js = {"page_name": "public/js/custom_page.js"}
# hooks.py — loads on specific Web Forms
webform_include_js = {"ToDo": "public/js/custom_todo.js"}
webform_include_css = {"ToDo": "public/css/custom_todo.css"}
bench build --app myapp<!-- Include script with correct hash -->
{{ include_script("myapp.bundle.js") }}
<!-- Include stylesheet with correct hash -->
{{ include_style("myapp.bundle.css") }}
<!-- Get path string only (no HTML tag) -->
<script src="{{ bundled_asset('myapp.bundle.js') }}"></script>
// Load asset on demand (returns Promise)
frappe.require("myapp.bundle.js", () => {
// Asset loaded, initialize component
myapp.init();
});
// Multiple assets
frappe.require(["widget.bundle.js", "widget.bundle.css"], () => {
// Both loaded
});
// myapp/public/css/myapp.bundle.scss
// Import Frappe variables (available in all apps)
@import "frappe/public/scss/variables";
// Import partials (NOT bundles — no .bundle. in name)
@import "./components/header";
@import "./components/sidebar";
.myapp-container {
padding: var(--padding-lg);
background: var(--bg-color);
}
Partials (files starting with _ or without .bundle. in the name) are NOT compiled as entry points. They are only included via @import:
public/css/
├── myapp.bundle.scss # Entry point — compiled
├── _variables.scss # Partial — imported only
└── components/
├── _header.scss # Partial — imported only
└── _sidebar.scss # Partial — imported only
# Auto-rebuild on file changes
bench watch
public/ directories for changeslive_reload is enabled)# Via config
bench set-config -g live_reload true
# Via environment variable
export LIVE_RELOAD=1
| Feature | Development (bench build) | Production (bench build --production) |
|---------|---------------------------|---------------------------------------|
| Minification | No | Yes |
| Source maps | Yes | No |
| Bundle size | Larger | Optimized |
| Build speed | Fast | Slower |
// myapp/public/js/mypage.bundle.js
import { createApp } from "vue";
import { FrappeUI } from "frappe-ui";
import App from "./App.vue";
const app = createApp(App);
app.use(FrappeUI);
app.mount("#myapp-page");
# Create a Page DocType or use www/ for web pages
# The bundle loads via hooks.py or include_script()
# Install from app directory
cd apps/myapp
yarn add vue frappe-ui dayjs
Dependencies are resolved by esbuild from node_modules/ during build.
ERROR: Could not resolve "some-package"
Fix: Install the missing npm package:
cd apps/myapp && yarn add some-package
Fix: Ensure files use the *.bundle.* naming convention and are in the public/ directory.
Fix: Force rebuild with cache clear:
bench build --force
bench clear-cache
Fix: Check that SCSS files import correctly and the entry point has .bundle. in the name:
bench build --app myapp --force
Fix: Migrate to *.bundle.* entry points. build.json is a v14-only feature.
bench build --productionassets/dist/ for unexpectedly large filesfrappe.require()app_include_js/csspublic/
├── js/
│ ├── myapp.bundle.js # Core — loaded on every page via hooks
│ ├── report-widget.bundle.js # Lazy — loaded only on report pages
│ └── chart-tools.bundle.js # Lazy — loaded only when charts needed
└── css/
├── myapp.bundle.scss # Core — loaded on every page via hooks
└── print.bundle.scss # Lazy — loaded only for print views
| Feature | v14 | v15+ |
|---------|:---:|:----:|
| Build system | build.json | esbuild |
| Entry point convention | Defined in JSON | *.bundle.* auto-discovery |
| TypeScript support | No | Yes |
| Vue SFC support | No | Yes |
| SCSS compilation | Via build pipeline | Via esbuild |
| Watch mode | bench watch | bench watch (faster) |
| Live reload | Manual | Automatic (configurable) |
| Source maps | Limited | Full support |
| Tree shaking | No | Yes |
| npm imports | Requires manual bundling | Direct ES6 imports |
| File | Contents |
|------|----------|
| examples.md | Complete build configuration examples |
| anti-patterns.md | Common build mistakes and fixes |
Toolkit for styling artifacts with a theme. These artifacts can be slides, docs, reportings, HTML landing pages, etc. There are 10 pre-set themes with colors/fonts that you can apply to any artifact that has been creating, or can generate a new theme on-the-fly.
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatting, or company design standards apply.
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
Suite of tools for creating elaborate, multi-component claude.ai HTML artifacts using modern frontend web technologies (React, Tailwind CSS, shadcn/ui). Use for complex artifacts requiring state management, routing, or shadcn/ui components - not for simple single-file HTML/JSX artifacts.
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.
Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling
Use Expo DOM components to run web code in a webview on native and as-is on web. Migrate web code to native incrementally.
Take impertio-studio/frappe-ops-frontend-build from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference yarn.
Without those the skill loads but fails at the first command.