Sonoma Partners Microsoft CRM and Salesforce Blog

Building CRM Web Resources with React

Web Resource Development

Microsoft Dynamics CRM has allowed us to develop and host custom user interfaces as Web Resources since CRM 2011.  Since then, the web has exploded with JavaScript frameworks.  In addition, browsers have started to converge on standards both in JavaScript object support and CSS.  In short, its a great time to be building custom user interfaces on top of Microsoft Dynamics CRM.

Today we’ll be working with React, an emerging favorite in the JavaScript world.  React’s key benefits are its fast rendering time and its support of JSX.  React is able to render changes to the HTML DOM quickly, because all rendering is first done to JavaScript objects, which are then compared to the previously generated HTML DOM for changes.  Then, only those changes are applied to the DOM.  While this may sound like a lot of extra work, typically changes to the DOM are the most costly when it comes to performance.  JSX is a syntax that combines JavaScript and an XML-like language and allows you to develop complex user interfaces succinctly.  JSX is not required to use React, but most people typically use it when building React applications.

The Sample Application

To demonstrate these benefits, we’ll build a simple dashboard component that displays a list of the top 10 most recently created cases.  We’ll have the web resource querying for new cases every 10 seconds and immediately updating the UI when one is found.

CaseSummary

The files that I will be creating, will have the following structure locally:

CaseSummary/ 
├── index.html 
├── styles.css 
├── app.jsx 
└── components/ 
    ├── CaseSummary.jsx     
    ├── CaseList.jsx 
    └── Case.jsx

However, when we publish them as web resources in CRM, they will be simplified to the following:

demo_/
└── CaseSummary/ 
    ├── index.html 
    ├── styles.css 
    └── app.js

Other than including the publisher prefix folder, the main change is that all of the JSX files have been combined into a single JavaScript file.  We’ll step through how to do this using some command line tools.  There are a few good reasons to “compile” our JSX prior to pushing to CRM:

  1. Performance – We can minify the JavaScript and bundle several frameworks together, making it more efficient for the browser to load the page.
  2. More Performance – JSX is not a concept that browsers understand by default.  By converting it to plain JavaScript at compile time, we can avoid paying the cost of conversion every time the page is loaded.
  3. Browse Compatibility – We can write our code using all of the features available in the latest version of JavaScript and use the compiler to fill in the gaps for any older browsers that might not support these language features yet.
  4. Maintainability – Separating our app into smaller components makes the code easier to manager.  As you build more advanced custom UI, the component list will grow past what I am showing here.  By merging multiple files together, no matter how many JSX files we add to the project we just need to push the single app.js file to the CRM server when we are ready.
  5. Module Support – Many JavaScript components and libraries are distributed today as modules.  By compiling ahead of time we can reference modules by name and still just deploy them via our single app.js file.

Exploring the Source Code

The full source code for the example can be found at https://github.com/sonomapartners/web-resources-with-react, but we will explore the key files here to add some context.

index.html

This file is fairly simple.  It includes a reference to CRM’s ClientGlobalContext, the compiled app.js and our style sheet.  The body consists solely of a div to contain the generated UI.

app.jsx

Now things start to get more interesting.  We start by importing a few modules.  babel-polyfill will fill in some browser gaps.  In our case it defines the Promise object for browsers that don’t have a native version (Internet Explorer).  The last three imports will add React and our top level CaseSummary component.  Finally we register an onload event handler to render our UI into the container div.

components/CaseSummary.jsx

CaseSummary is our top level component and is also taking care of our call to the CRM Web API.  This is also our first look at creating a component in React, so let’s take a look at each function.  React.createClass will take the object passed in and wrap it in a class definition.  Of the five functions shown here, four of them are predefined by React as component lifecycle methods: getInitialState, componentDidMount, componentWillUnmount and rendergetInitialState is called when an instance of the component is created and should return an object representing the starting point of this.state for the component.  componentDidMount and componentWillUnmount are called when the instance is bound to and unbound from the DOM elements respectively.  We use the mounting methods to set and clear a timer, which calls the loadCases helper method.  Finally, render is called each time the state changes and a potential DOM change is needed.  We also have an additional method, loadCases where we use the fetch API to make a REST call.  The call to this.setState will trigger a render whenever cases are loaded.  We definitely could have made this component smarter by only pulling case changes, but this version demonstrates the power of React by having almost no impact on performance even though it loads the 10 most recent cases every 10 seconds.

