小型前端腳手架工具Plop

隱冬發表於2020-12-30

小型的腳手架工具,是一款主要用於去建立專案中特定型別檔案的小工具,類似於Yeoman中的sub generator, 不過它一般不會獨立去使用,一般我們會把Plop整合到專案當中。

接下來我們來通過兩個案例的對比,去體會一下Plop的真正作用及他的優勢。

日常開發中經常會遇到這樣的問題,我們在開發當中,經常需要重複去建立相同型別的檔案,例如每一個元件都會有三個檔案去組成。分別是js,css,test.js, 如果我們需要建立一個元件,就要去建立三個檔案,並且每一個檔案中都要有一些基礎程式碼,這就比較繁瑣,而且我們很難統一每一個元件檔案中那些基礎的程式碼。Plop可以結局這個問題,我們只需要在命令列中取執行Plop

yarn plop component

會詢問我們一些資訊,並且自動的幫我們建立一些檔案,這也就保證了我們每次建立的檔案都是統一的,並且是自動的。

Plop的基本使用

接下來我們一起在一個專案彙總加入Plop的整合,去了解一下Plop他該如何使用,使用Plop的第一件事就是將Plop作為一個npm的模組安裝到我們的開發依賴當中。

yarn add plop --dev

安裝過後我們在專案的跟目錄下新建一個plopfile.js檔案,這個檔案是plop工作的一個入口檔案,需要匯出一個函式,而且這個函式可以接收一個叫plop的物件,並且這個物件提供了一系列工具函式,用於去幫我們建立生成器的任務。

module.exports = plop => {
    plop.setGenerator('component', {});
}

plop有個成員叫setGenerator, 接收兩個引數,第一個引數是生成器的名字,第二個引數是生成器的一些選項。

在配置選項中我們需要指定一下生成器的引數

{
    description: '生成器的描述',
    prompts: [ // 發出的命令列問題
        {
            type: 'input',
            name: 'name',
            message: 'component name',
            default: 'MyComponent'
        }
    ],
    actions: [ // 問題完成後的動作
        {
            type: 'add', // 新增一個全新的檔案
            path: 'src/components/{{name}}/{{name}}.js', // 指定新增的檔案會被新增到哪個具體的路徑, 可以通過雙花括號的方式使用命令列傳入的變數
            templateFile: 'plop-templates/component.hbs', // 本次新增檔案的母版檔案是什麼, 一般我們會把母版檔案放在plop-template目錄中,可以通過handlebars去建立模板檔案.hbs
        }

    ]
}

資料填寫完畢我們這個Plop就算是完成了。

在安裝Plop模組的時候plop提供了一個CLI程式,可以通過yarn啟動這個程式。
yarn plop ; // 生成器的名字

yarn plop component

yarn 會自動找到node_modules下bin目錄下的命令列工具,回車過後就會執行我們上面定義的plop

我們可以嘗試為生成器新增多個模板,就是新增多個actions, 官網中提供了多個type, 可以參考官網。

這就是Plop的一個基本使用,在這個過程中我們可以發現,Plop用來去建立專案當中同型別的檔案還是非常方便的。

總結一下我們在一個專案當中具體去使用Plop需要這樣幾個步驟,首先我們需要將plop模組作為專案開發依賴去安裝,然後我們需要在專案目錄下建立一個plopfile.js檔案,在有了plopfile檔案過後我們需要在plopfile.js檔案中定義一些腳手架任務,最後我們去編寫一些用於生成特定型別檔案的模板,這一切都完成過後我們需要通過plop提供的cli執行剛剛制定的腳手架任務,從而去生成我們在專案當中一些特定型別的檔案。

腳手架的工作原理

通過詢問你一些預設的問題,然後將你回答的結果結合一些模板檔案,給你生成一個專案結構。

那接下來我們以一個小型的腳手架工具為例,通過NodeJS完成一個Node工具,再來去深入體會一下Node工具的工作過程。

那我們知道腳手架工具實際上就是一個node-cli應用,那建立腳手架就是建立一個node-cli應用,那這裡我們具體來操作一下,我們首先進入到命令列,通過mkdir去建立一個工具目錄

mkdir samlpe-cli
cd sample-cli

