Server Side Rendering Improvements


#1

I’ve been waiting for this one for a while and it finally looks like it’s here. I’m working on a recent webpack es6 cli project and decided to give SSR a go. It took a little mucking around, slight learning curve, but nothing too hard for someone who has used aurelia for a while.

Here’s the main things that aren’t done that are crticial for SSR to be useful.

  1. You can’t have dynamic opengraph tags with it yet. That needs fixing. Meta tags should be dynamic. The whole template should be dynamic and avoid using comments. Use something like hogan or mustache/handlebars? I saw there was a comment in the config for uglify not to remove comments. How can any serious app that has its links shared not have opengraph implemented properly? That’s not great.

  2. Support for SSR in aurelia cli (I am sure this is on the todo list). It wasn’t trivial to add SSR into an es6 webpack cli project.

  3. Needs a leaner minified bundle. One without source maps and so on. Probably easy to configure, but the config needs cleaning up for this.

All of what I tried was taken from the SSR skeleton.

Overall, smooth upgrade, but needs more work for something that’s a critical feature.


#2

Tip: If you’re using babel/es6 and get: TypeError: Cannot assign to read only property ‘exports’ of object ‘#’

Use this for your server-main.js

module.exports = require('aurelia-ssr-bootstrapper-webpack').default(function(aurelia) {
  let PLATFORM = require('aurelia-pal').PLATFORM;
  aurelia.use.standardConfiguration();
  aurelia.start().then(() => aurelia.setRoot(PLATFORM.moduleName('app')));
});

#3

I’ve had a look at the ssr-engine code. Here’s a solution I intend to implement to fix the meta tag issue.

  1. Add a meta tag transformer to the ssr engine. Code would be similar to the styles one: https://github.com/aurelia/ssr-engine/blob/7e572b36a63ea141a0ab1c054faa2714caaf2ba6/src/transformers/styles.ts

  2. Add a preRenderStep that reads well known values from the properties of a view model. For instance, an opengraph property in a view model would be picked up by the preRenderStep and the preRenderStep would modify the DOM to update the meta tags. This then gets picked up by the ssr-engine meta tag transformer.

I’ll fork the ssr-engine and give it a go. Looks pretty easy.


#4

@rquast So exited that you are exited.
Keep us all posted.


#5

I have been poking around further and see that passing the aurelia context to the transformers is probably the way to go to get this data from the router directly. Meta tags don’t appear in the DOM, so that changes my earlier idea.


#6

A-ha… so they really should be rendered serverside…

there is a question on SO about adding meta tags via JS

I am still convinced that It would be better to have a navigation side effect that updates meta tags.
So It would work for both client and server.
But it can’t be part of the router…


#7

Yeah that was the original plan. Doing that with a preRenderStep. But the problem is the node DOM doesn’t have meta tags in it, so I can’t manipulate the DOM before render to add the meta tags and then have SSR copy them. So I’ll have to work with something closer to the current ssr transformers plus a meta one that builds its data from the aurelia context (somewhere in it like the router or probably a container?).


#8

