Skip to main content

Pages

Page Component

In tramvai application Page is a React component, created in routes directory and exported by default. Every Page represents a new URL in the application.

Example:

routes/index.tsx
import type { PageComponent } from '@tramvai/react';

const MainPage: PageComponent = () => <h1>Main Page</h1>;

export default MainPage;

PageComponent interface is used here for better typings - Page components may have additional static properties:

Actions

Page components support global actions in actions static property, these actions will executed only for this page:

MainPage.actions = [fetchPageDataAction];

This actions will be code-splitted with page component code.

Reducers

Page components support reducers in reducers static property, these reducers will be registered in application store:

MainPage.reducers = [SomeDataStore];

This reducers will be code-splitted with page component code.

Components

Page components support additional React components in components static property, this components will be registered in the application. You can directly access these components with PAGE_SERVICE:

import { usePageService } from '@tramvai/module-router';
import type { PageComponent } from '@tramvai/react';

const MainPage: PageComponent = () => {
const pageService = usePageService();
const ModalBox = pageService.getComponent('modal-box');

return (
<>
<h1>Main Page</h1>
<ModalBox />
</>
);
};

MainPage.components = {
'modal-box': () => <dialog>Modal Box</dialog>,
};

This components will be code-splitted with page component code.

SEO and Meta Tags

All possibilites below provided by SeoModule

Easy way to change page meta is to add a seo property to page component:

MainPage.seo = {
metaTags: {
title: 'Main Page Title',
},
};

File-System Routing

tramvai provides File-System Routing approach as default way to create new pages in the application, also you always have option to provide a list of routes directly in tramvai router. It is possible because in tramvai application every page represents plain Route object, and File-System routes is just high-level abstraction, easily converted in Route interface.

For example, you want to handle this urls by your application:

/
/login/
/comments/
/comments/:id/

In that case you need to create components with this file structure:

src
└── routes
├── index.tsx
├── login
└── index.tsx
└── comments
├── index.tsx
└── [id]
└── index.tsx

Where path with square brackets relates to dynamic parts of url.

info

Every page will be wrapped in dynamic import statement with lazy from @tramvai/react library, and will be separated into a different chunk - it is important optimization for better code splitting.

Under hood, tramvai will create this list of routes:

[
{
path: '/',
config: {
pageComponent: '@/routes/index',
},
},
{
path: '/login/',
config: {
pageComponent: '@/routes/login/index',
},
},
{
path: '/comments/',
config: {
pageComponent: '@/routes/comments/index',
},
},
{
path: '/comments/:id/',
config: {
pageComponent: '@/routes/comments/[id]/index',
},
},
];
info

File for /login/ page must be named login/index.tsx instead of login.tsx, because we must have strictly one way to convert url back to page component name.

Example application

Define routes manually

All components inside pages directory will be automatically read from the file system and registered inside an application, this feature is called File-System Components. You can use this components by unique name when manually configuring the routes.

For example, you create page components with this file structure:

src
└── pages
├── index.tsx
└── comments.tsx

This components will be available in the application with these names:

@/pages/index
@/pages/comments
info

Every component will be wrapped in dynamic import statement with lazy from @tramvai/react library, and will be separated into a different chunk - it is important optimization for better code splitting.

And you can create this routes with them:

import { SpaRouterModule } from '@tramvai/modules-router';

createApp({
modules: [
SpaRouterModule.forRoot([
{
name: 'main',
path: '/',
config: {
pageComponent: '@/pages/index',
},
},
{
name: 'comments',
path: '/comments/',
config: {
pageComponent: '@/pages/comments',
},
},
]),
],
});

Example application

Another way, for example if you want to define routes in different modules, is to use ROUTES_TOKEN:

import { Module } from '@tramvai/core';
import { SpaRouterModule } from '@tramvai/modules-router';

@Module({
providers: [
provide({
provide: ROUTES_TOKEN,
useValue: [
{
name: 'comments',
path: '/comments/',
config: {
pageComponent: '@/pages/comments',
},
},
],
}),
],
})
export class CommentsModule {}

Colocate non-components files

File-System pages by default will add every file inside pagesDir directory including test files, actions, inner components. Although it doesn't bring behaviour issues as these files are just registered as components with different names it can cause higher time builds and higher memory consumption as it requires more handling in build system internally.

To bypass mentioned issues and to make registering of components more explicit you can specify componentsPattern option for cli with the regex of the files that should be registered as components. If you provide this setting the files that is not satisfy the regexp will not be registered as File-System Components.

tramvai.json
{
"projects": {
"awesome-app": {
"fileSystemPages": {
"enabled": true,
"pagesDir": "pages",
"componentsPattern": "(Page|Layout)\\.tsx?"
}
}
}
}

Configuration

File-System Routing is configured by fileSystemPages option in tramvai.json:

tramvai.json
{
"projects": {
"awesome-app": {
"fileSystemPages": {
"enabled": true,
"routesDir": "routes",
"pagesDir": "pages"
}
}
}
}

How to

How to create page with dynamic parameters

Wrap dynamic part of url in square brackets in file path.

For /comments/:id/ create page component with this path routes/comments/[id]/index.tsx:

src
└── routes
└── comments
└── [id]
└── index.tsx

When you define routes manually, use colon - : in path segment:

import { SpaRouterModule } from '@tramvai/modules-router';

createApp({
modules: [
SpaRouterModule.forRoot([
{
name: 'single-comment',
path: '/comments/:id/',
config: {
pageComponent: '@/pages/single-comment',
},
},
]),
],
});

Dynamic parameter available in current route params, more information in Working with Url documentation.