新生代小鮮肉之代碼生成器

WX20210509-175440@2x.png

若是你能耐心看完這個對話,
也許你會想動動手配置一個代碼生成器,
這樣你的擼碼生活可能今後就會有所變化,變得愈發輕鬆。

從一個腳手架提及

丹尼爾: 最近要搞個代碼生成器,可以快速生成項目代碼那種,蛋兄有什麼推薦?vue

蛋先生: 過往一直使用 yeoman,快超 10k star 的開源項目。可是,今天要推薦給你的,並不是 yeoman,而是一個新生代的小鮮肉 ncgen,它可能顯得更加的平易近人。git

丹尼爾: 我最最喜歡簡單的了,這個咋用呢?github

蛋先生: 老規矩,你說你的需求,我試着一一解答npm

首先,你須要一個項目模板

丹尼爾: 我有一個項目模板(好比:vue3-ncgen-demo),我但願新建的項目都來自於這個項目模板,這樣我只需專心維護好這個項目模板便可。json

蛋先生: OK,這就是項目腳手架的功能了。咱們來看下 ncgen 是如何處理的。api

第一步 安裝 ncgenui

$ npm i ncgen -g # yarn global add ncgen

第二步 生成配置文件 ncgen-config.js,該配置文件描述了代碼生成器的邏輯this

$ ncgen genConf

第三步 修改 ncgen-config.js 中的 main.tmplSource 爲項目模板的地址。spa

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, 代碼生成器, 腳手架

相關文章
相關標籤/搜索