Lustre's CLI and development tooling: zero-config dev server, bundling, and scaffolding.
at main 2.9 kB view raw
1// IMPORTS --------------------------------------------------------------------- 2 3import filepath 4import gleam/result 5import gleam/string 6import glint.{type Command} 7import lustre_dev_tools/cli.{type Cli, do, try} 8import lustre_dev_tools/cli/build 9import lustre_dev_tools/cli/flag 10import lustre_dev_tools/cmd 11import lustre_dev_tools/error.{type Error, CannotWriteFile} 12import lustre_dev_tools/project 13import lustre_dev_tools/server 14import simplifile 15 16// COMMANDS -------------------------------------------------------------------- 17 18pub fn run() -> Command(Nil) { 19 let description = 20 " 21Start a development server for your Lustre project. This command will compile your 22application and serve it on a local server. If your application's `main` function 23returns a compatible `App`, this will generate the necessary code to start it. 24Otherwise, your `main` function will be used as the entry point. 25 26 27This development server does *not* currently watch your files for changes. 28Watchexec is a popular tool you can use to restart the server when files change. 29 " 30 use <- glint.command_help(description) 31 use <- glint.unnamed_args(glint.EqArgs(0)) 32 use port <- glint.flag(flag.port()) 33 use _proxy_from <- glint.flag(flag.proxy_from()) 34 use _proxy_to <- glint.flag(flag.proxy_to()) 35 use detect_tailwind <- glint.flag(flag.detect_tailwind()) 36 use _tailwind_entry <- glint.flag(flag.tailwind_entry()) 37 use _, _, flags <- glint.command() 38 let script = { 39 use port <- do(cli.get_int("port", 1234, ["start"], port)) 40 use detect_tailwind <- do(cli.get_bool( 41 "detect_tailwind", 42 True, 43 ["build"], 44 detect_tailwind, 45 )) 46 47 use _ <- do(check_otp_version()) 48 use _ <- do(build.do_app(False, detect_tailwind)) 49 use _ <- do(prepare_html()) 50 use _ <- do(server.start(port)) 51 52 cli.return(Nil) 53 } 54 55 case cli.run(script, flags) { 56 Ok(_) -> Nil 57 Error(error) -> error.explain(error) 58 } 59} 60 61// STEPS ----------------------------------------------------------------------- 62 63fn check_otp_version() -> Cli(Nil) { 64 use <- cli.log("Checking OTP version") 65 let version = project.otp_version() 66 case version <= 25 { 67 False -> cli.return(Nil) 68 True -> cli.throw(error.OtpTooOld(version)) 69 } 70} 71 72fn prepare_html() -> Cli(Nil) { 73 let assert Ok(cwd) = cmd.cwd() 74 let assert Ok(root) = filepath.expand(filepath.join(cwd, project.root())) 75 let index = filepath.join(root, "index.html") 76 77 case simplifile.is_file(index) { 78 Ok(True) -> cli.return(Nil) 79 Ok(False) | Error(_) -> { 80 use html <- cli.template("index.html") 81 use app_name <- do(cli.get_name()) 82 let html = string.replace(html, "{app_name}", app_name) 83 use _ <- try(write_html(index, html)) 84 85 cli.return(Nil) 86 } 87 } 88} 89 90fn write_html(path: String, source: String) -> Result(Nil, Error) { 91 simplifile.write(path, source) 92 |> result.map_error(CannotWriteFile(_, path)) 93}