Advertisement

#4 Step By Step: Javascript and Css

In this article we start from scratch and will examine what we need to do in order to have webpack create both a javascript and css bundle. We will see all the packages that we need to install from npm as well as their version numbers at the time of the writing of the article. We will also explain the purpose of each entry that we make within our webpack configuration file.

Won't get far without installing Webpack

  • WebUi
    • package.json

If you have not already created a package.jon file navigate a command propmpt to the root of our project and run the command npm init -y. Now that we have a package.json file we need to install the first two packages into our project using the install command shown in (a). The versions of the two packages that we just installed are shown in (b). In addition to the version numbers you should note the key value pair located within the scripts object. With this in place we will be able to run the command npm run build when we are ready to trigger bundling to be performed.

Terminal

npm install --save-dev
webpack
webpack-cli
(a) Installation command used to install webpack and its cli from the command line.

package.json

{
    ...
    "devDependencies": {
        "webpack": "^4.6.0",
        "webpack-cli": "^2.1.2"
    },
    "scripts": {
        "build": "set NODE_ENV=development&&webpack --progress"
    },
    ...}
(b) The names and versions of webpack and its cli that were installed at the time of the writing of this article.

Hello World strikes again

  • WebUi
    • Source
      • index.js
    • webpack.config.js

Now that webpack is installed we need to create a file for us to include in our bundle (c) and the configuration file that webpack will use when creating our bundles (d).

index.js

console.log("hello world");
(c) Going to guess that not much explanation is required here.

Our configuration file contains the least amount of information that we need to create our bundles. We start by specifying the location of the name of our bundle and its entry point. This is done via the cleverly named entry object. As you might have guessed the keys within our objects will be the name of our bundles and their values are the locations of the entry points. For now the entry point is a single string but we will soon make it an array of string. Next we have the output object. In the output we tell webpack that the file name should be whatever the key is in the entry object appended with '.bundle.js' and that the path to the bundle will be the js folder contained with a wwwroot folder that itself is contained within our current working directory. Lastly we add the mode to our exports because without it by default webpack will assume we are building a production bundle.

webpack.config.js

const mode = process.env.NODE_ENV || "development";

const entry = {
    "index": "./Source/index.js"
}

const output = {
    filename: "[name].bundle.js",
    path: __dirname + "/wwwroot/js/"
}

module.exports = {
    entry,
    mode,
    output
}
(d) Minimal configuration required to create our first bundles.

Now that our configuration is made we can have webpack get down to business by using the command npm run build that I mentioned previously. Once we do that we should output in our terminal very similar to (e);

(e) If everything goes as planned we should see output very similar to that shown here when we build our bundle.

If we look inside the bundle that was just created we should see a whole bunch of bootstrapping code at the top and at the bottom see a function wrapping the code that we created (f).

index.bundle.js

