Categories
Elixir

Understanding Elixir Macros

Some time ago when I was studying Elixir for the first time, I step out with a chapter in the documentation related with something called Macros. When I looked into this, some complicated terms started to show up and then I got scared. Things like:

  • Metaprogramming
  • Abstract Syntax Three
  • Elixir AST
  • AST Literals
  • quote & unquote

In order to understand Macros we should have an idea of what these new technical terms means, and how they are related with Elixir.

Metaprogramming

Almost all blogs, books or videos will say something like Code that writes codebut I really liked the explanation that @iamvery gave in one of his talks.

Metaprogramming it’s just programming …

Programming is performing some work in some data …

Data are quantities on which operations are performed.

Jay Hayes

So metaprogramming is like programming regularly. However the data where we perform operations can be whatever we want and not just the data structures that the language offers us. For example:

2 + 3

We know that ‘2 and ‘3 are data and ‘+’ is the operation. However in metaprogramming ‘+’ is considered data too. We can manipulate that, have access to it and do whatever we want with it.

Abstract Syntax Three

When we make programs, the compiler in charge of transforming our code into bytecode needs to know the syntactic structure of our program, so the instructions can be performed as we defined. An abstract syntax three is that representation. Let see some really simple examples:

2 + 3
AST (Abstract Syntax Tree)
2 + 3 == 5
AST (Abstract Syntax Tree)

Elixir AST

Elixir has it’s own way to represent AST, this is by converting almost everything to a three element tuple, just to recap a little bit on this, the Elixir compiler has some steps before it produces the .beam file, this is a really brief schema:

Elixir compiler phases

When using macros we are scripting and producing Elixir AST, we won’t touch the Expand Macros and Erlang AST. But, it’s good to know that those steps are there.

AST Literals

Basic data structures like atom, integer, float, string, list and two element tuples are considered literals. It means that when the compiler process that, they are the the same in AST form. Example:

AST Literal

3 element tuples

In the other hand, everything else is transformed to a three element tuple which has this basic structure:

If it is a variable:

First element is the variable name, second item is the metadata that it’s needed in order to this variable to exist (normally empty), and the last item is the context.

Variable to Elixir AST

If it is a call

First element is the function name, second is just metadata (normally you won’t care about this), and last item are the arguments.

Function call to Elixir AST

quote

Probably at this point you are thinking on quitting this article, AST are complicated nested structures. However, there are some helpful functions (actually they are Macros too) that can help us manage all this structures.

May be if you see an example of quote, you can understand what it is and how to use it:

iex> quote do: 2 + 3
{:+, [context: Elixir, import: Kernel], [2, 3]}

we can use it inline or multiline as any other function or macro.

iex(1)> quote do
...(2)>   if 2 + 3 == 5 do
...(3)>     "this is true"
...(4)>   else
...(5)>     "this is false"
...(6)>   end
...(7)> end
{:if, [context: Elixir, import: Kernel],
 [{:==, [context: Elixir, import: Kernel],
   [{:+, [context: Elixir, import: Kernel], [2, 3]}, 5]},
  [do: "this is true", else: "this is false"]]}

unquote

With unquote, the first thing that went to my mind was:

iex(1)> unquote do: {:+, [context: Elixir, import: Kernel], [2, 3]}
"2 + 3"

but that is not how unquote works, let’s put it this way.

quote and unquote are like “interpolated strings”

Imagine the next code:

iex(1)> name = "George"
"George"
iex(2)> "Hello name"
"Hello name"

We need to evaluate the variable namewith strings we use #{}

iex(1)> name = "George"
"George"
iex(2)> "Hello #{name}"
"Hello George"

With quoted expressions we use unquote.

iex(1)> number = 3
iex(2)> quote do: 2 + unquote(number)
{:+, [context: Elixir, import: Kernel], [2, 3]}

Macros

Finally, the main idea of this article is to show you what Macros are but as I said in the beginning, there are some other concepts that we needed to understand in order to write Macros.

Let’s define our first Macro:

defmodule MyMacros do
  defmacro nice_print({:+, _meta, [lhs, rhs]}) do
    quote do
      IO.puts """
        #{unquote(lhs)}
      + #{unquote(rhs)}
        --
        #{unquote(lhs+rhs)}
      """
    end
  end
