Opinionated, no nonsense starter kit for a simple Fastify API + JSX + HTMX application
MIT License
This starter kit aims to offer an efficient approach for initiating projects with both backend and frontend logic. It's designed to utilize a modern tech stack while maintaining minimal dependencies for simplicity and effectiveness.
This project renders all the HTML on the server (SSR), using JSX as the template language and HTMX to (progressively) enhance the frontend interactions. Let me clarify it once more: JSX is only used on the server, not on the client. The client is NOT a React application.
A typical use case could be a single web page that fetches some information from a third-party API, but you also want to have a small backend where to keep your API keys and maybe a cache to avoid hitting a rate limit on those external APIs.
The kit contains:
The kit does NOT contain:
ts-node
because we can do without itProbably worth mentioning that I have also created a (now deprecated) similar starter kit using Express and EJS (not JSX) if you prefer that server. I would suggest to not use it.
At the time of writing, Windows has not been tested as a dev environment.
npm create fastify-htmx-ts-app@latest my-app
# or
npx create-fastify-htmx-ts-app@latest my-app
After that, you have to install dependencies using your favourite package manager (i.e. npm
) and run some commands:
You also have npm lint
, npm build
and of course npm start
(for production).
Note that the project uses the (experimental) nodejs' native watch feature to monitor file changes and restart the server (in dev mode only). We don't use nodemon
but if you cannot use a fairly new version of nodejs (19+) you might need it. To use nodemon, just replace node --watch-path
with nodemon -w
.
If you need to use a .env
configuration file (not included), we suggest using nodejs >= 20.6, to be able to read a .env file without using an additional dependency (usually dotenv
). If you cannot use node 20+, then just install and use dotenv
.
This project uses ESLint and Prettier: don't forget to install/enable their extension in Visual Studio Code.
server/app.ts
contains just the bare-bone startup code for the serverserver/lib
contains any additional server module:
bootstrap.ts
is the module setting up Fastify and its pluginsjsxRender
is what makes it possible to use JSX with Fastify, as explained in the original post
router.tsx
contains the routes definition and the error handlingassets.ts
is used to generate a cache proof name for the assetsconstants.ts
server/views
contains the view templates in JSX format, mostly the Pages and the Components.client/app.ts
contains just some code that it's run when the page is loaded in the browserclient/lib/tools.ts
is just used as an example of natively including a js module at runtimeassets
contains js, css, and vendor files. Keep in mind that the js assets are symlinked from the dist
directory. All the assets are mounted under the /a
virtual folderSince this project doesn't use ts-node
, your app is run directly from the dist
folder (check the script in package.json to understand how).
This is on you. I own a small VPS and I run all my projects from there. I to run the server process behind a reverse proxy where I also end the TLS connection. I use ngnix and letsencrypt for my tls certificates. I find the guides from DigitalOcean extremely valuable for this kind of setup:
If you have successfully deployed a project inherited from this kit, in some cloud, and you want to share the steps please open a PR!
tools.js
in this project) is not, which means that they only rely to the cache settings of the static middleware. I will leave it up to you to decide if that's enough or if you want to add an additional build step to handle such casesA testing system is also not installed by default, but if you are like me and love Vitest, just follow these instructions (for the client, but it should work for the server as well):
npm install vitest --save-dev
client/tsconfig.json
and add an exclude
option for your tests: this is because vitest doesn't use tsc
for the typescript sources and you should tell tsc
to not compile and build the teststest
script in your package.json with something like vitest ./client/**/*.spec.ts
tsconfig.eslint.json
which extends our base, doesn't emit and includes the test files