DEV Community

loading...

Generate your web-app boilerplate like create-react-app does.

leopold profile image Leopold ・5 min read

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 :

npx my-dream-boilerplate app-name
Enter fullscreen mode Exit fullscreen mode

And boom ! Your project is magically there all setup with your favorite configs, tools and more.

That's what we will do right now.

 

Why ?

 
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.

 

Initialize the project

 
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.
 

Installing dependencies and setup

 
First let's initialize the project :

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

npm init
Enter fullscreen mode Exit fullscreen mode

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.
npm install -D parcel-bundler
npm install rimraf
Enter fullscreen mode Exit fullscreen mode

Change the npm scripts field in your package.json :

  "scripts": {
    "start": "parcel index.html",
    "build": "parcel build index.js"
  }
Enter fullscreen mode Exit fullscreen mode

 

Create the structure

 
Create an index.html and an index.js file.

Your index.html looks like this :

<html>
<body>
    <div>Cool</div>
    <script src="index.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Now verify that everything is working :

npm start
Enter fullscreen mode Exit fullscreen mode

Again, the project structure is ridiculous here but how to setup a web project isn't the point of the article.
 

Script + Npx = speed

 

More setup

 
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

  "bin": {
    "create-boilerplate": "./generate-app.js"
  }
Enter fullscreen mode Exit fullscreen mode

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.
 

The script

 
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).

const { execSync } = require('child_process');
const path = require('path');
const fs = require('fs');
Enter fullscreen mode Exit fullscreen mode

We verify that an app name is provided (npx create-boilerplate with no argument isn't a valid command) :

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);
}
Enter fullscreen mode Exit fullscreen mode

Declare variables we need :

const projectName = process.argv[2];
const currentPath = process.cwd();
const projectPath = path.join(currentPath, projectName);
const git_repo = YOUR_GIT_URL;
Enter fullscreen mode Exit fullscreen mode

Verify the project name is available otherwise cancel the process :

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);
}
Enter fullscreen mode Exit fullscreen mode

Now we reach the main part :

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();
Enter fullscreen mode Exit fullscreen mode

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 :

npm link create-my-boilerplate
Enter fullscreen mode Exit fullscreen mode

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 :

npx create-my-boilerplate app-name
Enter fullscreen mode Exit fullscreen mode

Your script runs and your project spawns.
Congratulation.
As you can see, a basic generation is definitely not complicated.

You can start :

npm start
Enter fullscreen mode Exit fullscreen mode

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

npm login
Enter fullscreen mode Exit fullscreen mode
bash npm publish
Enter fullscreen mode Exit fullscreen mode

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.

Discussion (0)

pic
Editor guide