components/CaseList.jsx

By comparison CaseList.jsx is pretty straight forward.  There are two interesting parts worth pointing out.  The use of this.props.cases is possible because CaseSummary.jsx set a property on the CaseList like this: <CaseList cases={this.state.cases} />.  Also, it is important to notice the use of the key attribute on each Case.  Whenever you generate a collection of child elements, each one should get a value for the key attribute that can be used when React is comparing the Virtual DOM to the actual DOM.

components/Case.jsx

The simplest of the components, Case.jsx outputs some properties of the case with some simple HTML structure.

Compiling the Code

We’re going to start with using NodeJS to install both development tools and runtime components that we need.  It is important to note that we’re using NodeJS as a development tool, but it isn’t being used after the code is deployed to CRM.  We’ll start by creating a package.json file in the same folder that holds our index.html file.

package.json

After installing NodeJS, you can open a command prompt and run “npm install” from the folder with package.json in it.  This will download the packages specified in package.json to a local node_modules folder.  At a high level, here are what the various packages do:

  • webpack, babel-*, imports-loader, and exports-loader: our “compiler” that will process the various project files and produce the app.js file.
  • webpack-merge and webpack-validator: used to help manipulate and validate the webpack.config.js (we will discuss this file next).
  • webpack-dev-server: a lightweight HTTP server that can detect changes to the source files and compile on the fly.  Very useful during development.
  • react and react-dom: The packages for React.
  • babel-polyfill and whatwg-fetch: They are bringing older browsers up to speed.  In our case we are using them for the Fetch API (no relation to Fetch XML) and the Promise object.

The scripts defined in the package.json are runnable by typing npm run build or npm run start from the command prompt.  The prior will run and produce our app.js file and the latter will start up the previously mentioned webpack-dev-server.  Prior to running either of them though, we need to finish configuring webpack. This requires one last config file to be placed in the same folder as package.json. It is named webpack.config.js

webpack.config.js

As the file name implies, webpack.config.js is the configuration file for webpack.  Ultimately it should export a configuration object which can define multiple entries.  In our case we have a single entry that monitors app.jsx (and its dependent files) and outputs app.js.  We use the webpack.ProvidePlugin plugin to inject whatwg-fetch for browsers that lack their own fetch implementation.  We also define that webpack should use the babel-loader for any .jsx or .js files it encounters and needs to load.  The webpack-merge module allows us to conditionally modify the configuration.  In our case we are setting the NODE_ENV environment variable to “production” for a full build and turning on JavaScript minification.  Finally we use the webpack-validator to make sure that the resulting configuration is a valid.

Deploying and Continuing Development

At this point all of the files should be set up.  To deploy the code, you would run npm run build and then deploy index.html, app.js, and styles.css as web resources to CRM. 

If it becomes tedious to keep deploying app.js to CRM as you make small changes, you can set up an AutoResponder rule in Fiddler to point at the webpack-dev-server.  Once this rule is in place, when the browser requests files like index.html and app.js from the right subfolder of the CRM server, Fiddler will intercept the request and provide the response from wepack-dev-server instead.  This way you can just save your local JSX files and hit refresh in the browser as you are developing.  Of course you need to be sure that you have started wepack-dev-server by running npm run start from the command line.  I have included an example for the rule I set up for this demo below:

fiddlerAutoResponder

With that you should be set to start building your own CRM Web Resources using React!

Topics: Microsoft Dynamics CRM Microsoft Dynamics CRM 2011 Microsoft Dynamics CRM 2013 Microsoft Dynamics CRM 2015 Microsoft Dynamics CRM 2016 Microsoft Dynamics CRM Online