Skip to content
This repository has been archived by the owner on Jun 29, 2021. It is now read-only.

SSR Status #420

Open
Saeeed-B opened this issue Dec 23, 2020 · 24 comments
Open

SSR Status #420

Saeeed-B opened this issue Dec 23, 2020 · 24 comments
Labels
in-discussion We are still discussing how to solve or implement it

Comments

@Saeeed-B
Copy link

Hello everyone, do not be tired.

Due to that, the server rendering package is incomplete.
1. Cannot subscribe to data
2. Cannot render based on user login status

Also, the packages included in this to solve these problems are incomplete:
1. They are no longer supported.
2. And they can not be used with the current situation, that is, they have many bugs.

I ask this question on behalf of many people, does meteor have a plan to solve this problem?
Does it intend to solve this problem from within and not pass users to incomplete packages?

I think after all these requests, we have the right to receive a clear answer.

@eugle
Copy link

eugle commented Dec 24, 2020

For the code splinter and SSR of Meteor, an official solution is expected

@filipenevola filipenevola changed the title SSR status in release 2 SSR Status Jan 17, 2021
@filipenevola filipenevola transferred this issue from meteor/meteor Jan 17, 2021
@filipenevola
Copy link
Collaborator

Hi @Saeeed-B what specific issues are you having with Meteor and SSR? I mean, issues, bugs, problems.

For example, I just search on Google and I found this repo https://github.com/juliancwirko/scotty and I just updated bcrypt and it's working for me.

I know it's not updated but if it was working on METEOR@1.6.1.1 I believe it is still working in Meteor 1.12.1.

What I think you are saying as "not working" actually you mean that we don't have up-to-date examples and education resources. Is that what you mean?

I know of some members in the community interested and probably using Meteor with SSR like Kevin Newman and The Spider.

We even have this item in our Roadmap https://github.com/meteor/meteor/blob/devel/Roadmap.md#ssr-documentation specifically for SSR documentation (@CaptainN @eric-burel) but it didn't move forward as we were expecting then we need to restart this work.

Let's list here what are the items that we need to work on and then we can move forward.

@filipenevola filipenevola added the in-discussion We are still discussing how to solve or implement it label Jan 17, 2021
@Saeeed-B
Copy link
Author

Saeeed-B commented Jan 17, 2021

@filipenevola Hi
We need to look more at meteor flaws in the rendering server.

1. Do not support data subscription
Unfortunately, the metoer internal rendering server package does not support subscriptions.Because the subscription method only runs on the client.
But this prevents data (which are the most important components) from being rendered on the server. And we have to render the data only on the client.
As a result, Google does not see the data and SEO is practically destroyed.
This issue has been raised several times but you have referred us to packages like Fast Render and Prerender.And this reference to the outside of the meteor is not appropriate at all.
I have said many times about fast rendering that it has many problems that make it practically impossible to use and its manufacturer does not support the package.

Server-side rendering should be flawless and transparent, with data support embedded in the meteor core.
This is the most important issue that if solved, can be solved with other rendering server problems.
Please pay special attention to this issue.

@CaptainN I think you have made a lot of efforts in this regard, thank you, explain the issue in detail

@dr-dimitru
Copy link

Until this one is resolved I'd be happy to help with SEO using pre-rendering service.
To be honest from my experience working with many JS based frameworks SSR won't ever satisfy your SEO goals for 100%. Implementing and maintaining SSR is continuous time consuming process and can get expensive with maintenance cost.
That's why we build and using this service.

P.S. yes, I'm affiliated with posted link.

@Saeeed-B
Copy link
Author

Saeeed-B commented Jan 17, 2021

@dr-dimitru I also use prerender now, but I believe the software should be integrated and have few external dependencies.
This is the purpose and basis of our companies.
A meteor is a powerful platform if it uses this at its core.
Solving this problem in the meteor core makes the software more flexible and provides more access.
On the other hand, the costs are lower.
To be honest, Prerender could be a competitor to the meteor core rendering server.
But it should not be the only option for good seo.
On the other hand, the issue of correct and complete rendering server is not only for SEO.
More important than SEO is the user experience that depends on the data rendering server.

@dr-dimitru
Copy link

@Saeeed-B no worries, and thank you for sharing your vision.

I won't jump in this thread unless you mentioned SEO.

True, for other purposes proper SSR can get handy.

I tired and comprehensively tested SSR in all major JS frameworks with purpose of SEO, unless it's based on rendering JS-pages to HTML, it won't serve SEO needs.

@Gorbus
Copy link

Gorbus commented Jan 19, 2021

For information we worked out with another member from the meteor forums a SSR boilerplate with Meteor/React/Apollo/React-Helmet-Async/React-Router/Styled-Component, all the latest libraries:

https://github.com/Gorbus/meteor-react-apollo-ssr

@nathanschwarz
Copy link

@Saeeed-B supporting subscriptions with ssr on the server would actually be simple.
On the client it should subscribe to the data, but on the server it should directly get the cursor :

