Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Server Rendering #103

Closed
jolyndenning opened this issue Aug 2, 2017 · 22 comments
Closed

RFC: Server Rendering #103

jolyndenning opened this issue Aug 2, 2017 · 22 comments

Comments

@jolyndenning
Copy link
Member

Some single-spa applications may want to server render some or all of the child applications that are active for a url. How to pull that off is not decided, but here's what I'm thinking for it so far:

const location = {href: '/url#/hash', hash: '#/hash'};
// New API for single-spa returns an array of string names.
const activeAppNames = singleSpa.findActiveApplications(location);

// The serverRender API will load the app but will probably not bootstrap it and will definitely not mount it. Instead it will check
// for a new lifecycle method (serverRender?) on the application. If the lifecycleMethod exists, it calls it. If not, it returns an empty string
Promise
  .all(activeAppNames.map(singleSpa.serverRender))
  .then(serverRenderedHtmls => {
    const finalHtml = serverRenderedHtmls.join("");
    res.write(finalHtml);
  })

Advantages of doing it that way:

  • The user of single-spa can control which applications to server render
  • findActiveApplications might have other use cases besides server rendering

Disadvantages:

  • You have to load the child application before you even know whether it supports server rendering or not. I'm not sure how this would be solved in any other way, though, besides perhaps including some configuration during declareChildApplication.
@rainboxx
Copy link

The user of single-spa can control which applications to server render

I think this one is very importing for people that are doing migrations from older frameworks, eg. AngularJS 1.x.

perhaps including some configuration during declareChildApplication.

I thought about this while reading the intro of that paragraph. One could set serverSideRendering: false and bypass the check at all, while for all others the app will be loaded and still checked for the respective method to render to a string.

Was there already some progress beside this ticket?

@jolyndenning
Copy link
Member Author

@rainboxx apologies for the (very) late response on this.

I have not begun writing code for this. Would you be interested in collaborating on this?

@rainboxx
Copy link

rainboxx commented Jan 9, 2018

Hey @joeldenning, interested definitely. I might be able to also get time from my client to work on this, since we're planning to integrate this framework. How would you start? What would be a timeline?

@jolyndenning
Copy link
Member Author

jolyndenning commented Jan 10, 2018

To start out, maybe let's find a time to chat about it? Maybe on single-spa's slack we could go over the suggestions and questions above and figure out exactly what API we want single-spa to implement? I am not an expert in server rendering and welcome all feedback and suggestions.

I am online during U.S. business hours and also during nighttimes. You're in germany? Maybe if the timezones don't line up we could continue discussing asynchronously here in this issue, but I think hashing things out all at once might be more productive.

Your thoughts?

@rainboxx
Copy link

rainboxx commented Jul 2, 2018

Hey @joeldenning, sorry for not responding so long. The single spa framework approach had a low priority in the project I was working on. I left this project as of last month so finding time got even more worse :-(.

@jolyndenning
Copy link
Member Author

Ah sorry to hear that. If you or anybody else would like to reopen the conversation about single-spa server rendering, please do! I'm closing this comment for now, but would love to explore this.

@jolyndenning
Copy link
Member Author

Reopening this - core team talked about this and thinks it would be valuable. Here are the steps I can think of:

  1. get single-spa and SystemJS running in node
  2. Figure out how to get activity functions to run properly in node and allow server code to provide url
  3. Figure out the domElementGetter stuff in node
  4. Defer to framework for server rendering
  5. Compose a single html file with everything
  6. Ensure hydration works

@StyleT
Copy link

StyleT commented Feb 28, 2020

Hi! We're actively working on our own implementation of the SSR support here https://github.com/namecheap/ilc
It uses "single-spa" & TailorX to achieve the desired behaviour.

PM me if you guys are interested.

@jolyndenning
Copy link
Member Author

@StyleT I'd love to hear the direction you're going with server rendering and TailorX. I mentioned you in a slack conversation in the #maintainers channel - let's discuss there!

https://single-spa.slack.com/archives/C9JV40F7V/p1582917635011100

@jolyndenning
Copy link
Member Author

After some discussion with namecheap and also with @ScriptedAlchemy, we are going to go a different direction with this. We think that we will encourage the following:

  1. Each microfrontend runs its own nodejs server. They do not share a server.
  2. single-spa's checkActivityFunctions() api will work in nodejs (see Support for running single-spa in nodejs. #494)
  3. The fetching of html and other data from microfrontends is still TBD

@ScriptedAlchemy
Copy link

I can provide an example of the render middleware if that helps

@jolyndenning
Copy link
Member Author

👍 please do

@ScriptedAlchemy
Copy link

Primitive example of SSR via module federation. https://github.com/module-federation/module-federation-examples/tree/master/server-side-rendering

webpack-dev-middleware has some bugs in HMR. If you need it, I wrote something that serves as a replacement for hmr on the client-side until webpack-dev-server is more stable. Currently using it in my upgraded next.js repo to power their HMR. In this example repo, I've done the bare minimum and only run it in production mode. But I do have this dev functionality working on Next, so I know its a matter of cleaning up the development.js middleware file.

@jolyndenning
Copy link
Member Author

Thanks for sharing that example.

I am doing a proof of concept at https://github.com/isomorphic-microfrontends - will share progress as I go along.

@jolyndenning
Copy link
Member Author

I'm shifting to a layout engine for now (#525) and will come back to server rendering after that. SSR might use the layout engine, so I think that this might be the proper order to do it in

@jolyndenning jolyndenning changed the title Figure out server rendering RFC: Server Rendering Apr 27, 2020
@ScriptedAlchemy
Copy link

Got SSR working over distributed networks. So I'm able to require() from s3 on-demand - treating it like the native file system, also could work with fetch() as well.

The layout engine is a good way to go if you cannot avoid the need for a controller somewhere at the head of the app. Since this is a non-webpack solution, it might be the optimal solution

@filoxo filoxo mentioned this issue Jun 24, 2020
@mbohgard
Copy link

@joeldenning What have you learned or tried since you last visited this subject? We're worried about the SEO of our planned huge project with multiple SPAs tied together with i.e. single-spa.

@jolyndenning
Copy link
Member Author

Hi @mbohgard - I've made a lot of progress, actually. Check out single-spa/single-spa.js.org#333, which has some documentation and a link to an example.

@mbohgard
Copy link

@joeldenning That's awesome. I'll dig in to that. Thank you!

@jolyndenning
Copy link
Member Author

The documentation for server-side rendering is now live at https://single-spa.js.org/docs/ssr-overview

@ScriptedAlchemy
Copy link

Well done!

@arumugamnambiraj
Copy link

Hi Joel,

We referred your git code, As we are in need of creating the same concept using Angular. we have implemented SEO friendly in micro-frontend using Angular-universal. So can you help us how to succeed rendering the multiple apps running in different port to be rendered in single port and in same location.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants