Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit 160174a

Browse files
committed
feat(Router): Add router
1 parent 2ff7a56 commit 160174a

File tree

9 files changed

+132
-23
lines changed

9 files changed

+132
-23
lines changed

examples/vue-app/main.js

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
import { Link, createSSRApp } from "aleph/vue";
2-
import App from "./app.vue";
1+
import { App, createSSRApp } from "aleph/vue";
32

4-
const app = createSSRApp(App)
5-
6-
app.component('Link', Link)
7-
8-
app.mount("#root", true)
3+
createSSRApp(App).mount("#root", true);

examples/vue-app/routes/blog.vue

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,14 @@ const msg = ref("blog page")
99
<h2>{{ msg }}</h2>
1010
<br />
1111
<Link to="/">go back</Link>
12-
</template>
12+
</template>
13+
14+
<style scoped>
15+
h2 {
16+
font-size: 24px;
17+
font-weight: 600;
18+
line-height: 1;
19+
color: #42b883;
20+
margin: 0;
21+
}
22+
</style>

examples/vue-app/routes/hello.vue

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,14 @@ const msg = ref("hello page")
99
<h2>{{ msg }}</h2>
1010
<br />
1111
<Link to="/">go back</Link>
12-
</template>
12+
</template>
13+
14+
<style scoped>
15+
h2 {
16+
font-size: 24px;
17+
font-weight: 600;
18+
line-height: 1;
19+
color: #42b883;
20+
margin: 0;
21+
}
22+
</style>

examples/vue-app/app.vue renamed to examples/vue-app/routes/index.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
<script setup>
22
import { ref } from "vue"
3-
import { Link } from "aleph/vue"
3+
import { Link, Head } from "aleph/vue"
44
55
const msg = ref("Hello world!")
66
</script>
77

88
<template>
9+
10+
<Head>
11+
<title>aleph/vue - hello world</title>
12+
</Head>
913
<h1 v-if="msg">{{ msg }}</h1>
1014
<h1 v-if="!msg" style="color: #ccc;">Please type something</h1>
1115
<input v-model="msg" placeholder="Please type something">

examples/vue-app/server.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { createSSRApp } from "aleph/vue";
1+
import { App, createSSRApp } from "aleph/vue";
22
import { serve } from "aleph/server";
33
import { renderToString } from "vue/server-renderer";
4-
import App from "./app.vue";
54

