An awesome app.
npx degit iamyuu/vitr
- Node v22.8.0
- pNpm v9.10.0
or, just use fnm and enable corepack, so it will automaticly set up for you.
You can run the below script to setup the project on your local device:
- clone this repo
- run
pnpm run setup
Nothing special in this section, but for VSCode (or Cursor) users, but to make lfe easier you can install our recommended extension by typing @recommended
at section extensions on primary sidebar.
Biome serves as a linting tool for JavaScript, helping developers in maintaining code quality and adhering to coding standards. Biome helps identify and prevent common errors, ensuring code correctness and promoting consistency throughout the codebase. This approach not only helps in catching mistakes early but also enforces uniformity in coding practices, thereby enhancing the overall quality and readability of the code.
Biome is effective for detecting language-related bugs in JavaScript. However, due to JavaScript's dynamic nature, Biome may not catch all runtime data issues, especially in complex projects. To address this, TypeScript is recommended. TypeScript is valuable for identifying issues during large refactoring processes that may go unnoticed. When refactoring, prioritize updating type declarations first, then resolving TypeScript errors throughout the project. It's important to note that while TypeScript enhances development confidence, but it does not prevent runtime failures.
We'll use Lefthook for implementing and executing git hooks. By utilizing Lefthook to run code validations before each commit, we can ensure that your code maintains high standards and that no faulty commits are pushed to the repository. Lefthook enables you to perform various tasks linting, code formatting, and type checking before allowing code pushes.
We use absolute import (~/path/file
) to make it easier to move files around and avoid messy import paths (../../sevice
). Wherever you move the file, all the imports will remain intact. That means that anything in the src folder can be accessed via ~
, e.g. some file that lives in src/utils/function
can be accessed using ~/utils/function
instead of ../../../utils/function
.
We also configured @poplix/ui
to resolve to a folder in src/components/ui
, this will help us in the future if we have a proper design system that will be used by the whole team. Another thing is we configure ~icons/pop
to resolve local icons on src/assets/icons
, this is to keep us consistent in importing icons.
We enforce to use kebab-case
for file naming conventions and folder naming conventions. This can help to keep our codebase consistent and easier to navigate.
We enforce adding a suffix (e.g. file-name.component
, file-name.service
, file-name.type
, etc) to each file in the features
folder to make it easier when opening many files simultaneously.
In the project directory, you can run:
pnpm run setup
: Setup local development environment.pnpm run dev
: Runs the app in the development mode. Open http://localhost:3000 to view it in the browser.pnpm run build
: Builds the app for production to thedist
folder.pnpm run preview
: Open http://localhost:4173 to view it in the browser.pnpm run lint
: Runs linting and formatting the code.pnpm run typecheck
: Check type checking.pnpm run test
: Launches the test runner in the interactive watch mode.pnpm run test:ui
: Launches the test runner with interactive ui.pnpm run test:ci
: Runs test runner only once (for ci environment).pnpm run test:report
: Show coverage report for unit and integration test.pnpm run test:e2e
: Runs end-to-end test runner. Used for smoke test.pnpm run test:e2e:report
: Show end-to-end smoke test test result.
- Tailwind CSS — Utility CSS framework.
- shadcn/ui — Collection of re-usable components.
- Phosphor — Icon pack.
- Recharts — Chart library.
- TanStack Router — A type-safe router.
- ky — Http client.
- TanStack Query — Server state management.
- XState Store — Client state management.
- React Hook Form — Form state management.
- TypeScript — Static type checker.
- Vitest — Unit and integration test.
- React Testing Library — avoid implementation details.
- Mock Service Worker — Mock http request.
- Playwright — End-to-end test.
- Sentry — Error monitoring.
Most of the code lives in the src
folder and looks something like this:
src
├── assets # static files e.g. icons, etc
├── components # shared component across domain e.g. ui, etc
├── constants # read-only constant variable e.g. env, etc
├── features
│ └── {domain}
│ ├── components # component for specific feature
│ ├── schemas # schema validation for specific feature
│ ├── screens # screen that will import on route
│ ├── stores # client side store for specific feature
│ ├── services # interaction with an external source
│ └── types # define interface for specific feature
├── generated # generated files e.g. route
├── hooks # shared React custom hooks used across domain
├── providers # all of the application providers
├── routes # screen that will show the user a specific path
├── tests # utility test, mock server, etc
├── types # shared interface, utility interface, reset types
└── utils # shared reuseable functions e.g. http client, etc
For easy scalability and maintenance, organize most of the code within the features folder. Each feature folder should contain code specific to that feature, keeping things neatly separated.
We're using file-based routing, to make sure you understand it you can see the example below:
Filename | Route Path | Component Output |
---|---|---|
__root.tsx | <Root> |
|
index.tsx | / (exact) | <Root><RootIndex> |
about.tsx | /about | <Root><About> |
posts.tsx | /posts | <Root><Posts> |
posts.index.tsx | /posts (exact) | <Root><Posts><PostsIndex> |
posts.$postId.tsx | /posts/$postId | <Root><Posts><Post> |
posts_.$postId.edit.tsx | /posts/$postId/edit | <Root><EditPost> |
settings.tsx | /settings | <Root><Settings> |
settings.profile.tsx | /settings/profile | <Root><Settings><Profile> |
settings.notifications.tsx | /settings/notifications | <Root><Settings><Notifications> |
_layout.tsx | <Root><Layout> |
|
_layout.layout-a.tsx | /layout-a | <Root><Layout><LayoutA> |
_layout.layout-b.tsx | /layout-b | <Root><Layout><LayoutB> |
files.$.tsx | /files/$ | <Root><Files> |
.
Separator: Routes can use the . character to denote a nested route.$
Token: Routes segments with the$
token are parameterized and will extract the value from the URL pathname as a routeparam
._
Prefix: Routes segments with the_
prefix are considered layout-routes and will not be used when matching its child routes against the URL pathname._
Suffix: Routes segments with the_
suffix exclude the route from being nested under any parent routes.(folder)
folder name pattern: A folder that matches this pattern is treated as a route group which prevents this folder to be included in the route's URL path.