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

Caching #36

Closed
benoneal opened this issue Mar 5, 2017 · 5 comments
Closed

Caching #36

benoneal opened this issue Mar 5, 2017 · 5 comments

Comments

@benoneal
Copy link

benoneal commented Mar 5, 2017

I have an application where it makes sense to cache the entire rendered html, because there is no user authentication and data changes infrequently. I'd like to implement a simple caching strategy, where rendered output is saved to memcached/redis, and every request both serves any cached page, then renders and caches a new version for the next visitor.

Serving up a blank page is unacceptable for my application, and waiting 100ms+ for render-on-demand is similarly bad.

Is there a way you could expose hooks at both ends of the process? The pre-hook would need to be passed res and location, and the post-hook would need to be passed the location and htmlstring.

Alternatively (or additionally), if you integrate something like Rapscallion, that would also solve my issues, and seems like a robust solution that would address all the concerns you raised in your caching write-up.

@catamphetamine
Copy link
Owner

I have abandoned server side rendering for my project for the time being (until someone else fixes it).
So one could say I took the Facebook approach.
As I'm in no need for it right now it's not a priority for me to get something like that working.

In case you find yourself needing Server Side Rendering optimization features you can fork the repo and experiment on it.
There's currently no ready-made caching solution as of the time of writing.

@vsaportas
Copy link

Hey @halt-hammerzeit, can you explain a bit more why you abandoned server side rendering? Was it for performance / caching reasons, complexity reasons, not needed by google anymore, etc?

@catamphetamine
Copy link
Owner

@vsaportas AFAIK google can parse javascript-rendered pages if the data is preloaded
http://andrewhfarmer.com/react-seo/
I dropped SSR for now because of the complexity and because I'm not using this framework on some high-load production website - it's just for my small project.

@benoneal
Copy link
Author

benoneal commented Mar 5, 2017

For me, SEO is the least of my concerns. SSR (and caching) are critical because I have a project with many large images above the fold. The standard method of linking to static assets causes the page to appear broken and jump all over the place as images are loaded in. Embedding 'above the fold' images as data URIs solves this, but causes a long delay of looking at nothing while the script loads.

So I want to cache the rendered html, so that visitors can see content faster, and the moment they see it, it is already complete and doesn't jump all over the place while content loads in. For me, SSR is about the experience a user has while navigating to the site, and caching is about performance. SEO is a very distant concern.

@catamphetamine
Copy link
Owner

catamphetamine commented Mar 6, 2017

The standard method of linking to static assets causes the page to appear broken and jump all over the place as images are loaded in.

why aren't you setting height and width then

Embedding 'above the fold' images as data URIs solves this, but causes a long delay of looking at nothing while the script loads.

only small images are applicable to data uri to to max length constraint

So I want to cache the rendered html, so that visitors can see content faster, and the moment they see it, it is already complete and doesn't jump all over the place while content loads in.

Well, you could hook up somewhere in the web service wrapping the render() call and examining the response.body and response.status:
https://github.com/halt-hammerzeit/react-isomorphic-render/blob/master/source/page-server/web%20server.js

Then response.body could go into some kind of a memory cache and when a new request with the same url comes then return the statics.
Like this:

	// Isomorphic rendering (Koa middleware)
	web.use(async (ctx) =>
	{
		// Trims a question mark in the end (just in case)
		const url = ctx.request.originalUrl.replace(/\?$/, '')

		const total_timer = timer()

		const cached = await cache.get(url)

		if (cached)
		{
			ctx.body = cached.content

			if (cached.status)
			{
				ctx.status = cached.status
			}
		}

		// Not simply awaiting for the promise here to prevent Koa waiting for the render
		const promise = render_page(settings,
		{
			application,
			assets,
			initialize,
			localize: localize ? parameters => localize(parameters, get_preferred_locales(ctx)) : undefined,
			render,
			loading,
			html,
			authentication,

			// The original HTTP request can be required
			// for inspecting cookies in `preload` function
			request: ctx.req,

			// Cookies for authentication token retrieval
			cookies: ctx.cookies
		})
		.then({ status, content, redirect, route, time })
		{
			if (redirect)
			{
				return ctx.redirect(redirect)
			}

			if (stats)
			{
				stats
				({
					url: ctx.path + (ctx.querystring ? `?${ctx.querystring}` : ''),
					route,
					time:
					{
						...time,
						total: total_timer()
					}
				})
			}

			const result = { content, status }
			cache.put(url, result)
			return result
		})

		if (!cached)
		{
			const { content, status } = await promise

			if (status)
			{
				ctx.status = status
			}

			ctx.body = content
		}
	})

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

3 participants