Skip to content
This repository has been archived by the owner on Jan 2, 2020. It is now read-only.

khalyomede/prerender

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

DEPRECATION

This library will no longer be maintained. Please see hypercharged for an up-to-date, and more flexible alternative.

Prerender

Prerenders your website into a static, SEO friendly, HTML version.

npm npm dev dependency version NPM Build Status Snyk Vulnerabilities for npm package

Summary

About

I am using a similar algorithm on one of my SPA to serve Google bots a static version of my website where my meta and my content is immediately present. I decided to open source it because I did not see another package that does it.

Installation

  1. Install the package
npm install --save-dev @khalyomede/prerender
  1. Install puppeteer (only if you did not have it already)
npm install --save-dev puppeteer

Usage

Note

These example use @babel-node to parse ES6 syntaxes. If you do not want to use it, please replace this:

import { Route, Prerendering } from "@khalyomede/prerender";

By:

const { Route, Prerendering } = require("@khalyomede/prerender");

Simple example

In this example, we will prerender 2 routes from http://example.com and save it into a folder named prerendered.

import { Route, Prerendering } from "@khalyomede/prerender";

const prerendering = new Prerendering();

prerendering.setBaseUrl("http://example.com");
prerendering.setFolderPath("prerendered");
prerendering.setDebugMode(true);

const home = new Route().setUrl("/").addSelectorToWaitFor("h1");
const about = new Route().setUrl("/about").addSelectorToWaitFor("p");

prerendering.setRoutes([home, about]);
prerendering.start();

You should see something like this:

[2019-05-25 00:49:10:219] opening Chrome...
[2019-05-25 00:49:10:340] opened Chrome (115ms)
[2019-05-25 00:49:10:342] opening a tab...
[2019-05-25 00:49:10:415] opened a tab (73ms)
[2019-05-25 00:49:10:416] navigating to http://example.com/...
[2019-05-25 00:49:10:794] successfully navigated (378ms)
[2019-05-25 00:49:10:795] waiting for 1 selectors...
[2019-05-25 00:49:10:807] found the selectors (11ms)
[2019-05-25 00:49:10:808] copying the HTML...
[2019-05-25 00:49:10:812] copied 1.26 kB of HTML (3ms)
[2019-05-25 00:49:10:813] saving into prerendered/index.html...
[2019-05-25 00:49:10:815] saved the file (1ms)
[2019-05-25 00:49:10:816] closing the tab...
[2019-05-25 00:49:10:821] closed the tab (4ms)
[2019-05-25 00:49:10:823] opening a tab...
[2019-05-25 00:49:10:890] opened a tab (66ms)
[2019-05-25 00:49:10:891] navigating to http://example.com/about...
[2019-05-25 00:49:11:014] successfully navigated (122ms)
[2019-05-25 00:49:11:015] waiting for 1 selectors...
[2019-05-25 00:49:11:025] found the selectors (9ms)
[2019-05-25 00:49:11:026] copying the HTML...
[2019-05-25 00:49:11:029] copied 1.26 kB of HTML (3ms)
[2019-05-25 00:49:11:029] saving into prerendered/about/index.html...
[2019-05-25 00:49:11:031] saved the file (1ms)
[2019-05-25 00:49:11:032] closing the tab...
[2019-05-25 00:49:11:035] closed the tab (2ms)
[2019-05-25 00:49:11:037] closing Chrome...
[2019-05-25 00:49:11:288] closed Chrome (249ms)

Saving html files

In this example, you will see that html files (ending with the .html extension) can be saved as well.

import { Route, Prerendering } from "../lib/main";

const prerendering = new Prerendering();

prerendering.setBaseUrl("http://example.com");
prerendering.setFolderPath("prerendered");
prerendering.setDebugMode(true);
prerendering.addRoute(new Route().setUrl("/about/us.html"));

prerendering.start();

You should see something like this in console:

[2019-05-25 15:15:49:866] opening Chrome...
[2019-05-25 15:15:49:988] opened Chrome (117ms)
[2019-05-25 15:15:49:990] opening a tab...
[2019-05-25 15:15:50:064] opened a tab (74ms)
[2019-05-25 15:15:50:065] navigating to http://example.com/about/us.html...
[2019-05-25 15:15:50:331] successfully navigated (265ms)
[2019-05-25 15:15:50:331] copying the HTML...
[2019-05-25 15:15:50:338] copied 1.26 kB of HTML (6ms)
[2019-05-25 15:15:50:339] saving into prerendered/about/us.html...
[2019-05-25 15:15:50:342] saved the file (2ms)
[2019-05-25 15:15:50:342] closing the tab...
[2019-05-25 15:15:50:346] closed the tab (3ms)
[2019-05-25 15:15:50:347] closing Chrome...
[2019-05-25 15:15:50:459] closed Chrome (112ms)

Add a greater timeout

In this example, we will instruct Puppeteer to wait for 10000 ms (10 sec) maximum, instead of the default 30s.

import { Route, Prerendering } from "../lib/main";

const prerendering = new Prerendering();

prerendering.setBaseUrl("http://example.com");
prerendering.setFolderPath("prerendered");
prerendering.setDebugMode(true);
prerendering.setTimeout(10000);
prerendering.addRoute(new Route().setUrl("/").addSelectorToWaitFor("h1"));
prerendering.start();

You should see something like this in console:

[2019-05-25 01:13:52:423] opening Chrome...
[2019-05-25 01:13:52:573] opened Chrome (144ms)
[2019-05-25 01:13:52:575] opening a tab...
[2019-05-25 01:13:52:649] opened a tab (73ms)
[2019-05-25 01:13:52:649] navigating to http://example.com/...
[2019-05-25 01:13:52:932] successfully navigated (282ms)
[2019-05-25 01:13:52:933] waiting for 1 selectors...
[2019-05-25 01:13:52:947] found the selectors (13ms)
[2019-05-25 01:13:52:948] copying the HTML...
[2019-05-25 01:13:52:953] copied 1.26 kB of HTML (4ms)
[2019-05-25 01:13:52:953] saving into prerendered/index.html...
[2019-05-25 01:13:52:955] saved the file (1ms)
[2019-05-25 01:13:52:956] closing the tab...
[2019-05-25 01:13:52:960] closed the tab (4ms)
[2019-05-25 01:13:52:961] closing Chrome...
[2019-05-25 01:13:53:097] closed Chrome (136ms)

Disable logs

In this example, we will remove the logs from the console.

import { Route, Prerendering } from "../lib/main";

const prerendering = new Prerendering();

prerendering.setBaseUrl("http://example.com");
prerendering.setFolderPath("prerendered");
prerendering.setDebugMode(false); // you do not need this line, by default it is false.
prerendering.addRoute(new Route().setUrl("/").addSelectorToWaitFor("h1"));
prerendering.start();

Prevent some routes to be prerendered

In this example, we will add 4 routes, but only instruct the program to prerender 2 of them. This is useful if you do not want to play comment/uncomment to do some adjustements or tests.

import { Route, Prerendering } from "@khalyomede/prerender";

const home = new Route().setUrl("/").addSelectorToWaitFor("h1");
const about = new Route().setUrl("/about").addSelectorToWaitFor("p");
const contactUs = new Route()
  .setUrl("/contact-us")
  .setSelectorsToWaitFor(["h1", "p"])
  .setInactive();
const news = new Route()
  .setUrl("/news?utm_medium=social")
  .addSelectorToWaitFor("h1")
  .setInactive();

const prerendering = new Prerendering();

prerendering.setBaseUrl("http://example.com");
prerendering.setFolderPath("prerendered");
prerendering.setRoutes([home, about, contactUs, news]); // no need to filter them here, you did it per route.
prerendering.start();

You should see something like this in console:

[2019-05-25 01:26:04:021] opening Chrome...
[2019-05-25 01:26:04:303] opened Chrome (270ms)
[2019-05-25 01:26:04:307] opening a tab...
[2019-05-25 01:26:04:439] opened a tab (131ms)
[2019-05-25 01:26:04:440] navigating to http://example.com/...
[2019-05-25 01:26:05:003] successfully navigated (562ms)
[2019-05-25 01:26:05:004] waiting for 1 selectors...
[2019-05-25 01:26:05:035] found the selectors (29ms)
[2019-05-25 01:26:05:036] copying the HTML...
[2019-05-25 01:26:05:043] copied 1.26 kB of HTML (6ms)
[2019-05-25 01:26:05:044] saving into prerendered/index.html...
[2019-05-25 01:26:05:047] saved the file (2ms)
[2019-05-25 01:26:05:047] closing the tab...
[2019-05-25 01:26:05:054] closed the tab (6ms)
[2019-05-25 01:26:05:056] opening a tab...
[2019-05-25 01:26:05:170] opened a tab (114ms)
[2019-05-25 01:26:05:171] navigating to http://example.com/about...
[2019-05-25 01:26:05:335] successfully navigated (163ms)
[2019-05-25 01:26:05:336] waiting for 1 selectors...
[2019-05-25 01:26:05:349] found the selectors (12ms)
[2019-05-25 01:26:05:350] copying the HTML...
[2019-05-25 01:26:05:353] copied 1.26 kB of HTML (3ms)
[2019-05-25 01:26:05:354] saving into prerendered/about/index.html...
[2019-05-25 01:26:05:356] saved the file (2ms)
[2019-05-25 01:26:05:357] closing the tab...
[2019-05-25 01:26:05:361] closed the tab (3ms)
[2019-05-25 01:26:05:362] closing Chrome...
[2019-05-25 01:26:05:574] closed Chrome (211ms)

API

You can find all the methods available for every classes of this package right here: api.md.

Contributing

The project uses typescript to transpile modern ES6 into Javascript.

To start adding features or fixing bugs, use this command:

npm run start

This will open Gulp and it will listen changes on your .ts files. When transpiled, the files are located in the lib folder .

The class Route.ts modelize the routes to prerender. The class Prerendering.ts modelize the prerendering step, and all the options involved the process. The main.ts file is just a facade to be able to provide three shaking ability to the user.

To add tests, I use chai as my assertion library and mocha to run the tests. I also use @stryker-mutator/core to run mutations tests, but for the moment it throws a lot of errors because I do not know how to tests my logs in console, and I have an issue testing the asynchronous Prerendering.start() method.

To run the test, use:

npm run test