如何為前端項目一鍵自動添加eslint和prettier的支持

本文來自讀者@那個曾經的少年回來了 寫的源碼共讀35期筆記文章,授權投稿,寫的真好。

本文參加了由公眾號@若川視野?發起的每周源碼共讀活動,點此加我微信 ruochuan12 了解詳情一起參與。

本文屬于源碼共讀第35期 | 為 vite 項目自動添加 eslint 和 prettier點擊了解本期詳情一起參與?https://juejin.cn/post/7113563466211786783

前言

我之前好多次都是一步一步的安裝eslint和prettier及相關依賴,一個配置文件一個配置文件的粘貼復制,并修改其中的相關配置。而且可能會在每個項目中都要去處理,如果項目工程規劃化以后,eslint和prettier確實是項目少不了的配置。不知道你有沒有像我一樣操作過呢?

那么有沒有一種更簡單的方式去處理呢?答案是我終于遇到了。通過若川大佬的源碼共讀活動發現了,真的是太棒了。

本文以vite腳手架創建的項目為基礎進行研究的,如果是其他腳手架創建的項目,那么就要自己去修改處理,但是原理是一樣的。

那么接下來,我就要來一探究竟,先看看如何使用,然后查閱一下它的源碼,看看它到底是如何實現的呢?

1、vite創建項目

  • 創建項目

yarn?create?vite

一頓操作以后項目就創建完畢了

c03962e28400387c46f04b3766320051.png
image.png
  • 2、安裝依賴

yarn
  • 3、運行項目

yarn?dev
  • 4、運行初始化eslint和prettier命令

yarn?create?vite-pretty-lint

先來看沒有執行命令前的文件目錄

3cf2ae21f2502d89f9f5b4e06b7b2535.png
image.png

再來看執行完命令后的文件目錄

33d796876ac721ac2df35e508796fd56.png
image.png

可以發現文件目錄中增加了eslint和prettier的相關配置,package.json中增加了相關的依賴、以及vite.config.xx文件也增加了相關配置,具體的文件變更可以查看https://github.com/lxchuan12/vite-project/commit/6cb274fded66634191532b2460dbde7e29836d2e。

一個命令干了這么多事情,真的太優秀了。接下來我們就去看看這如此優秀的源代碼吧

2、整個過程的示意圖

通過大致的查看源代碼,簡單總結出來的代碼執行過程示意圖,僅供參考

21dbba1e153b33abf5ae9dd739334212.png
未命名文件 (3).png

3、源碼調試過程

3.1、找到調試代碼的位置

通過package.json中的bin節點可以發現,yarn create vite-pretty-lint最終執行的便是lib/main.js中的代碼

"bin":?{"create-vite-pretty-lint":?"lib/main.js"},

3.2、 開始調試的命令

因為我們現在只是要執行lib/main.js這個入口文件,通過package.jsonscripts 也沒有發現執行命令,所以現在我們可以直接通過node來運行代碼

node?lib/main.js

調試成功的結果如下圖所示

f540aadbfb0b750250caf2349f4c40fc.png
企業微信截圖_16564645675849.png

3.3、 查看頭部引入的模塊

  • chalk終端多色彩輸出

npm?i?chalkimport?chalk?from?'chalk'const?log?=?console.log
//?字體背景顏色設置
log(chalk.bgGreen('chalk打印設置')?)//?字體顏色設置
log(chalk.blue('Hello')?+?'?World'?+?chalk.red('!'))//?自定義顏色
const?custom?=?chalk.hex('#F03A17')
const?bgCustom?=?chalk.bgHex('#FFFFFF')
log(custom('customer'))
log(bgCustom('bgCustom'))

執行效果如下圖所示

e9f96a108a6d8bbc71fa36851921fa36.png
image.png
  • gradient 文字顏色漸變

//?安裝
npm?i?gradient-string
//?引入
import?gradient??from?'gradient-string'//?使用
console.log(gradient('cyan',?'pink')('你好啊賽利亞歡迎來到編碼世界'));
console.log(gradient('cyan',?'pink')('你好啊賽利亞歡迎來到編碼世界'));
console.log(gradient('cyan',?'pink')('你好啊賽利亞歡迎來到編碼世界'));
console.log(gradient('cyan',?'pink')('你好啊賽利亞歡迎來到編碼世界'));
console.log(gradient('cyan',?'pink')('你好啊賽利亞歡迎來到編碼世界'));

執行效果如下圖所示