end

See how immediately we use quote, that’s because macros always return an Elixir AST, if you don’t you will get an error.

Let’s use that Macro:

iex(1)> require MyMacros
[MyMacros]
iex(2)> MyMacros.nice_print 2 + 3
  2
+ 3
  --
  5

Notice that our macro receives a three element tuple, that’s the Elixir AST of 2 + 3 in this case and not the evaluation of that expression which is 5.
quote & unquote are not the only tools that we have in order to manage Macros.

Macro.to_string

iex(1)> expression = quote do: 2 + 3
{:+, [context: Elixir, import: Kernel], [2, 3]}
iex(2)> Macro.to_string(expression)
“2 + 3”

Code.eval_quoted

iex(1)> expression = quote do: 2 + 3
{:+, [context: Elixir, import: Kernel], [2, 3]}
iex(2)> Code.eval_quoted(expression)
{5, []}

Pros & Cons

In Chris McCord book “Metaprogramming Elixir” he has a section called Macro Rules, and his first rule is:

Don’t Write Macros

Chris McCord

But why?, they are powerful and amazing, aren’t it?… I guess that’s the first reason, they are so powerful that you can get addicted to overuse them and by overuse them you code can look ugly and hard to read.

In one of the Jesse Anderson talks he show one really interesting quote:

Code is read many more times than it is written, which means that the ultimate cost of code is in its reading.

Jesse Anderson

And for me that’s true, we don’t have to lose the idea to writing code beautiful and easy to read.

The benefits of using Macros are the metaprogramming part, we can do things that with normal functions we can’t, arguments in functions are evaluated before we can even use them in our function body, with Macros this is not the case since we only receive the Elixir AST version of our expressions.

Macros are also good for hiding boilerplate, imagine that you had to write this

case(true) do
  x when x in [false, nil] ->
    false
  _ ->
    true
end

instead of this

if true do
  true
else
  false
end

o, with macros we have this possibility of hiding code by generating it inside the macro.

Hopefully you get the idea of what Macros are and how to use them, for me this topic is really awesome since this is the first time I do metaprogramming. Elixir make it easy and maintainable to read. If you have any question here is my twitter @jorgechavz. Thanks!

Resources

Macros don’t stop here, there is so many information out there related with this topic, I will leave some links here that really helped me to understand this interesting topic.

The minimum knowledge you need to start Metaprogramming in Elixir
https://dockyard.com/blog/2016/08/16/the-minumum-knowledge-you-need-to-start-metaprogramming-in-elixir

Don’t Write Macros But Do Learn How They Work — Jesse Anderson https://www.youtube.com/watch?v=Bo48sQDb-hk

Write less, do more (and have fun!) with elixir macros
Video:
 https://www.youtube.com/watch?v=mkoYqXdXl5Y
Slides: http://slides.com/chrismccord/elixir-macros#/

Understanding Elixir Macros
http://theerlangelist.com/article/macros_1

Categories
Cryptography

What’s the HMAC algorithm?

In my previous post I talked about something called String Hashing which is basically a function that generates a hash string based on a binary string.

In today post we will talk about on really useful algorithm called HMAC (Hash-based Message Authentication Code) which provides a way to generate a secure hash based on a string. Same as the hash function we wrote recently.

Why do we use something like HMAC?

On the internet we normally send messages between parties. The issue here is that, not being able to read the message doesn’t mean that you can’t interview with the meaning of the message. Anybody could interfiere with this communication and change the message between the parties.

This is when encrypted messages come into play and HMAC attempt protect this communication within the cipher and basically garantes that the messages hasn’t been changed.

In cryptography, a cipher (or cypher) is an algorithm for performing encryption or decryption.

One bit at the time

Let’s try to understand how a normal hashing function work.

What we normally do is to XOR every bit of our message against out secret binary which will produce our final hash.

"my message" XOR "myrandomstring" = "myhash"

The main issue is that a middle man could just reverse this process and see the actual message in the cipher.

HMAC allows us to encrypt and sign the message with a Secret key and then only decrypt it using the same key. So, our middle man cannot see the message while is being sent.

