Generate your web-app boilerplate like create-react-app does.
Tags: webdev, javascript, node, productivity
Published: 2021-04-08 17:24:00

Hello everyone, this is my first post here, and I hope my English is going to be smooth enough to make it enjoyable to read 👍.

It looks cool to create a npm package and type :
```bash
npx my-dream-boilerplate app-name
``` 
And boom ! Your project is magically there all setup with your favorite configs, tools and more.

That's what we will do right now.

&nbsp;
##Why ?##
&nbsp;
Before we really start, let's try to answer to this question :

**Why would you create your own wep-app boilerplate when there are great tools already in place such as create-react-app which also do a lot more that a simple project boilerplate ?**

Here is what motivated me :
When I create a web application, I started to be very bored of having to install each time the same packages, commands, folders, etc. over and over.

**I can extract some kind of layout of my projects.**
I mostly use React.js and I do need EACH TIME (or almost) to install/change the same bunch of things (react-router-dom, styled-component, build my components structure, redux, etc.) while at the contrary I don't need create-react-app to make a small app or fast prototyping stuffs. 
I waste time installing packages, add configs and organizing my folders.

So I get interested in making that **npx my-dream-boilerplate app-name** command works to generate the project starter i like.

&nbsp;
## Initialize the project
&nbsp;
For demo purpose let's keep things very very (and very) simple.
We'll do like in a lot of projects: add a package.json and install all the dependencies we need.
&nbsp;
### Installing dependencies and setup
&nbsp;
First let's initialize the project :

Create a new foler, for example "create-my-boilerplate" and run inside it :

```bash 
npm init
```

The only dependencies we will use here are parcel and rimraf.

- Parcel is a web application bundler, there are others Javascript bundlers (webpack, rollup, etc.) but parcel comes up with (almost) no config, a development server, hot module replacement, etc. So this is well enough for our need here.
- rimraf is a npm package used as the UNIX command equivalent rm -rf for node. We will only use it for a command in the script part.

```bash
npm install -D parcel-bundler
npm install rimraf
```

Change the npm scripts field in your package.json :

```js
  "scripts": {
    "start": "parcel index.html",
    "build": "parcel build index.js"
  }
```
&nbsp;
### Create the structure
&nbsp;
Create an index.html and an index.js file.

Your index.html looks like this :

``` html
<html>
<body>
    <div>Cool</div>
    <script src="index.js"></script>
</body>
</html>
```

Now verify that everything is working :

```bash 
npm start
```

Again, the project structure is ridiculous here but how to setup a web project isn't the point of the article.
&nbsp;
## Script + Npx = speed
&nbsp;
### More setup
&nbsp;
All right so how do i automatized all of this ? We want to type some kind of command like **npx create-react-app app-name** and boom my project appears !

This is possible thanks to **the 'bin' field in the package.json** and npx the package runner command.

Add to your package.json
```js
  "bin": {
    "create-boilerplate": "./generate-app.js"
  }
```
**Create at the root of the project a 'bin' repository with a generate-app.js file (name it as you want).**

So ./bin/generate-app.js is the script executed when we will type the command **npx create-my-boilerplate name-of-your-app**.

Before going any further we need to create a git repository.
So run **git init and create a .gitignore file.**.
Your .gitignore file have to ignore folders that parcel generate when you run/build : .cache, dist and build.

To finish the setup part, push your project to a new git repository, your git repo url is going to be use in the next part because we want to clone the repo.
&nbsp;
### The script
&nbsp;
We are working on create-app.js now.
Again, let's keep things simple, the script have to handle this :

- We want to execute a command who accepts an argument representing the application name and validate it.
- If it is valid, verify if the project name doesn't already exist in the current folder.
- Then we want to clone the github repository of this project boilerplate.
- We want to install all the dependencies.
- We want to delete files not useful.

Firstly we require the packages we need : (you don't need to install them).
```js
#!/usr/bin/env node

const { execSync } = require('child_process');
const path = require('path');
const fs = require('fs');
```

We verify that an app name is provided (npx create-boilerplate with no argument isn't a valid command) :
```js
if (process.argv.length < 3) {
    console.log('You have to provide a name to your app.');
    console.log('For example :');
    console.log('    npx create-my-boilerplate my-app');
    process.exit(1);
}
```

Declare variables we need :
```js
const projectName = process.argv[2];
const currentPath = process.cwd();
const projectPath = path.join(currentPath, projectName);
const git_repo = YOUR_GIT_URL;
```

Verify the project name is available otherwise cancel the process :
```js
try {
  fs.mkdirSync(projectPath);
} catch (err) {
  if (err.code === 'EEXIST') {
    console.log(`The file ${projectName} already exist in the current directory, please give it another name.`);
  } else {
    console.log(error);
  }
  process.exit(1);
}
```

Now we reach the main part :

```js
async function main() {
    try {
      console.log('Downloading files...');
      execSync(`git clone --depth 1 ${git_repo} ${projectPath}`);
  
      process.chdir(projectPath);
  
      console.log('Installing dependencies...');
      execSync('npm install');

      console.log('Removing useless files);
      execSync('npx rimraf ./.git');
      fs.rmdirSync(path.join(projectPath, 'bin'), { recursive: true});
  
      console.log('The installation is done, this is ready to use !');

    } catch (error) {
      console.log(error);
    }
}
main();
```

Read lines with console.log(), they pretty much explain every command.
This is a very basic CLI but you could do a lot more thanks to node environment, add colors, package.json generator, etc.

That's it.
You can test your package locally :
```bash
npm link
```
It creates a symbolic link so that you can use it as a node module in the folder you are currently located.

And now it is the great time, where the magic comes :

```bash
npx create-my-boilerplate app-name
```
Your script runs and your project spawns. 
Congratulation.
As you can see, a basic generation is definitely not complicated.

You can start :
```bash 
npm start
```

Go further, make your own boilerplate with your favorite setup and learn to publish on npm.

```bash
npm login
```

```sh
npm publish
```

Now check your package on https://www.npmjs.com/ !

I hope It wasn't too confused and that it will inspire you a little bit about Node.js scripting possibilities, yours project needs and/or new packages ideas.
I myself ending up building my own project boilerplate last week (and in fact thats my first npm package ever) for react-applications with parcel, which include features I use regularly such as prettier, css autoprefixer and reset, tests, styled-components, etc.
If you are interested you can have a look to the code on my github particularly the ./bin/ folder where i have a bit more advanced script than in this article : https://www.npmjs.com/package/react-parcel-app

Thanks for reading and have a good day.