一、Git
1. git 和 svn 的區(qū)別
- git 和 svn 最大的區(qū)別在于 git 是分布式的,而 svn 是集中式的。因此我們不能再離線的情況下使用 svn。如果服務(wù)器出現(xiàn)問題,就沒有辦法使用 svn 來提交代碼。
- svn 中的分支是整個(gè)版本庫(kù)的復(fù)制的一份完整目錄,而 git 的分支是指針指向某次提交,因此 git 的分支創(chuàng)建更加開銷更小并且分支上的變化不會(huì)影響到其他人。svn 的分支變化會(huì)影響到所有的人。
- svn 的指令相對(duì)于 git 來說要簡(jiǎn)單一些,比 git 更容易上手。
- GIT把內(nèi)容按元數(shù)據(jù)方式存儲(chǔ),而SVN是按文件:因?yàn)間it目錄是處于個(gè)人機(jī)器上的一個(gè)克隆版的版本庫(kù),它擁有中心版本庫(kù)上所有的東西,例如標(biāo)簽,分支,版本記錄等。
- GIT分支和SVN的分支不同:svn會(huì)發(fā)生分支遺漏的情況,而git可以同一個(gè)工作目錄下快速的在幾個(gè)分支間切換,很容易發(fā)現(xiàn)未被合并的分支,簡(jiǎn)單而快捷的合并這些文件。
- GIT沒有一個(gè)全局的版本號(hào),而SVN有
- GIT的內(nèi)容完整性要優(yōu)于SVN:GIT的內(nèi)容存儲(chǔ)使用的是SHA-1哈希算法。這能確保代碼內(nèi)容的完整性,確保在遇到磁盤故障和網(wǎng)絡(luò)問題時(shí)降低對(duì)版本庫(kù)的破壞
2. 經(jīng)常使用的 git 命令?
git init // 新建 git 代碼庫(kù)
git add // 添加指定文件到暫存區(qū)
git rm // 刪除工作區(qū)文件,并且將這次刪除放入暫存區(qū)
git commit -m [message] // 提交暫存區(qū)到倉(cāng)庫(kù)區(qū)
git branch // 列出所有分支
git checkout -b [branch] // 新建一個(gè)分支,并切換到該分支
git status // 顯示有變更文件的狀態(tài)
3. git pull 和 git fetch 的區(qū)別
- git fetch 只是將遠(yuǎn)程倉(cāng)庫(kù)的變化下載下來,并沒有和本地分支合并。
- git pull 會(huì)將遠(yuǎn)程倉(cāng)庫(kù)的變化下載下來,并和當(dāng)前分支合并。
4. git rebase 和 git merge 的區(qū)別
git merge 和 git rebase 都是用于分支合并,關(guān)鍵在 commit 記錄的處理上不同:
- git merge 會(huì)新建一個(gè)新的 commit 對(duì)象,然后兩個(gè)分支以前的 commit 記錄都指向這個(gè)新 commit 記錄。這種方法會(huì)保留之前每個(gè)分支的 commit 歷史。
- git rebase 會(huì)先找到兩個(gè)分支的第一個(gè)共同的 commit 祖先記錄,然后將提取當(dāng)前分支這之后的所有 commit 記錄,然后將這個(gè) commit 記錄添加到目標(biāo)分支的最新提交后面。經(jīng)過這個(gè)合并后,兩個(gè)分支合并后的 commit 記錄就變?yōu)榱司€性的記錄了。
二、Webpack
1. webpack與grunt、gulp的不同?
Grunt、Gulp是基于任務(wù)運(yùn)?的?具: 它們會(huì)?動(dòng)執(zhí)?指定的任務(wù),就像流?線,把資源放上去然后通過不同插件進(jìn)?加?,它們包含活躍的社區(qū),豐富的插件,能?便的打造各種?作流。
Webpack是基于模塊化打包的?具: ?動(dòng)化處理模塊,webpack把?切當(dāng)成模塊,當(dāng) webpack 處理應(yīng)?程序時(shí),它會(huì)遞歸地構(gòu)建?個(gè)依賴關(guān)系圖 (dependency graph),其中包含應(yīng)?程序需要的每個(gè)模塊,然后將所有這些模塊打包成?個(gè)或多個(gè) bundle。
因此這是完全不同的兩類?具,?現(xiàn)在主流的?式是?npm script代替Grunt、Gulp,npm script同樣可以打造任務(wù)流。
2. webpack、rollup、parcel優(yōu)劣?
- webpack適?于?型復(fù)雜的前端站點(diǎn)構(gòu)建: webpack有強(qiáng)?的loader和插件?態(tài),打包后的?件實(shí)際上就是?個(gè)?即執(zhí)?函數(shù),這個(gè)?即執(zhí)?函數(shù)接收?個(gè)參數(shù),這個(gè)參數(shù)是模塊對(duì)象,鍵為各個(gè)模塊的路徑,值為模塊內(nèi)容。?即執(zhí)?函數(shù)內(nèi)部則處理模塊之間的引?,執(zhí)?模塊等,這種情況更適合?件依賴復(fù)雜的應(yīng)?開發(fā)。
- rollup適?于基礎(chǔ)庫(kù)的打包,如vue、d3等: Rollup 就是將各個(gè)模塊打包進(jìn)?個(gè)?件中,并且通過 Tree-shaking 來刪除??的代碼,可以最?程度上降低代碼體積,但是rollup沒有webpack如此多的的如代碼分割、按需加載等?級(jí)功能,其更聚焦于庫(kù)的打包,因此更適合庫(kù)的開發(fā)。
- parcel適?于簡(jiǎn)單的實(shí)驗(yàn)性項(xiàng)?: 他可以滿?低?檻的快速看到效果,但是?態(tài)差、報(bào)錯(cuò)信息不夠全?都是他的硬傷,除了?些玩具項(xiàng)?或者實(shí)驗(yàn)項(xiàng)?不建議使?。
3. 有哪些常?的Loader?
- file-loader:把?件輸出到?個(gè)?件夾中,在代碼中通過相對(duì) URL 去引?輸出的?件
- url-loader:和 file-loader 類似,但是能在?件很?的情況下以 base64 的?式把?件內(nèi)容注?到代碼中去
- source-map-loader:加載額外的 Source Map ?件,以?便斷點(diǎn)調(diào)試
- image-loader:加載并且壓縮圖??件
- babel-loader:把 ES6 轉(zhuǎn)換成 ES5
- css-loader:加載 CSS,?持模塊化、壓縮、?件導(dǎo)?等特性
- style-loader:把 CSS 代碼注?到 JavaScript 中,通過 DOM 操作去加載 CSS。
- eslint-loader:通過 ESLint 檢查 JavaScript 代碼
注意:在Webpack中,loader的執(zhí)行順序是從右向左執(zhí)行的。因?yàn)閣ebpack選擇了compose這樣的函數(shù)式編程方式,這種方式的表達(dá)式執(zhí)行是從右向左的。
4. 有哪些常?的Plugin?
- define-plugin:定義環(huán)境變量
- html-webpack-plugin:簡(jiǎn)化html?件創(chuàng)建
- uglifyjs-webpack-plugin:通過 UglifyES 壓縮 ES6 代碼
- webpack-parallel-uglify-plugin: 多核壓縮,提?壓縮速度
- webpack-bundle-analyzer: 可視化webpack輸出?件的體積
- mini-css-extract-plugin: CSS提取到單獨(dú)的?件中,?持按需加載
5. bundle,chunk,module是什么?
- bundle:是由webpack打包出來的?件;
- chunk:代碼塊,?個(gè)chunk由多個(gè)模塊組合?成,?于代碼的合并和分割;
- module:是開發(fā)中的單個(gè)模塊,在webpack的世界,?切皆模塊,?個(gè)模塊對(duì)應(yīng)?個(gè)?件,webpack會(huì)從配置的 entry中遞歸開始找出所有依賴的模塊。
6. Loader和Plugin的不同?
不同的作?:
- Loader直譯為"加載器"。Webpack將?切?件視為模塊,但是webpack原?是只能解析js?件,如果想將其他?件也打包的話,就會(huì)?到 loader 。 所以Loader的作?是讓webpack擁有了加載和解析?JavaScript?件的能?。
- Plugin直譯為"插件"。Plugin可以擴(kuò)展webpack的功能,讓webpack具有更多的靈活性。 在 Webpack 運(yùn)?的?命周期中會(huì)?播出許多事件,Plugin 可以監(jiān)聽這些事件,在合適的時(shí)機(jī)通過 Webpack 提供的 API 改變輸出結(jié)果。
不同的?法:
- Loader在 module.rules 中配置,也就是說他作為模塊的解析規(guī)則?存在。 類型為數(shù)組,每?項(xiàng)都是?個(gè) Object ,??描述了對(duì)于什么類型的?件( test ),使?什么加載( loader )和使?的參數(shù)( options )
- Plugin在 plugins 中單獨(dú)配置。 類型為數(shù)組,每?項(xiàng)是?個(gè) plugin 的實(shí)例,參數(shù)都通過構(gòu)造函數(shù)傳?。
7. webpack的構(gòu)建流程
Webpack 的運(yùn)?流程是?個(gè)串?的過程,從啟動(dòng)到結(jié)束會(huì)依次執(zhí)?以下流程:
- 初始化參數(shù):從配置?件和 Shell 語句中讀取與合并參數(shù),得出最終的參數(shù);
- 開始編譯:?上?步得到的參數(shù)初始化 Compiler 對(duì)象,加載所有配置的插件,執(zhí)?對(duì)象的 run ?法開始執(zhí)?編譯;
- 確定??:根據(jù)配置中的 entry 找出所有的???件;
- 編譯模塊:從???件出發(fā),調(diào)?所有配置的 Loader 對(duì)模塊進(jìn)?翻譯,再找出該模塊依賴的模塊,再遞歸本步驟直到所有??依賴的?件都經(jīng)過了本步驟的處理;
- 完成模塊編譯:在經(jīng)過第4步使? Loader 翻譯完所有模塊后,得到了每個(gè)模塊被翻譯后的最終內(nèi)容以及它們之間的依賴關(guān)系;
- 輸出資源:根據(jù)??和模塊之間的依賴關(guān)系,組裝成?個(gè)個(gè)包含多個(gè)模塊的 Chunk,再把每個(gè) Chunk 轉(zhuǎn)換成?個(gè)單獨(dú)的?件加?到輸出列表,這步是可以修改輸出內(nèi)容的最后機(jī)會(huì);
- 輸出完成:在確定好輸出內(nèi)容后,根據(jù)配置確定輸出的路徑和?件名,把?件內(nèi)容寫?到?件系統(tǒng)。
在以上過程中,Webpack 會(huì)在特定的時(shí)間點(diǎn)?播出特定的事件,插件在監(jiān)聽到感興趣的事件后會(huì)執(zhí)?特定的邏輯,并且插件可以調(diào)? Webpack 提供的 API 改變 Webpack 的運(yùn)?結(jié)果。
8. 編寫loader或plugin的思路?
Loader像?個(gè)"翻譯官"把讀到的源?件內(nèi)容轉(zhuǎn)義成新的?件內(nèi)容,并且每個(gè)Loader通過鏈?zhǔn)讲僮?,將?件?步步翻譯成想要的樣?。
編寫Loader時(shí)要遵循單?原則,每個(gè)Loader只做?種"轉(zhuǎn)義"?作。 每個(gè)Loader的拿到的是源?件內(nèi)容(source),可以通過返回值的?式將處理后的內(nèi)容輸出,也可以調(diào)? this.callback() ?法,將內(nèi)容返回給webpack。 還可以通過this.async() ?成?個(gè) callback 函數(shù),再?這個(gè)callback將處理后的內(nèi)容輸出出去。 此外 webpack 還為開發(fā)者準(zhǔn)備了開發(fā)loader的?具函數(shù)集——loader-utils 。
相對(duì)于Loader??,Plugin的編寫就靈活了許多。 webpack在運(yùn)?的?命周期中會(huì)?播出許多事件,Plugin 可以監(jiān)聽這些事件,在合適的時(shí)機(jī)通過 Webpack 提供的 API 改變輸出結(jié)果。
9. webpack的熱更新是如何做到的?說明其原理?
webpack的熱更新?稱熱替換(Hot Module Replacement),縮寫為HMR。 這個(gè)機(jī)制可以做到不?刷新瀏覽器?將新變更的模塊替換掉舊的模塊。
原理:
?先要知道server端和client端都做了處理?作:
- 第?步,在 webpack 的 watch 模式下,?件系統(tǒng)中某?個(gè)?件發(fā)?修改,webpack 監(jiān)聽到?件變化,根據(jù)配置?件對(duì)模塊重新編譯打包,并將打包后的代碼通過簡(jiǎn)單的 JavaScript 對(duì)象保存在內(nèi)存中。
- 第?步是 webpack-dev-server 和 webpack 之間的接?交互,?在這?步,主要是 dev-server 的中間件 webpack-dev-middleware 和 webpack 之間的交互,webpack-dev-middleware 調(diào)? webpack 暴露的 API對(duì)代碼變化進(jìn)?監(jiān) 控,并且告訴 webpack,將代碼打包到內(nèi)存中。
- 第三步是 webpack-dev-server 對(duì)?件變化的?個(gè)監(jiān)控,這?步不同于第?步,并不是監(jiān)控代碼變化重新打包。當(dāng)我們?cè)谂渲?件中配置了devServer.watchContentBase 為 true 的時(shí)候,Server 會(huì)監(jiān)聽這些配置?件夾中靜態(tài)?件的變化,變化后會(huì)通知瀏覽器端對(duì)應(yīng)?進(jìn)? live reload。注意,這?是瀏覽器刷新,和 HMR 是兩個(gè)概念。
- 第四步也是 webpack-dev-server 代碼的?作,該步驟主要是通過 sockjs(webpack-dev-server 的依賴)在瀏覽器端和服務(wù)端之間建??個(gè) websocket ?連接,將 webpack 編譯打包的各個(gè)階段的狀態(tài)信息告知瀏覽器端,同時(shí)也包括第三步中 Server 監(jiān)聽靜態(tài)?件變化的信息。瀏覽器端根據(jù)這些 socket 消息進(jìn)?不同的操作。當(dāng)然服務(wù)端傳遞的最主要信息還是新模塊的 hash 值,后?的步驟根據(jù)這? hash 值來進(jìn)?模塊熱替換。
- webpack-dev-server/client 端并不能夠請(qǐng)求更新的代碼,也不會(huì)執(zhí)?熱更模塊操作,?把這些?作?交回給了webpack,webpack/hot/dev-server 的?作就是根據(jù) webpack-dev-server/client 傳給它的信息以及 dev-server 的配置決定是刷新瀏覽器呢還是進(jìn)?模塊熱更新。當(dāng)然如果僅僅是刷新瀏覽器,也就沒有后?那些步驟了。
- HotModuleReplacement.runtime 是客戶端 HMR 的中樞,它接收到上?步傳遞給他的新模塊的 hash 值,它通過JsonpMainTemplate.runtime 向 server 端發(fā)送 Ajax 請(qǐng)求,服務(wù)端返回?個(gè) json,該 json 包含了所有要更新的模塊的 hash 值,獲取到更新列表后,該模塊再次通過 jsonp 請(qǐng)求,獲取到最新的模塊代碼。這就是上圖中 7、8、9 步驟。
- ?第 10 步是決定 HMR 成功與否的關(guān)鍵步驟,在該步驟中,HotModulePlugin 將會(huì)對(duì)新舊模塊進(jìn)?對(duì)?,決定是否更新模塊,在決定更新模塊后,檢查模塊之間的依賴關(guān)系,更新模塊的同時(shí)更新模塊間的依賴引?。
- 最后?步,當(dāng) HMR 失敗后,回退到 live reload 操作,也就是進(jìn)?瀏覽器刷新來獲取最新打包代碼。
大概流程是我們用webpack-dev-server啟動(dòng)一個(gè)服務(wù)之后,瀏覽器和服務(wù)端是通過websocket進(jìn)行長(zhǎng)連接,webpack內(nèi)部實(shí)現(xiàn)的watch就會(huì)監(jiān)聽文件修改,只要有修改就webpack會(huì)重新打包編譯到內(nèi)存中,然后webpack-dev-server依賴中間件webpack-dev-middleware和webpack之間進(jìn)行交互,每次熱更新都會(huì)請(qǐng)求一個(gè)攜帶hash值的json文件和一個(gè)js,websocker傳遞的也是hash值,內(nèi)部機(jī)制通過hash值檢查進(jìn)行熱更新, 至于內(nèi)部原理,因?yàn)樗较拗?,目前還看不懂。
10. 如何?webpack來優(yōu)化前端性能?
?webpack優(yōu)化前端性能是指優(yōu)化webpack的輸出結(jié)果,讓打包的最終結(jié)果在瀏覽器運(yùn)?快速?效。
- 壓縮代碼:刪除多余的代碼、注釋、簡(jiǎn)化代碼的寫法等等?式??梢岳?webpack的 UglifyJsPlugin 和 ParallelUglifyPlugin 來壓縮JS?件, 利? cssnano (css-loader?minimize)來壓縮css
- 利?CDN加速: 在構(gòu)建過程中,將引?的靜態(tài)資源路徑修改為CDN上對(duì)應(yīng)的路徑??梢岳?webpack對(duì)于 output 參數(shù)和各loader的 publicPath 參數(shù)來修改資源路徑
- Tree Shaking: 將代碼中永遠(yuǎn)不會(huì)?到的?段刪除掉。可以通過在啟動(dòng)webpack時(shí)追加參數(shù) --optimize-minimize 來實(shí)現(xiàn)
- Code Splitting: 將代碼按路由維度或者組件分塊(chunk),這樣做到按需加載,同時(shí)可以充分利?瀏覽器緩存
- 提取公共第三?庫(kù): SplitChunksPlugin插件來進(jìn)?公共模塊抽取,利?瀏覽器緩存可以?期緩存這些?需頻繁變動(dòng)的公共代碼
11. 如何提?webpack的打包速度?
- happypack: 利?進(jìn)程并?編譯loader,利?緩存來使得 rebuild 更快,遺憾的是作者表示已經(jīng)不會(huì)繼續(xù)開發(fā)此項(xiàng)?,類似的替代者是thread-loader
- 外部擴(kuò)展(externals): 將不怎么需要更新的第三?庫(kù)脫離webpack打包,不被打?bundle中,從?減少打包時(shí)間,?如jQuery?script標(biāo)簽引?
- dll: 采?webpack的 DllPlugin 和 DllReferencePlugin 引?dll,讓?些基本不會(huì)改動(dòng)的代碼先打包成靜態(tài)資源,避免反復(fù)編譯浪費(fèi)時(shí)間
- 利?緩存: webpack.cache 、babel-loader.cacheDirectory、 HappyPack.cache 都可以利?緩存提?rebuild效率縮??件搜索范圍: ?如babel-loader插件,如果你的?件僅存在于src中,那么可以 include: path.resolve(__dirname,'src') ,當(dāng)然絕?多數(shù)情況下這種操作的提升有限,除?不??build了node_modules?件
12. 如何提?webpack的構(gòu)建速度?
- 多??情況下,使? CommonsChunkPlugin 來提取公共代碼
- 通過 externals 配置來提取常?庫(kù)
- 利? DllPlugin 和 DllReferencePlugin 預(yù)編譯資源模塊 通過 DllPlugin 來對(duì)那些我們引?但是絕對(duì)不會(huì)修改的npm包來進(jìn)?預(yù)編譯,再通過 DllReferencePlugin 將預(yù)編譯的模塊加載進(jìn)來。
- 使? Happypack 實(shí)現(xiàn)多線程加速編譯
- 使? webpack-uglify-parallel 來提升 uglifyPlugin 的壓縮速度。 原理上 webpack-uglify-parallel 采?了多核并?壓縮來提升壓縮速度
- 使? Tree-shaking 和 Scope Hoisting 來剔除多余代碼
13. 怎么配置單?應(yīng)??怎么配置多?應(yīng)??
單?應(yīng)?可以理解為webpack的標(biāo)準(zhǔn)模式,直接在 entry 中指定單?應(yīng)?的??即可,這?不再贅述多?應(yīng)?的話,可以使?webpack的 AutoWebPlugin 來完成簡(jiǎn)單?動(dòng)化的構(gòu)建,但是前提是項(xiàng)?的?錄結(jié)構(gòu)必須遵守他預(yù)設(shè)的規(guī)范。 多?應(yīng)?中要注意的是:
- 每個(gè)??都有公共的代碼,可以將這些代碼抽離出來,避免重復(fù)的加載。?如,每個(gè)??都引?了同?套css樣式表
- 隨著業(yè)務(wù)的不斷擴(kuò)展,??可能會(huì)不斷的追加,所以?定要讓??的配置?夠靈活,避免每次添加新??還需要修改構(gòu)建配置
三、其他
1. Babel的原理是什么?
babel 的轉(zhuǎn)譯過程也分為三個(gè)階段,這三步具體是:
- 解析 Parse: 將代碼解析?成抽象語法樹(AST),即詞法分析與語法分析的過程;
- 轉(zhuǎn)換 Transform: 對(duì)于 AST 進(jìn)?變換?系列的操作,babel 接受得到 AST 并通過 babel-traverse 對(duì)其進(jìn)?遍歷,在此過程中進(jìn)?添加、更新及移除等操作;
- ?成 Generate: 將變換后的 AST 再轉(zhuǎn)換為 JS 代碼, 使?到的模塊是 babel-generator。
更多建議: