Write your first webpack plugin
Tags: webpack, react, javascript, productivity
Published: 2019-11-19 14:21:39

If you have clicked on the title, then I assume you have a basic understanding of webpack and webpack plugins.

Plugins are great and helps you leverage the power of webpack.
There are tons of plugins available for webpack, some of the famous ones are HtmlWebpackPlugin , HotModuleReplacementPlugin and webpack-bundle-analyzer.

While these are great but there are always cases when you need a project specific plugin and it gets worse when you are unable to find any plugin for your needs.

## How about creating your own Plugin ?

![giphy](https://media.giphy.com/media/5hc2bkC60heU/giphy.gif)


In this post we will create a plugin to remove 'console.logs' from the production build.

Let's begin by creating a simple react project.

If your react project is not setup then follow these steps to create a basic react starter.

```bash
$ mkdir myplugin && cd myplugin
$ npx react-starter-lite

```

>  react-starter-lite is a simple boilerplate package to easily get your hands dirty on react projects.

Run the app to see if its working properly

```bash

$ yarn dev:hot

```

After setting up the directory create a file named logRemover.js in your project directory and paste the following code.

```javascript
//logRemover.js

module.exports = class RemoveLogs {
     constructor(options){
     this.options = options
}

  apply(compiler) {
    console.log("Hello from the new plugin")
};

```

### Lets see whats happening in the code.

   - In the first line we are exporting the class we are creating.Plugins can be created using functions also but I have used classes here.

   -  Constructor has an paramter options which accepts arguments related to the logic of the plugin. In this post we won't be needing the options but I showed you just show that you know.

   - apply() is a mandatory method which recieves a compiler instance as   an argument which contains basically everything you need to do make your plugin.Since we are not using compiler yet I will tell you a bit more compiler when we are done with  basic setup.

  - Console.log() just to see if our setup is working


After setting up the logRemover.js we need to invoke that plugin in our webpack configuration.

In the project directory we have three webpack configurations, one is the base config and the other two are development and production configs.

Since we just need to remove console.logs from the production build only, we need to add that plugin in the webpack production config.
But for testing the setup, for now, we'll add that to development config and will change that later when we'll have logic for our plugin.

So open webpack.config.dev.js and invoke the plugin like this.

```javascript

//webpack.config.dev.js

const merge = require("webpack-merge");
const baseConfig = require("./webpack.config-base");
const RemoveLogs = require('./logRemover.js');

module.exports = merge(baseConfig, {
  mode: "development",
  devServer: {
    port: 9000
  },
  devtool: "source-map",
  plugins: [new RemoveLogs()]
});


```

Now lets test if our setup was successfull.
Stop if the webpack server is running and run

```bash
$ yarn dev:hot

```

Now if you look in to you terminal you'll see that console.log statement.Since there is so much on terminal, you need to look carefully to find your log message.



![congrats](https://media.giphy.com/media/5GoVLqeAOo6PK/giphy.gif)

Congrats if you have made this far :p

___

Now since our basic setup is working let's write the logic for our plugin inside logRemover.js

```javascript

//logRemover.js

const fs = require("fs");
module.exports = class RemoveLogs {
  apply(compiler) {
    compiler.hooks.done.tap("RemoveLogs", stats => {
      const { path, filename } = stats.compilation.options.output;
      try {
        let filePath = path + "/" + filename;
        fs.readFile(filePath, "utf8", (err, data) => {
          const rgx = /console.log\(['|"](.*?)['|"]\)/;
          const newdata = data.replace(rgx, "");
          if (err) console.log(err);
          fs.writeFile(filePath, newdata, function(err) {
            if (err) {
              return console.log(err)
            }
            console.log("Logs Removed");
          });
        });
      } catch (error) {
        console.log(error)
      }
    });
  }
};


```
Let's see what this code is doing

1) apply(compiler) method takes in a compiler instance which contains events.
Compiler module is the main engine of the webpack which emits events   just like dom. It extends Tapable lib to register and call plugins. In this logic we are tapping on hook "done" which is emitted after the compilation is completed and bundle is generated.

2) using these compiler events we call our plugin to do its job

3) Its job is nothing fancy but just to take the bundled js and pass it through a regex and remove all the console.logs and output the bundled js in the dist directory.



Now since we are done with the logic we will remove the plugin from the dev config in webpack.config.dev.js and put it under production config in webpack.config.prod.js 

```javascript

//webpack.config.prod.js

const merge = require("webpack-merge");
const baseConfig = require("./webpack.config-base");
const RemoveLogs = require("./logRemover.js");
module.exports = merge(baseConfig, {
  mode: "production",
  plugins: [new RemoveLogs()]
});

```


To see if its working we will write a console.log statement in App.js file

```jsx
//src.App.js

import React from "react";
import "./styles.css";
const App = () => {
  console.log("test console.log statement ");
  return (
    <div className="card">
      <div className="content">
        {"{..."} &#9829;{"}"}
        <h5>! hate</h5>
      </div>
    </div>
  );
};

export default App;

```

Now stop the webpack server and generate the build by 

```bash

$ npm run build

```

Now open the index.html from the dist directory and check if there any console.log statement or you can check  in the bundeled js in the editor by doing ctr/cmd + F in bundeled file.


That's all for today :)

Please feel free to comment and ping me if you have any doubts.


Here is the github project if you want to see the full source code :

[webpack-LogRemover-plugin](github.com/royalbhati/webpack-LogRemover-plugin)


Additional Reading :

[Compiler](https://webpack.js.org/api/compiler-hooks/?source=post_page-----1c2a292da2fd----------------------)

[Plugins](https://webpack.js.org/contribute/writing-a-plugin/?source=post_page-----1c2a292da2fd----------------------)