This is an easy example of what would happen if a middle man tries to tweak our hash

If the hash is valid, then the payload can be verified

Categories
Computer Science

String Hashing

String hashing is a technique for converting a string into a hash number. Why do we need that? Sometimes we need to compare large strings, but instead comparing the string we can compare the generated hash.

Imagine that you had to compare the next two string:

const A = "imagine that this is a string of 200 characters"

const B = "imagine that this is a string of 200 characterz"

Both strings have 200 characters. A brute force way would be to compare each character and see if they match. Something like:

const A = "imagine that this is a string of 200 characters"

const B = "imagine that this is a string of 200 characterz"

function equal(A, B) {
  let i;
  for(i = 0; i < A.length; i++){
    if (A[i] !== B[i]) {
      return false;
    }
  }
  return true;
}

console.log(equal(A,B));

This isn’t optimal with big strings because of it’s O(min(A, B)) performance.

Of course we could make this O(n) by adding a condition that compares A size and B size. Something like:

function equal(A, B) {
  if (A.lenght !== B.length) return false;
  let i;
  for(i = 0; i < A.length; i++){
    if (A[i] !== B[i]) {
      return false;
    }
  }
  return true;
}

As I said, worst scenario would be O(n), but imagine that we had to compare a really large string.

String Hashing is a technique where we can convert our strings into an Integer which will act as a hash number. Therefore, we will be comparing two hashes hash(A) == hash(B) this will be considered O(1). That’s the best option we can have for comparing two strings.

String Hash Formula

Where p and m are prime numbers, and s[0], s[1], s[2]... are values for each character, in this case the char code.

p: It is a prime number roughly equal to number of different characters used. For example if we are going to calculate the hash for a word that includes only lower case characters of the English alphabet, 31 would be a good number. However, if we will include upper case characters, then 53 is an appropriate option.

m: The bigger this number is, the less chance we have to collide two random strings. this variable should be also a prime number. 10 ^9 + 9 is a common choice.

Lets use this data:

p = 31
m = 1e9 + 9
word = 'apple'

We want to know what’s the hash code for the word apple, so if we add our data to our formula, we would have something like this:

then

then we get the char code:

"a" = 97
"p" = 112
"p" = 112
"l" = 108
"e" = 101

and replace this in the formula:

then we reduce the formula:

Finally

So our final hash for the word apple would be 96604250

I’ll leave you the implementation on JavaScript

function hash(word) {
    var p = 31;
    var m = 1e9 + 9;
    var hash_value = 0;
    for(var i = 0; i < word.length; i++) {
        var letter = word[i];
        var charCode = letter.charCodeAt();
        hash_value = hash_value + (charCode * Math.pow(p, i))
    }
    return hash_value % m;
}

console.log(hash("apple"));

ping me on my twitter @jorgechavz and send me your own implementation.

Categories
Computer Science

Everything you need to know about Binary Search algorithm

This is probably one of the most useful search algorithms you will use when solving computer science problems. I’ll try to explain this search method the best I can.

In computer science, binary search, also known as half-interval search, logarithmic search, or binary chop, is a search algorithm that finds the position of a target value within a sorted array. Binary search compares the target value to the middle element of the array.

Wikipedia

When searching in an array with Binary Search we need to make sure that the array is sorted, you will see why in a moment.

Linear search

Let’s create a really simple scenario, let’s pretend I give you this array:

Then I ask you to find if this array has the number 90. A linear search approach would loop through the array and check if the current item is indeed our target value, in this case the number 90. JavaScript code would look alike this:

const items = [2, 9, 13, 53, 89, 90, 98];

const findElement = search => {
   for(let i = 0; i < items.length; i++) {
      if (items[i] == search) {
         return true;
      }
   }
   return false;
}

console.log(findElement(90));

Worst case scenario would be O(N) because if the element you want to find is the last one, you will loop on the entire array.

This isn’t optimal for a sorted array, binary search time complexity is O(Log N) which is normally a better option when we threat with large data sets.

Binary search approach

For this algorithm we will need 3 pointers:

  • L: Left pointer
  • R: Right pointer
  • M: Middle pointer

Graphically this would look like this:

The algorithm goes like this:

  • Start L pointing to the first element of the array.
  • Start R pointing to the last item.
  • Start a while loop until L <= R.
  • Everything inside this loop will be repeated each time:
    • Start M pointing to the greatest middle value (floor) between L and R.
    • Check if the element in M position is the one you a looking for. If so, return the value.
    • At this point we need to discard one half of the array, basically chop it from the M position. We can decide which side by either converting L = M + 1 or R = M - 1. This will depends on if the element is being pointed by M is greater or lower than our target value.
  • If L <= R the loop will end and it will mean that our target value is not in the array.

Code:

const items = [2, 9, 13, 53, 89, 90, 98];

const searchBinary = (elements, search) => {
  let L = 0;
  const n = elements.length;
  let R = n - 1;

  while(L <= R) {
    let M = Math.floor((L + R) / 2);
    if (elements[M] === search) return M;
    if (elements[M] < search) {
       L = M + 1;
    } else {
      R = M - 1;
    }
  }
  return -1;
}

console.log(searchBinary(items, 89));

Here is a little animation of how this algorithm would work:

Binary Search Animation

Special cases

What if there are duplicated values in our array? The previous approach will still works. However, it will only respond to the question “Is there any 90 in the array?” but what if you need the leftmost value, or the rightmost value. See the next example so you can visualize the issue with our first approach:

Leftmost

See how in the next animation, M starts in target value, but with this approach we will need to wait until L and R crosses, so it doesn’t matter if M is already in one of the target values..

Let’s tweak a little bit our current code so we can find the leftmost element.

const items = [2, 9, 13, 53, 89, 90, 90, 98, 100, 102];

const binarySearchLeftMost = (elements, search) => {
  let L = 0;
  const n = elements.length;
  let R = n;

  while (L < R) {
    M = Math.floor((L + R) / 2);
    if (elements[M] < search) {
      L = M + 1;
    } else {
      R = M;
    }
  }
  return L;
}

console.log(binarySearchLeftMost(items, 90));

Rightmost

Very similar to leftmost, we need need to chop all the right duplicated values right away, then start moving L closer and closer to R.

const items = [2, 9, 13, 53, 89, 90, 90, 98, 100, 102];

const binarySearchRightMost = (elements, search) => {
  let L = 0;
  const n = elements.length;
  let R = n;
  while (L < R) {
    M = Math.floor((L + R) / 2);
    if (elements[M] > search) {
      R = M;
    } else {
      L = M + 1;
    }
  }
  return L;
}

console.log(binarySearchRightMost(items, 90));

Conclusion

Binary search is a great algorithm for searching through a sorted array, we can either verify if an element is within the array, find the first occurrence or the last occurrence.

I hope you enjoyed and learned from this post, if you have any question let ping me on my twitter @jorgechavz

Categories
Computer Science

Big O Notation and Time Complexity

Sometimes, solving a problem isn’t the main issue. Problems can have many different solutions and we as developers need to fine the best solution. But what makes a solution better against others? The answer can vary. However, when we write an algorithm we will try to find the solution that solves the problem faster (time), and the one that uses less resources (memory).

Time complexity

Time complexity represents the time or memory that an algorithm takes in order to complete the solution. The less time an algorithm takes, the happier our end users will be. So, knowing how to write more efficient algorithms is crucial for having better performance in our software.

How do we go about analyzing which solutions are most efficient?

Big O Notation

We can represent time complexity with math, here is when Big O Notation come to play. This notation is just a way of analyzing how long an algorithm with a given number of inputs (n) will take to complete its task.

Here are some simple time complexities with its Big O Notation, feel free to look in Wikipedia for more in-depth definitions:

O(1) Constant time: It doesn’t matter the n number of elements in our data. It will just take a single step for complete the task. A clear example is the access of an item into an array

const fruits = ["apple", "pineapple", "orange"];

// The time for getting the last item will be
// the same than getting the first item.

console.log(fruits[0]);
console.log(fruits[2]);

O(s) Linear runtime: Everything will depends on the value of s. The bigger s is, the more time it will take to resolve the algorithm. A for loop could be an example. The loop will take s number of iterations to get out of the loop.

for(let i; i < s; i++) {
   console.log(i);
}
Representation of a linear time and a constant time.

O(s2) Quadratic time: It is really common on algorithms that involve nested iterations. Giving n size, it will take square n to complete the task.

for(let i; i < s; i++) {
  for(let j; j < s; j++) {
      console.log(`${i}, ${j}`);
  }
}

O(log n) Logarithmic time: Given an input of size n, the number of steps it takes to accomplish the task are decreased by some factor with each step. For example, a binary search could be logarithmic since with every step we reduce the possible solutions in half, so the more iterations the closest we are for completing the task.

Conclusion

Time complexity and Big O Notation will help us to understand an a more visible way if an algorithm is faster or not. Different data structures have different running time. So, understanding this topics will allow us to use data structures that can fit well for a better performance.

We won’t cover all time complexities. However, I hope this short post gives you an idea of what time complexity is and how to represent those running times with math (Big O Notation).

Categories
Frontend React Webpack

How to setup Sass with Webpack

In previous posts we have been configuring Webpack / React / Babel and webpack-dev-server in order to run a very basic application.

I todays article I will teach you how to integrate Sass for doing the styling on the app.

If you are here without reading the previous post, I would recommend you to go ahead and read with, worst case scenario you will learn something new. If you already have your project, keep reading.

Step 1: Dependencies

We will need sass-loader, node-sass, css-loader, and style-loader. First I’ll try to explain how those libraries work, and then we will inject them into our webpack configuration.

Whenever webpack detects a scss or sass file it will process it with several loaders.

First we have scss-loader which it’s only task is to compiles sass into CSS. Internally scss-loader will need a sass compiler obviously, that compiler is written in C++ and is called LibSass. In order to make LibSass to work with our node app, we will need node-sass.

Then, after we have our CSS hot and ready we will pass it to the next player which is our css-loader. This loader will transform our CSS into CommonJS, yes you read it well, CSS into JavaScript. Remember that webpack produces a bundle.js file? Well, at the end of the day, everything needs to be JavaScript. css-loader will help us with that.

Finally, when we import our bundle.js created by webpack, we will need some instructions inside that bundle in order to import those javascript styles into real CSS again. That’s where style-loader will be handy.

Now that you know why we need those dependencies, let’s install them as dev dependencies.

npm install sass-loader css-loader style-loader node-sass --save-dev

Step 2: Loaders

We will user these loaders kind of how we did for .js files. Let’s add a new rule into our webpack configuration file.

# webpack.config.js
...
module: {
    rules: [
      {
        test: /\.s[ac]ss$/,
        exclude: /node_modules/,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader'
        ]
      }
   ]
}
...

The Regex /.s[ac]ss$/ will help us to process any SCSS or SASS files

See how the loaders are in a certain order, that’s important because they act like a pipe in unix. The result of a loader is passed to the next one.

Step 3: SCSS

You can import Sass/SCSS files from any component from now on, let try to import a style file in our Homepage component.

I created a style inside public/stylesheets/styles.scss, our current file structure would be something like this.

index.html
package.json
webpack.config.js
public
-- stylesheets
---- styles.scss
---- index.js

Inside our index.js we created a component called MyComponent. Let’s import our styles.scss file there.

# public/index.js
...

import './stylesheets/styles.scss';

const MyComponent = () => {
  return (
    <div className='wrapper'>
      <h1>This is my first component</h1>
    </div>
  )
};

...

What will happen is, webpack will process the index.js file, and when it tries to resolve all the imports there, a scss file will be detected and all our loaders are going to take care of that.

I added a wrapper class to our main div of MyComponent, let’s add some basic styles just for testing.

# public/stylesheets/styles.scss

$main-color: #2B213A;
$wrapper-width: 90%;

body {
  font-family: 'Helvetica', 'Arial';
}

.wrapper {
  width: $wrapper-width;
  margin: auto;
  background-color: $main-color;
  padding: 20px;
  text-align: center;
  color: white;
}

Let’s run and open our app.

example component react

Vualá, the Scss file were compiled and injected inside our DOM. Open the Dev Tools and see where it was placed.