d2e6138a52d2da91f8d06128a9ff4653.png
image.png
  • child_process node.js中的子進程。

    在node.js中,只有一個線程執行所有的操作,如果某個操作需要大量消耗CPU資源的話,后續的操作就需要等待。后來node.js就提供了一個child_process模塊,通過它可以開啟多個子進程,在多個子進程之間可以共享內存空間,可以通過子進程的互相通信來實現信息的交換。

import?{?exec?}?from?'child_process';exec('ls',(error,?stdout,stderr)=>?{if(error)?{console.log(error)return;}console.log('stdout:?'?+?stdout)console.log('執行其他操作')
})

執行效果如下圖所示

b1832c9e216eb73383adf0db1c20e12d.png
image.png
  • fs fs用來操作文件的模塊

import?fs?from?'fs'//?同步的讀取方法,用來讀取指定文件中的內容
fs.readFileSync()?
//?同步的寫入方法,用來向指定文件中寫內容
fs.writeFileSync()
  • path路徑分類

import?path?from?'path';//?拼接路徑
console.log(path.join('src',?'task.js'));??//?src/task.js
  • nanospinner命令行中的加載動畫

//?安裝
npm?i?nanospinner//?引入模塊
import?{?createSpinner?}?from?'nanospinner';const?spinner?=?createSpinner('Run?test').start()setTimeout(()?=>?{spinner.success()
},?1000)

執行效果如下圖所示(Run test在加載的一個效果)

51ed08a085933103f10a0d2a21676894.gif
3.gif
  • enquirer (utils.js文件)

交互式詢問CLI 簡單說就是交互式詢問用戶輸入

npm?i?enquirer?import?enquirer?from?'enquirer'?let?tempArray?=?['major(1.0.0)','minor(0.1.0)',?'patch(0.0.4)',?"customer"?]
const?{?release?}?=?await?enquirer.prompt({type:?'select',name:?'release',message:?'Select?release?type',choices:?tempArray
})if(release?===?'customer')?{console.log(release,?'customer')
}?else?{const?targetVersion?=?release.match(/\((.*)\)/)[1]console.log(targetVersion,?'targetVersion')
}

執行效果如下圖所示:先出來一個下拉選擇,選擇完后根據if判斷進行輸出

892cd71996558ba99c78aa0ae6a6a064.gif
4.gif

3.4、 調試具體代碼

3.4.1、 main.js中的入口
async?function?run()?{//?所有的邏輯代碼
}run().catch((e)?=>?{console.error(e);
});

通過run函數封裝異步方法,這樣最外面調用run函數時可以通過異步方法的catch捕獲錯誤異常。

看一個小例子

const?runTest?=?async?()?=>?{console.log('Running?test')throw?new?Error('run?test報錯了')
}runTest().catch(err?=>?{console.log('Error:?'?+?err)
})

執行后打印順序如下

Running?test
Error:?Error:?run?test報錯了

可以發現catch中截獲了異常

接下來開始進入run函數了

3.4.2、 打印色彩字體
//?這個看上面的引入模塊解析即可
console.log(chalk.bold(gradient.morning('\n🚀?Welcome?to?Eslint?&?Prettier?Setup?for?Vite!\n'))
);
3.4.3、 交互式命令行
export?function?getOptions()?{const?OPTIONS?=?[];fs.readdirSync(path.join(__dirname,?'templates')).forEach((template)?=>?{const?{?name?}?=?path.parse(path.join(__dirname,?'templates',?template));OPTIONS.push(name);});return?OPTIONS;
}export?function?askForProjectType()?{return?enquirer.prompt([{type:?'select',name:?'projectType',message:?'What?type?of?project?do?you?have?',choices:?getOptions(),},{type:?'select',name:?'packageManager',message:?'What?package?manager?do?you?use?',choices:?['npm',?'yarn'],},]);
}try?{const?answers?=?await?askForProjectType();projectType?=?answers.projectType;packageManager?=?answers.packageManager;}?catch?(error)?{console.log(chalk.blue('\n👋?Goodbye!'));return;}

getOptions 函數根據fs.readdirSync讀取項目工程template文件夾下的所有文件,并通過path.parse轉換對象,來獲取文件名稱name

askForProjectType函數通過enquirer.prompt返回兩個交互式命令行,供用戶進行選擇projectType選擇項目類型:【react-ts】 【react】【vue-ts】 【vue】packageManager選擇項目包管理方式:【npm】 【yarn】

3.4.4、根據交互命令行返回結果進行匹配模板

假如我們上面選擇的是[vue-ts]

const?{?packages,?eslintOverrides?}?=?await?import(`./templates/${projectType}.js`
);

