DEV Community

Leopold
Leopold

Posted on • Edited on

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

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

#!/usr/bin/env node

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

Top comments (10)

Collapse
 
alienpr84 profile image
Alien Padilla Rodriguez • Edited

Hey Leopold, in the case of Create React App (CRA) you can create your custom template if you want, so you dont need to expend time making the same configuration every time. Here the link create-react-app.dev/docs/custom-t...

Collapse
 
nkilm profile image
Nikhil Mohite

NOTE: don't forget to add shebang to your .js file inside of bin folder.

#!/usr/bin/env node

// rest of the code
Enter fullscreen mode Exit fullscreen mode
Collapse
 
sardapv profile image
Pranav Sarda • Edited

Hey, I am trying to follow your steps to convert my angular boilerplate into npx command. I'm not using parcel anyways. But rest, I have bin command setup and js file.

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

but when I run npm link 'create-angular-bolerplate' it gives me

npm ERR! code E404
**npm ERR! 404 Not Found - GET https://registry.npmjs.org/create-angular-boilerplate - Not found**
npm ERR! 404
npm ERR! 404  'create-angular-boilerplate@latest' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)

Enter fullscreen mode Exit fullscreen mode

I don't understand where I am going wrong, I tried removing and adding back node-modules. Please help.

Collapse
 
sardapv profile image
Pranav Sarda

Fixed it.. thanks for article. ❤️ but there needs a lot of corrections. you have changed your file name, command name thrice above. also its only 'npm link' we have to run to create symbolic link. then in other folders you can run that command otherwise it tries to fetch from npm registry.

Collapse
 
leopold profile image
Leopold

Hey, thanks for the feedback, I will have a look at this !

Collapse
 
_pspkfan_ profile image
JSP Cult ✊

Hi Pranav, looks like the corrections you mentioned are correct. Would you mind sharing those corrected steps for linking and running

Collapse
 
jjunyjjuny profile image
DD

hello, I am a student studying programming.
I looked up your blog to make my own CRA.
My boilerplate is installable with npx on mac, but on windows it gives me an error.
As a result of looking for the cause, it seems that the command to run as "Node" was not specified when running create-app.js.

How did you solve this problem?

Your project can be installed with npx in both Mac and Windows environments. but my project is only on mac.

The Facebook CRA team specified the node environment via the scripts field in package.json, but you didn't.

How is that possible? Did you process it in the file registered in .gitignore?
I would really appreciate it if you could reply. Have a nice day!

here is my project repo!!

Collapse
 
leopold profile image
Leopold

Hey, I'm slightly confuse about your issue, but I tested to install your project and it works ! I answered in the github issue you opened.

Collapse
 
spacerumsfeldcode profile image
spacerumsfeld-code

Thanks for putting this out there! Am I correct in ascertaining that because you use git clone in your commands to build the repository, anyone using the npx command with your package will start off with the original repo as a remote by default that they then will need to point to their own project?

Collapse
 
leopold profile image
Leopold

You're partially right yes but for my package this is the reason why I am deleting the git repo during the installation process, so you can just type git init afterwards.
They are probably more elegants ways to do this and for example we could have a closer look at how something like create-react-app is handling this to have a fresh new git folder once we install the app.