Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

easy-template-x

Package Overview
Dependencies
Maintainers
1
Versions
42
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

easy-template-x

Generate docx documents from templates, in Node or in the browser.

  • 0.9.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
7.3K
decreased by-7.4%
Maintainers
1
Weekly downloads
 
Created
Source

easy-template-x

Generate docx documents from templates, in Node or in the browser.

CircleCI npm version npm license dependencies

Node Example

import * as fs from 'fs';
import { TemplateHandler } from 'easy-template-x';

// 1. read template file
const templateFile = fs.readFileSync('myTemplate.docx');

// 2. process the template
const data = {
    posts: [
        { author: 'Alon Bar', text: 'Very important\ntext here!' },
        { author: 'Alon Bar', text: 'Forgot to mention that...' }
    ]
};

const handler = new TemplateHandler();
const doc = await handler.process(templateFile, data);

// 3. save output
fs.writeFileSync('myTemplate - output.docx', doc);

Input:

input template

Output:

output document

Browser Example

The following example produces the same output while running in the browser. Notice that the actual template processing (step 2) is exactly the same as in the previous Node example.

import { TemplateHandler } from 'easy-template-x';

// 1. read template file

// (in this example we're loading the template by performing  
//  an AJAX call using the fetch API, another common way to  
//  get your hand on a Blob is to use an HTML File Input)
const response = await fetch('http://somewhere.com/myTemplate.docx');
const templateFile = await response.blob();

// 2. process the template
const data = {
    posts: [
        { author: 'Alon Bar', text: 'Very important\ntext here!' },
        { author: 'Alon Bar', text: 'Forgot to mention that...' }
    ]
};

const handler = new TemplateHandler();
const doc = await handler.process(templateFile, data);

// 3. save output
saveFile('myTemplate - output.docx', doc);

function saveFile(filename, blob) {

    // see: https://stackoverflow.com/questions/19327749/javascript-blob-filename-without-link

    // get downloadable url from the blob
    const blobUrl = URL.createObjectURL(blob);

    // create temp link element
    let link = document.createElement("a");
    link.download = filename;
    link.href = blobUrl;

    // use the link to invoke a download
    document.body.appendChild(link);
    link.click();

    // remove the link
    setTimeout(() => {
        link.remove();
        window.URL.revokeObjectURL(blobUrl);
        link = null;
    }, 0);
}

Live Demo

Checkout this live demo on CodeSandbox 😎

Plugins

easy-template-x uses a plugin model to support it's various template manipulation capabilities. There are some built-in plugins and you can also write your own custom plugins if required.

Default plugins

These are the plugins that comes bundled with easy-template-x:

Text plugin

The most basic plugin. Replaces a single tag with custom text. Preserves the original text style.

Input template:

input template

Input data:

{
    "First Tag": "Quis et ducimus voluptatum\nipsam id.",
    "Second Tag": "Dolorem sit voluptas magni dolorem molestias."
}

Output document:

output document

Loop plugin

Iterates text, table rows and lists.
Requires an opening tag that starts with # and a closing tag that has the same name and starts with /.

Input template:

input template

Input data:

{
    "Beers": [
        { "Brand": "Carlsberg", "Price": 1 },
        { "Brand": "Leaf Blonde", "Price": 2 },
        { "Brand": "Weihenstephan", "Price": 1.5 }
    ]
}

Output document:

output document

Image plugin

Embed images into the document.

Input template:

input template

Input data:

{
    "Kung Fu Hero": {
        _type: "image",
        source: fs.readFileSync("hero.png"),
        format: MimeType.Png,
        width: 200,
        height: 200
    }
}

Output document:

output document

Inserts hyperlinks into the document.
Like text tags link tags also preserve their original style.

Input template:

input template

Input data:

{
    "easy": {
        _type: 'link',
        text: 'super easy',  // optional - if not specified the `target` property will be used
        target: 'https://github.com/alonrbar/easy-template-x'
    }
}

Output document:

output document

Raw xml plugin

Add custom xml into the document to be interpreted by Word.

Tip:
You can add page breaks using this plugin and the following xml markup:
<w:br w:type="page"/>

Input template:

input template

Input data:

{
    "Dont worry be happy": {
        _type: 'rawXml',
        xml: '<w:sym w:font="Wingdings" w:char="F04A"/>'
    }
}

