New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

angular-ssr

Package Overview
Dependencies
Maintainers
1
Versions
221
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

angular-ssr

Angular server-side rendering implementation

  • 0.0.26
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
122
decreased by-75.5%
Maintainers
1
Weekly downloads
 
Created
Source

Introduction

The purpose of this library is to allow your application to support server-side rendering of your Angular 4+ applications with minimal code changes and mimimal difficulty. It supports both Angular CLI projects and projects that use custom webpack configurations. It works out of the box with @angular/material with no hot-fixes or workarounds! It also requires zero changes to your application code: you won't have to create separate @NgModules, one for the server-side rendered application and one for the regular client application. You can just take your Angular code as-is and follow the steps below to get server-side rendering working.

There are two ways you can use angular-ssr:

  1. If your application is an Angular CLI application with no custom webpack configuration, you can simply install it as a dependency, run a normal ng build, and then invoke ng-render from node_modules/.bin. This will result in several steps being taken:
    • It will use tsconfig.json and some other configuration elements to compile your application to a temporary directory and load the resulting JavaScript code (application code + .ngfactory.js files) into memory.
    • It will query your router configuration and collect all your application routes into a flattened array (eg. /, /foo, /bar)
    • For each of the discovered routes, it will instantiate your application and render that route to a static .html file in dist (or, if you specified an alternate output directory using --output, it will write the files there). It instantiates the application using the existing dist/index.html file that was produced as part of your normal application build as a template. The pre-rendered content will be inserted into that template and written out as a new .html file based on the route: e.g., /foo/index.html.
  2. If your application has custom webpack configurations and loaders, you probably will not be able to use ng-render. But that's alright. It just means that you will have to build a separate webpack program output: either a NodeJS HTTP server, or a NodeJS application whose sole purpose is to do prerendering. You will follow these rough steps:
    • Install angular-ssr as a dependency: npm install angular-ssr --save
    • If you already have multiple webpack configs (one for server and one for client), then you can skip down to the next section and begin writing code to interface with angular-ssr.
    • Otherwise, you will need to add an additional output to your existing webpack configurations. This can take two forms: either you modify your existing webpack.config.js and just add an additional output, or you create an entirely new webpack-server.config.js which will serve as your SSR webpack configuration. Regardless of how you accomplish it, you will ultimately need to produce two programs from webpack:
      • Your normal client-side JavaScript application
      • An additional server-side application that you will use to do server-side rendering. You have a couple choices here, as well:
        • If you want your application to use a NodeJS application with an HTTP server inside of it that will do on-demand pre-rendering of your application routes, then do that. We can then write a few lines of code to do the actual pre-rendering / caching inside of your route handlers. It doesn't matter if you use koa or express or any other HTTP server you wish to use -- angular-ssr will not integrate directly with the HTTP server anyway. It just exposes a very simple API to get pre-rendered HTML documents, and you can integrate this with your server in whichever way makes the most sense for your application.
        • Alternatively, you can build an application whose sole purpose is to do server-side rendering at build-time. This application will produce some static pre-rendered application content and then exit. This use-case makes sense if your application will not need to do on-demand server-side rendering. Let's say for example you just have an application with a few routes (/a, /b, /c, etc.). In this case, since all routes are known in advance and none of them take any URL parameters, we can just pre-render each route at build time and spit out some .html files.
        • Let's say that your application does need on-demand rendering, though. For example, you are writing a blog application that has URLs like /blog/post/1, /blog/user/3, etc. In this case, you will need to do on-demand server-side rendering. No problem! In this use-case, it makes sense to build a small HTTP server using express or koa and to write a few lines of code to integrate with angular-ssr. Then from inside your server, you can demand render and cache particular routes with arguments like /blog/post/1. I will show you some examples of how to do this below.

The simplest possible case: an Angular CLI application with no built-in HTTP server and no need for on-demand rendering

If your application was generated by ng new and does not use any custom webpack configuration, then you will be able to use the ng-render CLI tooll to automatically pre-render your application routes into static .html files. It is worth emphasizing that this use case is the easiest, but also the least flexible. If you need on-demand rendering, or if you have custom webpack configurations, then you should skip down to the examples below as they will cover your use-case better than this section.

