头图

WX20210509-175440@2x.png

If you can watch this dialogue patiently,
Maybe you want to configure a code generator,
In this way, your masquerade life may change and become more relaxed from then on.

Speaking from a scaffold

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

Mr. Egg: Yeoman has always been used in the past, and it is an open source project that is faster than 10k star. However, what I want to recommend to you today is not yeoman, but a new generation of fresh meat 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 ), 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 ncgen is handled.

The first step is to install ncgen

$ npm i ncgen -g # yarn global add ncgen

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

$ ncgen genConf

The third step is to modify ncgen-config.js in main.tmplSource as the address of the project template.

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

Try it out:

ncgen ncgen-config.js

Simple copying is not enough, minor revisions are the norm

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 modifications ncgen-config.js in main.prompt and main.updateFiles

Example description:
package.json file in the generated project, and the rules are as follows:
vue3-ncgen-demo string 0609b51aee5a4c with the project name entered by the user
Daniel.xiao string 0609b51aee5a60 with the author name entered by the user
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,
        });
      },
    },
  }
};

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.

The extra files were done yesterday? 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. We modify ncgen-config.js in main.removeFiles .

Example description:
ncgen-config.js and src/components/base/Template.vue files in the generated project
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: Yes, yes, 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.

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 is completed in just a few clicks. I think we need a friendly welcome and beautiful ending in the end.

Mr. Egg: As you wish, simply modify main.welcome and main.complete

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 code increase, 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 are code templates for components in the project template

Mr. Egg: OK. We first ncgen-config.js increase in a call add-component sub-command.

Example description (assuming that the values of category and name are'busi' and'demo' respectively):
description used to describe the function of the subcommand.
api.listDirs This API is very useful when allowing users to choose where to insert the code.
addFilesTo will insert the src/components/base/Template.vue in the project template into the src/components/busi/Demo.vue file in the project.
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`,
        };
      },
    },
  },
};

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 subcommands to generate part of the code for the project, yesterday?

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):
addFiles will create the src/components/busi/Demo.md file in the project. The content of this file is # Demo
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}`;
          },
        };
      },
    },
  },
};

Recommended replacement techniques for cracked walls

Daniel: Next, some file content changes (such as adding a page, 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 little trick 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>

api.insertBefore with the 0609b51af079a0 API to insert the specified content before the specified matching position of the file

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. Thanks to the egg brother, I feel that I have already started the second line of duty, and I am eager to try my first code generator

Mr. Egg: No thanks, looking forward to your feedback

Write at the end

Above-complete configuration

ncgen-config.js the complete configuration of 0609b51af07a3f in the example, https://github.com/daniel-dx/vue3-ncgen-demo/blob/master/ncgen-config.js

Below-ncgen official website


Keywords: ncgen, scaffolding, generator, code generator, scaffolding


蛋先生DX
307 声望2 粉丝

ncform / ncgen / nice-hooks 作者