Develop a koa scaffolding with nodejs+ts

Get into the habit of writing together! This is the 14th day of my participation in the "Nuggets Daily New Plan·April Update Challenge", click to view the details of the event .

foreword

In the Koa Getting Started series, we introduced the best practices of koa2 and provided a best practice template for koa2+TypeScript . But every time you copy the template and then modify it, it is always troublesome. It is better to develop a scaffold and use the command line to generate the koa2 project.

This article will introduce in detail how to develop scaffolding with node.js+typescript.

Post the github address of the finished product first: koa-generator-cli

There is also the address of npm: koa-generator-cli

will learn

  • Node.js scaffolding development
  • Node.js command line tool development
  • Several useful npm libraries

Introduction

What is scaffolding?

We've all used scaffolding, like vue-cli, react-native-cli, express-generator, etc.

Scaffolding provides these functions:

  • Quick initialization project
  • Ensure unity of collaborative team projects
  • Add common components or configurations

Determine what functionality the scaffolding will provide?

Our scaffolding is named koa-generator-cli. As the name suggests, this is a generator of koa projects. The main function is to produce koa projects and split the details. Our function points are as follows.

  • Download the koa2 template code to the local.
  • Receive the project name, description, etc. entered by the user, which is used to determine the directory name and modify the package file.
  • Receive user input and customize project content (such as middleware selection).
  • See help and version.
  • Provide feedback on creation progress and creation results.

get started

After determining the needs, we started step by step and started to operate!

Ready to work

Create npm project

First create the npm project.

npm init
复制代码

然后补充必要的信息,其中main是入口文件,bin用于引入一个全局的命令,映射到lib/index.js,有了bin字段后,我们就可以直接运行koa-generator-cli命令,而不需要node lib/index.js了。

// package.json
{
  "name": "koa-generator-cli",
  "version": "0.0.1",
  "description": "Koa2+TypeScript application generator",
  "main": "lib/index.js",
  "bin": {
    "koa-generator-cli": "lib/index.js"
  },
}  
复制代码

支持用ES6和TypeScript开发

安装typescript@types/node

npm install -save-dev typescript @types/node
复制代码

初始化tsconfig.json

tsc --i
复制代码

然后按我们工程的实际情况,修改下入口和输出。

// tsconfig.json
{
  "compilerOptions": {
    "target": "es2016",
    "module": "commonjs",
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "sourceMap": true,
    "outDir": "./lib",
  },
  "include": [".eslintrc.js", "src/**/*"],
  "exclude": ["node_modules", "lib/**/*"],
}
复制代码

我们在src/index.ts写个hello world,测试下ts编译是否正常。

// src/index.ts
#!/usr/bin/env node

const msg: string = 'Hello World'
console.log(msg)
复制代码

然后执行tsc,可以看到lib/index.js输出了编译后的js文件,而且node lib/index.js输出正常。

这一part完成。

引入ESLint

安装ESLint和其ts插件。

npm install eslint -save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin
复制代码

然后加上.eslintrc.js配置。

// .eslintrc.js
module.exports = {
  root: true,

  env: {
    node: true,
    es2021: true,
  },

  parser: '@typescript-eslint/parser',

  parserOptions: {
    ecmaVersion: 12,
    sourceType: 'module',
    tsconfigRootDir: __dirname,
    project: ['./tsconfig.json'],
  },

  plugins: ['@typescript-eslint'],

  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
  ],
}
复制代码

验收一下,package.json加上两条命令。

// package.json
"scripts": {
    "lint": "eslint --ext .js .",
    "lint:fix": "eslint --fix --ext .js ."
},
复制代码

运行npm run lint:fix,没有异常,完成!

npm link-本地调试

记得我们前面在package.json中有个bin配置,那我们直接跑koa-generator-cli这个命令试试。

bash: koa-generator-cli: command not found
复制代码