// on the server

export function getMyData(whatever) {
 // do something
}

Meteor.publish('whatever', getMyData)

// on the client

if (meteor.isSever) {
   import { getMyData } from 'whatever'

   // either this, or setup a REST endpoint to collect the data
   data = getMyData()
} else {
  Meteor.subscribe('whatever', 'whatever')
}

Implementing a quick fix like this on the core to support ssr for pub/sub should be done quite easily.

@Saeeed-B
Copy link
Author

Saeeed-B commented Jan 22, 2021

@nathanschwarz
This is certainly not a concise and efficient solution.
And it increases costs and increases codes.
Especially the codes in the handle of the received data are increased.

Finally, this offer must be tested in the subscription method itself.
In other words, the subscription method should itself detect whether it is running on a server or a client
And then prepare the desired data on it.

@nathanschwarz
Copy link

nathanschwarz commented Jan 22, 2021

This is certainly not a concise and efficient solution

@Saeeed-B If you want SSR you have no other choice, basically all the data on the first load is passed to the client as a string... So you must have all the data in hand before sending the response to the client (so you can't send a cursor).

Finally, this offer must be tested in the subscription method itself

that's just what I said...

Implementing a quick fix like this on the core for pub/sub should be done quite easily.

meaning, modifying the publication/subscription methods...

@Saeeed-B
Copy link
Author

@Saeeed-B supporting subscriptions with ssr on the server would actually be simple.
On the client it should subscribe to the data, but on the server it should directly get the cursor :

// on the server

export function getMyData(whatever) {
 // do something
}

Meteor.publish('whatever', getMyData)

// on the client

if (meteor.isSever) {
   import { getMyData } from 'whatever'

   // either this, or setup a REST endpoint to collect the data
   data = getMyData()
} else {
  Meteor.subscribe('whatever', 'whatever')
}

Implementing a quick fix like this on the core to support ssr for pub/sub should be done quite easily.

@filipenevola
Is it possible to address this proposal?

@eugle
Copy link

eugle commented Jan 28, 2021

有关信息,我们与流星论坛的另一位成员一起设计了一个SSR样板,其中包含流星/反应/阿波罗/反应头盔-异步/反应路由器/样式化组件,以及所有最新库:

https://github.com/Gorbus/meteor-react-apollo-ssr

Need an example of code splitting, in your near-perfect project go

@nathanschwarz
Copy link

So, I've been thinking on how exactly the implementation should go, and I think we should go for an Apollo SSR like mechanism.

So if subscribe is called on the server we should :

  • get the cursor passed down by publish, call fetch on the cursor.
  • the data will be then saved in an object which will be stringifyed and sent to the client.

On the client :

  • when hydrating the client, the object should be parsed and passed to minimongo.
  • the handle should be created then, and minimongo should associate the received data with each stream accordingly.

Maybe implementing a sort of serializeable minimongo instance on the server which will be sent in the <head> automatically ?

@pjsofts
Copy link

pjsofts commented Feb 13, 2021

@Saeeed-B you can easily add a Meteor.subscribe on the server, and wrap Meteor.publish on the server to do what you exactly want.
I myself use Next.js for my landing page and after CTA or Login switch to Meteor. Basically use two different projects.
I would be happy if Meteor's community made Meteor as powerful and as well-documented as Next.js.

@Saeeed-B
Copy link
Author

@pjsofts
Maybe I did not understand exactly what you mean.
But I know the subscription on the server does not work at all.
And that is exactly the problem.
On the other hand, it is very difficult and tedious to check every root in the server and get its data.
We may have to write as much code on the server side as the entire client code!

@Saeeed-B
Copy link
Author

@filipenevola One of the most important reasons for ssr is that it greatly reduces the initial response time of the server.
And this answer of the server must be accompanied by data.

@renanccastro
Copy link

Hello, @Saeeed-B.
I think I have sent this to you in another thread, but maybe you didn't have the chance to look at it.
This library I did: https://github.com/pathable/meteor-fast-methods Is solving exactly what you are asking for.

In the server, you call:

preloadData(sink => {
  return [Images.find({ communityId: community._id })];
});

This will preload your minimongo on each page load with the array of cursors you return there. Also, this.userId and Meteor.user() are available inside this function.
If you need to check if the data is available, you can call the following reactive dependency on the client: FastMethods.ready() and render your app after that, or inside a tracker.

Minimongo is automatically filled. Let me know if this does work for you and for others. A complete SSR solution, as proposed by @nathanschwarz would be really good, but I think this can do for now. It's also possible to return data based on routes. At least, it solved for us ;)

@Saeeed-B
Copy link
Author

Saeeed-B commented Feb 18, 2021

@renanccastro
Hi, I have not implemented your package yet and the reason is that this package does not provide data based on routes. And I think that will make things difficult.
The difficulty is that we have to manually check the data of each root and submit it. And this becomes more difficult when there are too many variables to present the data.
This means that we have to manually check all the possibilities so that we can provide the correct data!

If your package can provide data based on subscriptions, then it will good work

@Saeeed-B
Copy link
Author

In general, the package that wants to provide data on the server side must be fully compatible with the Meteor kernel, including the publishing and subscription system.

@renanccastro
Copy link

It's another approach. If you are using a SPA, you can't have server-side routing, unless you are doing a full SSR with react or something alike. In this case, It's also possible to use my package to get the right data, as you do have access to the current route being accessed, and then it's only a matter of returning the right cursors.
I know it's not a top-of-notch integration, but it solves some of the major cases.
And yet, I do think that the integration with the pub/sub system is not hard to be achieved, and can be indeed done in a package. I have already done that to make a system to use Methods using pub/sub api.

@eric-burel
Copy link

eric-burel commented Feb 18, 2021

Hi, lately I've been focused more on static + SSR rendering for authenticated apps, so I am not sure I can be of any help with Meteor specifics (I use graphql as my data layer), but I'll try to give a few insights.

Rendering subscriptions during SSR feels problematic to me, because subscriptions are per design a client-side feature. If you really need to have some data rendered during SSR, maybe "duplicate" your subscription logic: write a method that fetches a first set of data, without subscription, and then rely on subscription client side.

More broadly, I am not eager to automatically render data during SSR. Nowadays, the trend is instead to prefill caches, send the cache, and let the client actually render the data. Loading all data at once is often more costly (and thus damaging for SEO) than loading client-side. During SSR, you can instead focus on rendering page skeleton and actual static content + prefilling caches.
For Meteor, this would mean fetching data server-side, and give them to minimongo in the cache (btw isn't Meteor doing this already)?

Very theoretical, sorry in advance if it's not actionnable for your use cases

@Saeeed-B
Copy link
Author

@nathanschwarz We really need to do a strong test, thank you very much if you can let us know the result.

@Saeeed-B
Copy link
Author

I have said this elsewhere, perhaps it is worth further investigation.
I used npdev-react-loadable for code spliting and implemented it in ssr as well.
And I only handled the subscriptions on the client and told them not to run if they were on the server.

This is how my subscriptions work:

const handle = (Meteor.isClient) ? Meteor.subscribe('Pages.Articles') : { ready: () => true };

Client StartUp :

import React from 'react';
import {BrowserRouter as Router} from "react-router-dom";
import {HelmetProvider} from 'react-helmet-async';
import Routes from "../../Routes/Routes";
import ReactDOM from 'react-dom';
import { preloadLoadables } from 'meteor/npdev:react-loadable'

preloadLoadables().then(() => {
    const helmetContext = {}
    ReactDOM.hydrate(
        <HelmetProvider context={helmetContext}>
            <Router>
                <ScrollToTop />
                <Routes/>
            </Router>
        </HelmetProvider>
        , document.getElementById('App'));
});

Server StartUp :


    import React from "react";
	import { StaticRouter as Router } from "react-router-dom"
	import { onPageLoad } from "meteor/server-render";
    import { renderToString } from "react-dom/server"
    import { HelmetProvider } from 'react-helmet-async'
    import { LoadableCaptureProvider, preloadAllLoadables } from 'meteor/npdev:react-loadable'
	import Routes from "../../Routes/Routes";
	preloadAllLoadables().then(() => onPageLoad(sink => {
		const context = {};
		const loadableHandle = {};
		const helmetContext = {};

		const html = renderToString(
			<LoadableCaptureProvider handle={loadableHandle}>
				<HelmetProvider context={helmetContext}>
					<Router location={sink.request.url} context={context}>
						<Routes />
					</Router>
				</HelmetProvider>
			</LoadableCaptureProvider>
		);

		const { helmet } = helmetContext;
		sink.appendToHead(helmet.meta.toString());
		sink.appendToHead(helmet.link.toString());
		sink.appendToHead(helmet.title.toString());

		sink.renderIntoElementById('App', html)
	}))

But the result is amazing, so I see that all the data is also rendered on the server and rendered in the view page source. However, the case should have been the opposite and all components were rendered without data

I have no explanation for exactly what is happening.

@CaptainN If you have an explanation thank you, join us, maybe this is the perfect ssr solution

@Saeeed-B
Copy link
Author

Saeeed-B commented Feb 18, 2021

I have said this elsewhere, perhaps it is worth further investigation.
I used npdev-react-loadable for code spliting and implemented it in ssr as well.
And I only handled the subscriptions on the client and told them not to run if they were on the server.

This is how my subscriptions work:

const handle = (Meteor.isClient) ? Meteor.subscribe('Pages.Articles') : { ready: () => true };

Client StartUp :

import React from 'react';
import {BrowserRouter as Router} from "react-router-dom";

@nathanschwarz @CaptainN Have you seen my experience too?

Right now it is working well at the following address, that is, with the combination I mentioned above, the data is also rendered on the server :

https://ghadr.org/

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
in-discussion We are still discussing how to solve or implement it
Projects
None yet
Development

No branches or pull requests

9 participants