But, in the event that you do have a simple ng cli application, you can give angular-ssr a whirl just by doing:

npm install angular-ssr --save
ng build
./node_modules/.bin/ng-render

It should spit out some messages like:

[info] Writing rendered route / to /Users/bond/proj/dist/index.html
[info] Writing rendered route /foo to /Users/bond/proj/dist/foo/index.html
[info] Writing rendered route /bar to /Users/bond/proj/dist/bar/index.html

You can then do cd dist and run:

npm install -g http-server
http-server .

Then when you load the application by hitting http://localhost:8080, you should see the pre-rendered document in the initial HTTP response (for each route in your application).

On-demand server-side rendering and caching

Let's get this use-case out of the way first, because I think it is likely to be the most common usage of angular-ssr.

You have an HTTP server application that you build as part of your application using webpack. Your HTTP server is written in TypeScript. (If your HTTP server is written in JavaScript, the library will still work in the same way, but you won't be able to copy-paste the code below.)

When you build your application, you are outputting two targets: your actual Angular client application, and your HTTP server application. We are going to focus on the server application here because there will be zero changes to your application code.

Your actual HTTP server code will look something like the following:

import 'reflect-metadata';

import {
  ApplicationFromModule,
  fileFromString,
  routeToPath,
} from 'angular-ssr';

import {join} from 'path';

import {AppModule} from '../src/app/app.module';

const dist = join(process.cwd(), 'dist');

const templateDocument = fileFromString(join(dist, 'index.html'));

if (templateDocument.exists() === false) {
  throw new Error('dist/index.html must exist because it is used as an SSR template');
}

const application = new ApplicationFromModule(AppModule);

application.templateDocument(templateDocument.content());

// Pre-render all routes that do not take parameters (angular-ssr will discover automatically)
const prerender = async () => {
  const snapshots = await renderer.prerender();

  return snapshots.subscribe(
    snapshot => {
      app.get(snapshot.uri,
        (req, res) => res.send(snapshot.renderedDocument));
    }).toPromise();
};

prerender();

// On-demand rendering for routes that do take parameters
app.get('/blog/:postId',
  async (req, res) => {
    try {
      const snapshot = await application.renderRoute(req.url); // has internal cache
      res.send(snapshot.renderedDocument);
    }
    catch (exception) {
      res.send(templateDocument.content()); // fall back on client-side rendering
    }
  });

Single-use server-side rendering as part of a build process

If your application does not fall into the categories described above (i.e., you do not need on-demand server-side rendering of all URLs), then perhaps your application falls into another category: single-use server-side rendering as part of the application build process.

In this case, your code will look similar to the HTTP server code above, but instead of integrating with express, you will simply use ApplicationRenderer to pre-render all application routes and write them to static .html files, which you can then serve with the HTTP server of your choosing. Again: this case only makes sense if you do not need on-demand rendering of all application routes.

In this case, your code will look something like this:

import 'reflect-metadata';

import {
  ApplicationFromModule,
  ApplicationRenderer,
  HtmlOutput,
  fileFromString,
  pathFromString
} from 'angular-ssr';

import {join} from 'path';

import {AppModule} from '../src/app.module';

const dist = join(process.cwd(), 'dist');

const templateDocument = fileFromString(join(dist, 'index.html'));
if (templateDocument.exists() === false) {
  throw new Error('Build output dist/index.html must exist prior to prerender');
}

const application = new ApplicationFromModule(ServerModule);

application.templateDocument(templateDocument.content());

const html = new HtmlOutput(pathFromString(dist));

const renderer = new ApplicationRenderer(application);

renderer.renderTo(html)
  .then(() => {
    console.log('Rendering complete');
  })
  .catch(exception => {
    console.error('Failed to render', exception);
  });

More complete examples

I am in the process of building out some more complete example applications over the next day or two. In the meantime, if you have questions you want answered, you can email me at cb@clbond.org or post an issue in this repository and I would be more than happy to answer!

Christopher Bond

FAQs

Package last updated on 21 Mar 2017

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc