Transpile TypeScript for Dynamics 365 simply using rollup.js

Today we’re going to learn how to bring Dynamics form customisations to the modern era. No more files that are thousands of lines long, no more syntax errors, fewer bugs, and lower time to deploy.

Sep 24th 2018·6 min read


Today we’re going to learn how to bring Dynamics form customisations to the modern era. No more files that are thousands of lines long, no more syntax errors, fewer bugs, and lower time to deploy.

The community is filling with useful ideas on how to utilise TypeScript for Dynamics customisations. You may have seen Scott Durow recently detailed how to get started with TypeScript, or Max Ewing’s post on how to create packages for Dynamics in TypeScript. This post focuses on similar core concepts, but uniquely expands on the focus of modules and build processes to modernise Dynamics customisations.

Some assumptions

This post will begin with some assumptions (uh oh).

  • You’re a Dynamics developer
  • You’re using (or thinking of using) TypeScript for form customisations
  • You’re using (or thinking of using) a modular design structure in your form scripts

If either of points 2 or 3 are false, I’d like to briefly try and convince you to consider them. (If both are true, you may want to skip the next two sections.)

Giving modular TypeScript a go

Dynamics developers are increasingly turning to TypeScript to write their form customisations in Dynamics. The reasons behind this are TypeScript’s benefits which, in a Dynamics context, can be summarised as:

  • Providing all the features of JavaScript, with the addition of static type checking
  • Transpiling (think: compiling) down to plain old JavaScript

In practice, this means intellisense against the Dynamics Client API; no more typos causing syntax errors at runtime! All that’s required is a simple import of @types/Xrm into your code (which I later explain).

Modular code design

As projects evolve and grow, Dynamics form scripts can become large, unstructured and difficult to maintain. This is especially prominent when following the pattern of providing just one script per form.

As an alternative, I’d like to suggest modules.

Good authors divide their books into chapters and sections; good programmers divide their programs into modules.

Like a book chapter, modules are just clusters of words (or code, as the case may be).

Good modules, however, are self-contained with distinct functionality, allowing them to be shuffled, removed, or added as necessary, without disrupting the system as a whole.

Source: link

An example of modules in Dynamics

In this example, I demonstrate a requirement that gets the name of a lookup field value, and based on that value, toggles another field’s value.

The code to get a lookup’s name could be used elsewhere across different forms, so I’ve separated it into its own module called Common:

export class Common {
  public static getLookupName(
    schemaName: string,
    formContext: Xrm.FormContext
  ) {
    let name = "";
    const attribute: Xrm.Attributes.LookupAttribute = formContext.getAttribute(

    if (attribute) {
      const value: Xrm.LookupValue[] = attribute.getValue();

      if (value) {
        const firstLookup = value[0];

        if (firstLookup) {
          name =;

    return name;

Common is then imported into the Contact script, and used in an onLoad function:

import { Common } from "./common";

namespace Contact {
  export function onLoad(executionContext: Xrm.Events.EventContext): void {
    const formContext: Xrm.FormContext = executionContext.getFormContext();
    const countryName = Common.getLookupName("dc_country", formContext);

    if (countryName.toLowerCase() === "great britain") {

It’s important to note Contact is not a module, but a namespace. Its onLoad function doesn’t require an instantiated object and can be called directly from a Dynamics event handler.

If you’re following along, make sure to change your field schema names to fields that exist in your testing environment (mine are "dc_country" and "dc_umbrellarequired"), where the first is a lookup and the second is a boolean.

Rollup our example

Import and export syntax works while we develop: we can tell because intellisense is provided for imported modules. To a browser, these words currently don’t mean anything, and the relative paths of the files certainly don’t. We can’t serve our TypeScript files directly to the browser, so they must be transpiled to JavaScript first.

That’s where rollup.js comes in. It’s going to give us the tools to create a build pipeline that:

  1. Transpiles our code
  2. Recursively look through our code for dependencies from a given entry point
  3. Optionally run plugins such as babel
  4. Bundles our code into one, Dynamics and browser-ready output file

And it’s really simple. Here’s how.

Step 1: Install rollup

In the code directory from the code sample above, run the following from the command line:

npm install --global rollup npm install --save-dev rollup-plugin-typescript

Step 2: Create a rollup config file

Rollup can be run manually through the CLI each time. But config files are too powerful and convenient to pass up! So, create rollup.config.js in your code’s root as follows:

import typescript from "rollup-plugin-typescript";

export default {
  input: {
    contact: "src/contact.ts",
  output: {
    dir: "build",
    format: "cjs",
    name: "main",
  plugins: [typescript()],

Ensure the input relative path is set to your contact script’s directory as necessary.

3. Run your rollup

From the command line, run the following command to build your code, and output it to the /build/directory.

rollup -c --experimentalCodeSplitting

And that’s it! Upload the output .js file (should be in your /build/ directory) to Dynamics, add itto a Dynamics form and register the onLoad message as Contact.onLoad.


This post has detailed how we can structure our modular code on small to enterprise Dynamics 365 projects to increase our script’s:

  • Maintainability
  • Readability
  • Re-usability

We’ve learnt how to bundle our individual TypeScript-written modules into single JavaScript files that are browser-ready and usable to enhance forms in Dynamics with custom business logic.


There are many bundlers out there in the wild. This walkthrough uses rollup.js. Experiment with Webpack and Gulp to achieve the same results.

Test your TypeScript files with Xrm tests. Here’s a recent post of mine detailing how Web API calls can be tested using xrm-mock and sinon.js.

Add plugins to rollup.js. How about eslint to lint your code when it’s built, or uglify to minify your build output for production?

Dave Clark IO