Smallweb v0.8.0
was released yesterday, and it included the first smallweb
breaking change.
The
~/www
convention was dropped, the defaut folder is now~/smallweb
In addition to this change, the folder should now be named after the hostname:
- example.smallweb.run => ~/smallweb/example.smallweb.run/
- pomdtr.me => ~/smallweb/pomdtr.me/
- example.localhost => ~/smallweb/example.localhost/
This change was not really well received:
I'm not a fan of the new hostname folder convention. It feels noisy.
I'm also a bit frustrated by this change, and this is my main gripe with it too. And this "ugliness" is (for me) exacerbated by the fact that there's going to be a lot of repetition if all my smallweb apps are
<app>.localhost
. I would prefer a convention like~/smallweb/localhost/example
mapping toexample.localhost
In this post, I'll try to address:
- the drawbacks of the previous convention
- the options I've considered
The smallweb routing system was originally designed for a single usecase:
hosting a unlimited amount of websites locally, using *.localhost
domains.
The convention was to:
- store all of your website in the smallweb root (
~/www
by default) - use the folder name has the subdomain
So ~/www/example/
would be mapped to https://example.localhost
.
As the project expanded, new usecases emerged for smallweb: hosting smallweb on a raspberrypi, or even on a VPS from hetzner/digital ocean...
And the intitial design hold quite well with these usecases. You would just
assign a domain to your device (ex: *.pomdtr.me
), and ~/www/example/
would
map to https://example.pomdtr.me
.
But what if I wanted to assign multiple domains to a single machine ? If I route
both *.pomdtr.me
and *.smallweb.run
to my machine, ~/www/example
will
match both https://example.pomdtr.me
and https://example.smallweb.run
. This
is probably not what the user want in most cases.
Let's say we want to manage the following websites using smallweb.
- https://smallweb.run
- https://readme.smallweb.run
- https://assets.smallweb.run
- https://pomdtr.me
- https://example.localhost
- https://react.localhost
We'll assume that all of these websites are defined in a single main.ts
.
We could just allow arbitrary folder names, and just use a CNAME at the root of the app, specifying the domain name.
assets.smallweb.run
It sounds like a fine solution, but it means that every smallweb website would need to include it. I really want single-file websites to be able to exist, and I feel like file based routing is a core feature of smallweb, so I did not go with this option.
/
├── localhost
│ ├── example
│ │ └── main.ts
│ └── react
│ └── main.ts
├── me
│ └── pomdtr
│ └── main.ts
└── run
└── smallweb
├── main.ts
├── assets
│ └── main.ts
└── readme
└── main.ts
Of course, this is not acceptable. If we look at the /run/smallweb
folder, we
can see that it contains both:
- the code of the
https://smallweb.run
homepage at his root. - the code of
readme
andassets
subdomains
If we used a git repository to manage each of those websites, this would quickly become a mess.
To counter this, we can add a convention: if the request target a root domain,
we'll map it to the @
folder.
/
├── localhost
│ ├── example
│ │ └── main.ts
│ └── react
│ └── main.ts
├── me
│ └── pomdtr
│ └── @
│ └── main.ts
└── run
└── smallweb
├── assets
│ └── main.ts
├── readme
│ └── main.ts
└── @
└── main.ts
This looks better! However, it still feels like we have some uncessary nesting.
For example, the /run
folder only has one subfolder: /run/smallweb
. Folders
are supposed to group related websites, but websites sharing the same TLD
probably have nothing in common.
Even worse, Creating pomdtr.me requires 3 (!!!) level of nesting:
/me/pomdtr/@
.
Instead of splitting on .
, we'll use the apex domain as the first level of
subfolder, and the subdomain as the second one.
- The apex domain (
pomdtr.me
,smallweb.run
orlocalhost
)
/
├── localhost
│ ├── example
│ │ └── main.ts
│ └── react
│ └── main.ts
├── pomdtr.me
│ └── @
│ └── main.ts
└── smallweb.run
├── @
│ └── main.ts
├── assets
│ └── main.ts
└── readme
└── main.ts
We still have some uncessary nesting (pomdtr/@
), but the problem is limited.
Here the folder structure kind of reflect the process of updating DNS records in cloudflare.
Let's drop the nesting, and use the domain name as the folder name:
/
├── assets.smallweb.run
│ └── main.ts
├── example.localhost
│ └── main.ts
├── pomdtr.me
│ └── main.ts
├── react.localhost
│ └── main.ts
├── readme.smallweb.run
│ └── main.ts
└── smallweb.run
└── main.ts
Using the domain name as the folder looks kind of ugly, but it avoid the nested folders problem entirely. One big advantage of this architecture is that you can create a new website from a git repository by just doing:
git clone <repo-url> <hostname>
My main gripe with it (outside of the noisy folder names), is that related
websites appears in different places in the file tree (ex: react.localhost
and
example.localhost
are not next to each others).
We can fix it by reversing the folder names:
/
├── localhost.example
│ └── main.ts
├── localhost.react
│ └── main.ts
├── me.pomdtr
│ └── main.ts
├── run.smallweb
│ └── main.ts
├── run.smallweb.assets
│ └── main.ts
└── run.smallweb.readme
└── main.ts
I quite like this compromise, but I'm not sure it would address the noisyness reported by the community.
Here are the two options I'm considering as default:
- 2-level structure
- Reversed Flat structure
Writing this article, I've come to gain more appreciation of the two level-structure, as it mirrors the process of setting up DNS record in your domain registrar.
I wonder if we should support both options (remix-style).
I would love to hear your thoughts on all of this. Make sure to join the discord channel if you want your voice to be heard.