All the styles were placed inside a <style> tag, but we could use a different injection type like:

  • styleTag
  • singletonStyleTag
  • lazyStyleTag
  • lazySingletonStyleTag
  • linkTag

See the documentation for more details.

We are done for todays post, please if something wasn’t clear, let me know, send me a twitter DM, or leave a comment here in the post.

In the next post I will teach you how to split your CSS into a separate file than our bundle.js.

Categories
Frontend React Webpack

How to configure webpack-dev-server within a React application

In our previous tutorial we made a basic configuration using webpack, babel and React. This post is just a complement of that tutorial.

https://jorgechavez.dev/wordpress/2020/05/02/how-to-configure-react-app-with-webpack-and-babel/

We will setup webpack-dev-server for running our project using a web server. Here is the repository link in case you want to start with the project we made in the previous chapter. https://github.com/echavezNS/basic-react

Step 1: Install library

Let’s install webpack-dev-server in out project with the next command

npm install webpack-dev-server --save
  • –save: will save a reference for our library in our package.json file.

Step 2: Server script

Now, let’s create a new script in our package.json file.

"scripts": {
  "server": "webpack-dev-server"
},

This creates a new script called server which we can run with npm run server in order to run a web server, internally webpack-dev-server will use express for running the server.

ℹ 「wds」: Project is running at http://localhost:8080/
ℹ 「wds」: webpack output is served from /
ℹ 「wds」: Content not from webpack is served from basic-react
ℹ 「wdm」: Hash: b36fd9085373ec73fdf5

We can configure things like, which port do we need for this server to run on, what’s the path where assets will be virtually host, do we want to compress our hosted files (gzip).

All this can be done within the webpack configuration.

// webpack.config.js

{
...
   devServer: {
      port: 3000,
      compress: true
   }
}

All the custom configuration can be found in the documentation of webpack-dev-server.

https://webpack.js.org/configuration/dev-server/

Step 3: Assets

This is probably one of the most complex things I got stuck when I was working with webpack-dev-server for the first time, I didn’t know how assets works on web app. Linking frontend with backend in order to serve the assets can be a complicated at first. Let me try to explain.

When you run an express app, you normally need to indicate where the assets are going to serve from. This is because this is a way to express to track which files can be cached or not. Assets like images, javascript files, css files normally shouldn’t change at all.

As I explain webpack-dev-server uses express. So, through our webpack-dev-server configuration we can tell this express server to serve those assets from a certain route. For example:

  • /assets/bundle.js
  • /public/bundle.js
  • /myassets/bundle.js
  • /other/bundle.js

Normally what you would do is to match this assets route with whatever real server you will end up using in production. Kind of complex right?. You just need to remember that assets will be serve from either a custom route, or by whatever value you have in the output.path key.

Let’s serve our assets from /assets, in order to do that, we need to add a publicPath key inside the output section.

// webpack.config.js
...
output: {
     filename: 'bundle.js',
     publicPath: '/assets',
     path: path.resolve('dist/js')
  },
...

Again, the final bundle.js file will be placed inside the path route (dist/js) but the server will provide all assets from the route /assets.

If you have any questions about this, don’t doubt to hit my twitter and send me a DM, we can chat about it. @jorgechavz

In the next article I will teach you to setup Sass in your webpack configuration.

Thanks

Categories
Frontend React Webpack

How to configure a React application with Webpack & Babel

When working with an old school React app. It is highly possible that Webpack is involved in the base setup.

In this guide I would like to teach you how to setup a basic React app using Webpack and Babel. But first we need to understand some concepts.

  • React
  • Webpack
  • JSX
  • Babel

If you already know all of this, please jump to the Steps section (click here)

React

React is a library that uses components for building UI. All you need to know about React is:

  • It uses Components, and every component normally represents a piece of UI in your app.
  • Components are Functions
<MyComponent /> = function MyComponent() { ... };
  • Those functions must return a React component (normally JSX).
function MyComponent() {
  return React.createElement("h1", null, "Hi");
}
  • JSX it’s an extension of React for writing React elements as HTML (But remember, it’s not HTML).
