Baguette is a Bash server-side web framework geared towards internal tooling, or, for making reactive web forms with shell scripts. It's developed on top of htmx and uses websocketd for browser and server app communication.
It is still a work in progress, and some knowledge of htmx is required to use it effectively; however, any feedback, ideas, or contributions are welcomed. Please take a look at the issues page if you'd like to participate in its development.
NOTE: While it's possible to build a public-facing "web app" with Baguette, its main use case is for building reactive form-based UIs to existing tools / commands that are meant for internal consumptions within a secure private network.
- Websocket makes it easy to write stateful and reactive web applications.
- Built-in support for OOP and modeling via Bos.
- Built-in UI widgets / components (Experimental).
- Error reporting (when
set -eis used) with stack traces to help with app development.
-
A Baguette app is not RESTful; it exposes no HTTP endpoints, so you can't, for example, bookmark the state of your app via an URL, and you can't interact with it via HTTP requests (you can use CGI, but then it's a separate process).
-
It's slow and not scalable to high number of users. Though, depends on your use case, it might be fast enough; or, it might be good for prototyping.
Here's what a simple, single-page app (available as example-app.sh) in Baguette looks like:
#!/usr/bin/env bash
#
set -e
source baguette.sh
declare -A STATES
@main () {
main/ id=${FUNCNAME#@} data-scope
h2/ ="Welcome to Baguette"
: ${STATES[username]:=${val_name:-}}
if [[ ! ${STATES[username]:-} ]]; then
textfield name=name label="What's your name?" placeholder="First Last" ws-send=no
button label=Submit
else
markdown "_Hello ${STATES[username]:-World}!_"
fi
local label
for label in one two three; do
checkbox =${label^} name=$label value=${label^}
done
local checked=(${val_one:-} ${val_two:-} ${val_three})
markdown "You checked: **${checked[*]}**"
/main
}
baguettePlease see Guide for a getting-started guide.
- websocketd (this is a fork that fixed the issue with
--passenvfor CGI scripts) - htmx (>= 2.0)
- jq
- GNU Coreutils
- Bash (>= 4.3; preferably >= 5)
Take a look at the examples to get an idea on what a Baguette app looks like. Currently, a Dockerfile is provided for building an image with the dependencies needed to run the examples.
You can build the image and run the examples following these instructions:
$ cd baguette
$ docker build -t localhost/baguette .
$ d=/home/baguette/baguette image=localhost/baguette
$ opts=(--rm -v "$PWD:${d:?}" -e WSD_PORT=5000 -p 5000:5000)
# Pick one to try: (ctrl-c to exit)
$ docker run "${opts[@]}" -w "$d/examples/todo-app" $image ./main.sh
$ docker run "${opts[@]}" -w "$d/examples/markdown-app" $image ./main.sh
$ docker run "${opts[@]}" -w "$d/examples/contact-app" $image ./main.sh
$ docker run "${opts[@]}" -w "$d/examples/wiki-app" $image ./main.sh
# NOTE: The path to /index.html is required for the URL of these apps.Alternatively, there's now a bin/baguette-dev.sh that can be used to run any Baguette app script or folder in a docker container built from the Dockerfile.