/template/vue-ts.js模板中的代碼(其中代碼較多但一看就明白我就不貼了),就是export導出了兩個固定的模板變量數組,packages則相當于要引入的npm模塊列表,eslintOverrides這算是.eslintrc.json初始化模板。

3.4.5、拼接變量數組
const?packageList?=?[...commonPackages,?...packages];
const?eslintConfigOverrides?=?[...eslintConfig.overrides,?...eslintOverrides];
const?eslint?=?{?...eslintConfig,?overrides:?eslintConfigOverrides?};

commonPackagesshared.js中預定義的公共的npm 模塊eslint則是通過公共npm模塊中的eslintConfig和上面選擇的template/xxxx.js中的進行拼接組成。

3.4.6、 生成安裝依賴包的命令
const?commandMap?=?{npm:?`npm?install?--save-dev?${packageList.join('?')}`,yarn:?`yarn?add?--dev?${packageList.join('?')}`,
};

packageList數組通過join轉換為字符串,通過命令將所有拼接npm模塊一起安裝

058007c459991d312805f6178e1508ee.png
image.png
3.4.7、 讀取項目的vite配置文件
const?projectDirectory?=?process.cwd();const?viteJs?=?path.join(projectDirectory,?'vite.config.js');const?viteTs?=?path.join(projectDirectory,?'vite.config.ts');const?viteMap?=?{vue:?viteJs,react:?viteJs,'vue-ts':?viteTs,'react-ts':?viteTs,};const?viteFile?=?viteMap[projectType];const?viteConfig?=?viteEslint(fs.readFileSync(viteFile,?'utf8'));const?installCommand?=?commandMap[packageManager];if?(!installCommand)?{console.log(chalk.red('\n??Sorry,?we?only?support?npm?and?yarn!'));return;}

根據選擇的項目類型,來拼接vite.config的路徑,并讀取項目中的vite.config配置文件

上面用到了一個函數viteEslint,這個具體的實現可以去看shared.js中,主要就是讀取文件內容后,傳入的參數code,就是vite.config.ts中的所有字符

6e446af53b8b683d3c39da2a45847c5a.png通過babel的parseSync轉換為ast。ast對象如下圖所示

41e19b28d740ff66e4a79bdc80acf64e.png
1656558646620.png

對ast數據進行了一系列的處理后,再通過babeltransformFromAstSync將ast轉換為代碼字符串。

對于babel處理這一塊我也不太了解,有時間我得去加一下餐,具體的可以參考 https://juejin.cn/post/6844904008679686152

3.4.8 執行命令、執行完將eslint和prettier配置重寫
const?spinner?=?createSpinner('Installing?packages...').start();exec(`${commandMap[packageManager]}`,?{?cwd:?projectDirectory?},?(error)?=>?{if?(error)?{spinner.error({text:?chalk.bold.red('Failed?to?install?packages!'),mark:?'?',});console.error(error);return;}const?eslintFile?=?path.join(projectDirectory,?'.eslintrc.json');const?prettierFile?=?path.join(projectDirectory,?'.prettierrc.json');const?eslintIgnoreFile?=?path.join(projectDirectory,?'.eslintignore');fs.writeFileSync(eslintFile,?JSON.stringify(eslint,?null,?2));fs.writeFileSync(prettierFile,?JSON.stringify(prettierConfig,?null,?2));fs.writeFileSync(eslintIgnoreFile,?eslintIgnore.join('\n'));fs.writeFileSync(viteFile,?viteConfig);spinner.success({?text:?chalk.bold.green('All?done!?🎉'),?mark:?'?'?});console.log(chalk.bold.cyan('\n🔥?Reload?your?editor?to?activate?the?settings!'));});

首先通過createSpinner來創建一個命令行中的加載,然后通過child_process中的exec來執行[3.4.6]中生成的命令,去安裝依賴并進行等待。

如果命令執行成功,則通過fs.writeFileSync將生成的數據寫入到三個文件當中.eslintrc.json.prettierrc.json.eslintignorevite.config.xx

4、npm init、npx

印象里面大家可能對它的記憶可能都停留在,npm init之后是快速的初始化package.json,并通過交互式的命令行讓我們輸入需要的字段值,當然如果想直接使用默認值,也可以使用npm init -y

create-app-react創建項目命令,官網鏈接可以直接查看 https://create-react-app.dev/docs/getting-started

//官網的三種命令
npx?create-react-app?my-app
npm?init?react-app?my-app
yarn?create?react-app?my-app//我又發現npm?create也是可以的
npm?create?react-app?my-app

上述這些命令最終效果都是可以執行創建項目的

同樣的vite創建項目的命令

