Create New Project Using NPM package
Tags: npm, javascript
Published: 2022-01-03 16:37:16

In the last article, we can create a new project by using [Express Typescript Boilerplate](https://dev.to/maithanhdanh/create-express-typescript-boilerplate-3gf) template, it saves us pretty much time to do it from scratch. However, it is still not the best, we can optimize it using **NPM** and just 1 command line, we get everything.

## Setup account
- we will need an account in [npm](https://www.npmjs.com/)
- Login our account on our pc
- After that, we update our profile by access **profile > edit profile**. There are 2 things we need to pay attention **GitHub Username** and **Email**, they will cause some problems when publishing a package. For example, after running command `npm publish`, it returns `403 Forbidden - You do not have permission to publish. Are you logged in as the correct user?`. In case that we can fix it by changing email to whatever, then revert it back to our main email.

## Setup project
If we config npm account successfully, just running `npm publish`, then we will see the log below
![publishing successfully](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tp830d1xb47zpipnlpl4.png)

Then it will be shown on our npm packages, and the other developer can reach to [the package](https://www.npmjs.com/package/typescript-maker) also
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64r9i4aiykzwh3jb28w1.png)
 
In order to make our package more reliable, we should enable `security`. If there is any issue Github will show us as below.
![security issue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tj5p3h8qpasy1m14cgdi.png)

Otherwise, it will be green.
![green security](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ry8j4rqrrk7aiyctrzej.png)

## Config command
In this post, we will use our [last template](https://dev.to/maithanhdanh/create-express-typescript-boilerplate-3gf) as source code for the npm package. And below is my `package.json`.

```
{
  "name": "typescript-maker",
  "version": "1.1.1",
  "description": "Minimalistic boilerplate to quick-start Node.js development in TypeScript.",
  "engines": {
    "node": ">=14 <15"
  },
  "bin": {
    "typescript-maker": "./bin/generateApp.js"
  },
  "scripts": {
    "start": "node src/index",
    "dev": "nodemon --config restart.json",
    "clean": "rm -rf coverage build tmp",
    "prebuild": "npm run lint",
    "build": "tsc -p tsconfig.build.json",
    "build:watch": "tsc -w -p tsconfig.build.json",
    "lint": "eslint . --ext .ts,.tsx",
    "test": "jest"
  },
  "author": "Dantis Mai",
  "license": "Apache-2.0",
  "dependencies": {
    "commander": "^8.3.0",
    "express": "^4.17.1",
    "module-alias": "^2.2.2",
    "tslib": "~2.3.0",
    "winston": "^3.3.3"
  },
  "devDependencies": {
    "@tsconfig/recommended": "^1.0.1",
    "@types/express": "^4.17.13",
    "@types/jest": "^26.0.24",
    "@types/node": "~14.14.45",
    "@typescript-eslint/eslint-plugin": "~4.28.2",
    "@typescript-eslint/parser": "~4.28.2",
    "dotenv": "^10.0.0",
    "eslint": "~7.30.0",
    "eslint-config-prettier": "~8.3.0",
    "eslint-plugin-jest": "~24.3.6",
    "jest": "^27.0.6",
    "jest-html-reporter": "^3.4.1",
    "nodemon": "^2.0.12",
    "prettier": "~2.3.2",
    "rimraf": "^3.0.2",
    "supertest": "^6.1.5",
    "ts-jest": "^27.0.3",
    "ts-node": "^10.2.0",
    "ts-node-dev": "^1.1.8",
    "tsconfig-paths": "^3.10.1",
    "tsutils": "~3.21.0",
    "typescript": "~4.3.5"
  }
}
```

In the `package.json` file, there are 3 fields, we need to update:
- **name**: npm package name. This name will be our **npm package name**, ignoring the **GitHub repository name**. For example, my repository name is `express-typescript-boilerplate`, while the package name is `typescript-maker`.
- **version**: npm package version. By versioning, we can update the new features with backward compatibility.
- **bin**: command configuration. We will direct the source code for the command. As you can see the `bin` field in my `package.json`, I define `"typescript-maker": "./bin/generateApp.js"`, it means that `typescript-maker` is the command name, and the options and arguments are described in `./bin/generateApp.js`.

Now, let jump to config our command.
For a sample command, there are 4 steps:
- Verify arguments: verify the number of arguments to make sure, we have enough information.
- Parse arguments and options: get argument value from input
- Validate existing folder: prevent issues when creating a new folder or file. It will work like we clone a repository 2 times at the same directory. 
- Define workflow: define what thing we gonna do when we call the command.
- Clear unused files: keep the result clean to not distract the user after running the command. 
- Trigger workflow.

Combine everything and we have a sample config for `typescript-maker` below

```
# Verify arguments
if (process.argv.length < 3) {
  console.log('You have to provide a name to your app.');
  console.log('For example :');
  console.log('    typescript-maker my-app');
  process.exit(1);
}

# Parse arguments and option
const projectName = process.argv[2];
const currentPath = process.cwd();
const projectPath = path.join(currentPath, projectName);
const git_repo = 'https://github.com/Maithanhdanh/express-typescript-boilerplate.git';

# Validate existing folder
try {
  fs.mkdirSync(appPath);
} catch (err) {
  if (err.code === 'EEXIST') {
    console.log('Directory already exists. Please choose another name for the project.');
  } else {
    console.log(error);
  }
  process.exit(1);
}

# define steps in workflow
async function main() {
  try {
    console.log('Downloading files...');
    execSync(`git clone --depth 1 ${git_repo} ${projectPath}`);

    
    // Change directory
    process.chdir(appPath);

    // Install dependencies
    const useYarn = await hasYarn();
    console.log('Installing dependencies...');
    if (useYarn) {
      await runCmd('yarn install');
    } else {
      await runCmd('npm install');
    }
    console.log('Dependencies installed successfully.');
    console.log();

    # Clean unused files
    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);
  }
}

# trigger workflow
main();
```

In case we want a more complicated command, we can use module [commander](https://www.npmjs.com/package/commander), which supports us pretty much thing when we design the architecture of the command. After using the commander, I structure my command like [this](https://github.com/Maithanhdanh/express-typescript-boilerplate/blob/main/bin/generateApp.js).

![new project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9pq0qmi6q5bevb6ywm81.png) 

This is [mine](https://www.npmjs.com/package/typescript-maker), you can enjoy it.

[Paypal](https://paypal.me/DantisMai).

*I am really happy to receive your feedback on this article. Thanks for your precious time reading this.*