Why not ping jsdom guys for implementation (-:
I think you got a valid case…
If you do, please post issue number here so we can reference it in ssr issues for future reference as well (-:

Cheers mate. You rock. Keep going!!!


#10

@rquast - I’m also working in an ES6 webpack app (not TypeScript) and trying to wrap my head around how to implement SSR and OpenGraph/SEO. I’d GREATLY appreciate seeing a Github repo with your forked skeleton!

I’ve also been fighting trying to integrate webpack 4 to limited success over the past week (compiles, but results in a big “Cannot set property ‘endpoint’ of undefined” error during page load.

Lots of growing pains ahead.


#11

I didn’t get that error, but I put it together from a reasonably recent cli es6 project. I did get problems with the bootstrapper. It works really well, but I think it could do with some better error handling. It throws some errors internally and doesn’t let you know, without launching a debugger to see the errors.


#12

Latest updates… I’ve managed to get this rendering meta tags on the server side, and update the meta tags on the client side.

The project forks I made are here:



And here are some of the additions I put in my app to make it work:




And the site should be live soon (uploading it right now) at https://getcavy.com

Will add all of this to the es6 skeleton soonish.


#13

@rquast I hereby give you the ssr badge of honor (-:
now get some rest, please


#14

Hello everyone! When I started my project I used the esnext 1.1.2 skeleton. I’m wondering if anyone has seen or created a “How To” illustrating what is needed to add SSR to the esnext webpack 1.1.2 skeleton. Skeletons are great for getting started quickly, but I’m find that my ignorance with knowing the intricacies of the skeleton are going to increase my learning curve when adding SSR.

Thanks in advance!
–Steve B.


#15

@sboyd I still have to get around to doing the PR for this. I’ll probably include a short video on how to use SSR and where to look for anyone who is interested once it’s done. Waiting for some feedback from anyone who has looked at or tried my fork (above) to see if it’s okay.


#16

I’m going to try out your fork! I’ve got to spend some time wrapping my head around how to use Koa, and how to rewrite a ton of my code to use the Aurelia PAL.

The opengraph/meta stuff is really the holy grail and reason for me even exploring SSR at all. Our app/site will have tens of thousands of user-facing pages that need to be Google-indexed, and they’re all dynamic depending on what data is being pulled for a given page, so it’s not something I can just drop into the router’s config. It all has to be generated dynamically on-the-fly.

I’m getting really worried that Aurelia is going to end up having been a bad choice for a customer-facing website that requires lots of meta/SEO value. I’m not sure if ANY frontend solution is ideal in that regard. Might have to go back to an all server-side solution like .NET Core or the new Blazor or something.


#17

A video would be super-helpful!


#18

Think support in Aurelia CLI will be great and will help us span new project quickly as well as move existing project that works perfectly with webpack configured by aurelia cli
any clue when aurelia cli will support SSR ?


#19

@nathanchase Good luck with the fork… let me know what you think (if you can figure it out). I think Aurelia is fine… all of the code is there, it’s just that I don’t think the existing SSR code has been used to any great extent yet. It’s definitely a much more practical system to use for SEO than Blazor IMO (Blazor is a cool idea by the way). I think Blazor would be going 10 steps back, first being that there’s no debugger for it, second is the SSR for it is still being discussed, third is the size of the files it has to download. It’s basically a VM running in WASM, so if file size is an issue for SEO it may not be the best choice.


#20

@arin I think SSR in CLI is the next logical step after things have settled down with its code.


#21

So, I have this in my package.json:

  "dependencies": {
    "aurelia-binding": "^1.6.0",
    "aurelia-bootstrapper": "^2.1.1",
    "aurelia-fetch-client": "^1.1.3",
    "aurelia-framework": "^1.1.5",
    "aurelia-history": "^1.1.0",
    "aurelia-history-browser": "^1.1.0",
    "aurelia-loader-webpack": "^2.1.0",
    "aurelia-logging-console": "1.0.0",
    "aurelia-middleware-koa": "https://github.com/rquast/middleware-koa",
    "aurelia-ssr-bootstrapper-webpack": "https://github.com/rquast/ssr-bootstrapper-webpack",
    "aurelia-pal": "^1.4.0",
    "aurelia-pal-browser": "^1.3.0",
    "aurelia-pal-nodejs": "^1.0.0-beta.2.0.0",
    "aurelia-polyfills": "^1.2.2",
    "aurelia-router": "^1.4.0",
    "aurelia-templating": "^1.6.0",
    "aurelia-templating-resources": "^1.5.4",
    "aurelia-templating-router": "^1.2.0",
    "aurelia-webpack-plugin": "^2.0.0-rc.5",
    "autoprefixer": "^7.1.6",
    "bootstrap": "^3.3.7",
    "font-awesome": "^4.7.0",
    "isomorphic-fetch": "^2.2.1",
    "jquery": "^3.2.1",
    "koa": "^2.4.1",
    "koa-static": "^4.0.1",
    "aurelia-ssr-engine": "https://github.com/rquast/ssr-engine"
  }

but I’m getting an error:

TypeError: Cannot read property 'reconfigure' of undefined at start

Do I have all of the right pointers to the correct components in the package.json? Not sure what I’m missing here.