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
, 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 how ncgen
is processed.
The first step is to install ncgen
$ 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
$ ncgen genConf
Step 3 Modify main.tmplSource
in ncgen-config.js
to the url 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, 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 thepackage.json
file in the generated project, the rules are as follows:
Replace the stringvue3-ncgen-demo
with the project name entered by the user
Replace the stringDaniel.xiao
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.
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 thencgen-config.js
andsrc/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: 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.
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
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 ofaddFilesTo
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 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 ofaddFiles
will create a 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}`;
},
};
},
},
},
};
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
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
Keywords: ncgen, scaffolding, generator, code generator
Top comments (0)