Skip to content

Commit e05f131

Browse files
authored
feature: multiroot (#188)
1 parent 9dea149 commit e05f131

29 files changed

+741
-571
lines changed

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,10 @@ import { renderComponent } from "@lifeart/gxt";
206206
import App from "./App.gts";
207207

208208
const Instance = renderComponent(
209-
new App().template(),
209+
App, {
210+
// application arguments
211+
name: 'My App'
212+
},
210213
document.getElementById("app"),
211214
);
212215
```

server.js

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ async function createServer() {
7070
});
7171

7272
app.listen(5173);
73+
console.info(`http://localhost:5173`);
7374
}
7475

7576
createServer();

src/components/Application.gts

+6-16
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
renderComponent,
3-
runDestructors,
4-
Component,
5-
tracked,
6-
} from '@lifeart/gxt';
1+
import { runDestructors, Component, tracked } from '@lifeart/gxt';
72
import { PageOne } from './pages/PageOne.gts';
83
import { PageTwo } from './pages/PageTwo.gts';
94
import { PageThree } from './pages/PageThree.gts';
@@ -12,10 +7,13 @@ import { NestedRouter } from './pages/NestedRouter.gts';
127
import { router } from './../services/router';
138

149
export class Application extends Component {
15-
router = router;
10+
declare router: typeof router;
11+
constructor(args: { router?: typeof router }) {
12+
super(args);
13+
this.router = args.router || router;
14+
}
1615
@tracked
1716
now = Date.now();
18-
rootNode!: HTMLElement;
1917
components = {
2018
pageOne: PageOne,
2119
pageTwo: PageTwo,
@@ -24,14 +22,6 @@ export class Application extends Component {
2422
};
2523
async destroy() {
2624
await Promise.all(runDestructors(this));
27-
this.rootNode.innerHTML = '';
28-
this.rootNode = null!;
29-
}
30-
constructor(rootNode: HTMLElement) {
31-
super({});
32-
this.rootNode = rootNode;
33-
// @ts-ignore
34-
renderComponent(this, this.rootNode);
3525
}
3626
<template>
3727
{{#if IS_GLIMMER_COMPAT_MODE}}

src/components/Application.gts.d.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
export class Application {
2-
constructor(root: HTMLElement) {}
1+
import type { Root } from "../utils";
2+
import { Component } from '@lifeart/gxt';
3+
export class Application extends Component {
4+
35
}

src/components/pages/IsPolarisReady.gts

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// SOURCE: https://github.com/NullVoxPopuli/is-polaris-ready-yet/
22
import data from './is-polaris-ready/services/issue-data.json';
33
import { Component } from '@lifeart/gxt';
4+
import { getDocument } from '@/utils/context';
45

56
// import { Filters } from './is-polaris-ready/filters';
67
import { Header } from './is-polaris-ready/Header.gts';
78
import { Section } from './is-polaris-ready/Section.gts';
8-
import { getDocument } from '@/utils/dom-api';
99

1010
const GetStarted = <template>
1111
To get started with a Polaris App:
@@ -20,8 +20,10 @@ const GetStarted = <template>
2020
@embroider/addon-blueprint</a>.
2121
</template>;
2222

23-
function pageTitle(text: string) {
24-
getDocument().title = text;
23+
function pageTitle(ctx: Component<any>, text: string) {
24+
const document = getDocument(ctx);
25+
// TODO: solve SSR
26+
document.title = text;
2527
}
2628

2729
export class IsPolarisReady extends Component {
@@ -30,7 +32,7 @@ export class IsPolarisReady extends Component {
3032
<style>
3133
@import url('./is-polaris-ready.css');
3234
</style>
33-
{{pageTitle 'is Polaris ready yet?'}}
35+
{{pageTitle this 'is Polaris ready yet?'}}
3436

3537
<div class='inner'>
3638
<Header />

src/components/pages/NestedRouter.gts

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export class NestedRouter extends Component<{ Args: RouterArgs }> {
2121
get components() {
2222
return this.args.components ?? {};
2323
}
24-
get Component(): typeof Component {
24+
get Component(): typeof Component<any> {
2525
return this.model?.component || this.components[this.route] || DefaultRoute;
2626
}
2727
get route() {

src/components/pages/ToDoMVC.gts

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
import { Component } from '@lifeart/gxt';
1+
import { Component, Root } from '@lifeart/gxt';
22
import { Layout } from './todomvc/Layout.gts';
33
import { Attribution } from './todomvc/Attribution.gts';
44
import Page from './todomvc/page.gts';
55
import { repo } from './todomvc/repo';
6-
import { getDocument } from '@/utils/dom-api';
7-
function pageTitle(text: string) {
8-
getDocument().title = text;
6+
import { getDocument } from '@/utils/context';
7+
8+
function pageTitle(ctx: Component<any>, text: string) {
9+
const document = getDocument(ctx);
10+
// TODO: solve SSR
11+
document.title = text;
912
}
1013

1114
export class ToDoMVC extends Component {
@@ -14,7 +17,7 @@ export class ToDoMVC extends Component {
1417
<style>
1518
@import url('/todomvc.css');
1619
</style>
17-
{{pageTitle 'ToDoMVC'}}
20+
{{pageTitle this 'ToDoMVC'}}
1821
<Layout>
1922
{{#if @hasChildren}}
2023
{{yield}}

src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export default async function render() {
1919
await import('@lifeart/gxt/ember-inspector');
2020
}
2121
await router.mount(window.location.pathname);
22-
const benchmark = createBenchmark();
22+
const benchmark = createBenchmark(document);
2323

2424
// starting app
2525

src/server.ts

+8-17
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,18 @@ import 'glint-environment-gxt';
22
import 'decorator-transforms/globals';
33

44
import { URL } from 'node:url';
5-
import { router } from '@/services/router';
5+
import { createRouter } from '@/services/router';
66
import { Application } from '@/components/Application.gts';
77
import { render as renderSSR } from '@/utils/ssr/ssr';
88

9-
const queue: Promise<any>[] = [];
10-
119
export async function render(url: string) {
12-
await Promise.all(queue);
13-
let resolve = () => void 0;
14-
const p = new Promise((_resolve) => {
15-
resolve = _resolve as any;
16-
});
17-
queue.push(p);
1810
const urlInstance = new URL(url);
11+
const router = createRouter();
1912
await router.mount(urlInstance.pathname, true);
20-
// @ts-expect-error
21-
const result = await renderSSR((el: HTMLElement) => new Application(el), {
22-
url,
23-
});
24-
await router.unmount();
25-
resolve();
26-
queue.splice(queue.indexOf(p), 1);
27-
return result;
13+
const result = await renderSSR(Application, {router}, {url});
14+
try {
15+
return result;
16+
} finally {
17+
router.unmount();
18+
}
2819
}

src/services/router.ts

+96-90
Original file line numberDiff line numberDiff line change
@@ -15,98 +15,104 @@ class GlimmerRouter extends Router {
1515
@tracked activeRoute;
1616
}
1717

18-
// @ts-expect-error
19-
export const router = new GlimmerRouter({
20-
main: '',
21-
tests: '/tests',
22-
benchmark: '/benchmark',
23-
pageOne: '/pageOne',
24-
pageTwo: '/pageTwo',
25-
isPolarisReady: '/is-polaris-ready',
26-
todomvc: '/todomvc',
27-
'todomvc.all': '/todomvc/all',
28-
'todomvc.active': '/todomvc/active',
29-
'todomvc.completed': '/todomvc/completed',
30-
}) as RouterType;
18+
export function createRouter() {
19+
// @ts-expect-error
20+
const router = new GlimmerRouter({
21+
main: '',
22+
tests: '/tests',
23+
benchmark: '/benchmark',
24+
pageOne: '/pageOne',
25+
pageTwo: '/pageTwo',
26+
isPolarisReady: '/is-polaris-ready',
27+
todomvc: '/todomvc',
28+
'todomvc.all': '/todomvc/all',
29+
'todomvc.active': '/todomvc/active',
30+
'todomvc.completed': '/todomvc/completed',
31+
}) as RouterType;
32+
33+
router.addResolver('isPolarisReady', async () => {
34+
// preload css <link rel="preload" href="style.css" as="style" />
35+
if (!import.meta.env.SSR) {
36+
const link = document.createElement('link');
37+
link.rel = 'preload';
38+
link.href = '/is-polaris-ready.css';
39+
link.as = 'style';
40+
document.head.appendChild(link);
41+
}
42+
const { IsPolarisReady } = await import(
43+
// @ts-ignore import
44+
'@/components/pages/IsPolarisReady.gts'
45+
);
46+
return {
47+
component: IsPolarisReady,
48+
};
49+
});
3150

32-
router.addResolver('isPolarisReady', async () => {
33-
// preload css <link rel="preload" href="style.css" as="style" />
34-
if (!import.meta.env.SSR) {
35-
const link = document.createElement('link');
36-
link.rel = 'preload';
37-
link.href = '/is-polaris-ready.css';
38-
link.as = 'style';
39-
document.head.appendChild(link);
40-
}
41-
const { IsPolarisReady } = await import(
42-
// @ts-ignore import
43-
'@/components/pages/IsPolarisReady.gts'
44-
);
45-
return {
46-
component: IsPolarisReady,
47-
};
48-
});
51+
router.addResolver('todomvc', async () => {
52+
// preload css <link rel="preload" href="style.css" as="style" />
53+
console.log('todomvc');
54+
if (!import.meta.env.SSR) {
55+
const link = document.createElement('link');
56+
link.rel = 'preload';
57+
link.href = '/todomvc.css';
58+
link.as = 'style';
59+
document.head.appendChild(link);
60+
}
61+
const { ToDoMVC } = await import(
62+
// @ts-ignore import
63+
'@/components/pages/ToDoMVC.gts'
64+
);
65+
const model = {
66+
component: ToDoMVC,
67+
};
68+
router._resolvedData['todomvc'] = {
69+
model,
70+
params: {},
71+
};
72+
return model;
73+
});
4974

50-
router.addResolver('todomvc', async () => {
51-
// preload css <link rel="preload" href="style.css" as="style" />
52-
console.log('todomvc');
53-
if (!import.meta.env.SSR) {
54-
const link = document.createElement('link');
55-
link.rel = 'preload';
56-
link.href = '/todomvc.css';
57-
link.as = 'style';
58-
document.head.appendChild(link);
59-
}
60-
const { ToDoMVC } = await import(
61-
// @ts-ignore import
62-
'@/components/pages/ToDoMVC.gts'
63-
);
64-
const model = {
65-
component: ToDoMVC,
66-
};
67-
router._resolvedData['todomvc'] = {
68-
model,
69-
params: {},
70-
};
71-
return model;
72-
});
75+
router.addResolver('todomvc.all', async () => {
76+
console.log('todomvc.all');
7377

74-
router.addResolver('todomvc.all', async () => {
75-
console.log('todomvc.all');
78+
const page = await import(
79+
// @ts-ignore import
80+
'@/components/pages/todomvc/page.gts'
81+
);
82+
return {
83+
component: page.default,
84+
get model() {
85+
return repo.all;
86+
},
87+
};
88+
});
89+
router.addResolver('todomvc.active', async () => {
90+
const page = await import(
91+
// @ts-ignore import
92+
'@/components/pages/todomvc/page.gts'
93+
);
94+
return {
95+
component: page.default,
96+
get model() {
97+
return repo.active;
98+
},
99+
};
100+
});
76101

77-
const page = await import(
78-
// @ts-ignore import
79-
'@/components/pages/todomvc/page.gts'
80-
);
81-
return {
82-
component: page.default,
83-
get model() {
84-
return repo.all;
85-
},
86-
};
87-
});
88-
router.addResolver('todomvc.active', async () => {
89-
const page = await import(
90-
// @ts-ignore import
91-
'@/components/pages/todomvc/page.gts'
92-
);
93-
return {
94-
component: page.default,
95-
get model() {
96-
return repo.active;
97-
},
98-
};
99-
});
102+
router.addResolver('todomvc.completed', async () => {
103+
const page = await import(
104+
// @ts-ignore import
105+
'@/components/pages/todomvc/page.gts'
106+
);
107+
return {
108+
component: page.default,
109+
get model() {
110+
return repo.completed;
111+
},
112+
};
113+
});
114+
115+
return router;
116+
}
100117

101-
router.addResolver('todomvc.completed', async () => {
102-
const page = await import(
103-
// @ts-ignore import
104-
'@/components/pages/todomvc/page.gts'
105-
);
106-
return {
107-
component: page.default,
108-
get model() {
109-
return repo.completed;
110-
},
111-
};
112-
});
118+
export const router = createRouter();

src/tests/index.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ import 'qunit-theme-ember/qunit.css';
44

55
import * as QUnit from 'qunit';
66
import { setup } from 'qunit-dom';
7-
import { getDocument } from '@/utils/dom-api';
8-
import { cleanupRender } from '@/tests/utils';
7+
import { cleanupRender, getDocument} from '@/tests/utils';
98
import { DEBUG_MERGED_CELLS, DEBUG_CELLS } from '@/utils/reactive';
109

1110
setup(QUnit.assert, {

0 commit comments

Comments
 (0)