/******/ (function(modules) { // webpackBootstrap
...

/***/ "./Source/index.js":
/*!*************************!*\
  !*** ./Source/index.js ***!
  \*************************/
/*! no static exports found */
/***/ (function(module, exports) {

eval("console.log(\"hello world\");\n\n//# sourceURL=webpack:///./Source/index.js?");

/***/ })
...
(f) The bundle that we just created has our code located at the bottom wrapped in a function call.

An index file needs an index page

  • WebUi
    • index.html

Now that we have a bundle we need to create a webpage that we can included it in. For now we will just create a static html page located in the root of our project (g).

index.html

<!DOCTYPE html>
<html>
<head>
    <title>Webpack 4 - Step By Step</title>
</head>
<body>
<script src="wwwroot/js/index.bundle.js"></script>
</body>
</html>
(g) Our index page just needs to have a script tag pointing to our bundle for now.

Now that the script is included we can take a look in the developer console and we should see our 'hello world' string as shown in (h).

Hello world in the console means so far so good.
(h) Hello world in the console means so far so good.

If there was only javascript we would be done

  • WebUi
    • Source
      • index.css
    • webpack.config.js

The next thing we are going to tackle is creating a css bundle. Not suprsingly our first step is to create a css file (i).

index.css

body { background-color: blue; }
(i) My professional design skills have created the most wonderful looking UI you just have to wait to see it.

Now that we have another file we need to tell webpack that we need to include it within a bundle. To do this we will just return to our config file and modify the entry point to be an array of strings instead of a single string (j).

webpack.config.js

...
const entry = {
    "index": ["./Source/index.js", "./Source/index.css"]
}
...
(j) We will create two different bundles, each with the name 'index', by using an array.

Now if we kick off the building of our bundles again we are unfortunately going to be greeted with a bunch of red text as shown in (k). We are receiving this error because on its own webpack only knows how to deal with javascript. Since we are trying to create a css bundle we need to give it a little help.

We are receiving our first error since webpack knows nothing about css by default.
(k) We are receiving our first error since webpack knows nothing about css by default.
Advertisement

Loaders loaders everywhere

  • WebUi
    • package.json
    • webpack.config.js

The way that we tell webpack how to deal with different file types is by using loaders within our configuration file. Bet you can't guess what type of loader we need now. The first loader that we are going to include within our project will be the css loader. You can once again us the terminal to isntall it (l) which again at the time of the writing of this article will import the version shown in (m).

Terminal

npm install --save-dev css-loader
(l) Time to install the css loader.

package.json

{
    ...
    "devDependencies": {
        "css-loader": "^0.28.11",
    },
    ...
}
(m) At the time of the writing of this article the version of the css loader is shown here.

Now that the loader is added we need to tell webpack when and how to use it. To do this we specify a new object that we will add to our export (n). As you can see this new object contains a rules array. Each element within the array may contain several properties. Here we are using a regex expression as the test in order to tell webpack when to apply this rule, an exclude regex to tell webpack not to deal with these files, and a use array. The use array may contain any number of loaders which are applied from the top to the bottom.

webpack.config.js

...

const _module = {
    rules: [
        {
            test: /\.css$/,
            exclude: /node_modules/,
            use: [
                "css-loader"
            ]
        }
    ]
}

module.exports = {
    ...,
    module: _module,
    ...
}
(n) The module object that we need to add to our exports that will tell webpack when and how to deal with css files.

If we once again build our bundle and take a look inside in addition to what we had before we now have an array that corresponds to the content of our index.css file (o).

index.bundle.js

...

/***/ "./Source/index.css":
/*!**************************!*\
  !*** ./Source/index.css ***!
  \**************************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

eval("exports = module.exports = __webpack_require__(/*! ../node_modules/css-loader/lib/css-base.js */ \"./node_modules/css-loader/lib/css-base.js\")(false);\n// imports\n\n\n// module\nexports.push([module.i, \"body { background-color: blue; }\", \"\"]);\n\n// exports\n\n\n//# sourceURL=webpack:///./Source/index.css?");

/***/ }),
...
(o) Now that we have modified our configuration file webpack is now including our css as a string within our javascript bundle.

Don't want to use a javascript string to style my page

  • WebUi
    • package.json
    • webpack.config.js

Although not impossible at least in this instance we do not want to use the string that is now included within our javascript bundle to style our page. What we want is to create a separate css bundle that we can serve to the page via a link tag. To do that we need to return our saviour npm. The command to install the plugin to extract our css is shown in (p) and its version number at the time of the writing of this article is shown in (q).

Terminal

npm install --save-dev mini-css-extract-plugin
(p) Console command used to install the extract text plugin.

package.json

{
    ...
    "devDependencies": {
        "mini-css-extract-plugin": "^0.4.0",
    },
    ...
}
(q) Version number of the extract text plugin at the time of the writing of this article.

Now that we have installed a plugin the obvious next step is to return to our configuration file. What we need to do is require the plugin and add it to the top of our rule that deals with css files. Once that is done we need to configure the plugin with we do by creating a new plugins object, instantiating an instance of the plugin and including a configuration object when we do so (r).

webpack.config.js

...
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
...
const _module = {
    rules: [
        {
            test: /\.css$/,
            exclude: /node_modules/,
            use: [
                MiniCssExtractPlugin.loader,
                "css-loader"
            ]
        }
    ]
}
...
const plugins = [
    new MiniCssExtractPlugin({
        filename: "../css/[name].bundle.css"
    })
];

module.exports = {
    ...,
    plugins
}
(r) Modifying our webpack configuration so that we can extract our css from the javascript bundle and include it a new css bundle.

Take note of the filename that we have specified for our css bundle. If you remember at the start we specified that our javascript bundles should be located within a js folder inside of our wwwroot folder. Since I want the css to live in a css folder that is a sibling of the js folder we simply need to move up one directory and then into the css folder. Once again we are using the [name] token so that the key for the entry point is used as the name for our bundle.

Now when we build our bundles we should see in our console that webpack has now emitted two different bundles (s).

Image showing that webpack now
             emits two different bundles. One for javascript and one for css.
(s) Image showing that webpack now emits two different bundles. One for javascript and one for css.

Time to style that page

  • WebUi
    • index.html

Now that we have our css bundle all we need to do is add it to our page using a link tag (t). I am going to refrain from adding an image of the result as I am sure you can guess what it should look like.

index.html

<!DOCTYPE html>
<html>
<head>
    ...
    <link rel="stylesheet" href="wwwroot/css/index.bundle.css">
</head>
...
</html>
(t) Time to add a link tag to our page so that our css is included.
Exciton Interactive LLC
Advertisement