Using Sass with Create React App V1 (Without Ejecting)

Originally published 6.9.17 — Last updated 10.2.18

Final Update:

Create React App 2.0 has officially been released. It includes Sass and CSS Modules out of the box. Check it out here:

https://reactjs.org/blog/2018/10/01/create-react-app-v2.html

Introduction

If you’ve been using React for any length of time you’re probably well aware of the Create React App project. If you’re not familiar, Create React App (CRA) provides a handy CLI for spinning up a boilerplate React app. By typing create-react-app my-app you can have a bootstrapped app running in a couple minutes. One thing you can’t do easily, is change the configuration of CRA. That is by design. Essentially the team has decided on a configuration they like and bundled it all together. The underlying config files aren’t exposed until you run yarn run eject to eject the config. Some folks love this, some do not. Naturally, on the internet, there are opinions. Personally I really like being able to quickly spin up an app without spending a bunch of time setting up Webpack the same way, every time, or customizing a folder structure etc.

The one area that some folks, myself included, seem to struggle with is that CRA doesn’t ship with any CSS tools. This is also by design. My assumption is that the team behind CRA didn’t want to play favorites or build for every CSS tool: (Sass, Less, etc.). So it’s up to the user to add them in.

You can run the eject script to get access to the Webpack config, and add in Sass loaders, but once you eject you can never go back. This means you could, potentially, lose out on painless upgrades to CRA in the future.

Other options?

Sass is a preprocessor that is taking our .scss files and compiling them to .css . Sass also lets you --watch a folder for changes and compile your styles on the fly to .css . This gives us an option for using Sass with CRA. We’ll configure Sass to watch our scss folder and export css files that we’ll import in our CRA. Essentially CRA will never know that we’re using Sass at all.

Getting Started:

UPDATE:

I’ve created an updated demo repo with CRA 1.5.2 running React 16. It can be found here.

To get started, we’ll need to install Sass and then make some adjustments to the default file structure.

Sass is a Ruby gem so you’ll need to install Ruby if you haven’t already. Ruby comes installed by default on Mac and (I believe) some Linux distros. If you’re running Windows, you can use Ruby Installer. To install Sass you can run: gem install sass from your terminal.

Don’t want to install Ruby?

A few folks have pointed out that it is not required to install Ruby to get Sass running. You have options like node-sass, and the CRA-Readme suggests using node-sass-chokidar. The method I’m outlining below is what is suggested in the Sass docs. When I started playing around with adding Sass to CRA it wasn’t documented in the Readme and I hadn’t gone back to revisit the docs recently.

Update:

I’ve added node-sass support to the demo repo. Simply check out or fork the node-sass branch. More info about node-sass is available in the readme on the demo repo.

File structure changes:

#new-folder: src/styles

#new-folder: src/styles/css

#new-folder: src/styles/scss

#rename/move index.css: src/styles/scss/index.scss

#rename & move App.css: src/styles/scss/App.scss

Our /src folder should now look like this:

Next we’ll update our src/index.js file to import index.css from the correct location. We need to change the line import './index.css' to import './styles/css/index.css' Our index.js file should now look like:

We can also remove the import ‘./App.css' line from the App.js file. Our App.js file should now look like:

Note: We don’t currently have an index.css file, we’ll get to that in a moment.

Let’s update the index.scss file. By default it has a small block of body styling. I prefer to move that into the App.scss file, but you could create a Body.scss file and move it there if you’d rather. These are the default styles that ship with CRA, and you’ll likely overwrite them later anyways. Our index.scss file only needs to import our other Sass partials. After moving the body style block to another file, our index.scss file should only have @import ‘App’ and @import 'Body' if you opted to create that file.

Our index.scss file

We’re going to use the Sass watch mode to keep an eye on our scss folder zand have it compile our stylesheets to the css folder for us. To do that, we’ll add a script to the package.json file.

"sass" : "sass --watch src/styles/scss:src/styles/css"

This tells Sass to watch the scss folder and compile output to the css folder. Now we simply open a 2nd tab in our terminal of choice and yarn run sass to start watching/compiling our scss to css.

That’s all we need to get started! To fire up your app you’ll need to open a couple terminal processes. In one you’ll run yarn start to start the dev server and in another you’ll run yarn run sass to start Sass in watch mode.

Disclaimers:

2 terminal processes?! Yeah, I know, it’s not awesome that this configuration means you’ll have to have 2 processes running in the terminal while you’re developing. You’ll need the dev server along with the sass --watch process. I’ve not found a good way around this. I’ve seen ways to automate opening separate processes but it’s all dependent on the terminal environment you’re in. I’ve not found anything universal.

The other bad part: At some point, you’re going to forget to start up the Sass process. Then you’re going to pull your hair out and probably say some choice words while you try to figure out why the changes you’re making aren’t being reflected in the browser. Just know that it’ll happen.

Moving on!

The first time we run our new Sass process we’ll get a bunch of new files in our css folder:

src/styles/css/App.css

src/styles/css/App.css.map

src/styles/css/Body.css

src/styles/css/Body.css.map

src/styles/css/index.css

src/styles/css/index.css.map

The good news is that we never have to look inside the css folder and therefore we don’t have to care that there are so many files being created. The other good news is that Sass is smart enough to recognize changes and build new files as needed so even if you make a bunch of new files and changes before running the sass script, once you do, it’ll output all your new css files for you.

One last step I would recommend: add .sass-cache to your .gitignore file. Sass uses local cache files to track your changes, and you probably don’t want those in your repo.

That’s it! If you run yarn start now you should have the default CRA screen showing and looking just as it should. If you want to double-check that your Sass files are indeed being compiled properly, be sure to run yarn run sass and then maybe add a background-color to the body.

A note about building for production/deployment:

Because we are using Sass to transpile our scss files to css files, CRA is completely unaware that we’re even writing scss. Using these methods will have no impact to the default build and deployment process of a CRA app. One thing I’ve done, on more than one occasion, is forget to transpile my stylesheets before running a new build. This is annoying. To get around this, I suggest adding another script to your package.json that will do a one-time build of your styles:

“sass:build”: “sass — update src/styles/scss:src/styles/css”,

I would then suggest updating the build script to:

”build”: “yarn sass:build && react-scripts build”,

This gives you one less thing to think about. Your stylesheets will automatically transpile before the build process happens.

Final Thoughts:

For just a little bit of extra configuration, we get to have our cake and eat it too. We get to quickly build React apps using CRA and we get to enjoy the styling benefits that come with using Sass. Let me know if you found this to be useful. Thanks for reading!