您現在的位置是:首頁 > 遊戲

前端工程化之專案腳手架

由 前端學習棧 發表于 遊戲2023-02-04
簡介我們後端採用了 feathersjs 庫,但是不太喜歡它提供的腳手架,於是自己定製了一個,效果如下:製作腳手架製作腳手架整個過程分如下 5 個步驟(簡稱 cpcar):cli 專案初始化parse 命令列引數clone 腳手架模板ask 用

前端腳手架是什麼意思

前端工程化之專案腳手架

前端工程化之專案腳手架

在建築領域,腳手架是為了保證各施工過程順利進行而搭設的工作平臺。在軟體開發領域,如果把搭建專案想象成建造大型建築的話,腳手架就是為了方便大家快速進入業務邏輯的開發,一個好的腳手架能顯著提升工程效率,例如三大前端框架都提供了自己的腳手架工具:

Angular 中的 @angular/cli

Vue 中的 @vue/cli

React 中的 create-react-app

上述工具雖好,但相信很多公司為了滿足自身業務需要,也造了不少自己的輪子,約定使用自己的那一套配置,如果沒有腳手架,就只能把原專案程式碼複製過來,刪除無用的邏輯,只保留基礎能力,這個過程瑣碎且耗時。

因此,在這種情況下,就需要定製自己的開發模板,搭建一套屬於自己的前端腳手架了。

預備知識

要寫一個腳手架首先要掌握 node。js 的各種 API,然後還要充分利用別人寫好的一些類庫,例如下面就是必備的:

commander :TJ 大神的又一神作,腳手架必備工具,能夠幫我們解析命令列的各種引數,透過回撥完成具體邏輯實現。

inquirer:強大的互動式命令列工具,使用者可以在命令列進行單選或多選,也可以用 prompts 這個庫,用法和效果都是類似的。

chalk :能夠在命令列中給文字上色,從而突出重點,例如 error 用紅色,warning 用黃色,success 用綠色,視覺效果非常好。

metalsmith :靜態網站生成器,可以讀取指定資料夾下面的模板檔案,經過一系列的外掛處理,把檔案輸出到新的目錄下。

掌握了上面的工具之後,就可以寫一個自己的腳手架了。我們後端採用了 feathersjs 庫,但是不太喜歡它提供的腳手架,於是自己定製了一個,效果如下:

前端工程化之專案腳手架

製作腳手架

製作腳手架整個過程分如下 5 個步驟(簡稱 cpcar):

cli 專案初始化

parse 命令列引數

clone 腳手架模板

ask 使用者專案配置

render 專案檔案

接下來逐一介紹:

cli 專案初始化

首先建立空目錄並進行初始化:

$ mkdir feathers-cli

$ cd feathers-cli

$ npm init -y

複製程式碼

然後用 vscode 開啟,為 package。json 新增 bin 欄位如下:

{

“name”: “feathers-cli”,

“main”: “index。js”,

“bin”: {

“feat”: “。/bin/feat。js”

}

}

複製程式碼

然後建立 bin 資料夾,在裡面新建一個 feat。js 檔案,內容是:

#! /usr/bin/env node

console。log(‘My custom feathers scaffold’)

複製程式碼

然後在根目錄下執行:

$ npm link

$ feat

My custom feathers scaffold

複製程式碼

到這裡,專案初始化就完成了。此時,npm 會在全域性下建立一個 feat 可執行檔案,它是一個軟連結,指向 bin/feat。js,所以後面每次修改內容,都會輸出最新的結果,不需要重新執行 npm link 命令。

parse 命令列引數

接下來需要利用 commander 來解析命令列引數,例如當用戶輸入 feat ——help 的時候能夠輸出幫助提示,首先安裝依賴包:

$ npm i commander

複製程式碼

然後修改 bin/feat。js 內容為:

#! /usr/bin/env node

const program = require(‘commander’)

program。parse(process。argv)

複製程式碼

此時輸入命令就能看到提示訊息了:

$ feat ——help

Usage: feat [options]

Options:

-h, ——help display helpforcommand

複製程式碼

這是 commander 預設幫我們新增的幫助資訊,目前還沒有配置任何的命令,接下來完善程式碼如下:

#! /usr/bin/env node

const program = require(‘commander’)

const pkg = require(‘。。/package。json’)

program

。command(‘create ’)

。description(‘create a new project powered by feathers-cli’)

。option(‘-f, ——force’, ‘override’)

。action((name, cmd) => {

console。log(‘name’, name)

console。log(‘cmd。options’, cmd。options)

console。log(‘cmd。args’, cmd。args)

})

program。version(pkg。version)。usage(` [options]`)

program。parse(process。argv)

複製程式碼

此時輸出內容就豐富多了:

$ feat ——help

Usage: feat [options]

Options:

-V, ——version output the version number

-h, ——help display helpforcommand

Commands:

create [options] create a new project powered by feathers-cli

help [command] display helpforcommand

複製程式碼

