vikejs / vike

🔨 Flexible, lean, community-driven, dependable, fast Vite-based frontend framework.
https://vike.dev
MIT License
4.09k stars 345 forks source link

Clash between multiple instances in one page #254

Closed wheerd closed 2 years ago

wheerd commented 2 years ago

I'm currently trying to build a microfrontend architecture with vite-plugin-ssr. I have a frontend that renders a fragment of a page. When I have multiple of those fragments in the page, I run into issues because each of them serialises the page context into a script with the same id vite-plugin-ssr_pageContext. Do you think it would make sense to make that id configurable or generate a unique id automatically? I could try to provide a PR for that if you are willing to take it.

brillout commented 2 years ago

Can you elaborate your microfrontend architecture?

My first impression is that what you trying to achieve is out of vite-plugin-ssr's scope.

wheerd commented 2 years ago

There are multiple frontends running in separate services, each built with vite-plugin-ssr. Their content gets combined via Nginx SSI into a single page which looks something like this (/header/ and /footer/ here are served by different frontends):

<!DOCTYPE html>
<html>
    <head>
        <script src="https://unpkg.com/vue@next"></script>
        <!--#include virtual="/header/?__HEAD__" -->
        <!--#include virtual="/footer/?__HEAD__" -->
    </head>
    <body>
        <!--#include virtual="/header/?__BODY__" -->
        <div id="app">Some content here</div>
        <!--#include virtual="/footer/?__BODY__" -->
    </body>
</html>

Each of those includes brings it's own page context. So this leads to the problem, that loading the correct route does not work, because the wrong context is loaded.

brillout commented 2 years ago

So yea I'd say it's out of scope for this plugin.

Honestly, I don't see the benefits of your approach. In my experience, a clear seperation of concerns in source code leads to better scalability results.

I'd seperate by concern not by tool. But I'm happy to be shown wrong and I may then reconsider supporting your use case.

j0weiss commented 2 years ago

Hi,

I'm interested in the same use case and I'd like to explain a bit more to see if we find common ground so that this plugin could support this usecase.

Let's consider an eCommerce application with multiple vertical teams, each with a specific domain focus. For simplicity we pick only two teams: one team is responsible for the header and footer and another team is responsible for the product detail page.

The second team wants to integrate the header/footer into their page via server-side-includes (SSI), similar to the code snippet above https://github.com/brillout/vite-plugin-ssr/issues/254#issuecomment-1028940717.

To achieve this, the header/footer team provides three endpoints:

  1. the head endpoint, to include styles, preload-tags, ...
  2. the content endpoint, which returns the server side rendered header/footer HTML markup
  3. the scripts endpoint, to provide the necessary JavaScript assets (could be a SPA) which add functionality to the header/footer.

I would say, this plugin is doing exactly the same thing while rendering the HTML markup on the server-side, except its responsible for the page as a whole. Whereas in my example the header/footer team doesn't know where their frontends will be included, but the teams would have agreed on those three endpoints and can achieve almost the same behaviour in a "page-assembly-server" (like NGNIX with SSIs). The product detail page team could use this plugin as is and render the code snippet from above in the render() function of the product.page.server.ts and the SSIs (head, content, scripts) of the resulting HTML markup would then be resolved in the NGINX.

This setup could be possible with this plugin, if it would expose the three main rendering parts head, content and scripts (including the pageContext of every app as @wheerd also mentioned). I actually got it working in a proof of concept with some workarounds like e.g. duplicating the inferAssetTag logic in the head endpoint with calling _getPageAssets beforehand (as it is described here). I also stumbled on the pageContext because I would need to extract the JSON from the serialized script tag and merge the pageContext from every app into one JSON. But since all of that is not using the official API it is of course error prone.

If this explanation helps demonstrating an use case, maybe we can pick up the discussion again to support this.

And thanks for your awesome work on this plugin. I really enjoy using it.

brillout commented 2 years ago

@j0weiss

To be sure we are on the same page: the goal is to split a large number of developers into several small teams in such a way that each team can focus & develop topics independently of each other, correct?

I'm still doubtful this is the right approach but I'm happy to be shown wrong.

I do care about team scalability and that's something I have in mind while designing my work.

One thing I'm particularly excited about is enabling folks to build frameworks on top of vps ("Vike Frameworks"). That's something vps 0.4 (see branch) is going to support in a first-class manner.

The idea here is that the complex part of an app is 1. choosing the right technology and 2. integrating all tools together. In other words: writing React/Vue components is usually the easy part.

The renderer/ of a vps app is the hard part and the idea is to have all complex integrations happening in the renderer/ folder. The less-senior developers then hack on the files living in pages/.

This is a powerful separation of concerns: ideally renderer/ and pages/ can be developed independently of each other which I believe is possible especially with tools like Telefunc.

j0weiss commented 2 years ago

Thanks for the zwift response.

Yes, I think we are one the same page. I am talking about domain focused teams (e.g. product detail page) which are responsible for their domain, which on the tech side includes the full tech stack from frontend, backend, db layer, operations in contrast to tech teams which would be responsible for the frontend layer or the backend layer and so on.

Concerning the frontend, this results in a micro-frontend-architecture with the challenge to integrate frontend parts of several teams in one page.

I was poking around in the 0.4 branch earlier, and I'm curious how it plays out. When you say it will support the ability to build a framework on top of this plugin, do you think this use case could be achieved then?

I agree that in a larger project the actual components aren't the complex part of the application. So, if it is possible to have the ability in the renderer/ of the app to get access to the necessary vps functionalities like link and script tag rendering based on the manifest or the pageContext serialization I think it would be sufficient to create a layer which would suit the approach I have in mind.

Telefunc looks interesting and I'll have a deeper look into it, but from what I saw it is more concerned with the way we communicate with the backend, rather than integrating black box HTML snippets I cannot control, correct?

brillout commented 2 years ago

I am talking about domain focused teams (e.g. product detail page) which are responsible for their domain, which on the tech side includes the full tech stack from frontend, backend, db layer, operations in contrast to tech teams which would be responsible for the frontend layer or the backend layer and so on.

Makes sense.

Concerning the frontend, this results in a micro-frontend-architecture with the challenge to integrate frontend parts of several teams in one page.

I'm not sure about that.

In theory, you could have your entire app in a single big repo which is seamlessly deployed. I don't see why that would hurt team scalability, as each team only changes certain parts of the big repo. I'm not saying this is the right approach, I'm just saying that I don't see the benefit of a microfrontend architecture for team scalability.

j0weiss commented 2 years ago

I think both ways can work and it depends on further factors which to choose, e.g. on the general team setup. I definitely see pros and cons in both setups. I like for example the idea of one frontend application, since mirco-frontends introduce technical complexity. But at the same time I see organizational challenges by working in one large repository with many people (I'm thinking of 20 - 100 persons).

My question would be if you could see this plugin support both ways? Or if you see a way to set up a custom framework for this use case with the changes in v0.4.x coming regarding your comment:

One thing I'm particularly excited about is enabling folks to build frameworks on top of vps ("Vike Frameworks"). That's something vps 0.4 (see branch) is going to support in a first-class manner.

If we could support our usecase by building upon those upcoming changes, this would be perfectly fine for me as well.

I still think that it would not be a very incisive change (in regard to the current version v0.3.x) since the plugin does the splitting into the three to four parts (head, content, scripts and pageContext) anyways.

brillout commented 2 years ago

I'm not sure I understand your approach, a concrete example how you approach would work and its benefits would prob help :-).

j0weiss commented 2 years ago

I'll try to provide an example as soon as possible. Thanks for opening the new issue #336.