Article
5 comments

How to use Handlebars in SharePoint Framework Projects – SPFX

I believe one on the most used front end tools in the web development world is out there is Moustache or Handlebars. It is easy to use; you can write native HTML and compelling too.
In the SharePoint world, many web parts directly show data on the page, and therefore this is the right weapon of choice to get fast going.
Right after the first version of SPFx become public available, I created a ticket in GitHub on how to use this front end tool. With the RC0 drop of the framework, a new functionality has become available that allows you to embed Handlebars through a so-called webpack loader. I was pretty excited when Pat Miller tweeted me about this.

Let me show and explain what steps are required to make use of it in your next project.

Install WebPack Handlebar loader

As mentioned earlier additional functionalities can now be added via webpack. In general, the list of available loaders is huge but only two options are available for handlebars. –https://webpack.github.io/docs/list-of-loaders.html
I tested both, but the ‘handlebar-template-loader’ is the better choice from my point of view.
To install this loader execute the following command:

npm install handlebars-template-loader --save-dev

The ‘save-dev’ switch is required because this loader is only needed during development. The next step is to make SPFx aware of this new extensions.

Configure Handlebars webpack loader

In a regular webpack project you have the complete configuration in your control. In SPFx it was abstracted away from the developer and will by dynamically generated during build and runtime.
With the RC0 drop of the SharePoint Framework, a new configuration option for web pack has become available.
First, it is useful to store all additional settings in a separate variable or constant. I this case the ‘loaderConfig’ constant contains the particular loader configuration.

// Custom config section starts here
const loaderConfig = [{
  test: /\.hbs/,
  loader: "handlebars-template-loader"
}];

The test attribute includes the file extension that should be used to launch the loader. I prefer to use the ‘hbs’ extension for all my templates rather than writing ‘handlebars’ all the time.
Now we are ready to add this base configuration the SPFx with the following lines of code.

build.configureWebpack.mergeConfig({
  additionalConfiguration: (generatedConfiguration) => {
    generatedConfiguration.module.loaders.push(loaderConfig);

    return generatedConfiguration;

  }
});

The loader is now installed and configured for our project, but there are still some things to do before handlebars work correctly.

Copy static assets to `lib` folder

Whenever you save your SASS or Typescript files, the framework compiles all the assets and adds them to the ‘lib’ as well to the ‘dist’ folder. It works well for the know file types the project is aware of, be we also need to make sure that the newly introduced files were pushed down the build pipeline and available in the ‘lib’ folder.
To copy the Handlebar templates automatically from the ‘src’ to the ‘dist’ folder a new configuration needs to be introduced.

copy static assets

Create a new file in the config folder of the project and name it ‘copy-static-assets.json’ and paste the lines below into it.

// copy-static-assets.json
{
  "includeExtensions": [
    "hbs"
  ]
}

All files extensions with extensions defined in the “includeExtensions” array will be automatically copied whenever a new build of the web part will be forced.
The only downside right is that this ‘dynamic’ content can only be handled as a ‘static’ content. To force the copy the typescript file of the web part needs to be modified otherwise the handlebar won’t be copied to the ‘lib’ and ‘dist’ folder.
Finally, the core integrations of Handlebars in SPFx is completed. The following section only handles additional information to get the development started using Handlebars.

Add your first handlebar template to your code

The first thing now that needs to be added is proper type support for the handlebar templates. To install the type definition execute:

typings install dt~handlebars --save --global

Add HandlebarsJS Library

The template will be automatically pre-compiled now, but to load it in the web part, we need to make sure that Handlebars itself is registered. To make sure the HandlebarJS library loads the configuration file config.json needs to be modified.
There are basically only the following two options available. Load Handlebars from CDN or load the library locally.

Load HandlebarJS from CDN

To include Handlebars from a CDN define the following external in the config.json file.

"externals": {
    "handlebars": "https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.amd.js"
},

Load HandlebarJS from local project

To load Handlebars locally first install it via ‘npm’.

npm install --save handlebars

Once the installation has been completed, add a reference to the ‘node_modules’ folder.

"externals": {
    // load handlebars from node_modules
    "handlebars": "./node_modules/handlebars/dist/handlebars.amd.min.js"

}

Ready to go

This blog post focused more the overall setup rather than the development. It shows in an excellent way to bring your favorite weapon of choice to the SharePoint Framework. Especially the webpack loader opens a whole now a range of supported technologies to address in SPFx project. In this case, only Handlebars was integrated, but there are much more techniques to be discovered.
For now, it only uses the default ‘Hello World’ content in a Handlebar template in an upcoming blog post I will focus more on the development aspects.
You will find the code and configuration used for this blog post on GitHub.

UPDATE: In addition to this blog post I published another post that explains more about the coding details.

5 Comments

  1. Thanks for posting this, it is very helpful. This is working well for me, however the handlebars library is being bundled with the webpack despite the fact that I am referencing the library as an external on a CDN. This is a problem because I plan to use multiple web parts on the same page with Handlebars. Am I doing something wrong?

    Thanks,

    Mark Gabriel

    Reply

    • Hi Mark,
      you need to check in the config directory the config.json there are the instructions how to use Handlebars from CDN.

      “`
      “externals”: {

      // Load Handlebar templates from CDN
      // “handlebars”: “https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.6/handlebars.amd.js”

      // load handlebars from node_modules
      “handlebars”: “./node_modules/handlebars/dist/handlebars.amd.min.js”

      },
      “`

      Uncomment the first “handlebars” definition and comment out the second one.

      Nevertheless you still need to have Handlebars locally installed, because the pre-compilation will be done by web pack, when you save the template. Therefor Handlebars is needed as a npm package.
      Hope this helps you.

      Reply

      • Thank you for your assistance, I think I have a better understanding now. I am new to using webpacks, and I was concerned because my Handlebars webpart’s JS bundle was over 100K and it did little more than say “helloworld”.

        After performing a gulp bundle –production, my bundle shrinks down to a slim 18KB. So, I am very happy! Again, thank you for your extremely helpful article.

        Reply

  2. FYI, I think they may have changed something with one of the more recent builds of the @microsoft/sharepoint generator (1.1.0 or 1.1.1 maybe?).

    I suddenly could no longer get mergeConfig to work in the gulpfile.js of newly generated projects because gulp was reporting that generatedConfiguration.module.loaders was null.

    I eventually got it working again using this snippet instead:

    const loaderRule = {
    “use”: [{
    “loader”: “handlebars-template-loader”
    }],
    “test”: /.hbs/
    };

    build.configureWebpack.mergeConfig({
    additionalConfiguration: (generatedConfiguration) => {
    generatedConfiguration.module.rules.push(loaderRule);

    return generatedConfiguration;

    }
    });

    I’m not sure why they changed it or why they didn’t document the change. Maybe it’s a bug, or the documentation hasn’t been updated yet.

    I hope this helps.

    Thanks,

    Mark

    Reply

  3. Also since TypeScript 2.0 recommends using @types over typings, may want to substitute ‘typings install dt~handlebars –save –global’ with ‘npm install –save @types/handlebars’

    Reply

Leave a Reply

Required fields are marked *.


This site uses Akismet to reduce spam. Learn how your comment data is processed.