关于脚手架:新生代小鲜肉之代码生成器

24次阅读

共计 5245 个字符,预计需要花费 14 分钟才能阅读完成。

如果你能急躁看完这个对话,
兴许你会想动动手配置一个代码生成器,
这样你的撸码生存可能从此就会有所变动,变得愈发轻松。

从一个脚手架说起

丹尼尔: 最近要搞个代码生成器,可能疾速生成我的项目代码那种,蛋兄有什么举荐?

蛋学生: 过往始终应用 yeoman,快超 10k star 的开源我的项目。然而,明天要举荐给你的,并非 yeoman,而是一个新生代的小鲜肉 ncgen,它可能显得更加的平易近人。

丹尼尔: 我最最喜爱简略的了,这个咋用呢?

蛋学生: 老规矩,你说你的需要,我试着一一解答

首先,你须要一个我的项目模板

丹尼尔: 我有一个我的项目模板(比方:vue3-ncgen-demo),我心愿新建的我的项目都来自于这个我的项目模板,这样我只需分心保护好这个我的项目模板即可。

蛋学生: OK,这就是我的项目脚手架的性能了。咱们来看下 ncgen 是如何解决的。

第一步 装置 ncgen

$ npm i ncgen -g # yarn global add ncgen

第二步 生成配置文件 ncgen-config.js,该配置文件形容了代码生成器的逻辑

$ ncgen genConf

第三步 批改 ncgen-config.js 中的 main.tmplSource 为我的项目模板的地址。

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

运行一下试试:

ncgen ncgen-config.js

简略复制还不行,小修小改是常态

丹尼尔: 哎呦不错哦。不过目前生成的我的项目跟我的项目模板是截然不同的,但它总会有属于本人的跟我的项目模板不一些的信息,比方项目名称,作者姓名等。这些我可不心愿每次生成完我的项目还要手工批改哦。

蛋学生: OK,要求十分正当。因为这些信息是创立我的项目的人才能提供,所以咱们须要通过一些问题来收集这些信息,而后就能够依据这些信息对生成的我的项目作一些批改。咱们批改下 ncgen-config.js 中的 main.promptmain.updateFiles

示例阐明:
对生成我的项目中的 package.json 文件进行字符串替换,规定如下:
vue3-ncgen-demo 字符串替换成用户录入的项目名称
Daniel.xiao 字符串替换成用户录入的作者名称

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,
        });
      },
    },
  }
};

丹尼尔: 咦,我留神到这里并没应用模板引擎,而是间接应用字符串替换

蛋学生: 是的,这个设计有很大的意义。用了模板引擎来替换文件,可能会导致我的项目模板本身无奈失常运行,因为模板引擎须要占位符,而占位符可能会导致代码解析谬误

丹尼尔: 也是,这样一来我的项目模板就是一个一般的我的项目而已,也不必特意去做一些模板占位符的革新

多余的文件昨办?请删除

丹尼尔: 那我持续。我的我的项目模板外面放了一些模板目录和文件(比方模块模板目录,组件模板文件),但我不想在生成的我的项目外面看到这些模板的货色。

蛋学生: OK,没问题,就是须要删除指定的文件和目录。咱们批改下 ncgen-config.js 中的 main.removeFiles

示例阐明:
删除生成我的项目中的 ncgen-config.jssrc/components/base/Template.vue 文件

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

一条龙服务:主动装置依赖

丹尼尔: 我刚刚有留神到,下面的例子在运行的时候会主动装置依赖,应该是用 npm 装置的吧,这个能反对 yarn 吗?如果我是非 NodeJS 我的项目,比方 Python,Go 等,也能做到吗?

蛋学生: 嗯,没错,生成的 ncgen-config.js 默认是应用 npm i 来装置依赖,看下边的示例。如果你想换成 yarn,只需把 command 改成 yarn install。而如果是 Python,Go 等其它语言,也只需将 command 改成对应的依赖装置命令即可

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

最初,给点敌对的提醒

丹尼尔: 太棒了,我的项目脚手架就这么配几下就实现了,我想最初须要来个敌对的欢送和丑陋的 ending

蛋学生: 如你所愿,简略批改下 main.welcomemain.complete 即可

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

高频应用的并非脚手架

丹尼尔: 脚手架是搞定了,但它只在新建我的项目时才应用,高频操作还是局部代码的减少,比方加一个功能模块,加一个组件,加一个 API 之类的

蛋学生: 我了解你的意思。老规矩,你问我答

代码模板存在于我的项目模板中

丹尼尔: 我当初要在一个我的项目中新加一个组件,我并不心愿复制一个已有组件,而后进行各种批改删除代码的操作。事实上我的项目模板中有组件的代码模板

蛋学生: OK。咱们先在 ncgen-config.js 中减少一个叫 add-component 的子命令。

示例阐明(假如 category 和 name 的值别离为 ‘busi’ 和 ‘demo’):
description 用于形容子命令的性能。
api.listDirs 这个 API,在让用户抉择将代码插入到哪个地位时十分有用。
addFilesTo 的配置会将我的项目模板中的 src/components/base/Template.vue 插入到我的项目中的 src/components/busi/Demo.vue 文件。

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`,
        };
      },
    },
  },
};

代码模板不存在于我的项目模板中

丹尼尔: 丑陋。不过对于曾经存在的我的项目,这些我的项目并非来自我的项目模板,而我也想加一些子命令来为我的项目生成局部代码,昨整?

蛋学生: 子命令反对两种增加文件的形式,一种就是下面提到的来自于我的项目模板的代码模板,还有一种就是你动态创建。两者可同时应用。以下示例演示如何动态创建代码文件

示例阐明(假如 category 和 name 的值别离为 ‘busi’ 和 ‘demo’):
addFiles 的配置会在我的项目中创立 src/components/busi/Demo.md 文件,这个文件的内容为 # 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}`;
          },
        };
      },
    },
  },
};

墙裂举荐的替换技巧

丹尼尔: 接着,又是进行一些文件内容的批改(比方减少了页面,会主动批改路由规定文件为页面注册路由),跟主命令一样的操作是吧。

蛋学生: 悟性很高嘛。这里举荐一个小技巧,就是在须要插入片段代码的中央退出一些标识正文,如 src/App.vue 代码所示:

<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 这个 API 在文件的指定匹配地位前插入指定的内容

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}`,
          });
        },
      };
    },
  },
};

丹尼尔: 完满。谢了蛋兄,我感觉我曾经打道任督二脉,蠢蠢欲动我的第一个代码生成器了

蛋学生:不谢,期待你的反馈

写在最初

以上 – 残缺配置

例子中 ncgen-config.js 的残缺配置请查看:https://github.com/daniel-dx/…

以下 – ncgen 官网


关键字:ncgen, scaffolding, generator, 代码生成器, 脚手架

正文完
 0