provisioning-outreach/presentations/rust-laspalmas-250926/auroraframe/wb

612 lines
18 KiB
Text
Raw Normal View History

#!/usr/bin/env nu
# Web Builder Framework CLI
# Multi-page web builder with shared assets and optimization
# Framework paths
let FRAMEWORK_ROOT = ($env.PWD)
let FRAMEWORK_CORE = ($FRAMEWORK_ROOT | path join "framework" "core")
let FRAMEWORK_OPTIMIZERS = ($FRAMEWORK_ROOT | path join "framework" "optimizers")
let FRAMEWORK_TEMPLATES = ($FRAMEWORK_ROOT | path join "framework" "templates")
let SHARED_ASSETS = ($FRAMEWORK_ROOT | path join "shared")
let PAGES_DIR = ($FRAMEWORK_ROOT | path join "pages")
let SITES_DIR = ($FRAMEWORK_ROOT | path join "sites")
# Import framework modules will be done dynamically in functions
# Main CLI entry point
def main [command?: string = "help"] {
match $command {
"help" => { show_help }
"page" => { print "Use: wb page <subcommand>. Run 'wb page help' for options." }
"site" => { print "Use: wb site <subcommand>. Run 'wb site help' for options." }
"shared" => { print "Use: wb shared <subcommand>. Run 'wb shared help' for options." }
"init" => { print "Use: wb init <project-name>" }
"dev" => { print "Use: wb dev <page> [--port N]. Shortcut for 'wb page dev <page> --watch'" }
"build-all" => { build_all_pages }
"clean" => { clean_all_builds }
_ => { show_help }
}
}
# Page management commands
def "main page" [
subcommand: string = "help",
name?: string,
--template(-t): string = "single",
--dev(-d),
--prod(-p),
--watch(-w),
--port: int = 8080
] {
match $subcommand {
"create" => {
if ($name | is-empty) {
print "Error: Page name required"
return
}
create_page $name $template
}
"build" => {
if ($name | is-empty) {
print "Error: Page name required"
return
}
if $dev {
build_page_dev $name
} else if $prod {
build_page_prod $name
} else {
build_page_dev $name
}
}
"dev" => {
if ($name | is-empty) {
print "Error: Page name required"
return
}
dev_page $name $port $watch
}
"list" => { list_pages }
"help" => { show_page_help }
_ => { show_page_help }
}
}
# Site management commands
def "main site" [
subcommand: string = "help",
name?: string
] {
match $subcommand {
"create" => {
if ($name | is-empty) {
print "Error: Site name required"
return
}
create_site $name
}
"build" => {
if ($name | is-empty) {
print "Error: Site name required"
return
}
build_site $name
}
"list" => { list_sites }
"help" => { show_site_help }
_ => { show_site_help }
}
}
# Shared asset management
def "main shared" [
subcommand: string = "help",
file?: string,
--type(-t): string = "css"
] {
match $subcommand {
"add" => {
if ($file | is-empty) {
print "Error: File path required"
return
}
add_shared_asset $file $type
}
"list" => { list_shared_assets }
"help" => { show_shared_help }
_ => { show_shared_help }
}
}
# Initialize new project
def "main init" [project_name: string] {
print $"🚀 Initializing Web Builder project: ($project_name)"
# Create project structure
mkdir $project_name
cd $project_name
# Copy framework
cp -r $FRAMEWORK_ROOT $project_name
print $"✅ Project ($project_name) initialized successfully!"
print $"📁 Navigate to the project: cd ($project_name)"
print $"🎯 Create your first page: ./wb page create homepage"
}
# Load page configuration with asset resolution
export def load_page_config [page_name: string] {
let page_config_path = ($PAGES_DIR | path join $page_name "config.toml")
if not ($page_config_path | path exists) {
error make {msg: $"Page config not found: ($page_config_path)"}
}
let config = (open $page_config_path)
# Return config as-is for now (asset resolution will be done in build scripts)
$config
}
# Resolve asset paths (@shared, @page references)
export def resolve_asset_path [asset_path: string] {
if ($asset_path | str starts-with "@shared/") {
let relative_path = ($asset_path | str replace "@shared/" "")
($SHARED_ASSETS | path join $relative_path)
} else if ($asset_path | str starts-with "@page/") {
let parts = ($asset_path | str replace "@page/" "" | split row "/")
let page_name = ($parts | first)
let asset_path = ($parts | skip 1 | str join "/")
($PAGES_DIR | path join $page_name "src" "assets" $asset_path)
} else {
$asset_path
}
}
# Create new page from template
def create_page [name: string, template: string] {
print $"📝 Creating page: ($name) with template: ($template)"
let page_dir = ($PAGES_DIR | path join $name)
if ($page_dir | path exists) {
print $"❌ Page ($name) already exists"
return
}
# Create page structure
mkdir ($page_dir | path join "src" "assets" "css")
mkdir ($page_dir | path join "src" "assets" "svg")
mkdir ($page_dir | path join "dist")
# Copy and customize config template
let template_path = ($FRAMEWORK_TEMPLATES | path join "page.config.toml.template")
let config_content = (open $template_path)
let customized_config = ($config_content
| str replace "{{PAGE_NAME}}" $name
| str replace "{{PAGE_TITLE}}" $name
| str replace "{{PAGE_TYPE}}" $template
| str replace "{{PAGE_DESCRIPTION}}" $"Page created with ($template) template"
)
$customized_config | save ($page_dir | path join "config.toml")
# Create basic HTML file
let html_content = $'<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>($name)</title>
<link rel="stylesheet" href="assets/css/main.min.css">
</head>
<body>
<div class="container">
<h1 class="animated-title">($name)</h1>
<p class="text-gray-400">Created with Web Builder Framework</p>
</div>
</body>
</html>'
$html_content | save ($page_dir | path join "src" "index.html")
# Create basic CSS
let css_content = $'/* Page-specific styles for ($name) */
.container {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
body {
background: #0a0a0a;
color: #ffffff;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}'
$css_content | save ($page_dir | path join "src" "assets" "css" "main.css")
print $"✅ Page ($name) created successfully!"
print $"📁 Location: ($page_dir)"
print $"🎯 Build it: wb page build ($name)"
print $"🔥 Develop: wb page dev ($name) --watch"
}
# Build page in development mode
def build_page_dev [page_name: string] {
print $"🔨 Building page: ($page_name) \(development mode\)"
let config = (load_page_config $page_name)
let page_dir = ($PAGES_DIR | path join $page_name)
cd $page_dir
nu ($FRAMEWORK_CORE | path join "build.nu") --dev --verbose
}
# Build page in production mode
def build_page_prod [page_name: string] {
print $"🏭 Building page: ($page_name) \(production mode\)"
let config = (load_page_config $page_name)
let page_dir = ($PAGES_DIR | path join $page_name)
cd $page_dir
nu ($FRAMEWORK_CORE | path join "prod.nu") --analyze --compress --verbose
}
# Start development server for page
def dev_page [page_name: string, port: int, watch: bool] {
print $"🚀 Starting development server for: ($page_name)"
let page_dir = ($PAGES_DIR | path join $page_name)
cd $page_dir
if $watch {
nu ($FRAMEWORK_CORE | path join "dev.nu") --watch --port $port
} else {
nu ($FRAMEWORK_CORE | path join "dev.nu") --port $port
}
}
# List all pages
def list_pages [] {
print "📄 Available pages:"
if not ($PAGES_DIR | path exists) {
print " No pages found"
return
}
ls $PAGES_DIR | where type == dir | each { |page|
let page_name = ($page.name | path basename)
let config_path = ($PAGES_DIR | path join $page_name "config.toml")
if ($config_path | path exists) {
let config = (open $config_path)
print $" 📝 ($page_name) - ($config.page.title) [($config.page.type)]"
} else {
print $" 📝 ($page_name) - No config found"
}
}
}
# List shared assets
def list_shared_assets [] {
print "🔗 Shared assets:"
if not ($SHARED_ASSETS | path exists) {
print " No shared assets found"
return
}
# List CSS assets
let css_dir = ($SHARED_ASSETS | path join "css")
if ($css_dir | path exists) {
print " 📄 CSS assets:"
ls -la $css_dir | each { |item|
if $item.type == "dir" {
let subdir = ($item.name | path basename)
print $" 📁 ($subdir)/"
let css_files = (glob ($css_dir | path join $subdir "*.css"))
$css_files | each { |file|
let basename = ($file | path basename)
let size = (ls $file | get size | first | into int)
let size_kb = ($size / 1024 | math round -p 1)
print $" 📝 ($basename) - ($size_kb) KB"
}
} else if ($item.name | str ends-with ".css") {
let basename = ($item.name | path basename)
let size = ($item.size | into int)
let size_kb = ($size / 1024 | math round -p 1)
print $" 📝 ($basename) - ($size_kb) KB"
}
}
}
# List SVG assets
let svg_dir = ($SHARED_ASSETS | path join "svg")
if ($svg_dir | path exists) {
print " 🖼️ SVG assets:"
let svg_files = (glob ($svg_dir | path join "*.svg"))
$svg_files | each { |file|
let basename = ($file | path basename)
let size = (ls $file | get size | first | into int)
let size_kb = ($size / 1024 | math round -p 1)
print $" 📝 ($basename) - ($size_kb) KB"
}
}
# List JS assets
let js_dir = ($SHARED_ASSETS | path join "js")
if ($js_dir | path exists) {
print " 📜 JavaScript assets:"
let js_files = (glob ($js_dir | path join "*.js"))
$js_files | each { |file|
let basename = ($file | path basename)
let size = (ls $file | get size | first | into int)
let size_kb = ($size / 1024 | math round -p 1)
print $" 📝 ($basename) - ($size_kb) KB"
}
}
}
# Add shared asset
def add_shared_asset [file_path: string, asset_type: string] {
print $"📦 Adding shared asset: ($file_path) as ($asset_type)"
if not ($file_path | path exists) {
print $"❌ File not found: ($file_path)"
return
}
# Create shared assets directory structure
mkdir ($SHARED_ASSETS | path join $asset_type)
# Copy file to shared assets
let filename = ($file_path | path basename)
let dest_path = ($SHARED_ASSETS | path join $asset_type $filename)
cp $file_path $dest_path
print $"✅ Added shared asset: @shared/($asset_type)/($filename)"
print $" Use in page config: \"@shared/($asset_type)/($filename)\""
}
# Create multi-page site
def create_site [name: string] {
print $"🌐 Creating site: ($name)"
let site_dir = ($SITES_DIR | path join $name)
if ($site_dir | path exists) {
print $"❌ Site ($name) already exists"
return
}
# Create site structure
mkdir ($site_dir | path join "pages")
mkdir ($site_dir | path join "shared")
mkdir ($site_dir | path join "dist")
# Create site configuration
let site_config = $'[site]
name = "($name)"
title = "($name)"
description = "Multi-page site created with Web Builder Framework"
[build]
output_dir = "dist"
shared_assets = true
[pages]
# Add page references here
# homepage = { path = "homepage", template = "landing" }
'
$site_config | save ($site_dir | path join "site.toml")
print $"✅ Site ($name) created successfully!"
print $"📁 Location: ($site_dir)"
print $"🎯 Add pages to the site configuration"
}
# Build multi-page site
def build_site [name: string] {
print $"🏗️ Building site: ($name)"
let site_dir = ($SITES_DIR | path join $name)
let site_config_path = ($site_dir | path join "site.toml")
if not ($site_config_path | path exists) {
print $"❌ Site config not found: ($site_config_path)"
return
}
let site_config = (open $site_config_path)
print $"📦 Building all pages for site: ($site_config.site.title)"
print " (Site building not fully implemented yet - build individual pages for now)"
# TODO: Implement multi-page site building
# This would iterate through all pages defined in site.toml
# and build them into a unified site structure
}
# List all sites
def list_sites [] {
print "🌐 Available sites:"
if not ($SITES_DIR | path exists) {
print " No sites found"
return
}
ls $SITES_DIR | where type == dir | each { |site|
let site_name = ($site.name | path basename)
let config_path = ($SITES_DIR | path join $site_name "site.toml")
if ($config_path | path exists) {
let config = (open $config_path)
print $" 🌐 ($site_name) - ($config.site.title)"
} else {
print $" 🌐 ($site_name) - No config found"
}
}
}
# Help functions
def show_help [] {
print "🌐 Web Builder Framework"
print "========================"
print ""
print "Commands:"
print " wb page <subcommand> - Manage individual pages"
print " wb site <subcommand> - Manage multi-page sites"
print " wb shared <subcommand> - Manage shared assets"
print " wb init <name> - Initialize new project"
print " wb dev <page> [--port N] - Quick dev server (shortcut)"
print " wb build-all [--prod] - Build all pages"
print " wb clean [--all] - Clean build artifacts"
print " wb help - Show this help"
print ""
print "Examples:"
print " wb page create homepage"
print " wb dev homepage - Quick development server"
print " wb page build homepage --prod"
print " wb build-all --prod - Build all pages for production"
print " wb clean --all - Deep clean all artifacts"
print " wb shared list"
print ""
print "💡 For faster JS minification, install SWC:"
print " npm install -g @swc/cli @swc/core"
}
def show_page_help [] {
print "📄 Page Management"
print "=================="
print ""
print "Commands:"
print " wb page create <name> [--template <type>] - Create new page"
print " wb page build <name> [--dev|--prod] - Build page"
print " wb page dev <name> [--watch] [--port N] - Start dev server"
print " wb page list - List all pages"
print ""
print "Templates: single, landing, article, poster"
print ""
print "Examples:"
print " wb page create about --template landing"
print " wb page dev homepage --watch --port 3000"
}
def show_site_help [] {
print "🌐 Site Management"
print "=================="
print " wb site create <name> - Create multi-page site"
print " wb site build <name> - Build entire site"
print " wb site list - List all sites"
}
def show_shared_help [] {
print "🔗 Shared Assets"
print "================"
print " wb shared add <file> --type <css|svg|js> - Add shared asset"
print " wb shared list - List shared assets"
}
# Shortcut commands
def "main dev" [page?: string = "homepage", --port: int = 8080] {
if ($page | is-empty) {
print "Error: Page name required"
print "Usage: wb dev <page> [--port N]"
return
}
print $"🚀 Starting development server for: ($page)"
dev_page $page $port true # true for watch mode
}
def "main build-all" [--prod(-p)] {
print "🏗️ Building all pages..."
if not ($PAGES_DIR | path exists) {
print "❌ No pages directory found"
return
}
let pages = (ls $PAGES_DIR | where type == dir | get name)
if ($pages | length) == 0 {
print "📄 No pages found to build"
return
}
print $"📦 Found ($pages | length) pages to build"
for page_path in $pages {
let page_name = ($page_path | path basename)
let config_path = ($page_path | path join "config.toml")
if ($config_path | path exists) {
print $"🔨 Building ($page_name)..."
if $prod {
build_page_prod $page_name
} else {
build_page_dev $page_name
}
print $"✅ ($page_name) completed"
} else {
print $"⚠️ Skipping ($page_name) - no config found"
}
}
print "🎉 All pages built successfully!"
}
def "main clean" [--all(-a)] {
print "🧹 Cleaning build artifacts..."
if not ($PAGES_DIR | path exists) {
print "❌ No pages directory found"
return
}
let pages = (ls $PAGES_DIR | where type == dir | get name)
mut cleaned_count = 0
for page_path in $pages {
let page_name = ($page_path | path basename)
let dist_dir = ($page_path | path join "dist")
if ($dist_dir | path exists) {
print $"🗑️ Cleaning ($page_name)/dist/"
rm -rf $dist_dir
$cleaned_count = ($cleaned_count + 1)
}
}
if $all {
# Clean additional artifacts
print "🧽 Deep cleaning..."
# Clean compressed files
for page_path in $pages {
let page_name = ($page_path | path basename)
glob ($page_path | path join "**/*.gz") | each { |file|
if ($file | path exists) {
print $"🗑️ Removing ($file | path basename)"
rm $file
}
}
}
}
print $"✅ Cleaned ($cleaned_count) pages"
}