1//// Lustre's Dev Tools is a CLI (Command Line Interface) that provides a set of commands
2//// for running and building Lustre projects. If you're familiar with frontend Web
3//// development, you could consider the Lustre Dev Tools as something similar to
4//// [vite](https://vitejs.dev) but built right into the framework! If you're not
5//// familiar with what these tools are used for... then read on.
6////
7//// > **Note**: currently one of lustre_dev_tools' dependencies is not compatible
8//// > with the most recent version of `gleam_json`, making it impossible to install.
9//// > To fix this, add `gleam_json = "1.0.1"` as a dependency in your `gleam.toml`
10//// > file.
11////
12//// Lustre Dev Tools is written in Gleam and requires **Erlang** to be installed even
13//// if you are only building a JavaScript project. Most methods of installing Gleam
14//// will guide you through installing Erlang too, but make sure you have it installed
15//// before you try to use the Lustre CLI!
16////
17//// Because the CLI is written in Gleam, you will run it using the `gleam` command.
18//// As an example, starting a development server looks like this:
19////
20//// ```sh
21//// gleam run -m lustre/dev start
22//// ```
23////
24//// <h2 id="add" class="member-name">
25//// <a href="#add">lustre/dev add</a>
26//// </h2>
27////
28//// This command lets you install development-specific binaries and tools from outside
29//// the Gleam ecosystem. Lustre tries to be smart about the executables it understands:
30//// if you try to build a project without esbuild it will grab it, if it finds a
31//// tailwind.config.js it will use tailwind, and so on. All binaries are added to
32//// `build/.lustre/bin` in case you need to execute them manually.
33////
34//// ### `lustre/dev add esbuild`
35////
36//// [Esbuild](https://esbuild.github.io) is a bundler and build tool for JavaScript
37//// projects. This is the backbone of a lot of Lustre's build tooling and will be
38//// installed automatically if you use `lustre build` or `lustre dev`.
39////
40//// Example:
41////
42//// ```sh
43//// gleam run -m lustre/dev add esbuild
44//// ```
45////
46//// ### `lustre add tailwind`
47////
48//// [Tailwind CSS](https://tailwindcss.com) is a utility-first CSS framework popular
49//// among devs that want to quickly iterate on designs without touching CSS directly.
50//// This will be installed automatically if Lustre detects a `tailwind.config.js` file
51//// in your project.
52////
53//// Example:
54////
55//// ```sh
56//// gleam run -m lustre/dev add tailwind
57//// ```
58////
59//// <h2 id="build" class="member-name">
60//// <a href="#build">lustre/dev build</a>
61//// </h2>
62////
63//// Gleam projects can be compiled to JavaScript but this output is not always
64//// desirable for frontend projects where many individual modules can cause HTTP
65//// bottlenecks and slower load times. The `lustre build` command produces different
66//// _bundles_ that are single JavaScript files containing all the code needed for an
67//// application to run.
68////
69//// If a `lustre build` subcommand is run without the necessary tooling installed,
70//// Lustre will attempt to install it automatically.
71////
72//// ### `lustre/dev build app`
73////
74//// Bundle a Gleam application into a single JavaScript file. This requires a Gleam
75//// module in your project with the same name as the project itself, and a public
76//// `main` function that will be called when the application starts.
77////
78//// _This can be any Gleam program_, but if your `main` function returns an
79//// `App(Nil, model, msg)` then Lustre will automatically generate some boilerplate
80//// to mount the app onto an element with the id `"app"` and start it.
81////
82//// In addition to bundling, Lustre's dev tools will apply the following
83//// transformations to the output:
84////
85//// - FFI modules will be copied into Gleam's build directory even if they are
86//// not directly under the `src/` directory. This is a temporary patch until
87//// the Gleam compiler supports this itself.
88////
89//// - FFI modules that have *relative* imports to `*.gleam` modules will have
90//// their imports rewritten to point to the compiled `*.mjs` files instead.
91////
92//// Flags:
93////
94//// - `--minify` - Reduce the size of the output bundle by removing whitespace and
95//// renaming variables. This is useful for production builds.
96////
97//// Example:
98////
99//// ```sh
100//// gleam run -m lustre/dev build app
101//// ```
102////
103//// ### `lustre/dev build component`
104////
105//// Lustre components are based on standard Web Components. This means they should
106//// be usable outside of Lustre and Gleam! The `lustre build component` command takes
107//// a module and bundles it into a single JavaScript file that can be included in
108//// _any_ Web app to register a new Custom Element that can be used like native HTML
109//// elements.
110////
111//// For a module to be bundled as a component, it must adhere to the following rules:
112////
113//// - There must be a `pub const name` that is a string representing the name of the
114//// component to register. Remember that it must always contain a hyphen and follow
115//// [these rules](https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define#valid_custom_element_names).
116////
117//// - There must be a `pub fn` that has the type `fn() -> App(Nil, model, msg)`. It's
118//// name is not important but in cases where multiple functions in a module fit this
119//// type, the _first_ one will be used.
120////
121//// In addition to bundling, Lustre's dev tools will apply the following
122//// transformations to the output:
123////
124//// - FFI modules will be copied into Gleam's build directory even if they are
125//// not directly under the `src/` directory. This is a temporary patch until
126//// the Gleam compiler supports this itself.
127////
128//// - FFI modules that have *relative* imports to `*.gleam` modules will have
129//// their imports rewritten to point to the compiled `*.mjs` files instead.
130////
131//// Arguments:
132////
133//// - `<module_path>` - The path to the Lustre component you want to bundle. This should
134//// be in the same format that you would write to import the module in a Gleam file,
135//// e.g. `ui/my_componnt` and **not** `src/ui/my_component.gleam`.
136////
137//// Flags:
138////
139//// - `--minify` - Reduce the size of the output bundle by removing whitespace and
140//// renaming variables. This is useful for production builds.
141////
142//// Example:
143////
144//// ```sh
145//// gleam run -m lustre/dev build component ui/counter
146//// ```
147////
148//// <h2 id="start" class="member-name">
149//// <a href="#start">lustre/dev start</a>
150//// </h2>
151////
152//// The `lustre/dev start` command starts a development server that builds and serves your
153//// project. This lets you focus on development without having to worry about a backend
154//// or additional tooling. The page will automatically reload when you make changes
155//// to your project.
156////
157//// Flags:
158////
159//// - `--port` - The port to serve the project on. Defaults to `1234`.
160////
161//// Example:
162////
163//// ```sh
164//// gleam run -m lustre/dev start --port=8080
165//// ```
166////
167//// ## Getting help
168////
169//// Lustre Dev Tools is still an experimental work in progress. If you run in to issues
170//// or have ideas for how it could be improved we'd love to hear from you, either by
171//// [opening an issue](https://github.com/lustre-labs/dev-tools/issues) or reaching out
172//// on the [Gleam Discord server](https://discord.gg/Fm8Pwmy).
173////
174
175// IMPORTS ---------------------------------------------------------------------
176
177import argv
178import glint
179import lustre_dev_tools/cli/add
180import lustre_dev_tools/cli/build
181import lustre_dev_tools/cli/start
182
183// MAIN ------------------------------------------------------------------------
184
185/// The `main` function is used as the entry point for Lustre's dev tools. You
186/// shouldn't run this function in your code, but instead use `Gleam run` to run
187/// this module from the command line. To see what the dev tools can do, run:
188///
189/// ```
190/// gleam run -m lustre/dev -- --help
191/// ```
192///
193pub fn main() {
194 let args = argv.load().arguments
195
196 glint.new()
197 |> glint.as_module
198 |> glint.with_name("lustre/dev")
199 |> glint.path_help(["add"], add.description)
200 |> glint.add(at: ["add", "esbuild"], do: add.esbuild())
201 |> glint.add(at: ["add", "tailwind"], do: add.tailwind())
202 |> glint.add(at: ["build"], do: build.app())
203 |> glint.add(at: ["build", "app"], do: build.app())
204 |> glint.add(at: ["build", "component"], do: build.component())
205 |> glint.add(at: ["start"], do: start.run())
206 |> glint.run(args)
207}