🎸 Some mandatory soundtracks for this project:
- Karate by Karate
- Stratosphere by Duster
- Giles Corey by Giles Corey
- On Fire by Galaxie 500
- North Star Deserter by Vic Chesnutt
This is a simple starter for Remix. I am using this framework quite often and I wanted to have a simple starter to kickstart my development. It's, like always, opinionated. I hope you like it, and would greatly appreciate any feedback and/or contributions.
Please note that this is not a fullstack template per se. I am using this as a backed-for-frontend solution, with the actual being a separate project (or another part of a monorepo).
Install it with
npx create-remix@latest --template tomekbuszewski/slowcore-stack
or
pnpm create remix@latest --template tomekbuszewski/slowcore-stack
or whatever package manager is currently in fashion.
- Formatting with Prettier;
- Linting with ESLint;
- Type safety with TypeScript;
- Styling with Tailwind CSS;
- Tests with Vitest and Testing Library;
- E2E with Playwright;
For more detailed description and explanation of some of my choices, please read on 👇.
I am using Prettier for formatting and ESLint for linting. There isn't much uncommon rules, mostly detects empty functions and interfaces and sorts imports.
I've added Tailwind CSS to the project. It's a great utility-first CSS framework, and it comes with neat plugins:
- view transitions (to apply route transitions if needed);
- animate (to have basic animations out of the box);
- forms (to have basic form styles).
Obviously, all of these can be turned off using tailwind.config.ts
file.
This starter comes with a simple mechanism to verify whether all the environment
variables are set. It checks your environment against .env.example
file and
throws if any of the variables are missing.
It also generates type definitions for your environment variables in
./config/env.ts
, so you can use them in your code. There's a very simple
mechanism to check for the type, so instead of having everything as string
,
you'll get number
, boolean
, or string
.
You can either use env
object, which provides a Record of environment variables,
or getEnv
function, which is typed by env keys, so you'll get code completion.
The validator is bound to Vite and runs before starting the server. In development mode, it will generate the types, but on production, it will not.
Last, but not least, you can access the variables using @env
package. It
checks whether this is browser or server and picks the correct implementation.
Important thing, public types have to be prefixed with VITE_
.
Important thing 2, it only checks for keys, it won't verify your values.
Starter comes with Vitest and Testing Library for React. You can write unit and integration tests for everything.
It also comes with Playwright, and is bound to the built local instance. Running
pnpm run test:e2e
will first build the project and start the server
at localhost:3000
, and then run the tests.
MSW is added to the project. You can use it to mock all the external communication your project uses. This way you will never query your API in tests, but you will also don't have to catch requests and patch them. Simply define a handler and you're good.
This starter comes with a simple mechanism to generate UI components based on Plop. You can generate UI elements according to Atomic Design guidelines.
If you want to know more about Atomic Design, or the generator, consider checking my blogposts and/or YouTube videos:
Hooks are generated using Plop. Name it "use [my hook name]", it will convert to camelCase (useMyHookName) and will be placed in the hooks folder.
The generator will also add a test, but it's up to you to fill it with the actual cases.
Hooks are exported from @hooks
path, linking to ./app/hooks/index.ts
folder.
Features can be generated using Plop. It will create a basic scaffolding, but you can extend it however you see fit. There's an example feature in the starter, so you can see how it works and how I envision the structure.
What's important for me, is to have things in different files. Form actions,
data loaders, types, components, all this in separate files. It's easier to
navigate and to read it. Then, it has one "public" index.ts
file, which
is utilized by the main index
in the features folder.
Features can be tested with integration tests using Vitest, or with Playwright for E2E tests. I suggest doing the former for more complex features that require navigation and general user interaction. For smaller, integration testing is enough.