Skip to content

Commit 1423cbf

Browse files
authored
docs: update extensions section in PLAN.md
Signed-off-by: windstone <[email protected]>
1 parent 587f866 commit 1423cbf

File tree

1 file changed

+61
-4
lines changed

1 file changed

+61
-4
lines changed

docs/PLAN.md

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ Make a page that fetches extensions from some remote repository
1818

1919
That repository must include only moderated extensions. Moderation process should require extension's source code and, if differs from usual, a build manual. Every extension update must go through the moderation process. This is the only way to make custom extensions secure, I guess
2020

21-
Those extensions should be loaded once at application launch. Programming language must be a JavaScript. Any framework is ok, as long as it is capable running in a browser. Extensions need to be able to communicate with launcher
21+
Those extensions should be loaded once at application launch. Programming language must be a JavaScript. Any framework is ok, as long as it is capable running in a browser. Extensions will be able to communicate with the launcher
2222

2323
### More
2424

25+
**Previous implementation details**
26+
2527
Any JS code can be dynamically fetched in runtime from somewhere and executed with the `new Function` constructor. Example (I implemented it in [one of my projects](https://github.com/notwindstone/tsuki)):
2628

2729
```ts
@@ -44,11 +46,66 @@ Unfortunately, if VSCode, Obsidian, Vencord and other apps can't implement a sec
4446

4547
Btw, Figma chose security over functionality with their `iframe` approach
4648

47-
// 19.09.2025 update
49+
**Latest implementation details (19.09.2025)**
50+
51+
Microfrontends supremacy >.<
52+
53+
Using a Module Federation Runtime we can load any Vue component just like an ordinary component in the node tree. To make it possible for plugins to render components anywhere, a `<Teleport />` could be used. Module Federation Runtime also allows us to share dependencies, so the final extension budle size should be low.
54+
55+
For other JS frameworks, we can run them using the previous implementation: `new Function`.
4856

49-
consider using runtime microfrontends. mounting components can be achieved using portals (react)/teleports (vue)
57+
Launcher should expose everything that it can through the `window.__KAEDE__`. Previously, communication was done using the `window.postMessage` function, but now I came up with the idea of exposing an array of functions for almost every action in app. That array can be changed by extensions, and then the launcher will execute every function listed in that array.
58+
59+
For example, see the next code:
60+
61+
```ts
62+
/** Launcher */
63+
window.postMessage("kaede-route-changed", /* some data */)
64+
65+
/** Extension */
66+
const handleRouteChange = (pathname: string) => {
67+
if (pathname === "/home") {
68+
// do something
69+
}
70+
};
71+
const handleKaedeMessages = (event: { data: string ) => {
72+
if (event.data === "tsuki_updated_window") {
73+
handleRouteChange(/* some data from the 'event', or maybe pass down the 'window.__KAEDE__.dynamic.currentRoute' variable */);
74+
75+
return;
76+
}
77+
78+
// other code
79+
};
80+
81+
window.addEventListener("message", handleKaedeMessages);
82+
```
83+
84+
While it works, it doesn't look good to me. Adding a lot of window listeners can affect a launcher performance. If user has 20 extensions, that `handleKaedeMessages` function will fire on every new event in every extension, even if the event wasn't needed.
85+
86+
Now I'm suggesting the next structure:
87+
88+
```ts
89+
/** Launcher */
90+
window.__KAEDE__.hooks.onRouteChange.before = [];
91+
92+
/** Extension */
93+
const currentRoute = ref<RouteType>("home");
94+
95+
window.__KAEDE__.hooks.onRouteChange.before.push(({ pathname }: { pathname: RouteType }) => {
96+
currentRoute.value = pathname;
97+
});
98+
99+
/** Launcher */
100+
// example with the '@kitbag/router'
101+
onBeforeRouteChange(() => {
102+
for (const hook of window.__KAEDE__.hooks.onRouteChange.before) {
103+
hook({ pathname });
104+
}
105+
});
106+
```
50107
51-
plugin manifest should also contain a `customLoader: string | undefined` field
108+
Extensions are not needed to listen for window events anymore. Only specified actions will be triggered. Must be a perfect solution? Maybe. I'm not sure that this will work, because, well, launcher doesn't have the same scope as that extension code block where `window.__KAEDE__` was reassigned (?)
52109
53110
</details>
54111

0 commit comments

Comments
 (0)