Advanced Use of Sass with Vue-Loader

January 29, 2017

As I've mentioned before, I've been using Vue.js a bit lately, and really enjoying it. This weekend, I set out to use Sass with vue-loader, using Webpack 2.2. Getting it working was really simple, just install node-sass and sass-loader, add lang="sass" to your style tag, and everything works.

The problem is, when your styles get built, they get built into your javascript. This is fine for development, but when you create a "build" of your application for hosting, you want at least one separate CSS file with all of your styles in it. CSS loads in parallel with Javascript, and then can also be cached separate from your scripts. Plus, users don't have to wait for all your scripts to load to get styling on the site.

Setting it up looked simple enough, the vue-loader docs have a section on using pre-processors, and another section talks about extracting CSS, which is exactly what I wanted. However, it wasn't clear how to set up both a pre-processor and the CSS extraction, perhaps because I'm also very new to Webpack. To make matters worse, the site that hosts the Webpack 2 docs was offline, so I couldn't try to make sense of the configuration. I figured the solution was probably a mix of both of the above configurations, and while it took a little trial and error, I did manage to get it working.

I ended up using the extract-text-webpack-plugin package as recommneded in the vue-loader docs. First, I modified the the vue component rule with some advanced loader configuration for sass files.

module: {
  rules: [
    {
      test: /\.vue$/,
      loader: 'vue-loader',
      options: {
        loaders: {
          sass: ExtractTextPlugin.extract({
            loader: 'css-loader!sass-loader?indentedSyntax',
            fallbackLoader: 'vue-style-loader',
          }),
        },
      },
    },
  ],
},

Then, following the extract-text-webpack-plugin docs, I added a plugin to extract the styles out into a file. I used the contenthash to get a unique file every time the content changed, which is useful for cache busting. This just required one new rule in the plugins configuration.

plugins: [
  new ExtractTextPlugin(path.join('css', 'style.[contenthash].css')),
]

Now, I can add sass markup to my Vue components, even using libraries I've added from npm packages, and it all gets compiled into a single css file. For example, I can install Bulma via npm, and @import it into my own markup.

<style lang="sass">
  @import '~bulma/sass/utilities/_all'
  @import '~bulma/sass/base/_all'
</style>

And when I create the build, I get my uniquely named css file, which changes only as I make style changes. Even better, I can use html-webpack-plugin to automatically inject that markup in the <head> of my built index.html file. Pretty slick.

I started working on a loopback and vue.js boilerplate that now has this feature. When I have it in a state that I'm happy with, I plan to turn all this into a vue-cli template too.

See all 65 posts