在這個目錄下面我們通過yarn init 方式去初始化一個package.json檔案

yarn init

有了這個檔案之後通過編輯器開啟這個目錄,緊接著我們需要在package.json中新增一個bin欄位,用於去指定一下我們cli應用的入口檔案, 我們這裡叫cli.js

{
  "name": "sample-cli",
  "bin": "cli.js",
  ...
}

再然後我們新增這個cli.js檔案,跟以往我們在Node中書寫的檔案有所不同,cli的入口檔案必須要有一個特定的檔案頭, 也就是在這個檔案頂部寫上這樣一句話 #! /usr/bin/env node我們在這個檔案中console.log一句話。

#! /usr/bin/env node

console.log('cli working')

如果說你的作業系統是linux或者mac系統你還還需要去修改這個檔案的讀寫許可權,把他修改成755,這樣才可以作為一個cli的入口檔案。

我們回到命令列,我們通過yarn link 將這個模組對映到全域性

yarn link

這時候我們就可以在命令列使用sample這樣一個命令, 通過執行這個命令我們的console.log成功列印出來,表示程式碼執行了。也就意味著我們這個cli基礎就已經ok了。

sample-cli

接下來我們實現一下腳手架的具體業務,也就是我們腳手架的工作過程。

首先我們需要通過命令列互動的的方式去詢問使用者的一些資訊,然後緊接著呢根據使用者反饋回來的結果我們去生成檔案,

  1. 通過命令列互動的方式詢問使用者資訊

  2. 根據使用者反饋回來的結果生成檔案

在Node當中去發起命令列互動詢問我們使用inquirer這樣一個模組,那我們需要通過npm安裝一下這個模組,我這裡使用yarn,安裝在依賴檔案當中。

yarn add inquirer --dev

那有了這個模組過後就可以在程式碼中去載入, inquirer這個模組提供一個叫做prompt的方法用於發起一個命令列的詢問。

他可以接收一個陣列引數,陣列中每一個成員就是一個問題,可以通過type指定問題輸入方式,然後name指定返回值的鍵,message去指定螢幕上給使用者的一個提示,在promise的then裡面拿到這個問題接收到使用者的答案。

我們這裡不著急往下寫,我們先通過console.log去列印一下。

const inquirer = require('inquirer');

inquirer.prompt([
    {
        type: 'input',
        name: 'name',
        message: 'Project name'
    }
]).then(answer => {
    console.log(answer);
})

回到控制檯,我們命令列執行sample-cli, 此時就會提示我們需要輸入專案的名稱。

sample-cli

這樣就可以看到問題和返回的結果。這也就證明inquirer確實可以幫我們發起命令列互動詢問。

那有了inquirer之後接下來我們要考慮的就是動態的去生成我們的專案檔案。

我們一般會根據模板去生成,所以我們在專案的跟目錄下新建一個templates目錄,在這個目錄下我們去新建一些模板。

由於我們這裡是討論腳手架的工作過程,所以我們也不去關心模板裡面有什麼,我們就隨便寫點什麼。我們可以通過 <%%>去替換詢問過程中得到的答案。

index.html

<head>
    <title><%= name %></title>
</head>

我們還可以新增一些其他的模板檔案,比如style.css

style.css

body {
    margin: 0;
    background-color: red;
}

回到cli.js檔案, 這時候我們可以在得到問題答案的位置,根據使用者回答的問題去生成檔案。不過在生成前我們一般會先將模板路徑和目標目錄確定下來。

模板的目錄應該是專案當前目錄的templates,我們可以通過path獲取。

const path = require('path');

// 工具當前目錄
const tmplDir = path.join(__dirname, 'templates');

輸出的目標目錄一般是我們命令列在哪個目錄去執行就應該是哪個路徑,也就是cwd目錄

const path = require('path');

// 工具當前目錄
const tmplDir = path.join(__dirname, 'templates');
// 命令列所在目錄
const destDir = process.cwd();

明確這兩個目錄,我們就可以通過fs模組去讀取一下模板目錄下一共有哪些檔案。把這些檔案全部輸入到我們的目標目錄,我們通過fs的readDir方法,這個方法會自動掃描目錄下的所有檔案

