Aurelia + Webpack + PostCSS + CSSnext + CSS Modules + pushState + IIS, Oh My!

As with any advancement of a fledgling framework, Aurelia’s path has been laid using JSPM and SystemJS as a way of grabbing assets and importing them into the browser on demand.

Webpack has been around a while, but its availability as an option to be used with Aurelia instead of SystemJS has been my introduction to it.

So now, I’m pushing forward using Webpack and NPM because of a few different opportunities it presents:

  1. Webpack seems to do a much better (and, ultimately, less complicated) job of compiling, concatenating, minifying, and bundling all the .html, .js., and .css into a neat, tidy package ready to upload to your production server. It can be done with JSPM, but it’s not nearly as simple.
  2. Webpack looks to have some really great hooks into the bleeding-edge of CSS — namely PostCSS (a CSS processor —sort of like SASS on steroids) and CSS Modules (a new methodology for making CSS easier to manage in a componentized site/app).

Hurdle #1 — Making pushState work in production

One of the biggest hurdles I ran into was the fact that we are using IIS (Azure) as our production host, and utilizing pushState for lovely extension-less URLs works just fine when developing on the local machine using:

module.exports = {
devServer: {
host: ‘localhost’,
port: 3000,
historyApiFallback: {
index: ‘/’
}

},
...

That historyApiFallback is the key component to making pushState work when testing locally, but there’s no such way to use this in production on IIS, so I needed to use a web.config to tell IIS to do something similar.

Our web.config has a rewrite rule that makes this happen:

<rule name=”pushState” stopProcessing=”true”>
<match url=”.*” />
<conditions logicalGrouping=”MatchAll”>
<add input=”{REQUEST_FILENAME}” matchType=”IsFile” negate=”true” />
<add input=”{REQUEST_FILENAME}” matchType=”IsDirectory” negate=”true” />
</conditions>
<action type=”Rewrite” url=”/” />
</rule>

BUT… it didn’t work.

And I looked all over the web for the answer. Nothing. No one seemingly had ever tried to run a webpack production dist folder on IIS/Azure. So here we are.

Then after much Googling™ and StackOverflowing™, I stumbled upon a line that you can add to the webpack.prod.config.js called ‘publicpath’.

This turned out to be the essential component to making things work on production. Here’s the magic line:

module.exports = {
output: {
path: path.join(__dirname, 'dist'),
filename: '[name]' + outputFileTemplateSuffix + '.js',
chunkFilename: '[id]' + outputFileTemplateSuffix + '.js',
publicPath: '/'
},

That one line in the config made all the difference! Stuff like this is maddening to deal with as a front-end developer, but hopefully my frustration ends in your aha moment after having read this!

Hurdle #2 — Getting PostCSS, CSSnext, and CSS Modules to work

I haven’t beaten this one yet, but I’m getting close.

This line in the webpack.config.js (and will also live in webpack.prod.config.js) is close, but I’m still fighting something.

{ test: /\.css?$/, loader: ‘style-loader!css-loader?&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss-loader’ }

What’s it doing? Good question!

In webpack, the loader goes right to left (for some inane reason), so the css gets processed by the PostCSS module first (which applies whatever PostCSS transforms you want to your source .css files), then gets a local alias before getting pushed through CSS Modules and hashed (webpack is served a nice .json file mapping all the exclusively scoped CSS files back to something the loader understands), then finally getting loaded into webpack dynamically.

I think.

There’s also the matter of making sure all the styles are bound accordingly in Aurelia using something like

class.one-time="styles.myWidget"

instead of just

class="myWidget"

and then figuring out whether to <require> them or import them in my Aurelia viewmodels… It’s all quite overwhelming and confusing, but I’m forging ahead.

I’ll have to follow up with another post if I am ultimately able to get it all playing together nicely.

Wish me luck!

Like what you read? Give Nathan Chase a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.