!!!嗯?原来我们现在的npm包还没发布和安装,没办法找到命令,为了方便调试,我们需要跑一下这个命令。

npm link
复制代码

重新koa-generator-cli,可以了!

为了方便调试,我们在package.json中再加两个配置,用于调试和打包。

// package.json
"scripts": {
    "dev": "tsc && node lib/index.js",
    "build": "tsc",
},
复制代码

命令行工具开发

接下来我们开始真正的脚手架开发。

commander-处理命令

我们用到commander来处理命令。commander是一个用于简化node.js命令行开发的库。

安装commander

npm install -save commander
复制代码

我们先从简单的开始,接收一个输入作为新建工程的名称,先不做处理直接输出出来。

#!/usr/bin/env node
// src/index.ts
import { Command } from 'commander';

const program = new Command();

program
  .name('koa-generator-cli')
  .description('"Koa2+TypeScript application generator')
  .version('0.0.1');

program
  .command('init <name>')
  .description('init a koa project')
  .action((name: string) => {
    console.log('start init koa project:', name)
  })

program.parse();  
复制代码

tsc后,运行 koa-generator-cli init firstProject,成功输出start init koa project: firstProject,可以了!

inquirer-处理交互

下面开始搞用户交互。

为了脚手架尽量简单易用,我们先只运行用户有少量的交互操作,inquirer是简化node.js命令行开发的一个库。

我们先确定交互有哪些,思考一下,我们先确定有下面这几个交互。

  • 输入项目描述
  • 输入项目作者

安装inquirer

npm install -save inquirer @types/inquirer
复制代码

继续完善一下代码,添加交互提示。

#!/usr/bin/env node

import { Command } from 'commander';
import inquirer from 'inquirer'
import gitclone from 'git-clone';

const InitPrompts = [
  {
    name: 'description',
    message: 'please input description',
    default: '',
  },
  {
    name: 'author',
    message: 'please input author',
    default: '',
  }
];

const program = new Command();

program
  .name('koa-generator-cli')
  .description('"Koa2+TypeScript application generator')
  .version('0.0.1');

program
  .command('init <name>')
  .description('init a koa project')
  .action(async (name: string) => {
    console.log('start init koa project:', name);
    const initOptions = await inquirer.prompt(InitPrompts);
    console.log('initOptions', initOptions);
  })

program.parse();   
复制代码

好了,现在我们试验一下。运行npm run dev init myproject,输出下面的结果。

LUCIOZHANG-MC1:koa-generator-cli luciozhang$ npm run dev init myproject

> [email protected] dev
> tsc && node lib/index.js "init" "myproject"

start init koa project: myproject
? please input description 
? please input author 
? 请选择子模块(comm子模块为必选项) koa-body, koa-router, koa-static, koa-views, koa-logger
initOptions {
  description: '',
  author: '',
  middleware: [ 'koa-body', 'koa-router', 'koa-static', 'koa-views', 'koa-logger' ]
}
? install npm now Yes
复制代码

OK,没问题,继续下一part。

git-clone-下载模板

不使用download-git-repo是因为这个库有些依赖有安全问题,且已经不在维护。

我们使用git-clone这个库来下载git上的模板,这个库更小而且功能也够用。

安装git-clone

npm install -save git-clone @types/git-clone
复制代码

新建一个download.ts,加上下载模板的代码,并在index.ts中引用。

注意!!下载完模板,要删除.git目录。

// download.ts
import gitclone from 'git-clone/promise';
import fs from 'fs-extra';
import path from 'path';

export const downloadTemplate = (name: string, templateGitUrl: string, downloadPath: string)=>{
  return new Promise(async (resolve, reject)=>{
    try {
      await gitclone(templateGitUrl, downloadPath, { checkout: 'master', shallow: true });
      fs.removeSync(path.join(downloadPath, '.git'))
      resolve('download success');
    } catch (error) {
      reject(error);
    }
  });
}
复制代码

