Skip to content
34 changes: 22 additions & 12 deletions frontend/src/scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { build } from "vite"
import vue from "@vitejs/plugin-vue"
import path from "node:path"
import { fileURLToPath } from "node:url"
import { parseArgs } from "node:util"
import frappeui from "frappe-ui/vite"

const __dirname = fileURLToPath(new URL(".", import.meta.url))
Expand All @@ -15,25 +16,31 @@ if (!fs.existsSync(TEMP_DIR)) {
fs.mkdirSync(TEMP_DIR, { recursive: true })
}

const args = process.argv.slice(2)
const appName = args[0]
const components = args[2]

if (!appName) {
console.error("App name is required")
const { values: argv } = parseArgs({
options: {
app: { type: "string" },
components: { type: "string" },
"out-dir": { type: "string" },
base: { type: "string" },
},
strict: false,
})

if (!argv.app) {
console.error("--app is required")
process.exit(1)
}

await generateAppBuild(appName, components)
await generateAppBuild(argv.app, argv.components, argv["out-dir"], argv.base)

export async function generateAppBuild(appName, components) {
export async function generateAppBuild(appName, components, outDir, base) {
if (!appName) return

const componentList = components ? components.split(",") : []
const componentSources = findComponentSources(componentList)
const rendererContent = getRendererContent(componentSources)
const tempRendererPath = writeRendererFile(appName, rendererContent)
await buildWithVite(appName, tempRendererPath)
await buildWithVite(appName, tempRendererPath, outDir, base)
deleteRendererFile(tempRendererPath)
}

Expand Down Expand Up @@ -111,11 +118,14 @@ function writeRendererFile(appName, content) {
return rendererPath
}

async function buildWithVite(appName, entryFilePath) {
async function buildWithVite(appName, entryFilePath, outDir, basePath) {
outDir = outDir || path.resolve(__dirname, `../../../studio/public/app_builds/${appName}`)
basePath = basePath || `/assets/studio/app_builds/${appName}/`

console.log(`Building ${appName} with Vite`)
await build({
root: path.resolve(__dirname, "../"),
base: "/assets/studio/app_builds/",
base: basePath,
server: {
// explicitly set origin of generated assets (images, fonts, etc) during development.
// Required for the app renderer running on webserver port
Expand Down Expand Up @@ -145,7 +155,7 @@ async function buildWithVite(appName, entryFilePath) {
studioRenderer: path.resolve(__dirname, entryFilePath),
},
},
outDir: path.resolve(__dirname, `../../../studio/public/app_builds/${appName}`),
outDir: outDir,
emptyOutDir: true,
target: "es2015",
sourcemap: true,
Expand Down
59 changes: 0 additions & 59 deletions studio/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,62 +100,3 @@ def check_app_permission() -> bool:
):
return True
return False


@frappe.whitelist()
def get_app_components(app_name: str, field: Literal["blocks", "draft_blocks"] = "blocks") -> set[str]:
import re

from studio.constants import DEFAULT_COMPONENTS, NON_VUE_COMPONENTS

filters = dict(studio_app=app_name, published=1)
filters[field] = ("is", "set")

pages = frappe.get_all(
"Studio Page",
filters=filters,
pluck=field,
)
if not pages:
return set()
components = set(DEFAULT_COMPONENTS)

def add_h_function_components(text: str) -> set[str]:
"""Extract component names from h(ComponentName...) function calls"""
pattern = r"\bh\(\s*([A-Z][a-zA-Z0-9_]*)"

matches = re.findall(pattern, text)
for match in matches:
components.add(match)

def add_block_components(block: dict):
if block.get("isStudioComponent"):
add_studio_components(block)
elif block.get("componentName") not in NON_VUE_COMPONENTS:
components.add(block.get("componentName"))
for child in block.get("children", []):
add_block_components(child)

if slots := block.get("componentSlots"):
for slot in slots.values():
if isinstance(slot.get("slotContent"), str):
continue
for slot_child in slot.get("slotContent"):
add_block_components(slot_child)

def add_studio_components(block: dict):
component_block = frappe.db.get_value("Studio Component", block.get("componentName"), "block")
if isinstance(component_block, str):
component_block = frappe.parse_json(component_block)
add_block_components(component_block)

for blocks in pages:
if not blocks:
continue
if isinstance(blocks, str):
add_h_function_components(blocks)
blocks = frappe.parse_json(blocks)
root_block = blocks[0]
add_block_components(root_block)

return components
Loading
Loading