DEV Community

Edielton Dantas
Edielton Dantas

Posted on • Edited on

Transpiling React with Babel

In part one of this series, we learned the bare minimum configuration and setup to build our very first React component and have it rendered into the browser.

In part two we will discuss a concept very useful in webpack called Loaders and why they are so important.

Note: If you inspect the webpack.config.js file from the previous example, you'll see that we used a loader to transform .jsx source code into regular javascript code.

Loaders

According to the docs:

Loaders are transformations that are applied to the source code of a module. They allow you to pre-process files as you import or β€œload” them.

As of now, we configured webpack to only transform .jsx files. Let's see what happens when we try to import a .css file from our index.js file.

$ touch src/App.css
$ open src/App.css
Enter fullscreen mode Exit fullscreen mode
body {
    background: rgb(246, 174, 45);
    color: #1f2d3d;
}
Enter fullscreen mode Exit fullscreen mode

Head on to our index.js file and import the newly created css file:

$ open src/index.js
Enter fullscreen mode Exit fullscreen mode
import React from 'react'
import { render } from 'react-dom'

import './App.css'

const App = () => (
  <div>Hello world!</div>
)

render(
  <App />,
  document.getElementById('app')
)
Enter fullscreen mode Exit fullscreen mode

This time, instead of executing webpack manually by running yarn webpack, let us create a more semantic command in our package.json file. We can also leverage webpack to automatically build our project whenever a file is changed, by adding the --watch flag:

$ open package.json
Enter fullscreen mode Exit fullscreen mode
{
  ...
  "scripts": {
    "build": "webpack",
    "build:watch": "webpack --watch"
  },
  ...
 }
Enter fullscreen mode Exit fullscreen mode

Now if you run $ yarn build you will get a pretty self-explanatory error:

ERROR: You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file

To fix this, we'll need first to install two packages: css-loader and style-loader.

$ yarn add css-loader style-loader -D
Enter fullscreen mode Exit fullscreen mode
  • css-loader: Allows css files to be imported as regular javascript modules;
  • style-loader: Inserts the imported css into DOM's header tag;
