日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

手写一个合格的前端脚手架

發(fā)布時間:2023/12/9 HTML 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 手写一个合格的前端脚手架 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

為什么我們需要一套腳手架

為什么我們需要一套腳手架,它能幫助我們解決哪些痛點問題。

?前端項目配置越來越繁瑣、耗時,重復(fù)無意義的工作?項目結(jié)構(gòu)不統(tǒng)一、不規(guī)范?前端項目類型繁多,不同項目不同配置,管理成本高?腳手架也可以是一套命令集,不只用來創(chuàng)建項目

那么為什么不用一些開源框架自身的 CLI 工具,需要自己開發(fā)呢,這里仁者見仁智者見智,我個人建議就是對于中型團隊以上需要自己維護一套腳手架,因為可控性高,能滿足團隊特定需求的研發(fā)。

如何按照開源要求開發(fā)一個前端腳手架?

下面是我們常見的前端開源目錄結(jié)構(gòu)

腳手架的設(shè)計

思路

?解耦:腳手架與模板分離?腳手架負責構(gòu)建流程,通過命令行與用戶交互,獲取項目信息?模板負責統(tǒng)一項目結(jié)構(gòu)、工作流程、依賴項管理?腳手架需要檢測模板的版本是否有更新,支持模板的刪除與新建?……

流程圖

代碼講解

目錄結(jié)構(gòu)

配置 Git hook

首先進行開發(fā)前的準備工作,來保證你代碼的質(zhì)量。

Husky + Lint-staged

通過 Git hook 完成 commitlint、ESLint、prettiter 等,具體配置我后面會給源碼,有興趣的可以自己搜索下。

// package.json "husky": {"hooks": {"pre-commit": "lint-staged","commit-msg": "commitlint -E HUSKY_GIT_PARAMS"}},"lint-staged": {"**/*.js": ["eslint --fix","prettier --write","git add"]}

package.json 下的 bin 字段

bin:配置內(nèi)部命令對應(yīng)的可執(zhí)行文件位置,配置命令后,npm 會尋找到對應(yīng)的可執(zhí)行文件,然后在 node_modules/.bin 目錄下建立對應(yīng)的符號鏈接。

由于 node_modules/.bin 會在運行時候加入到系統(tǒng)的環(huán)境變量,因此我們可以通過 npm 調(diào)用命令來執(zhí)行腳本。

所有 node_modules/.bin 目錄下的命令都可以通過 npm run [命令] 執(zhí)行。

所以我們需要在 package.json 配置入口

"bin": {"easy": "bin/easy.js"}

npm link 本地調(diào)試

這里介紹下開發(fā)腳手架的調(diào)試方法。npm link 官網(wǎng)使用介紹。使用方法:

// cd 到你項目的bin目錄(腳本)下 $ npm link

去掉 link 也非常方便:

npm unlink linkname

bin 目錄下的入口文件

#!/usr/bin/env nodeconst program = require('commander'); // 命令行工具 const chalk = require('chalk'); // 命令行輸出美化 const didYouMean = require('didyoumean'); // 簡易的智能匹配引擎 const semver = require('semver'); // npm的語義版本包 const enhanceErrorMessages = require('../lib/util/enhanceErrorMessages.js'); const requiredNodeVersion = require('../package.json').engines.node;didYouMean.threshold = 0.6;function checkNodeVersion(wanted, cliName) {// 檢測node版本是否符合要求范圍if (!semver.satisfies(process.version, wanted)) {console.log(chalk.red('You are using Node ' +process.version +', but this version of ' +cliName +' requires Node ' +wanted +'.\nPlease upgrade your Node version.'));// 退出進程process.exit(1);} }// 檢測node版本 checkNodeVersion(requiredNodeVersion, '@easy/cli');program.version(require('../package').version, '-v, --version') // 版本.usage('<command> [options]'); // 使用信息// 初始化項目模板 program.command('create <template-name> <project-name>').description('create a new project from a template').action((templateName, projectName, cmd) => {// 輸入?yún)?shù)校驗validateArgsLen(process.argv.length, 5);require('../lib/easy-create')(lowercase(templateName), projectName);});// 添加一個項目模板 program.command('add <template-name> <git-repo-address>').description('add a project template').action((templateName, gitRepoAddress, cmd) => {validateArgsLen(process.argv.length, 5);require('../lib/add-template')(lowercase(templateName), gitRepoAddress);});// 列出支持的項目模板 program.command('list').description('list all available project template').action(cmd => {validateArgsLen(process.argv.length, 3);require('../lib/list-template')();});// 刪除一個項目模板 program.command('delete <template-name>').description('delete a project template').action((templateName, cmd) => {validateArgsLen(process.argv.length, 4);require('../lib/delete-template')(templateName);});// 處理非法命令 program.arguments('<command>').action(cmd => {// 不退出輸出幫助信息program.outputHelp();console.log(` ` + chalk.red(`Unknown command ${chalk.yellow(cmd)}.`));console.log();suggestCommands(cmd); });// 重寫commander某些事件 enhanceErrorMessages('missingArgument', argsName => {return `Missing required argument ${chalk.yellow(`<${argsName}>`)}`; });program.parse(process.argv); // 把命令行參數(shù)傳給commander解析// 輸入easy顯示幫助信息 if (!process.argv.slice(2).length) {program.outputHelp(); }// easy支持的命令 function suggestCommands(cmd) {const avaliableCommands = program.commands.map(cmd => {return cmd._name;});// 簡易智能匹配用戶命令const suggestion = didYouMean(cmd, avaliableCommands);if (suggestion) {console.log(` ` + chalk.red(`Did you mean ${chalk.yellow(suggestion)}?`));} }function lowercase(str) {return str.toLocaleLowerCase(); }function validateArgsLen(argvLen, maxArgvLens) {if (argvLen > maxArgvLens) {console.log(chalk.yellow('\n Info: You provided more than argument. the rest are ignored.'));} }