function MyComponent() {
  return <h1>I'm not HTML, I'm JSX</h1>;
}
  • You can pass properties (props) to components like you do with HTML tags.
<MyComponent name="Jorge" role="frontend" />
  • Components also have a life cycle, you can identify some callbacks when rendering a new component, like componentDidMount, componentWillUnmount, etc.
  • And other crazy things…

Webpack

Normally when creating a web application, you will have a main index.html and then you will import JS/CSS files.

A React app it’s quite similar, but consider that every file that you import needs to be imported it in a certain order for working correctly.

This how normally a web application structure would be:

Webpack will create a bundle of all the imported files that you are using in your app, including JavaScript libraries, CSS, etc.

Webpack is a little bit more complicated than that, you can package more than one bundle, and if you are using things like SCSS, TypeScript, or any other web technology. You can configure webpack to bundle those kind of files too.

Let’s start with some steps for configuring webpack.

Step 1: Basic Scaffold

We will start by generating our main folder directory. Let’s call it basic-react and then enter to this new directory.

mkdir basic-react
cd basic-react

Create a package.json file with the command npm init -y.

  • -y is a parameter that tells npm to create a package.json with the most basic possible information.

This is what we have right now:

basic-react
-- package.json

Step 2: Install dependencies

We will need to install a few dependencies for having everything setup correctly, install this libraries with the --save or --save-dev arguments for saving the references inside the package.json file.

npm install react --save
npm install react-dom --save
npm install path --save
npm install @babel/core --save-dev
npm install @babel/preset-react --save-dev
npm install babel-loader --save-dev
npm install webpack --save-dev
npm install webpack-cli --save-dev

Step 3: Create a script

Let’s take a look of the package.json file. See that we have a script already:

...
"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1"
},
...

The scripts are custom scripts that we create in order to run custom commands inside our app.

You can run your scripts with npm run SCRIPT_NAME

Let’s create one script for generate the bundle we just talked above.

...
"scripts": {
  "build": "webpack"
},
...

We need to configure how webpack is going to bundle our app.

Step 4: Webpack configuration

Every webpack configuration needs three things:

This means that webpack.config.js needs to export those 3 keys:

module.exports = {
  mode: ...
  entry: ...
  output: ...
}
  • mode: webpack can do different stuff depending of the mode environment (production, development, etc). By default webpack uses development if we don’t tell a specific mode.
  • entry: This is the path where webpack will try to search for a root file to start chaining our bundle. By default webpack search into src/index.js
  • output: We need to tell webpack an absolute path of where our bundle is going to be created.

If we don’t specify any configuration to webpack, it will try to look for a an entry file in src/index.js and the final output will be placed in dist/main.js.

Since our basic-react project doesn’t have the src/index.js file, then it will throw the next message:

ERROR in Entry module not found: Error: Can't resolve './src' ...

Try to run npm run build in order to verify that.

In order to configure webpack ourself, we need to create a configuration file.

Let’s create a webpack.config.jsfile in the root directory.

touch webpack.config.js

We should have something like this:

basic-react
-- node_modules
-- package.json
-- webpack.config.js

Let’s create our configuration

const path = require('path');

module.exports = {
  mode: 'development',
  entry: './public/index.js',
  output: {
     filename: 'bundle.js',
     path: path.resolve('dist/js')
  }
}

We are using path library for specifying an absolute path in the output section, this is required.

Let’s create our entry file in public/index.js

mkdir public
cd public
touch index.js
public cd ..

Our current three directory should look something like this:

basic-react
-- public
---- index.js
-- node_modules
-- package.json
-- webpack.config.js

Then run npm run build

> basic-react@1.0.0 build basic-react
> webpack

Hash: 7c0a5056798f58c491e3
Version: webpack 4.43.0
Time: 56ms
Built at: 2020-05-24 02:39:35
    Asset      Size  Chunks             Chunk Names
bundle.js  3.79 KiB    main  [emitted]  main
Entrypoint main = bundle.js
[./public/index.js] 0 bytes {main} [built]

You just created your first bundle, which if you see in your three directory you will now see a new dist/js/bundle.js file.

