The new generation of code generator
Published: 2021-05-09 11:54:10


![WX20210509-175440@2x.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d8a53e83571242f0b399dfdeb0b52819~tplv-k3u1fbpfcp-watermark.image)

## Speaking from a scaffold

Daniel: Recently I want to build a code generator that can quickly generate project codes. What recommendation does Brother Egg have?

Mr. Egg: I have always used yeoman in the past, and it is an open source project that is nearly 10k stars. However, what I want to recommend to you today is not yeoman, but a new generation code generator [`ncgen`](https://daniel-dx.github.io/ncgen/), it may seem more approachable.

Daniel: I like the simple one the most. How does it work?

Mr. Egg: Old rules, you say your needs, I will try to answer them one by one

### First, you need a project template

Daniel: I have a project template (for example: [vue3-ncgen-demo](https://github.com/daniel-dx/vue3-ncgen-demo.git)), I hope all new projects come from this project template, so I only need to concentrate on maintaining this project template.


Mr. Egg: OK, this is the function of the project scaffolding. Let's take a look at how `ncgen` is processed.

The first step is to install ncgen

```sh
$ npm i ncgen -g # yarn global add ncgen
```

The second step is to generate the configuration file `ncgen-config.js`, which describes the logic of the code generator

```sh
$ ncgen genConf
```

Step 3 Modify `main.tmplSource` in `ncgen-config.js` to the url of the project template.

```js
export default {
  main: {
    tmplSource: "https://github.com/daniel-dx/vue3-ncgen-demo.git",
  },
};
```

Try it out:

```sh
ncgen ncgen-config.js
```

![](https://camo.githubusercontent.com/ca5a5dc46a9b4148dd97b52fb1fd6c95b5c751f75ccf59bb81015f9d3f817b7a/68747470733a2f2f70332d6a75656a696e2e62797465696d672e636f6d2f746f732d636e2d692d6b3375316662706663702f65313232353236626236663934306333386565396163663165633161623365387e74706c762d6b3375316662706663702d77617465726d61726b2e696d616765)

### Simple copying is not enough, modification is necessary

Daniel: Whoops is good. However, the currently generated project is exactly the same as the project template, but it will always have its own information that is different from the project template, such as the name of the project, the name of the author, etc. I don’t want to modify these manually every time the project is generated.

Mr. Egg: OK, the request is very reasonable. Since this information can only be provided by the person who created the project, we need to collect this information through some questions, and then we can make some modifications to the generated project based on this information. We modify the `main.prompt` and `main.updateFiles` in `ncgen-config.js`

> Example description:  
> Perform string replacement on the `package.json` file in the generated project, the rules are as follows:  
> Replace the string `vue3-ncgen-demo` with the project name entered by the user  
> Replace the string `Daniel.xiao` with the author name entered by the user

```js
export default {
  main: {
    prompt: [
      {
        type: "input",
        name: "author",
        message: "What is the author's name",
      },
    ],

    ...

    updateFiles: {
      "package.json": function (content, options) {
        const answers = this.$answers
        return api.replace(content, {
          "vue3-ncgen-demo": answers.projectNameObj.kebabCase,
          "Daniel.xiao": answers.author,
        });
      },
    },
  }
};
```

![](https://camo.githubusercontent.com/389f2870fb39d3538e773c62035291a9e3d7d07585d54272ee132e6d64c1f15f/68747470733a2f2f70392d6a75656a696e2e62797465696d672e636f6d2f746f732d636e2d692d6b3375316662706663702f34346530363866656138353734653338386233393634396363346530336338367e74706c762d6b3375316662706663702d77617465726d61726b2e696d616765)

Daniel: Hey, I noticed that the template engine is not used here, but the string replacement is used directly

Mr. Egg: Yes, this design has a lot of meaning. Using a template engine to replace files may cause the project template itself to fail to run normally, because the template engine requires placeholders, and placeholders may cause code parsing errors

Daniel: Yes, in this way the project template is just an ordinary project, and there is no need to make some template placeholder transformations.

### What about extra files? please delete

Daniel: Then I will continue. There are some template directories and files (such as module template directories, component template files) in my project template, but I don't want to see these templates in the generated project.

Mr. Egg: OK, no problem, just delete the specified files and directories. Let's modify the `main.removeFiles` in `ncgen-config.js`.

> Example description:  
> Delete the `ncgen-config.js` and `src/components/base/Template.vue` files in the generated project

```js
export default {
  main: {
    removeFiles: ["ncgen-config.js", "src/components/base/Template.vue"],
  },
};
```

### One-stop service: automatic installation of dependencies

Daniel: I just noticed that the above example will automatically install dependencies when it runs. It should be installed with `npm`, can this support `yarn`? If I am a non-NodeJS project, such as Python, Go, etc., can I do it?

Mr. Egg: Of course! The generated `ncgen-config.js` uses `npm i` to install dependencies by default. See the example below. If you want to change to `yarn`, just change `command` to `yarn install`. And if it is Python, Go and other languages, you only need to change `command` to the corresponding dependency installation command.

```js
export default {
  main: {
    installDependencies: {
      skip: false,
      tips: "Dependencies are being installed, it may take a few minutes",
      command: "npm i",
    },
  },
};
```

### Finally, give some friendly tips

Daniel: That’s great. The project scaffolding was completed in just a few clicks. I think a friendly welcome and beautiful ending is needed in the end.

Mr. Egg: Simply modify the `main.welcome` and `main.complete` as you wish

```js
export default {
  main: {
    welcome: "Welcome to use (Vue 3 + TypeScript + Vite) project generator",
    
    ...
    
    complete: "Congratulations, the operation is successful",
  },
};
```

## High-frequency use is not scaffolding

Daniel: The scaffolding is done, but it is only used when building a new project. High-frequency operations are still part of the increase in code, such as adding a functional module, adding a component, adding an API, etc.

Mr. Egg: I understand what you mean. Old rules, you ask me to answer

### The code template exists in the project template

Daniel: I want to add a new component to a project. I don't want to copy an existing component and then perform various operations to modify and delete the code. In fact, there is a component template in the project template

Mr. Egg: OK. Let's first add a subcommand called `add-component` in `ncgen-config.js`.

> Example description (assuming that the values ​​of category and name are'busi' and'demo' respectively):  
> `description` is used to describe the function of a subcommand.  
> `api.listDirs` This API is very useful for allowing users to choose where to insert the code.  
> The configuration of `addFilesTo` will insert the src/components/base/Template.vue in the project template into the src/components/busi/Demo.vue file in the project.

```js
export default {
  sub: {
    "add-component": {
      description: "Add vue component",
      
      prompt: [
        {
          type: "list",
          choices: function () {
            return api.listDirs("src/components/");
          },
          name: "category",
          message: "Please select the category",
        },
        {
          type: "input",
          name: "name",
          message: "What is the component name",
          validate(input) {
            if (!input) return "The component name is required";
            return true;
          },
        },
      ],
      
      tmplSource: "https://github.com/daniel-dx/vue3-ncgen-demo.git",
      
      addFilesTo: function () {
        const answers = this.$answers;
        return {
          "src/components/base/Template.vue": `src/components/${answers.category}/${answers.nameObj.upperFirstCamelCase}.vue`,
        };
      },
    },
  },
};
```

![](https://camo.githubusercontent.com/7acb96a3fdffb99386744eac7ef6f59a166eab84b784de19dd4fdab31329c8ce/68747470733a2f2f70362d6a75656a696e2e62797465696d672e636f6d2f746f732d636e2d692d6b3375316662706663702f32336332616533636637343434373735623161636537616531643834616630617e74706c762d6b3375316662706663702d77617465726d61726b2e696d616765)

### The code template does not exist in the project template

Daniel: Pretty. But for the existing projects, these projects are not from the project template, and I also want to add some sub-commands to generate part of the code for the project, how to do?

Mr. Egg: The subcommand supports two ways to add files, one is the code template from the project template mentioned above, and the other is dynamically created by you. Both can be used at the same time. The following example demonstrates how to dynamically create a code file

> Example description (assuming that the values ​​of category and name are'busi' and'demo' respectively):  
> The configuration of `addFiles` will create a src/components/busi/Demo.md file in the project. The content of this file is `# Demo`

```js
export default {
  sub: {
    "add-component": {
      addFiles: function () {
        const answers = this.$answers;
        return {
          [`src/components/${answers.category}/${answers.nameObj.upperFirstCamelCase}.md`]: function () {
            return `# ${answers.nameObj.upperFirstCamelCase}`;
          },
        };
      },
    },
  },
};
```

### Highly recommended replacement technique

Daniel: Next, some file contents are modified (for example, when a page is added, the routing rules file will be automatically modified to register routes for the page), right? The operation is the same as the main command.

Mr. Egg: Well savvy. A tip recommended here is to add some identification comments where you need to insert the fragment code, as shown in the **src/App.vue** code:

```
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
  <!-- Don't touch me-place component -->