Output document:

output document

Writing your own plugins

To write a plugin inherit from the TemplatePlugin class.
The base class provides two methods you can implement and a set of utilities to make it easier to do the actual xml modification.

To better understand the internal structure of Word documents check out this excellent source.

Example plugin implementation (source):

/**
 * A plugin that inserts raw xml to the document.
 */
export class RawXmlPlugin extends TemplatePlugin {

    // Declare the unique "content type" this plugin handles
    public readonly contentType = 'rawXml';

    // Plugin logic goes here:
    public simpleTagReplacements(tag: Tag, data: ScopeData): void {

        // Tag.xmlTextNode always reference the actual xml text node.
        // In MS Word each text node is wrapped by a <w:t> node so we retrieve that.
        const wordTextNode = this.utilities.docxParser.containingTextNode(tag.xmlTextNode);

        // Get the value to use from the input data.
        const value = data.getScopeData() as RawXmlContent;
        if (value && typeof value.xml === 'string') {

            // If it contains a "xml" string property parse it and insert.
            const newNode = this.utilities.xmlParser.parse(value.xml);
            XmlNode.insertBefore(newNode, wordTextNode);
        }

        // Remove the placeholder node.
        // We can be sure that only the placeholder is removed since easy-template-x
        // makes sure that each tag is isolated into it's own separate <w:t> node.
        XmlNode.remove(wordTextNode);
    }
}

The content type that this plugin expects to see is:

export interface RawXmlContent extends PluginContent {
    _type: 'rawXml';
    xml: string;
}

Extensions

Although most document manipulation can be achieved by using plugins, there are some cases where a more powerful tool is required. In order to extend the document manipulation process you can specify extensions that will be run before and/or after the standard template processing.

Some cases where an extension may be a good fit:

  • Manipulating the document metadata (author, keywords, description, etc.).
  • Adding and manipulating Content Controls.
  • Leveraging Data Binding (where the data is stored in files other than the base Word files).

By default no extensions will be loaded.

Extensions and the order they run in are specified via the TemplateHandlerOptions.

const handler = new TemplateHandler(
    new TemplateHandlerOptions({
        extensions: {
            afterCompilation: [
                new ContentControlExtension(),
                new DataBindingExtension()
            ]
        }
    });
);

Scope resolution

easy-template-x supports tag data scoping. That is, you can reference "shallow" data from within deeper in the hierarchy similarly to how you can reference an outer scope variables from within a function in JavaScript. You can leverage this property to declare "top level" data (your logo and company name or some useful xml snippets like page breaks, etc.) to be used anywhere in the document.

Input template:

(notice that we are using the "Company" tag inside the "Employees" loop)

input template

Input data:

(notice that the "Company" data is declared outside the "Employees" loop, in it's so called "outer scope")

{
    "Company": "Contoso Ltd.",
    "Employees": [
        { "Surname": "Gates", "Given name": "William" },
        { "Surname": "Nadella", "Given name": "Satya" },
    ]
}

Output document:

output document

Note - Advanced API

You'll usually just use the TemplateHandler as seen in the examples but if you want to implement a custom plugin or otherwise do some advanced work yourself checkout the typings file. Do note however that while the advanced API is mostly documented in the typings file it's still considered an internal implementation detail and may break between minor versions, use at your own risk.

Supported Binary Formats

The library supports the following binary formats:

Philosophy

The main principal the package aspire to adhere to is being simple and easy.
It tries to keep it simple and has the following priorities in mind:

  1. Easy for the end user who writes the templates.
  2. Easy for the developer who process them using the exposed APIs.
  3. Easy for the maintainer/contributor who maintain the easy-template-x package itself.

Prior art and motivation

There are already some very good templating libraries out there, most notably these two:

easy-template-x takes great inspiration from both. It aspires to take the best out of both and to add some good of it's own.

While these packages has some great features such as GraphQL and inline JavaScript support in docx-templates and a breadth of additional (payed) modules in docxtemplater. This package, in accordance with it's declared above philosophy, offers some unique benefits including a most simple, non-programmer oriented template syntax, an even neater API (IMHO 😄), a free image insertion plugin and a TypeScript code base. Hopefully it will serve you well :)

Changelog

The change log can be found here.

Keywords

FAQs

Package last updated on 10 Feb 2020

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