fs.readdir(tmplDir, (err, files) => {
    if (err) {
        throw err;
    }
    files.forEach(file => {
        console.log(file); // 得到每個檔案的相對路徑
    })
})

我們可以通過模板引擎去渲染路徑對應的檔案,先去安裝一款模板引擎,這裡我們使用ejs

yarn add ejs --dev

安裝過後,回到程式碼中引入這個模板引擎, 通過模板引擎提供的renderFile去渲染這個路徑對應的檔案。

第一個引數是檔案的絕對路徑,第二個引數是模板引擎在工作的時候的資料上下文,第三個引數是回撥函式,也就是我們在渲染成功過後的回撥函式,當然如果你在渲染過程中出現了意外那你可以通過throw err的方式把這個錯誤丟擲去。

我們可以先把result通過列印的方式列印出來看一下。

const fs = require('fs');
const path = require('path');
const inquirer = require('inquirer');
const ejs = require('ejs');

// 工具當前目錄
const tmplDir = path.join(__dirname, 'templates');
// 命令列所在目錄
const destDir = process.cwd();

inquirer.prompt([
    {
        type: 'input',
        name: 'name',
        message: 'Project name'
    }
]).then(answer => {
    fs.readdir(tmplDir, (err, files) => {
        if (err) {
            throw err;
        }
        files.forEach(file => {
            ejs.renderFile(path.join(tmplDir, file), answer, (err, result) => {
                if (err) {
                    throw err;
                }
                console.log(result);
            })
        })
    })
})

編輯完成之後我們執行一下腳手架工具。

sample-cli

此時列印出來的這個結果其實是已經經過模板引擎工作過後的結果,我們只需要將這個結果通過檔案寫入的方式寫入到目標目錄就可以了,那目標目錄應該是通過path.join把我們destDir以及我們的file做一個拼接。內容就是我們這裡的result。

files.forEach(file => {
    ejs.renderFile(path.join(tmplDir, file), answer, (err, result) => {
        if (err) {
            throw err;
        }
        fs.writeFileSync(path.join(destDir, file), result);
    })
})

完成過後我們找到一個新的目錄,使用一下這個腳手架

sample-cli

我們輸入專案名稱過後,就會發現他會自動把我們模板裡面的檔案自動生成到對應的目錄裡面,至此我們就已經完成了一個非常簡單,非常小型的一個腳手架應用。

那我們也回顧了一下腳手架的工作過程,其實腳手架的工作原理並不複雜,但是他的意義卻是很大的,因為他確實在建立專案環節大大提高了我們的效率。

我們可以將自己的工具釋出至npm上,提供給更多的人使用。

至於釋出npm也非常的簡單,首先我們需要註冊npm賬號,有兩種方式可以註冊,一種是登入npm官網https://www.npmjs.com/, 另一種是使用命令npm adduser

npm adduser

會提示你輸入使用者名稱,密碼,以及郵箱。

註冊好後登入npm賬號。

npm login

依次輸入第二步中第一種方法註冊的使用者名稱、密碼和郵箱。

登入成功後執行npm釋出命令。

npm publish

注意:如果報錯:‘You do not have permission to publish “samlpe-cli”. Are you logged in as the correct user?’

表示包samlpe-cli名字已經在包管理器已經存在被別人用了,需要更該包名稱,我們可以前往package.json中的name中換一個名字。

{
  "name": "sample-cli1",
  "version": "1.0.0",
  "bin": "cli.js",
  ...
}

再次執行publish命令。出現 +sample-cli1@1.0.0即表示釋出成功。

如果釋出時報錯:no_perms Private mode enable, only admin can publish this module:

表示當前不是原始映象,要切換回原始的npm映象

npm config set registry https://registry.npmjs.org/

至此你的node工具就可以提供給其他人使用了。

如果需要更新你的工具,只要繼續執行npm publish就可以更新發布了,不過需要注意,每次釋出都需要修改版本號version的值,同一個版本不允許釋出兩次。

{
  "name": "sample-cli1",
  "version": "1.0.1",
  "bin": "cli.js",
  ...
}

如果想要撤銷本次釋出可以執行

npm unpublish

不過需要注意,只有在發包的24小時內才允許撤銷釋出的包,超過24小時,就無法撤回了。

相關文章