basic-react
-- dist
---- js
------ bundle.js
-- public
---- index.js
-- node_modules
-- package.json
-- webpack.config.js

This means that if we write something in our public/index.js file, and then run npm run build it will ends out in dist/js/bundle.js file.

Our configuration is not ready yet, but we can say the base is already done.

Now, let’s integrate @babel/core so we can write ECMA6 in all our JavaScript files with no problem.

Loaders

Loaders are some kind of modules that helps webpack to integrate new libraries in order to process every single file with some kind of compiler. We can represent it with the next image:

For example, if use ECMA6, we need to teach webpack how to transform ECMA6 into standard JavaScript, this is where the loaders are useful.

We need to teach webpack how to compile ECMA6 -> JavaScript.

const path = require('path');

module.exports = {
  mode: ...,
  entry: ...,
  output: ...,
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  }
}

module is an option to determine how the different types of modules within a project will be treated.

Inside module we have an array of Rules, every rule can have this three elements:

...
{
  test: /\.js$/,
  exclude: /node_modules/,
  loader: 'babel-loader'
}
...
  • test: It’s just a regular expression for every processed file in out chain, in this case we are telling webpack “Hey, use babel-loader only in javascript files”.
  • exclude: We are just saying “Do not process any file inside node_modules folder, this is because this would take a lot of time, and normally node modules already have a dist version.
  • loader: The name of the loader we will use for the previous rules.

There are a lot of different configurations you can use inside every rule, but in this tutorial we will only use the basic stuff. Try to read the webpack documentation for reference.

Step 5: Create your HTML file

Now that we are processing all our JS files with @babel/core which transforms our ECMA6 into a more standard JavaScript, we need to insert our bundle in an actual HTML.

Let’s create an index.html file in the root directory

touch index.html

Currently you should have something like this:

basic-react
-- dist
---- js
------ bundle.js
-- public
---- index.js
-- node_modules
-- package.json
-- webpack.config.js
-- index.html

This file should only import the dist/js/bundle.js file for now

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Basic React</title>
</head>
<body>
  <div id='root'></div>
  <script src='dist/js/bundle.js'></script>
</body>
</html>

Notice that we have a <div id='root'></div> element, we will insert our whole app inside this div.

Let’s test everything we have done by doing a console.log(“hello world”) inside our public/index.js file, running our npm run build command and then opening our new index.html file. You should see “hello world” inside the console.

Perfect! We are almost there.

Step 6: Create your first component

Now, we can start with React. If you don’t know anything about how to write react components or how to insert them inside the DOM. I highly recommend you to read the Getting Started guide from the react documentation page.

Check the next code:

import React from 'react';
import ReactDOM from 'react-dom';

const container = document.getElementById('root');

const MyComponent = () => {
  return (
    <h1>This is my first component</h1>
  )
};

ReactDOM.render(<MyComponent />, container);

We are doing two things basically:

  • Creating a component
  • Inserting the component inside our <div id='root'></div> container.

Once you have this, run the build script and…

Dexter: Surprise Motherfucker - YouTube

A huge error telling you “Hey dude! I don’t understand what is that "HTML" inside the JavaScript file” This is completely normal since babel doesn’t know how to read JSX.

Step 7: Teach JSX to Babel

By default, Babel doesn’t know how to transform JSX into JavaScript, here is where our library @babel/preset-react takes place.

Let’s tweak a little bit our webpack configuration:

...
module: {
  rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-react']
        }
      }
    }
  ]
}

With this, now we can run our build script this no problem, Babel will know how to transform JSX into JavaScript, and our components will render correctly.

Note: We are injecting @babel/preset-react inside the webpack configuration, but you could do it in your .babelrc file too.

Try to open your index.html file, it will render our h1 tag correctly.

We are pretty much done for this post, if you have any questions try to reach me through my twitter @jorgechavz.

Probably you noticed that you have to run npm run build every time you make a change in your public/index.js file. There is something we can do about it, we can use webpack-dev-server in order to run a server locally which will be handy when you want to develop fast, it will have some really cool features including hot reload so we can se our changes instantly.

In the next post you will learn how to configure webpack-dev-server.

Github repository: https://github.com/echavezNS/basic-react