运行npm run dev init myproject,发现myproject目录被创建了,而且下载了github仓库的内容。

又搞定一个,继续继续!!

handlebars-语义化模板

继续完善,接下来我们要用输入的名称和描述、作者等文本,替换模板的对应字段。

在替换前,我们需要修改模板的package.json,添加一些插槽,方便后面替换。

// 模板仓库的package.json
{
  "name": "{{name}}",
  "version": "1.0.0",
  "description": "{{description}}",
  "author": "{{author}}"
}
复制代码

下面开始修改package.json

安装handlebars

npm install -save handlebars
复制代码

安装fs-extra

npm install -save fs-extra @types/fs-extra
复制代码

开始修改package.json

import fs from 'fs-extra';
import path from 'path';
import handlebars from 'handlebars'

export const modifyPackageJson = function (downloadPath: string, options: any) {
  console.log('modifying package.json……');
  const packagePath = path.join(downloadPath, 'package.json');
  if (fs.existsSync(packagePath)) {
    const content = fs.readFileSync(packagePath).toString();
    const template = handlebars.compile(content);

    const param = { name: options.name, description: options.description, author: options.author };

    const result = template(param);
    fs.writeFileSync(packagePath, result);
    console.log('modify package.json complate');
  } else {
    throw new Error('no package.json');
  }
}
复制代码

ora-命令行美化

功能部分已经完成了,但是现在的提示是下面这样的,比较简陋。

wecom-temp-115f0af1a3f46a91325ae36abe4bda0c

我们来升级一下。

安装ora

npm install -save ora
复制代码

我们已下载的代码为例,美化下输出。

import gitclone from 'git-clone/promise';
import fs from 'fs-extra';
import path from 'path';
import ora from 'ora';

export const downloadTemplate = (name: string, templateGitUrl: string, downloadPath: string)=>{
  const loading = ora('download template');
  return new Promise(async (resolve, reject)=>{
    try {
      loading.start('start download template');
      await gitclone(templateGitUrl, downloadPath, { checkout: 'master', shallow: true });
      fs.removeSync(path.join(downloadPath, '.git'))
      loading.stop();
      loading.succeed('download success');
      resolve('download success');
    } catch (error) {
      reject(error);
      loading.stop();
      loading.fail('download fail');
    }
  });
}
复制代码

Run it again, this time there is a loading animation, which is much more beautiful.

wecom-temp-3cbeb2250eba78295e142a4d80e7b44e

Summarize

This article implements the simplest koa generator component. The idea is that the scaffolding and templates are as simple as possible.

The highlight of the implementation process is the use of ts and a lot of ES7 syntactic sugar. Personally, I feel that the code style is relatively good haha.

Post the github address of the finished product: koa-generator-cli .

There is also the address of npm: koa-generator-cli

references

[Medium and advanced front-end essentials] Teach you to build a scaffold by touching your hands

Develop node.js projects with Typescript - simple environment configuration

Good articles in the past

koa entry series

Basic use of [koa Quick Start]

Best Practices of [koa Quick Start]

The principle of [koa quick start]

"Farewell to Bad Code"

2022 Code Specification Best Practices (with examples of optimal configuration for web and applets)

[Front-end exploration] Say goodbye to bad code! Encapsulate network requests with Chain of Responsibility pattern

[Front-end exploration] Farewell to the second issue of bad code! Encapsulate shared components with strategy pattern

Code Life

[Thinking about front-end development for three years] How to effectively read requirements?

A must-see guide for front-end stepping on the pit

[Front-end exploration] Best practices for image loading optimization

[Front-end exploration] Exploration of mobile terminal H5 to generate screenshots and posters

[Front-end exploration] H5 obtains user positioning? Enough to read this

[Front-end Exploration] Exploration of WeChat Mini Program Jump - Why Does Open Tab Exist?

Guess you like

Origin juejin.im/post/7086340583697940516