refactor(web): page state with its page, the root keeps the shell's
Only what the header needs from the start stays at the root: the session, my projects for the command palette, the inbox and push for the bell, and their adapters. The home page's facades (my work, the rest of the home, my views, the calendar), Explore's and the proposal form's are provided by their routes, whose injectors keep them for when you come back. The other adapters come with the tracker's routes, now loaded lazily. The web libs declare "sideEffects": false, so a chunk carries what it uses and not everything an index.ts exports: main goes from 1.31 MB to 432 kB of the same initial total, which is still held up by @pi/ui (one module, with all of Material) and the GraphQL documents, both needed by the header. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,7 +16,7 @@ import {
|
||||
} from '@task-stream/web/shared/infrastructure';
|
||||
import { providePiUi, ToastService } from '@task-stream/web/shared/ui';
|
||||
import { Notifications } from '@task-stream/web/tracker/application';
|
||||
import { provideTrackerInfrastructure } from '@task-stream/web/tracker/infrastructure';
|
||||
import { provideTrackerShellInfrastructure } from '@task-stream/web/tracker/infrastructure';
|
||||
import { appRoutes } from './app.routes';
|
||||
|
||||
/*
|
||||
@@ -39,9 +39,9 @@ export const appConfig: ApplicationConfig = {
|
||||
provideApiConfig(apiConfigFromLocation()),
|
||||
provideGraphql(),
|
||||
|
||||
// Ports → adapters
|
||||
// Ports → adapters: the shell's here; the pages' with their lazy routes (tracker.routes.ts).
|
||||
provideIdentityInfrastructure(),
|
||||
provideTrackerInfrastructure(),
|
||||
provideTrackerShellInfrastructure(),
|
||||
{ provide: Notifications, useExisting: ToastService },
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
import { Route } from '@angular/router';
|
||||
import { authGuard } from '@task-stream/web/identity/presenters';
|
||||
import { appRoutes } from './app.routes';
|
||||
|
||||
/** The tracker's routes, behind the lazy `''` route (and its providers' parent route). */
|
||||
async function trackerChildren(): Promise<Route[]> {
|
||||
const lazy = appRoutes.find(
|
||||
(route) => route.path === '' && route.loadChildren,
|
||||
);
|
||||
const loaded = (await lazy?.loadChildren?.()) as Route[];
|
||||
expect(loaded[0].providers?.length).toBeGreaterThan(0);
|
||||
return loaded[0].children ?? [];
|
||||
}
|
||||
|
||||
describe('appRoutes', () => {
|
||||
it('keeps home behind the auth guard, and public projects and «Explorar» open', () => {
|
||||
it('keeps home behind the auth guard, and public projects and «Explorar» open', async () => {
|
||||
const paths = appRoutes.map((route) => route.path);
|
||||
expect(paths).toEqual(
|
||||
expect.arrayContaining(['login', 'auth/callback', '', '**']),
|
||||
);
|
||||
|
||||
const app = appRoutes.find((route) => route.path === '' && route.children);
|
||||
const children = app?.children ?? [];
|
||||
const children = await trackerChildren();
|
||||
expect(children.map((route) => route.path)).toEqual([
|
||||
'',
|
||||
'portfolio',
|
||||
@@ -27,10 +37,16 @@ describe('appRoutes', () => {
|
||||
expect(children[4].redirectTo).toBe('explore');
|
||||
});
|
||||
|
||||
it('exposes every project section', () => {
|
||||
const project = appRoutes
|
||||
.find((route) => route.path === '')
|
||||
?.children?.find((route) => route.path === 'p/:key');
|
||||
it('gives each page its own state, not the root', async () => {
|
||||
const children = await trackerChildren();
|
||||
expect(children[0].providers?.length).toBe(4);
|
||||
expect(children[2].providers?.length).toBe(1);
|
||||
});
|
||||
|
||||
it('exposes every project section', async () => {
|
||||
const project = (await trackerChildren()).find(
|
||||
(route) => route.path === 'p/:key',
|
||||
);
|
||||
expect(project?.children?.map((route) => route.path)).toEqual([
|
||||
'',
|
||||
'proponer',
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Route } from '@angular/router';
|
||||
import { identityRoutes } from '@task-stream/web/identity/presenters';
|
||||
import { trackerRoutes } from '@task-stream/web/tracker/presenters';
|
||||
|
||||
export const appRoutes: Route[] = [
|
||||
...identityRoutes,
|
||||
// Not all behind the guard: public projects are readable without a session.
|
||||
{ path: '', children: trackerRoutes },
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () => import('./tracker.routes').then((m) => m.routes),
|
||||
},
|
||||
{ path: '**', redirectTo: '' },
|
||||
];
|
||||
|
||||
15
apps/web/src/app/tracker.routes.ts
Normal file
15
apps/web/src/app/tracker.routes.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Route } from '@angular/router';
|
||||
import { provideTrackerPagesInfrastructure } from '@task-stream/web/tracker/infrastructure';
|
||||
import { trackerRoutes } from '@task-stream/web/tracker/presenters';
|
||||
|
||||
/**
|
||||
* The tracker, loaded lazily: its pages, and the adapters only they use,
|
||||
* come in this chunk instead of the one that boots the app.
|
||||
*/
|
||||
export const routes: Route[] = [
|
||||
{
|
||||
path: '',
|
||||
providers: [provideTrackerPagesInfrastructure()],
|
||||
children: trackerRoutes,
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user