Ekpunobi Stanley
Ekpunobi Stanley

Reputation: 21

How can i pre-rendered on the server in Angular Unviersal Project?

I am calling apis on the server side using TransferState Module of Angular Universal. And it takes about 6 ~ 7 seconds and the server side rendering is implemented. So when reload the page, i can see the loaded page after 6 ~ 7 seconds every time. Those apis are being called only on the server when the page is loaded. How can i pre-render this page on the server so that to improve the loading time?

Upvotes: 2

Views: 935

Answers (2)

Neo Liu
Neo Liu

Reputation: 419

Basically, to prerender Angular, you need to have these things ready:

  1. Pages routes if you have two pages such as 'home' and 'contact', then your final project structure should be like this:
|---root
|---index.html
|---/home
    |---index.html
|---/contact
    |---index.html
  1. Rendering Engine You need to use render engine to get the index.html files by loop your routes params in Rendering Engine. In Angular, we use renderModuleFactory() as the render engine.

You can refer to this post for more details: Prerender Angular and Host It on AWS S3.

Upvotes: 0

gorniv
gorniv

Reputation: 200

You can run prerender based Angular Universal:

package.json

 "build:prerender": "npm run build:universal && npm run generate:prerender",
 "generate:prerender": "node prerender.js"

prerender.ts

import { environment } from './src/environments/environment';

const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(path.join(__dirname, '.', 'dist', 'index.html')).toString();
const win = domino.createWindow(template);
const files = fs.readdirSync(`${process.cwd()}/dist-server`);

global['window'] = win;
Object.defineProperty(win.document.body.style, 'transform', {
  value: () => {
    return {
      enumerable: true,
      configurable: true,
    };
  },
});
global['document'] = win.document;
global['CSS'] = null;
// global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
global['Prism'] = null;

// Load zone.js for the server.
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
import { join } from 'path';

import { enableProdMode } from '@angular/core';
// Faster server renders w/ Prod mode (dev mode never needed)
enableProdMode();

// Express Engine
import { ngExpressEngine } from '@nguniversal/express-engine';
// Import module map for lazy loading
import { provideModuleMap } from '@nguniversal/module-map-ngfactory-loader';
import { renderModuleFactory } from '@angular/platform-server';
import { ROUTES } from './static.paths';

// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const mainFiles = files.filter((file) => file.startsWith('main'));
const hash = mainFiles[0].split('.')[1];
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require(`./dist-server/main.${hash}`);
import { REQUEST, RESPONSE } from '@nguniversal/express-engine/tokens';

const BROWSER_FOLDER = join(process.cwd(), 'static');

// Load the index.html file containing referances to your application bundle.
const index = readFileSync(join('dist', 'index.html'), 'utf8');

let previousRender = Promise.resolve();

// Iterate each route path
ROUTES.forEach((route) => {
  const fullPath = join(BROWSER_FOLDER, route);

  // Make sure the directory structure is there
  if (!existsSync(fullPath)) {
    let syncpath = BROWSER_FOLDER;
    route.split('/').forEach((element) => {
      syncpath = syncpath + '/' + element;
      mkdirSync(syncpath);
    });
  }

  // Writes rendered HTML to index.html, replacing the file if it already exists.
  previousRender = previousRender
    .then((_) =>
      renderModuleFactory(AppServerModuleNgFactory, {
        document: index,
        url: route,
        extraProviders: [
          provideModuleMap(LAZY_MODULE_MAP),
          {
            provide: REQUEST,
            useValue: { cookie: '', headers: {} },
          },
          {
            provide: RESPONSE,
            useValue: {},
          },
          {
            provide: 'ORIGIN_URL',
            useValue: environment.host,
          },
        ],
      }),
    )
    .then((html) => writeFileSync(join(fullPath, 'index.html'), html));
});

static.paths.ts

export const ROUTES = ['/routePrerenderPage', '/home' ];

Upvotes: 0

Related Questions