How to Tame your Web App - UX and DX

Blog Post created by jpeterson-esristaff Employee on Mar 7, 2017
First, the links:

Crowdsource Reporter Repo:

My Migration Repo:


Where we are

This is the sixth part in a seven-part blog series called How to Tame your Web App. Here’s where we are:

  1. The Plan
  2. ES6 and Modern Modules
  3. Module Bundling 101
  4. Module Bundling 201 - Optimization
  5. Linting
  6. UX and DX: The Best of Both Worlds (you are here)
  7. Legacy Support - coming soon


Today's place: Rotterdam

Header: De Kuip, home of Feyenoord Rotterdam



Erasmusbrug, Rotterdam


The Plan

Optimize for both Developer Experience and User Experience. We'll create a second webpack config file so we can target our development environment and the production environment separately.


The Reason

We want a great developer experience as well as the ability to deploy our code in the most optimized way possible. These two things are not always possible without branching the build pipeline.


The Commits


Webpack offers a few options for developer tooling. We’ll use webpack-dev-server, but you can read this doc for an explanation of the other options. We’ll also use HtmlWebpackPlugin to send our index.html through Webpack’s bundling process.


> npm install webpack-dev-server html-webpack-plugin –-save-dev


All we need to do with the dev-server for now is add a new npm script to run our app in development mode:

"start": "webpack-dev-server --open"


Running webpack-dev-server is now as easy as:


> npm start


Next we’ll use HtmlWebpackPlugin in our config file:

new HtmlWebpackPlugin({
template: 'index.html',
inject: false


We can do many more powerful things with this plugin by injecting templated values into our index.html file at build time – but we’ll just use it to copy the file into our output folder for now.


Important note – we need to specify inject: false to tell Webpack not to inject a script tag into our html (as it does by default). We need to do this because we have to invoke our code using a require() statement to placate the Dojo loader.


Markthal (Rotterdam)

The awesome Markthal in Rotterdam


At this point we’ll duplicate our webpack.config.js and create a webpack.production.config.js, then modify our build script to reference this new config file:

"build": "webpack -p --config webpack.production.config.js"


Notice I slipped that -p into our build script. This is the production flag which tells webpack to run its awesome optimization routine on all our code and assets.


From this point on, we’ll be managing two webpack configs. It is highly recommended that you take advantage of the fact that these config files are simple CommonJS modules which can be composed rather easily. For this exercise though, I’m going to keep them separate.


The final curveball Dojo threw at me was internationalization (i18n) support. Crowdsource Reporter has great i18n support via the dojo/i18n! Dojo Loader plugin. I fought with this for a bit before realizing I needed to just let it do its thing. Handling i18n files in the Webpack build would mean packaging up every language together for download by every user – not ideal. Instead, I used a Webpack plugin called CopyWebpackPlugin to just pipe those files as-is into our /dist folder and let Dojo handle them at runtime.


I only added the CopyWebpackPlugin to my production config file (since the dev server runs at the root of my project and can directly access the /nls folder):

new CopyWebpackPlugin([{ from: 'js/nls', to: 'js/nls' }])


Montevideo (Rotterdam)

Montevideo, Rotterdam


So now we have two fully functioning environments for our app. To test that your prod build is working, run your build, then copy the /dist folder into an unrelated web server location and see if it runs. If you run into issues, it’s likely that you forgot to output some files/folders into your /dist folder.


I know I didn't talk much about why we want to use webpack-dev-server... I'll just point you to the doc page and have you check out things like hot module replacement and stats.


Alright, onto the last post! Legacy Support - coming soon (no, the irony is not lost on me).