輸入 feat create xxx 的時候可以在回撥裡面獲取到相關引數:

name hello-world

cmd。options [

Option {

flags: ‘-f, ——force’,

required: false,

optional: false,

variadic: false,

mandatory: false,

short: ‘-f’,

long: ‘——force’,

negate: false,

description: ‘override’,

defaultValue: undefined

}

cmd。args [ ‘hello-world’ ]

複製程式碼

接下來就是完善回撥函數里面的邏輯了。

clone 腳手架模板

我們根據業務需求自己定義了一套模板 feathers-template-default,用腳手架建立專案的本質上就是把這套模板下載下來,然後再根據使用者的喜好,按照模板生成不同結構的工程檔案而已。

一般來講,模板都是放到使用者根目錄下的一個隱藏檔案中的,我們定義的目錄名為 ~/。feat-templates,首次透過 feat create xxx 的時候透過 git clone 把這套模板下載到上面定義的目錄中,後面再建立專案只需 git pull 更新即可,所以接下來就是實現倉庫的下載和更新方法了,其實就是利用 spawn 對 git 命令進行封裝:

git clone 的封裝

// 克隆倉庫

functionclone(repo, opts) {

returnnewPromise((resolve, reject) => {

const args = [‘clone’]

args。push(repo)

args。push(opts。targetPath)

const proc = spawn(‘git’, args, {cwd: opts。workdir})

proc。stdout。pipe(process。stdout)

proc。stderr。pipe(process。stderr)

proc。on(‘close’, (status) => {

if (status == 0) return resolve()

reject(newError(`‘git clone’ failed with status ${status}\n`))

})

})

}

複製程式碼

git pull 的封裝

asyncfunctionpull(cwd) {

returnnewPromise((resolve, reject) => {

const process = spawn(‘git’, [‘pull’], { cwd })

process。on(‘close’, (status) => {

if (status == 0) return resolve()

reject(newError(`‘git pull’ failed with status ${status}`))

})

})

}

複製程式碼ask 使用者專案配置

有了模板,專案主體結構就定下來了,接下來就是定義一些問題,讓使用者自己選擇專案配置:

const questions = {

projectName: {

type: ‘text’,

message: ‘專案名’,

validate: (answer) => (answer。trim() ? true : ‘專案名不能為空’),

initial: ‘my-project’,

},

projectDescription: {

type: ‘text’,

message: ‘專案描述’,

initial: ‘My Awesome Project!’,

},

needCacher: {

type: ‘toggle’,

message: ‘需要快取嗎?’,

initial: true,

active: ‘是’,

inactive: ‘否’,

},

cacher: {

type: ‘select’,

message: ‘請選擇快取方案’,

choices: [

{ title: ‘Memory’, value: ‘Memory’ },

{ title: ‘Redis’, value: ‘Redis’ },

],

when(answers) {

return answers。needCacher

},

initial: 1,

},

needWebsocket: {

type: ‘toggle’,

message: ‘需要 websocket 嗎?’,

initial: false,

active: ‘是’,

inactive: ‘否’,

},

needLint: {

type: ‘toggle’,

message: ‘需要 ESLint 嗎?’,

initial: true,

active: ‘是’,

inactive: ‘否’,

},

needJest: {

type: ‘toggle’,

message: ‘需要 Jest 嗎?’,

initial: true,

active: ‘是’,

inactive: ‘否’,

},

}

複製程式碼

然後透過一個迴圈進行遍歷,挨個詢問:

asyncfunctionask(questions, data) {

const names = Object。keys(questions)

for (let i = 0; i < names。length; i++) {

const name = names[i]

const value = questions[name]

// 拿到問題,然後組裝成 Inquirer 或 prompts 所需要的格式

const question = { /* 省略組裝程式碼 */ }

const answer = await prompts(question)

Object。assign(data, answer)

}

}

複製程式碼render 專案檔案

模板引擎有很多,例如 ejs、handlebars 等都可以用,在這裡以 handlebars 為例,先定義兩個幫助函式:

Handlebars。registerHelper(‘if_eq’, function (a, b, opts) {

return a === b

? opts。fn(this)

: opts。inverse(this)

})

Handlebars。registerHelper(‘unless_eq’, function (a, b, opts) {

return a === b

? opts。inverse(this)

: opts。fn(this)

})

複製程式碼

然後透過 metalsmith 外掛進行渲染:

Metalsmith(process。cwd())

。metadata({

projectName: ‘專案名稱’,

projectDescription: ‘專案描述’,

// 這裡的資料實際上是上一步 ask 獲得的

})

。source(‘~/。feat-templates/feathers-template-default/templates/app’) // 模板檔案位置

。destination(process。cwd()) // 專案位置

。use(msPlugins。filterFiles(options。filters)) // 過濾檔案

。use(msPlugins。renderTemplateFiles()) // 渲染模板

。build((err) => {

if (err) {

log(`Metalsmith build error: ${err}`)

}

})

複製程式碼

推薦文章