關於webpack的一些面試題(緩慢更新)
1.webpack與Grunt、Gulp這類打包工具有什麼不同
像Grunt、Gulp這類構建工具,打包的思路是: 遍歷原始檔 → 匹配規則 → 打包,這個過程中做不到按需載入,即對於打包起來的資源,到底頁面用不用,打包過程中是不關心的。
webpack跟其他構建工具本質上的不同之處在於: webpack 是從入口檔案開始,經過模組依賴載入、分析和打包三個流程完成專案的構建。在加載入、分析和打包的三個過程中,可以針對性的做一些解決方案,比如code split(拆分公共程式碼等)。
當然,webpack還可以輕鬆的解決傳統構建工具解決的問題:
- 模組化打包,一切皆模組,js是模組,css等也是模組
- 語法糖轉換:比如ES6轉ES5、TypeScript
- 前處理器編譯:比如less、sass等
- 專案優化:比如壓縮、CDN
- 解決方案封裝:通過強大的Loader和外掛機制,可以完成解決方案的封裝,比如PWA;
- 流程對接:比如測試流程、語法檢測等。
2.wepback有幾種寫法
webpack的配置型別是多樣的,最常見的是直接作為一個物件來使用,除了使用物件,webpack還支援函式 promise和多配置陣列。
3.我們要開發一個jQuery外掛、vue元件等,需要怎麼配置webpack
如果我們打包的目的是生成一個共別人使用的庫,那麼可以使用output.library來指定庫的名稱庫的名稱支援佔位符與普通字串。使用output.library確定了庫的名稱之後,還可以使用output.libraryTarget指定庫打包出來的規範。使用output.externals配置項去除輸出的打包檔案中依賴的某些第三方js模組(例如jquery,vue等)。這些被依賴的模組應該由使用者提供,而不應該包含再js庫檔案中。
4.webpack的佔位符[hash],[chunkhash],[contenthash] 有什麼區別和聯絡。
-
[hash]:是整個專案的hash值,其根據每次編譯內容計算得到,每次編譯之後都會生成新的hash,即修改任何檔案都會導致所有檔案的hash發生改變;在一個專案中雖然入口不同,但是hash是相同的;hash無法實現前端靜態資源在瀏覽器上長快取,這時候應該使用chunkhash
-
[chunkhash]:根據不同的入口檔案(entry)進行依賴檔案解析,構建對應的chunk,生成相應的hash;只要組成entry的模組檔案沒有變化,則對應hash也是不變的,所以一般專案優化時,會將公共程式碼庫拆分到一起,因為公共程式碼庫程式碼變動較少的,使用chunkhash可以發揮最長快取的作用
-
[contenthash]:使用chunkhash存在一個問題,當在一個js檔案引入css檔案,編譯後他們的hash是相同的。而且,只要js檔案內容發生改變,與其關聯的css檔案hash也會改變,針對這種情況,可以把css從js中抽離出來並使用contenthash。
5.什麼是bundle,chunk,module
- module:開發中的每一個檔案都可以看作是module,模組不侷限於js,也包含css,圖片等。
- chunk:表示程式碼塊,一個chunk可以由多個模組組成。
- bundle:最終打包完成的檔案,一般就是和chunk一一對應的關係,bundle就是對chunk進行編譯壓縮打包等處理後的產出。
6.能不能手寫一個Webpack配置?
// 手寫一個webpack配置最主要的就是 entry, output,module.rules(loader)和plugin
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new ExtractTextPlugin({
filename: 'style.css'
})
]
}
7.在js中怎麼呼叫Loader來處理一個模組?
const html = require('html-loader!./test.html');
console.log(html)
8.Loader的解析順序是怎樣的?
從右向左或者從下至上。
9.什麼是JavaScript模組化開發,有哪些可遵循的規範
模組是指為了完成某種功能所需的程式或者子程式,模組是系統中職責單一且可替換的部分。模組化開發是指如何開發新的模組和複用已用的模組來實現應用的功能。JavaScript可遵循的主流規範有:commonJS,AMD和ES6 module。
10.webpack中怎麼獲取一個模組引用另外一個模組時傳入的query
// main.js
const component = require('./component-loader?commponent=demo')
// component-loader.js
const querystring = require('querystring')
const query = querystring.parse(__resourceQuery.slice(1)) // 去掉 ?
consolelog(query); // {comonent: demo}
11.怎麼實現webpack的按需載入?什麼是神奇註釋?
在webpack中,import不僅僅是ES6 module的模組匯入方式,還是一個類似require的函式,我們可以通過import('module')的方式引入一個模組,import()返回的是一個Promise物件;使用import()方式就可以實現webpack的按需載入。在import()裡可以新增一些註釋,如定義該chunk的名稱,要過濾的檔案,指定引入的檔案等等,這類帶有特殊功能的註釋被稱為神器註釋。
12.Babel的preset-env是什麼
babel的語法轉換是通過強大的外掛系統來支援的。babel的外掛分為兩類:轉換外掛和語法解析外掛。
不同的語法對應著不同的轉換外掛,比如我們要將箭頭函式轉換成為es5的函式寫法,那麼可以單獨安裝@babel/plugin-transform-arrow-functrions外掛,如果不想一個個的新增外掛,那麼可以使用外掛組合preset(外掛預設,外掛組合更加好理解一些),最常見的preset是@babel/preset-env。
13.懂得babel的原理媽?你會手寫babel外掛嗎?
babel是一個JavaScript的靜態解析分析編譯器,所謂靜態分析指的的在不需要執行程式碼的前提下對程式碼進行分析和處理的過程。要實現babel從一個語法轉換成另外一種語法,需要經過三個主要步驟:解析,轉換,生成。
-
解析:指的的首先將程式碼經過詞法解析和語法解析,最終生成一棵AST(抽象語法樹),在babel中,語法解析器是Babylon;
-
轉換:得到AST之後,可以對其進行遍歷,在此過程中對節點進行新增,更新和移除等操作,babel中AST遍歷工具是@babel/traverse;
-
生成:經過一系列轉換之後得到的一棵新樹,要將樹轉換成程式碼,就是生成的過程,babel用到的是@babel/generator。
在babel中,程式碼會由babel先進行解析AST,babel外掛做的事情就是寫vistor而已,所以babel外掛固定的模板如下:
module.exports = () => { return { name: 'example-plugin', visitor: { Identifier(path, state) {
}
}
}
}
14.babel怎麼做polyfill,polyfill的最佳實踐是什麼?
babel只負責進行語法轉換,即將es6語法轉換成es5語法,但如果是在es5中,有些物件,方法實際在瀏覽器中可能是不支援的,例如:promise,array.prototype.includes,這時候就需要@babel/polyfill來做模擬。
@babel/polyfill雖然可以解決模擬瀏覽器不存在物件方法的事情,但是有以下兩個問題:
- 直接修改內建的原型,造成全域性汙染;
- 無法按需引入,webpack打包時,會把所有的polyfill都載入進來,導致產出檔案過大。
為了解決這個問題,babel社群又提出了@babel/runtime的方案,@babel/runtime不再修改原型,而是採用替換的方式,比如我們用promise,使用@babel/polyfill會產生一個window.promise物件,而@babel/runtime則會生成一個_Promise(示例而已)來替換掉我們程式碼中用到的Promise.另外@babel/runtime還支援按需引入。
babel怎麼針對不同的瀏覽器打包不同的適配程式碼
browserslist就是幫助我們來設定目標瀏覽器的工具。它實際上就是聲明瞭一段瀏覽器的集合,我們的工具可以根據這段集合描述,針對性的輸出