</template>

<script lang="ts">
import {defineComponent} from'vue'
import HelloWorld from'./components/busi/HelloWorld.vue'
// <!-- Don't touch me-import component -->
export default defineComponent({
  name:'App',
  components: {
    HelloWorld,
    // <!-- Don't touch me-register component -->
  }
})
</script>
```

Cooperate with `api.insertBefore` this API to insert the specified content before the specified matching position of the file

```js
export default {
  sub: {
    updateFiles: function () {
      const answers = this.$answers;
      return {
        "src/App.vue": function (content, options) {
          return api.insertBefore(content, {
            "// <!-- Don't touch me-import component -->": `import ${answers.nameObj.upperFirstCamelCase} from'./components/${answers.category}/${answers.nameObj.upperFirstCamelCase }.vue'`,
            "// <!-- Don't touch me-register component -->": `${answers.nameObj.upperFirstCamelCase},`,
            "<!-- Don't touch me-place component -->": `<${answers.nameObj.upperFirstCamelCase}/>`,
          });
        },
        [`src/components/${answers.category}/${answers.nameObj.upperFirstCamelCase}.vue`]: function (
          content,
          options
        ) {
          return api.replace(content, {
            Template: `${answers.nameObj.upperFirstCamelCase}`,
          });
        },
      };
    },
  },
};
```

Daniel: Perfect. Thank you brother egg. I am now eager to try my first code generator

Mr. Egg: Welcome, looking forward to your feedback


## Written at the end

### Above - complete configuration

For the complete configuration of `ncgen-config.js` in the example, please view: https://github.com/daniel-dx/vue3-ncgen-demo/blob/master/ncgen-config.js

### Below - ncgen official website

[![](https://daniel-dx.github.io/ncgen/logo.png)](https://daniel-dx.github.io/ncgen/)

---

Keywords: ncgen, scaffolding, generator, code generator