//官網的命令
npm?create?vite@latest
yarn?create?vite
pnpm?create?vite//?指定具體模板的
//?npm?6.x?
npm?create?vite@latest?my-vue-app?--template?vue?
//npm?7+,?extra?double-dash?is?needed:?
npm?create?vite@latest?my-vue-app?--?--template?vueyarn?create?vite?my-vue-app?--template?vuepnpm?create?vite?my-vue-app?--template?vue

可以發現vite官網沒有使用npx命令,不過我在我自己電腦上嘗試了另外幾個命令確實也是可以的

npx?create-vite?my-app
npm?init?vite?my-app
b2536e5aaabf11187f826307fe184b97.png
image.png

通過上面的對比可以一個小問題,yarn create去官網查了是存在這個指令的,官網地址可看 https://classic.yarnpkg.com/en/docs/cli/create#search

而對于npm create這個命令在npm官網是看不到的,但是在一篇博客中發現了更新日志

ceb6ebbc4b18d2b63b971f3737548d34.png
image.png

意思就是說npm create xxxnpm init xxx 以及yarn create xxx效果是一致的。那么我們來本文的命令行

//?我們是通過npm安裝的,并且包名里是包含create的
npm?i?create-vite-pretty-lint//?那么以下幾種方式都可以使用的
npm?init?vite-pretty-lint
npm?create?vite-pretty-lint
yarn?create?vite-pretty-lint
npx?create-vite-pretty-lint

再來看一下npx

假如我們只在項目中安裝了vite,那么node_modules.bin文件夾下是會存在vite指令的

d1926712c93afb1fc639b03496075aff.png
image.png

如果我們想在該項目下執行該命令第一種方式便是

90df14eda5afec9652312282c5605bd5.png
image.png

第二種方式就是直接在package.json的scripts屬性下

932bcaf30626a0f17763f039d5c31b07.png
image.png

關于npx的詳細說明可以看一下阮一峰大佬的精彩分享 http://www.ruanyifeng.com/blog/2019/02/npx.html

5、總結

  • npm init xxx的妙用,以及對npx的了解,感覺對package.json的每一個屬性,可以專門去學習一下

  • 對于自動添加eslint和prettier配置的原理分析

  • .eslintrc.json、.eslintignore、.prettierrc.json算是直接新增文件,處理相對簡單一些

  • 最重要的學習點:對vite.config文件在原有基礎上的修改,這里就涉及到了AST抽象語法樹

6、加餐 V8下的AST抽象語法樹

有興趣的話可以看看我前幾天剛剛總結的關于V8引擎是如何運行JavaScript代碼的,其中就涉及到關于AST的部分https://juejin.cn/post/7109410330295402509。

接下來有時間我會簡單的把AST詳細的學習一下,查了很多資料發現AST還是非常重要的,無論是babel、webpack、vite、vue、react、typescript等都使用到了AST。

c8917c257eeedc0945322f0fa8c056e9.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經堅持寫了8年,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助4000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

fceedffdbba1ccb5b21d6126ef31b6e6.jpeg

掃碼加我微信 ruochuan12、拉你進源碼共讀

今日話題

目前建有江西|湖南|湖北?籍 前端群,想進群的可以加我微信 ruochuan12?進群。分享、收藏、點贊、在看我的文章就是對我最大的支持

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274607.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274607.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274607.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Server.Transfer方法在頁面間傳值