$ open ./webpack.config.js
Enter fullscreen mode Exit fullscreen mode
module.exports = {
  resolve: {
    extensions: ['.jsx', '.js']
  },
  module: {
    rules: [
      {
        test: /\.(jsx|js)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              '@babel/preset-react'
            ]
          }
        }
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode
  • test: A regular expression used to match the loader against the file you are interested in;
  • use: The name(s) of the loader(s) that will load/transform the target file.

Note: Your loaders will be evaluated from right to left. In the example above css-loader will be executed first, and style-loader after.

If you refresh the page there should be no errors this time. Also, when the page opens with our rendered React component, try inspecting the header tag. You should see that whatever styles we put on App.css will be injected into the <style /> tag.

Adding support to .scss files

To support .scss files you just need to install sass-loader along with node-sass and create a configuration similar to that of our .css loader.

$ yarn add sass-loader node-sass -D
Enter fullscreen mode Exit fullscreen mode
  • sass-loader: Loads a Sass/SCSS file and compiles it to CSS;
  • node-sass: Allows .scss compilation to .css and is required by sass-loader

Note: Because we are installing new packages and webpack is watching the files, it may crash. It's better to always run yarn build whenever you install something new.

Add a new rule to allow webpack to load .scss files:

$ open webpack.config.js
Enter fullscreen mode Exit fullscreen mode
module.exports = {
  resolve: {
    extensions: ['.jsx', '.js']
  },
  module: {
    rules: [
      // Content ommited for better readability...
      {
        test: /\.scss$/,
        use: ['style-loader', 'css-loader', 'sass-loader']
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode
# Rename the .css extension to .scss
$ mv src/App.css src/App.scss
Enter fullscreen mode Exit fullscreen mode

Fix the import from index.js:

$ open src/index.js
Enter fullscreen mode Exit fullscreen mode
import React from 'react'
import { render } from 'react-dom'

import './App.scss'

const App = () => (
  <div>Hello world!</div>
)

render(
  <App />,
  document.getElementById('app')
)
Enter fullscreen mode Exit fullscreen mode

Great job! Now your project supports .scss files!

Loading assets

Working with images, or any other kind of file extensions for that matter is fairly straightforward. We'll be using file-loader to emit the imported file into the output folder.

Note: You could also inline your assets as data uri or import them as string, but that requires other loaders such as url-loader or raw-loader.

$ yarn add file-loader -D
$ open webpack.config.js
Enter fullscreen mode Exit fullscreen mode
module.exports = {
  resolve: {
    extensions: ['.jsx', '.js']
  },
  module: {
    rules: [
      // Content omitted for better readability...
      {
        test: /\.(jpe?g|png|svg)$/,
        use: 'file-loader'
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

For testing purposes, let's add an image to our src folder and have it imported from our ./src/App.scss.

Note: There's a sample image named "let-there-be-sun.png" in the repo. I'm using it in this example.

$ open src/App.scss
Enter fullscreen mode Exit fullscreen mode
body {
    background-image: url(./let-there-be-sun.png);
    color: #1f2d3d;
}
Enter fullscreen mode Exit fullscreen mode

If you refresh the browser you will notice that the background image is loaded as expected.

Note: With this configuration you can even import images from .jsx files!

Loading Fonts

Depending on your needs, you might want to load fonts hosted on external servers (CDN) or those hosted on your own (i.e, woff2, woff, eot...).

CDN

Say you want to load the free version of LinearIcons font in your project. You could accomplish this task by simply importing it in your .css file without additional configuration.

$ open src/App.scss
Enter fullscreen mode Exit fullscreen mode
@import url(https://cdn.linearicons.com/free/1.0.0/icon-font.min.css);

body {
    background-image: url(./let-there-be-sun.png);
    color: #1f2d3d;
}
Enter fullscreen mode Exit fullscreen mode

Local assets

On the other hand, you might want to use the version you have installed on your project.

Note: You can find the fonts for this example in the repo.

1) We will start by defining the fonts we want file-loader to load for us:

module.exports = {
  resolve: {
    extensions: ['.jsx', '.js']
  },    
  module: {
    rules: [
       // Content omitted for better readability...
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: 'file-loader'
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

2) In your .scss file, configure which fonts you want to load from your local server:

$ open src/App.scss
Enter fullscreen mode Exit fullscreen mode
@font-face {
    font-family: 'Linearicons-Free';    
        src:url('fonts/Linearicons-Free.woff2') format('woff2'),
        url('fonts/Linearicons-Free.woff') format('woff');
    font-weight: normal;
    font-style: normal;
}

.lnr-clock:before {
    content: "\e864";
}

body {
    font-family: "Linearicons-Free";
    background-image: url(./let-there-be-sun.png);
    color: #1f2d3d;
}
Enter fullscreen mode Exit fullscreen mode

3) Use the font in your component:

import React from 'react'
import { render } from 'react-dom'

import './App.scss'

const App = () => <span className='lnr lnr-clock' />

render(
  <App />,
  document.getElementById('app')
)
Enter fullscreen mode Exit fullscreen mode

Conclusion

In this tutorial, we learned that thanks to Loaders, we can import and transform files by simply defining which extensions our loader has to load from.

Up to this point, our project supports compiling .jsx files to regular js, .scss into .css and also loading assets such as images and fonts.

Top comments (5)

Collapse
 
dance2die profile image
Sung M. Kim • Edited

Thanks for the series, Edielton~

Can I request to add series front matter?

because adding series would combine articles (and look like this - dev.to/bettercodingacademy/i-m-a-p... below the title)

You can refer to the Editor Guideline :)

Collapse
 
th3n0m4d profile image
Edielton Dantas

Thanks for pointing that out Sung! By the way, happy new year =)

I added the series front matter. Let me know if this looks good and if not, any ideas will be highly appreciated =)

Collapse
 
dance2die profile image
Sung M. Kim

Happy New Year to you too, Edielton~

I am not seeing the series header for some reason.

Something like this is what I was expecting but don't see it...
demo

Thread Thread
 
th3n0m4d profile image
Edielton Dantas

You totally right! Sorry about that... I did for the second but not the first post. Fixed =)

Thread Thread
 
dance2die profile image
Sung M. Kim

Looks great, Edielton.
Thank you for taking time to update the post :)