其他代碼就不貼了我會給出源碼鏈接,下面分享一下幾個有意思的點。建議大家有興趣的跟著敲一遍,有很多小細節(jié)需要注意。

發(fā)布腳本

// script/release.jsconst { execSync } = require('child_process'); const semver = require('semver'); const inquirer = require('inquirer');const currentVerison = require('../package.json').version;const release = async () => {console.log(`Current easy cli version is ${currentVerison}`);const releaseActions = ['patch', 'minor', 'major'];const versions = {};// 生成預(yù)發(fā)布版本標示releaseActions.map(r => (versions[r] = semver.inc(currentVerison, r)));const releaseChoices = releaseActions.map(r => ({name: `${r} (${versions[r]})`,value: r}));// 選擇發(fā)布方式const { release } = await inquirer.prompt([{name: 'release',message: 'Select a release type',type: 'list',choices: [...releaseChoices]}]);// 優(yōu)先自定義版本const version = versions[release];// 二次確認發(fā)布const { yes } = await inquirer.prompt([{name: 'yes',message: `Confirm releasing ${version}`,type: 'confirm'}]);if (yes) {execSync(`standard-version -r ${release}`, {stdio: 'inherit'});} };release().catch(err => {console.error(err);process.exit(1); });

npm version 與 tag

官網(wǎng)關(guān)于 npm version 的介紹:

https://docs.npmjs.com/cli/version.html

如果不熟悉 Node 語義化版本可以閱讀:

https://semver.org/lang/zh-CN/ npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]'npm [-v | --version]' to print npm version 'npm view <pkg> version' to view a package's published version 'npm ls' to inspect current package/dependency versions

其實我們自己使用 npn publish,最終執(zhí)行的還是 npm version 下命令。

官網(wǎng)關(guān)于 npm-dist-tag 的介紹:

npm-dist-tag[1]

npm install <name>@<tag> npm install --tag <tag>

npm 也有 tag 的概念,一般情況下我們不會指定 tag,這個時候默認使用的就是 latest 這個 tag,所有的發(fā)布與安裝都是最新的正式版本,如果指定 tag 之后,我們可以在這個 tag 上發(fā)布一個新的版本,用戶安裝時候也可以指定這個 tag 來進行安裝,你可以簡單理解 tag 類型 git 中的 branch。

常用的一些關(guān)于 tag 的命令:

# 查看當前的tag和對應(yīng)的version。 npm dist-tag ls# 查看my-package發(fā)布過的所有版本號。 npm view my-package versions# 給my-package設(shè)置tag,對應(yīng)到版本version。 npm dist-tag add my-package@version tag

如果一不小心把測試版發(fā)布成了正式版?發(fā)布之前我們是這樣的:

latest: 1.0.0 next: 1.0.0-alpha.0

錯誤的把 1.0.0-alpha.1 直接 npm publish:

latest: 1.0.0-alpha.1 next: 1.0.0-alpha.0

解決方法:

# 把原來的1.0.0設(shè)置成最新的正式版 $ npm dist-tag add my-package@1.0.0 latest# 把1.0.0-alpha.1更新到最新的測試版 $ npm dist-tag add my-package@1.0.0-alpha.1 next