a.aspx頁面代碼: protected void Button5_Click(object sender, EventArgs e){Server.Transfer("b.aspx");}public string name{get{return this.TextBox1.Text;}} b.aspx頁面代碼: private void TheFour(){a newWebContext.Handler as a;//創…

極端原理_為極端而設計

極端原理*You can also read this article in German here.*您也可以 在此處 閱讀 德語文章 。 In this article I’m going to draw on the Design thinking concept of designing for extreme users and I will argue that designing for extreme users can be considered a…

當CV工程師碰到了拷貝粘貼的需求——useClipboard的使用及源碼解析

大家好,我是若川。持續組織了近一年的源碼共讀活動,感興趣的可以 點此加我微信ruochuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。…

centos利用tar包安裝phpmyadmin

我的網站根目錄地址為/var/www/html,phpmyadmin安裝包在/tmp下。 注意:php版本低于5.1的建議安裝phpmyadmin2.11,因為phpmyadmin3.3對php版本的最低要求是php5.2 1 [rootCentOS ~]# tar -zxvf /tmp/phpMyAdmin-2.11.9-all-languages.tar.gz …

ux和ui_從UI切換到UX設計

ux和uiI still remember those days, when I was a soon-to-be graphic design graduate who started to question what my future will be. At that time, I realized that I loved graphic design, but I wasn’t sure if I enjoyed doing it. Creating logos, posters, broc…

春季招聘后前端工程師的就業指南

盡管疫情反復,大廠裁員,招聘季仍是在困難中有條不紊地落下了尾聲。回顧今年的春季招聘,北京青年報記者發現,互聯網“大廠”依然對“研發崗”需求最為旺盛。但許多企業最近都在圍繞“降本提效”來進行業務調整,這對技術…

探索式測試的思維模型

上一章介紹了探索式測試的定義。在實際項目的測試執行過程中,讀者是否曾遇到如下的幾個現象: 測試人員按照一個測試用例來執行測試,得到的程序輸出與預期輸出不一致。 測試人員判斷程序的行為并不是缺陷,但根據新的輸出想到了新的…

圖解Git分支和命令

大家好,我是若川。持續組織了近一年的源碼共讀活動,感興趣的可以 點此加我微信ruochuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。…

vsco_VSCO重新設計:更直觀,更簡化的界面

vscoAmong the many photo-editing apps, VSCO has definitely become a popular favorite among both experienced photographers as well as “aesthetic” Instagram users. However, my interaction with the app starts and ends with using a few key filters and (maybe…

不同長度數據項的排序

注:本文改編自windmissing博客,感謝作者整理! 題目: a)給定一個整數數組,其中不同的整數中包含的數字個數可能不同,但是該數組中,所有整數中總的數字數為n。說明如何在O(n)時間內對該數組進行排…

淺談前端埋點監控

大家好,我是若川。持續組織了近一年的源碼共讀活動,感興趣的可以 加我微信lxchuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外&…

css版式_第2部分:使版式具有響應能力,并為以后的版本奠定基礎

css版式The feedback I’ve received over the past week has been amazing, and matches my own excitement about this project. I’ve spent a lot of time researching, writing, and teaching about creating better typography for reading on digital devices over the …

BBS項目--登錄

BBS階段性測試總要求 django登錄報錯 Error: [WinError 10013] 以一種訪問權限不允許的方式做了一個訪問套接字的嘗試。 原因分析:出現這種情況在Windows中很常見,就是端口被占用 解決措施:這時我們只需改一下端口便可以了 登錄前端頁面(HTML…

【聲明】

我的公眾號和朋友圈有時會有一些課程推廣廣告,微博的收入來源。我接的廣告一般來說都是比自己去買會優惠不少,我也會想方設法爭取到更多福利(優惠)。買過的都知道確實優惠。如果有人看到覺得不合適,不想看到&#xff0…

Win7 訪問共享時輸入正確密碼仍然提示密碼錯誤

1、直接按下winr鍵,輸入secpol.msc,打開本地安全策略。 2、找到“安全設置”的“本地策略”的“安全選項” 3、在右邊一欄找到“網絡安全:LAN管理器身份驗證級別”,雙擊進入 4、在默認狀態選項下,英文版應該為"no…

怎么實現頁面友好跳轉_如何實現軟,友好和一致的UI設計

怎么實現頁面友好跳轉重點 (Top highlight)Design trends are constantly changing, aren’t they? Each month there is a new visual effect or a trick that becomes “設計趨勢在不斷變化,不是嗎? 每個月都有一個新的視覺效果或技巧,成為…

前端趨勢 2022

大家好,我是若川。持續組織了近一年的源碼共讀活動,感興趣的可以 加我微信lxchuan12 參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列。另外&…

MySQL Connector/ODBC 5.2.2 發布

MySQL Connector/ODBC 5.2.2 發布,這是一個穩定版本,下載地址: http://dev.mysql.com/downloads/connector/odbc/5.2.html MySQL Connector/ODBC 是 MySQL 官方發布的 ODBC 驅動程序包。轉載于:https://www.cnblogs.com/shihao/archive/2012/…

優秀測試管理工具必備九大功能分析

摘要:測試管理工具對測試的重要性毋庸質疑,兩位筆者有著多年的測試實戰經驗,對市面上的一些測試管理工具有過一定的研究,還根據目前比較流行的敏捷開發過程設計了一款測試管理工具。 這篇文章算是對這個設計過程的總結與分享&…

lightroom預設使用_在Lightroom中使用全景圖增強照片游戲

lightroom預設使用Everyone here has taken a panorama with an iphone. We’ve spun around in a circle, trying to keep that arrow right on the line, and more than likely ended up with a strange, squiggly, horizontal photo. Every so often you might get lucky an…