前端如何搭建一個成熟的腳手架
有了之前的基礎( 前端如何搭建一個簡單的腳手架 ),我們現在可以講講一個成熟的腳手架是怎麼做了。
這裡我們參考vue-cli的原始碼,基於rollup和typescript一步步搭建。vue-cli作為vue的腳手架,給如此多的前端開發者使用,已經算是成熟了吧。
開始
以下我們的命令仍然是 ds ~,模板是 ds-cli-lib-template
目錄結構
├─ bin# 打包檔案目錄 │├─ ds.js# package.json裡的bin欄位引用檔案 ├─ src │├─ lib# 具體命令目錄 │├─ list# ds list │├─ init# ds init │├─ utils# 工具函式 ├─ main.ts# 入口檔案 ├─ typings# typescript型別檔案目錄 ├─ rullup.config.js # rollpu構建配置 ├── test#測試用例 複製程式碼
編寫構建配置
現如今,webpack用來開發應用(熱更新hmr,程式碼拆分等),rollup用來開發類庫(簡單易上手,打包後代碼能讀懂,至於其他的特性webpack目前基本已支援)。
現在來明確我們的需求
- 使用typescript編寫模組程式碼
- 打包成umd模組規範的程式碼
- 可以引用commonjs規範的包(因為歷史原因,大多數包都不是ES模組規範)
- 壓縮打包程式碼,減少體積
//rollup.config.js import typescript from "rollup-plugin-typescript2"; import commonjs from 'rollup-plugin-commonjs' import { uglify } from 'rollup-plugin-uglify' export default { //入口檔案 input: "src/main.ts", output: [ { banner: "#!/usr/bin/env node", /** * 頭部插入這段程式碼 * */ name: "ds", file: "bin/ds.js", //打包成umd模組規範 format: "umd" } ], plugins: [ typescript(), commonjs({ include: "node_modules/**", extensions: ['.js', '.ts'] }), uglify() ], }; 複製程式碼
npm指令碼命令("scripts"欄位)
{ "clean": "rm -rf ./bin && mkdir bin", "build": "npm run clean && rollup --config" } 複製程式碼
編寫入口檔案
是一些非常基礎的東西,我們一般不放很複雜的邏輯在入口檔案裡。
const cmd = require('commander'); const config = require('../package.json'); //這裡cli-init.ts和cli-list.ts我們可以簡單匯出一個函式,如 // export default function(...args) { //console.log('init') // } import init from './lib/init/cli-init'; import list from './lib/list/cli-list'; const command= { init, list }; //map對應的type,從而執行 function exec(type, ...args) { config.debug = args[0].debug; command[type](...args); } cmd .usage('<command>') .version(config.version) .description('歡迎使用ds-cli'); cmd .command('init') .description('初始化元件模板') .action((...args) => exec('init', ...args)); cmd .command('list') .description('檢視線上元件模板') .action((...args) => exec('list', ...args)); cmd.command('help') .description('檢視幫助') .action(() => cmd.help()); // 解析輸入的引數 cmd.parse(process.argv); if (!cmd.args.length) { cmd.help(); } 複製程式碼
我們打包(執行npm run build)到bin資料夾下後,配置一下package.json的bin欄位為bin/ds.js,然後釋出npm(參考 快速釋出一個vue-fullpage元件到npm 試一下命令。
如果失敗,請重新審視上述之流程。
初始化模板
我們對模板的要求
- 檔案目錄必須含有template資料夾,並且所需模板檔案放在該目錄下

- 可用meta.js提高自定義程度(所謂動態化模板)
- 模板檔名命名規範是ds-cli-‘name’-template,方便腳手架拉取
- 可以不用線上的模板,如果本地有模板,可直接用之。如果是線上模板,那麼應該先下載到本地使用者目錄的.ds-templates目錄下(~/.ds-templates)
期望命令
ds init <template-name> <app-name> #模板名字和應用名字 複製程式碼
流程與邏輯
if(當前目錄下構建){ 詢問一下是不是當前目錄,是的話進入run函式 }else{ 進入主流程run函式 } //run函式 function run(){ if(模板路徑是本地檔案路徑){ //支援本地模板如ds init /usr/webpack test if(路徑存在){ //動態構造模板到你的目錄如test generate() }else{ //報錯日誌 } }else{ //1.檢查當前process的node版本,大於6才可以用 //2.檢查當前package.json的版本,跟遠端倉庫的版本比較一下。如果不一樣,就提醒一下使用者有新版本 //3.下載遠端倉庫到本地(本地一般存放使用者目錄裡的.ds-template資料夾下),然後執行generate函式 } } 複製程式碼
動態模板
大家也看到了,其實最重要的就是generate函式~
- 而如果我們去掉這一步generate模板的話,其實就是相當於下載一個 靜態模板 ,如果我們對於使用者自定義沒要求的話,其實可以跳過這一步。
- generate函式裡面用到了 metalsmith ,這個就相當於我們之前用的gulp,通過不斷地編寫中介軟體來優化打包後的結果。
function generate(){ const opts = getOptions(name, templatePath) as meta;// 獲取meta.js配置,存到opts裡 // 我們把所需檔案放在原始檔的template目錄下,其他一些如測試放在外面。初始化一下metalsmith const metalsmith = Metalsmith(path.join(templatePath, 'template')) //我們約定,將模板所有檔案放在ds-cli-lib-template/template裡 //中介軟體 metalsmith.use(askQuestions(opts.prompts))// 詢問問題,將資訊存metalsmith.metadata() .use(filterFiles(opts.filters))// 通過問題互動過濾掉不需要的檔案 .use(renderTemplateFiles()); // 模板裡面可以使用handlebar語法,作為佔位符,我們這裡重新渲染模板檔案 // 源目錄打包到目標目錄to metalsmith.clean(false) .source('.') .destination(to) .build((err, files) => { done(err); }); } 複製程式碼
- 我們在模板(如 ds-cli-lib-template )目錄下需要構造meta.js,自定義我們所需的欄位
module.exports={ //會通過中介軟體把這些欄位存在metalsmith.metadata(),方便接下來的中介軟體呼叫 prompts:{ //格式可以參考https://github.com/SBoudrias/Inquirer.js/#question name: { type: 'string', required: true, message: 'Project name', }, author: { type: 'string', message: 'Author', }, description: { type: 'string', required: false, message: 'Project description', default: '構建一個lib', }, lint: { "type": "confirm", "message": "是否用tslint" }, }, filters: { //當上面prompts的lint為false的時候,就過濾掉檔案 "tslint.json": "lint", "tsconfig.json": "lint" } } 複製程式碼
至此,這裡我們已經說明了基本原理,你應該已經可以搭出適合你團隊的腳手架和模板了。
參考
- ds-cli :目前暫時命令有init和list(獲取所有模板列表),含有詳細註釋,不懂你來!!!
- ds-cli-lib-template :基於rollup和typescript構建類庫
- ds-cli-doc-template :基於vuepress的文件模板