Project layout¶
JoltUI does not prescribe a folder structure, but the following layout keeps the roles of the files obvious and matches the examples in this documentation:
my-app/
├── index.html
├── package.json
├── tsconfig.json
├── vite.config.ts
└── src/
├── main.ts creates the App and calls init()
└── app/
├── app.ts MyApp extends App<MyApp>
├── router.ts MyRouter extends Router<MyApp>
├── errorHandler.ts MyErrorHandler extends ErrorHandler<MyApp>
├── types.ts shared types (User, Post, ...)
├── dependencies.ts shared lazy() dependencies
├── layouts/
│ └── mainLayout.ts
├── pages/
│ ├── homePage.ts
│ └── aboutPage.ts
├── components/
│ └── counterButton.ts
└── errorPages/
└── notFoundPage.ts
| File | Role |
|---|---|
main.ts |
Entry point. The Vite plugin injects the page registry here. |
app.ts |
The application class: router, error handlers, app-level hooks. |
router.ts |
The router subclass: authentication checks and title generation. |
errorHandler.ts |
Error handlers. |
layouts/ |
Components decorated with @layout. |
pages/ |
Components decorated with @page, one per file, default-exported. |
components/ |
Ordinary components. |
errorPages/ |
Components shown with router.showErrorPage(). |
Conventions¶
- One page per module, as the default export. The Vite plugin requires it, and it makes the route table easy to read.
- Type the application everywhere. Declare components as
CustomElement<MyApp>, routers asRouter<MyApp>and handlers asErrorHandler<MyApp>.this.appis then typed as your own class. - Import components where they are used. Importing a module is what registers its custom element.
- Use
import typefor the application class in components, to avoid circular runtime imports betweenapp.tsand the modules it references.
The demo application¶
The JoltUI repository contains Fieldnotes, a complete demo in dev/: a story list, article
pages, a login, a protected drafts area and a profile section with a sublayout. Run it with: