ePub is a common format for eBooks supported by most eBook readers other than Amazon Kindle, like Google Play Books. The epub-gen npm module lets you create ePubs from HTML documents. Here's how it works.

Getting Started

A .epub file is just a zip file containing a bunch of HTML, images, and metadata about your eBook. Unfortunately, the ePub format is arcane and testing that your ePub works correctly on all readers is difficult, so using a pre-built tool is a good idea.

First, install epub-gen:

npm install epub-gen

epub-gen has 4 required parameters: title, author, an output path to write the epub to, and an array of content. Each entry in content corresponds to one chapter of the book. For example, here's how you can generate an epub that contains the first few words of Moby-Dick:

const epub = require('epub-gen');

const options = {
  title: 'Moby-Dick',
  author: 'Herman Melville',
  output: './moby-dick.epub',
  content: [
    {
      title: 'Chapter 1: Loomings',
      data: `<p>
        Call me Ishmael. Some years ago—never mind how long precisely
      </p>`
    }
  ]
};

new epub(options).promise.then(() => console.log('Done'));

Here's what the above PDF looks like on the EPUBReader Chrome extension.

With some extra work, you can download the entire text version of Moby-Dick from Project Gutenberg using Axios.

const axios = require('axios');
const epub = require('epub-gen');

axios.get('http://www.gutenberg.org/files/2701/2701-0.txt').
  then(res => res.data).
  then(text => {
    text = text.slice(text.indexOf('EXTRACTS.'));
    text = text.slice(text.indexOf('CHAPTER 1.'));

    const lines = text.split('\r\n');
    const content = [];
    for (let i = 0; i < lines.length; ++i) {
      const line = lines[i];
      if (line.startsWith('CHAPTER ')) {
        if (content.length) {
          content[content.length - 1].data = content[content.length - 1].data.join('\n');
        }
        content.push({
          title: line,
          data: ['<h2>' + line + '</h2>']
        });
      } else if (line.trim() === '') {
        if (content[content.length - 1].data.length > 1) {
          content[content.length - 1].data.push('</p>');
        }
        content[content.length - 1].data.push('<p>');
      } else {
        content[content.length - 1].data.push(line);
      }
    }

    const options = {
      title: 'Moby-Dick',
      author: 'Herman Melville',
      output: './moby-dick.epub',
      content
    };

    return new epub(options).promise;
  }).
  then(() => console.log('Done'));

Styling and Formatting

epub-gen allows specifying custom CSS and fonts. For example, here's how you can set line-height to 1.5 and use a custom font from Google fonts.

const options = {
  title: 'Moby-Dick',
  author: 'Herman Melville',
  output: './moby-dick.epub',
  css: `
    * { font-family: 'PT Serif'; }
    p { line-height: 1.5em; }
  `,
  // You need to download the TTF file from Google Fonts
  fonts: ['./PT_Serif/PTSerif-Regular.ttf'],
  content
};

Below is what the newly formatted eBook looks like.

You can also add a custom cover. Note that your cover must be an image, you can't use HTML or PDF.

const options = {
  title: 'Moby-Dick',
  author: 'Herman Melville',
  output: './moby-dick.epub',
  cover: './moby-dick.jpg',
  css: `
    * { font-family: 'PT Serif'; }
    p { line-height: 1.5em; }
  `,
  // You need to download the TTF file from Google Fonts
  fonts: ['./PT_Serif/PTSerif-Regular.ttf'],
  content
};

Here's what the epub looks like in Google Play Books with the fancy new cover:

Moving On

Along with PDF, Mobi, and Kindle's proprietary format, ePub is one of the most popular formats for eBooks. It has the neat advantage of being more structured than PDF, and easier to style using vanilla CSS. Next time you find yourself wanting a nicely formatted version of a book for summer reading, try generating an ePub for it.

Found a typo or error? Open up a pull request! This post is available as markdown on Github
comments powered by Disqus