frontend-module

FrontendModule - Server-Side Rendering

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "frontend-module" with this command: npx skills add psincraian/myfy/psincraian-myfy-frontend-module

FrontendModule - Server-Side Rendering

FrontendModule provides Jinja2 templates with Tailwind 4, DaisyUI 5, and Vite bundling.

Quick Start

from myfy.core import Application from myfy.web import WebModule, route from myfy.frontend import FrontendModule, render_template

app = Application() app.add_module(WebModule()) app.add_module(FrontendModule(auto_init=True)) # Auto-scaffolds!

@route.get("/") async def home() -> str: return render_template("home.html", title="Welcome")

Configuration

Environment variables use the MYFY_FRONTEND_ prefix:

Variable Default Description

MYFY_FRONTEND_ENVIRONMENT

development

Environment mode

MYFY_FRONTEND_ENABLE_VITE_DEV

True

Start Vite dev server

MYFY_FRONTEND_VITE_DEV_SERVER

http://localhost:3001

Vite server URL

MYFY_FRONTEND_STATIC_URL_PREFIX

/static

Static files URL path

MYFY_FRONTEND_CACHE_STATIC_ASSETS

True

Enable static caching

MYFY_FRONTEND_CACHE_MAX_AGE

31536000

Cache max-age (1 year)

MYFY_FRONTEND_SHOW_VITE_LOGS

False

Show Vite console output

Module Options

FrontendModule( templates_dir="frontend/templates", # Template directory static_dir="frontend/static", # Static files directory auto_init=True, # Auto-scaffold if missing )

Auto-Scaffolding

With auto_init=True , FrontendModule creates:

frontend/ templates/ base.html # Base template with Tailwind home.html # Example home page static/ src/ main.js # Entry point main.css # Tailwind imports package.json # Node dependencies vite.config.js # Vite configuration tailwind.config.js # Tailwind configuration

Template Rendering

Basic Rendering

from myfy.frontend import render_template

@route.get("/") async def home() -> str: return render_template("home.html", title="Home")

With Context

@route.get("/users/{user_id}") async def user_profile(user_id: int, session: AsyncSession) -> str: user = await session.get(User, user_id) return render_template("profile.html", user=user)

With Request Context

from starlette.requests import Request

@route.get("/dashboard") async def dashboard(request: Request, user: User) -> str: return render_template( "dashboard.html", request=request, # For url_for, CSRF, etc. user=user, )

Base Template

<!-- frontend/templates/base.html --> <!DOCTYPE html> <html lang="en" data-theme="light"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}My App{% endblock %}</title> {{ vite_assets("src/main.js") }} </head> <body class="min-h-screen bg-base-100"> <div class="navbar bg-base-200"> <a class="btn btn-ghost text-xl" href="/">My App</a> </div> <main class="container mx-auto px-4 py-8"> {% block content %}{% endblock %} </main> </body> </html>

Page Template

<!-- frontend/templates/home.html --> {% extends "base.html" %}

{% block title %}{{ title }} - My App{% endblock %}

{% block content %} <div class="hero min-h-[50vh]"> <div class="hero-content text-center"> <div class="max-w-md"> <h1 class="text-5xl font-bold">Hello, World!</h1> <p class="py-6">Welcome to your myfy application.</p> <button class="btn btn-primary">Get Started</button> </div> </div> </div> {% endblock %}

DaisyUI Components

DaisyUI 5 provides ready-to-use components:

<!-- Buttons --> <button class="btn btn-primary">Primary</button> <button class="btn btn-secondary">Secondary</button> <button class="btn btn-outline">Outline</button>

<!-- Cards --> <div class="card bg-base-100 shadow-xl"> <div class="card-body"> <h2 class="card-title">Card Title</h2> <p>Card content here.</p> <div class="card-actions justify-end"> <button class="btn btn-primary">Action</button> </div> </div> </div>

<!-- Forms --> <div class="form-control"> <label class="label"> <span class="label-text">Email</span> </label> <input type="email" class="input input-bordered" /> </div>

<!-- Alerts --> <div class="alert alert-success"> <span>Success! Your action was completed.</span> </div>

Theme Switching

<!-- Theme toggle --> <label class="swap swap-rotate"> <input type="checkbox" class="theme-controller" value="dark" /> <svg class="swap-on w-6 h-6" fill="currentColor"><!-- sun icon --></svg> <svg class="swap-off w-6 h-6" fill="currentColor"><!-- moon icon --></svg> </label>

Static Assets

Vite Helper

<!-- Loads JS and CSS with HMR in development --> {{ vite_assets("src/main.js") }}

Manual Asset URLs

<img src="{{ asset_url('images/logo.png') }}" alt="Logo">

Development Workflow

Start the application:

myfy run

Vite dev server starts automatically with HMR.

Edit templates and CSS - changes reflect instantly.

Build for production:

npm run build

Creates optimized assets in frontend/static/dist/ .

Production Build

Build assets

npm run build

Set production mode

export MYFY_FRONTEND_ENVIRONMENT=production export MYFY_FRONTEND_ENABLE_VITE_DEV=false

Run application

myfy run

Assets are served from the built manifest with cache headers.

Custom Jinja Filters

from myfy.frontend import FrontendModule from starlette.templating import Jinja2Templates

After module initialization

templates: Jinja2Templates = container.get(Jinja2Templates) templates.env.filters["currency"] = lambda x: f"${x:.2f}"

Use in templates:

<span>{{ price | currency }}</span>

Best Practices

  • Use auto_init for new projects - Gets you started quickly

  • Extend base.html - Keep consistent layout

  • Use DaisyUI components - Pre-styled, accessible

  • Enable caching in production - Set long cache max-age

  • Build assets before deploy - Don't rely on Vite in production

  • Use template inheritance - Keep templates DRY

  • Pass request for url_for - Enables dynamic URL generation

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

dependency-injection

No summary provided by upstream source.

Repository SourceNeeds Review
General

image-gen

Generate AI images from text prompts. Triggers on: "生成图片", "画一张", "AI图", "generate image", "配图", "create picture", "draw", "visualize", "generate an image".

Archived SourceRecently Updated
General

explainer

Create explainer videos with narration and AI-generated visuals. Triggers on: "解说视频", "explainer video", "explain this as a video", "tutorial video", "introduce X (video)", "解释一下XX(视频形式)".

Archived SourceRecently Updated