65
serve({
76
config: {

framework/vue/context.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
1-
import { ref } from "vue";
1+
import { Ref, ref } from "vue";
22

33
export const RouterContext = ref({
44
url: new URL("http://localhost/"),
55
params: {},
66
});
7+
8+
type DataContextProps = Ref<{
9+
dataUrl: string;
10+
dataCache: Map<any, any>;
11+
ssrHeadCollection?: string[];
12+
}>;
13+
14+
export const DataContext: DataContextProps = ref({
15+
dataUrl: "/",
16+
dataCache: new Map(),
17+
});

framework/vue/head.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { defineComponent, onBeforeUnmount } from "vue";
2+
import { DataContext } from "./context.ts";
3+
import util from "../../lib/util.ts";
4+
5+
export const Head = defineComponent({
6+
name: "Head",
7+
props: {},
8+
setup(_props, ctx) {
9+
if (ctx.slots.default) {
10+
const ssrHeadCollection: string[] = [];
11+
const children = ctx?.slots.default();
12+
children.forEach((vnode) => {
13+
const { type, children } = vnode;
14+
if (type === "title") {
15+
if (util.isFilledString(children)) {
16+
ssrHeadCollection.push(`<title ssr>${children}</title>`);
17+
} else if (util.isFilledArray(children)) {
18+
ssrHeadCollection.push(`<title ssr>${children.join("")}</title>`);
19+
}
20+
}
21+
DataContext.value.ssrHeadCollection = ssrHeadCollection;
22+
});
23+
}
24+
},
25+
beforeMount() {
26+
// remove ssr head elements
27+
const { head } = window.document;
28+
Array.from(head.children).forEach((el: Element) => {
29+
if (el.hasAttribute("ssr")) {
30+
head.removeChild(el);
31+
}
32+
});
33+
},
34+
mounted() {
35+
const { document } = window;
36+
const insertedEls: Array<HTMLElement> = [];
37+
if (this.$slots.default) {
38+
const defaultSlots = this.$slots.default();
39+
defaultSlots.forEach((vnode) => {
40+
const { type, children } = vnode;
41+
if (type === "title") {
42+
const el = document.createElement(type);
43+
if (util.isFilledString(children)) {
44+
el.innerText = children;
45+
} else if (util.isFilledArray(children)) {
46+
el.innerText = children.join("");
47+
}
48+
document.head.appendChild(el);
49+
insertedEls.push(el);
50+
}
51+
});
52+
}
53+
onBeforeUnmount(() => {
54+
insertedEls.forEach((el) => document.head.removeChild(el));
55+
});
56+
},
57+
render() {
58+
return [];
59+
},
60+
});

framework/vue/mod.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
export { App, createApp, createSSRApp } from "./router.ts";
22
export { Link } from "./link.ts";
3+
export { Head } from "./head.ts";

framework/vue/router.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { Component, createApp, createSSRApp } from "vue";
1+
import { Component, createApp, createSSRApp, defineComponent, resolveComponent } from "vue";
22
import type { SSRContext } from "../../server/renderer.ts";
3-
import { RouterContext } from "./context.ts";
4-
import { defineComponent } from "vue";
3+
import { DataContext, RouterContext } from "./context.ts";
54
import { RouteModule } from "../core/route.ts";
5+
import { Link } from "./link.ts";
6+
import { Head } from "./head.ts";
67

78
// deno-lint-ignore no-explicit-any
89
const global = window as any;
@@ -16,7 +17,10 @@ export const App = defineComponent({
1617
},
1718
},
1819
setup() {
19-
console.log("App");
20+
console.log("App setup");
21+
},
22+
mounted() {
23+
console.log("App mounted");
2024
},
2125
render() {
2226
return this.$slots.default ? this.$slots.default() : [];
@@ -31,19 +35,34 @@ const createSSRApp_ = (app: Component, props?: RootProps) => {
3135
const { ssrContext } = props || {};
3236
const routeModules = ssrContext?.routeModules || loadSSRModulesFromTag();
3337

34-
if (ssrContext?.url) {
35-
RouterContext.value.url = ssrContext?.url;
36-
}
38+
let routeComponent = undefined;
3739

3840
if (routeModules && routeModules.length > 0) {
3941
const defaultRouteModules = routeModules[0];
4042
const { defaultExport } = defaultRouteModules;
41-
if (defaultExport) {
42-
return createSSRApp(defaultExport as Component);
43+
if (defaultExport) routeComponent = defaultExport as Component;
44+
}
45+
46+
const ssrApp = createSSRApp(routeComponent || app);
47+
48+
if (ssrContext?.url) {
49+
RouterContext.value.url = ssrContext?.url;
50+
}
51+
52+
const ssrHeadCollection = DataContext?.value?.ssrHeadCollection;
53+
if (ssrHeadCollection && ssrHeadCollection.length > 0) {
54+
if (ssrContext?.headCollection) {
55+
ssrHeadCollection.forEach((item) => {
56+
ssrContext.headCollection.push(item);
57+
});
4358
}
4459
}
4560

46-
return createSSRApp(app);
61+
// registe aleph/vue component
62+
ssrApp.component("Link", Link);
63+
ssrApp.component("Head", Head);
64+
65+
return ssrApp;
4766
};
4867

4968
function getRouteModules(): Record<string, { defaultExport?: unknown; withData?: boolean }> {

0 commit comments

Comments
 (0)