npm publish 一個包

1.創(chuàng)建一個 npm 賬戶2.cd 到你需要發(fā)布的 repo 倉庫下, 記得切換到 npm 源(或者公司內(nèi)網(wǎng)自建源)3.npm login,需要輸入用戶名、密碼、郵箱4.npm publish

集成 CI(Travis CI)自動發(fā)布

每次手動發(fā)布太 low 了,要是可以自動發(fā)布就好了。

Travis CI 提供的是持續(xù)集成服務(wù)(Continuous Integration,簡稱 CI)。它綁定 GitHub/GitLab 等上面的項目,只要有新的代碼,就會自動抓取。然后,提供一個運行環(huán)境,執(zhí)行測試,完成構(gòu)建,還能部署到服務(wù)器。

持續(xù)集成指的是只要代碼有變更,就自動運行構(gòu)建和測試,反饋運行結(jié)果。確保符合預(yù)期以后,再將新代碼“集成”到主干。

簡單理解就是:它的作用是自動幫你做好從代碼測試到發(fā)布的一系列流程,配合版本控制使用的話可以設(shè)置成每一次 push 都自動進行一次集成,保證代碼的正確性。

注意現(xiàn)在 GitHub 也出了集成工具,感興趣的可以去體驗下。

如果你的項目是在 GitHub 并且是開源的,推薦使用這個?org[2]

使用 GitHub 進行登錄 Travis CI,完成一些授權(quán)工作,Travis CI 才能監(jiān)聽到你的 GitHub 項目代碼的變化。

Travis CI 要求你項目的根目錄必須有一個配置文件 .travis.yml 文件,這是一個配置文件,指定 travis 的行為,該文件還必須保存在 GitHub 的倉庫。一旦有新的 push,travis 就會找到這個文件進行執(zhí)行。

關(guān)于 travis 更多使用推薦閱讀官網(wǎng)[3],這里主要講下利用?travis 自動發(fā)布包到 npm[4],Continuous Integration environments[5]

下面是一個 .travis.yml 配置文件:

language: node_js node_js:- '8' cache:directories:- node_modules install:- npm install script:- npm run lint deploy:provider: npmemail: "$NPM_EMAIL"api_key: "$AUTH_TOKEN"skip_cleanup: trueon:branch: master # after_success:

然后在你的 travis 上選擇需要開啟 CI 的項目。

配置對應(yīng)環(huán)境變量到該倉庫下如:

環(huán)境變量名格式必須為“大寫字母_大寫字母”格式。

token 生成也非常簡單,官網(wǎng)[6]介紹,可以直接在你的 npm 賬戶下的 tokens 頁面手動生成或者通過 npm 命令行生成。

# 切換到npm源下, 登陸npm npm login# 生成token, npm可以指定生成token的權(quán)限(只讀或者可讀可寫) npm token create

然后配置一些腳本來執(zhí)行 npm version,這樣當你包版本有更新后 push 到 GitHub repo,就會觸發(fā) travis 自動發(fā)包到 npm。

DEMO

源碼鏈接[7]

推薦閱讀

若川知乎高贊:有哪些必看的 JS庫?
我在阿里招前端,我該怎么幫你?(現(xiàn)在還可以加模擬面試群)
如何拿下阿里巴巴 P6 的前端 Offer
如何準備阿里P6/P7前端面試--項目經(jīng)歷準備篇
大廠面試官常問的亮點,該如何做出?
如何從初級到專家(P4-P7)打破成長瓶頸和有效突破
若川知乎問答:2年前端經(jīng)驗,做的項目沒什么技術(shù)含量,怎么辦?

末尾

你好,我是若川,江湖人稱菜如若川,歷時一年只寫了一個學(xué)習(xí)源碼整體架構(gòu)系列~(點擊藍字了解我)

  • 關(guān)注若川視野,回復(fù)"pdf" 領(lǐng)取優(yōu)質(zhì)前端書籍pdf,回復(fù)"1",可加群長期交流學(xué)習(xí)

  • 我的博客地址:https://lxchuan12.gitee.io?歡迎收藏

  • 覺得文章不錯,可以點個在看呀^_^另外歡迎留言交流~

  • 精選前端好文,伴你不斷成長

    若川原創(chuàng)文章精選!可點擊

    小提醒:若川視野公眾號面試、源碼等文章合集在菜單欄中間【源碼精選】按鈕,歡迎點擊閱讀,也可以星標我的公眾號,便于查找

    總結(jié)

    以上是生活随笔為你收集整理的手写一个合格的前端脚手架的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。