webpack
談談你對webpack的看法
webpack是一個模組打包工具,可以使用它管理專案中的模組依賴,並編譯輸出模組所需的靜態檔案。它可以很好地管理、打包開發中所用到的HTML,CSS,JavaScript和靜態檔案(圖片,字型)等,讓開發更高效。對於不同型別的依賴,webpack有對應的模組載入器,而且會分析模組間的依賴關係,最後合併生成優化的靜態資源。
webpack的基本功能和工作原理?
- 程式碼轉換:TypeScript 編譯成 JavaScript、SCSS 編譯成 CSS 等等
- 檔案優化:壓縮 JavaScript、CSS、HTML 程式碼,壓縮合並圖片等
- 程式碼分割:提取多個頁面的公共程式碼、提取首屏不需要執行部分的程式碼讓其非同步載入
- 模組合併:在採用模組化的專案有很多模組和檔案,需要構建功能把模組分類合併成一個檔案
- 自動重新整理:監聽本地原始碼的變化,自動構建,重新整理瀏覽器
- 程式碼校驗:在程式碼被提交到倉庫前需要檢測程式碼是否符合規範,以及單元測試是否通過
- 自動釋出:更新完程式碼後,自動構建出線上釋出程式碼並傳輸給釋出系統。
webpack構建過程
- 從entry裡配置的module開始遞迴解析entry依賴的所有module
- 每找到一個module,就會根據配置的loader去找對應的轉換規則
- 對module進行轉換後,再解析出當前module依賴的module
- 這些模組會以entry為單位分組,一個entry和其所有依賴的module被分到一個組Chunk
- 最後webpack會把所有Chunk轉換成檔案輸出
- 在整個流程中webpack會在恰當的時機執行plugin裡定義的邏輯
webpack打包原理
將所有依賴打包成一個bundle.js,通過程式碼分割成單元片段按需載入
什麼是webpack,與gulp,grunt有什麼區別
- webpack是一個模組打包工具,可以遞迴地打包專案中的所有模組,最終生成幾個打包後的檔案。
- 區別:webpack支援程式碼分割,模組化(AMD,CommonJ,ES2015),全域性分析
什麼是entry,output?
- entry 入口,告訴webpack要使用哪個模組作為構建專案的起點,預設為./src/index.js
- output 出口,告訴webpack在哪裡輸出它打包好的程式碼以及如何命名,預設為./dist
什麼是loader,plugins?
- loader是用來告訴webpack如何轉換某一型別的檔案,並且引入到打包出的檔案中。
- plugins(外掛)作用更大,可以打包優化,資源管理和注入環境變數
什麼是bundle,chunk,module?
bundle是webpack打包出來的檔案,chunk是webpack在進行模組的依賴分析的時候,程式碼分割出來的程式碼塊。module是開發中的單個模組
如何自動生成webpack配置?
可以用一些官方腳手架
- webpack-cli
- vue-cli
// 首先安裝
npm install -g @vue/cli
// 新建專案hello
vue create hello
複製程式碼
- nuxt-cli
// 確保安裝了npx,npx在npm5.2.0預設安裝了
// 新建專案hello
npx create-nuxt-app hello
複製程式碼
webpack如何配置單頁面和多頁面的應用程式?
- 單個頁面
module.exports = {
entry: './path/to/my/entry/file.js'
}
複製程式碼
- 多頁面應用程式
module.entrys = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js'
}
}
複製程式碼
webpack-dev-server和http伺服器如nginx有什麼區別?
webpack-dev-server使用記憶體來儲存webpack開發環境下的打包檔案,並且可以使用模組熱更新,相比傳統http伺服器開發更加簡單高效
什麼是模組熱更新?
webpack的一個功能,可以使程式碼修改後不用重新整理瀏覽器就自動更新,高階版的自動重新整理瀏覽器
dev-server是怎麼跑起來的
webpack-dev-server支援兩種模式來自動重新整理頁面
- iframe模式(頁面放在iframe中,當傳送改變時過載)
無需額外配置,只要以這種格式url訪問即可。
http://localhost:8080/webpack-dev-server/index.html
- inline模式(將webpack-dev-server的客戶端入口新增到bundle中) inline模式下url不用發生變化,但啟動inline模式分兩種情況
// 以命令列啟動webpack-dev-server有兩種方式
// 方式1 在命令列中新增--inline命令
// 方式2 在webpack-config.js新增devServer:{inline: true}
// 以node.js API啟動有兩種方式
// 方式1 新增webpack-dev-server/client?http://localhost:8080/到webpack配置的entry入口點
config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/");
// 將<script src="http://localhost:8080/webpack-dev-server.js"></script>新增到html檔案中
複製程式碼
使用過webpack裡面哪些plugin和loader
loader
- babel-loader: 將ES6+轉移成ES5-
- css-loader,style-loader:解析css檔案,能夠解釋@import url()等
- file-loader:直接輸出檔案,把構建後的檔案路徑返回,可以處理很多型別的檔案
- url-loader:打包圖片
// url-loader增強版的file-loader,小於limit的轉為Base64,大於limit的呼叫file-loader
npm install url-loader -D
// 使用
module.exports = {
module: {
rules: [{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: {
outputPath: 'images/',
limit: 500 //小於500B的檔案打包出Base64格式,寫入JS
}
}]
}]
}
}
複製程式碼
plugins
- html-webpack-plugin: 壓縮html
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
//...
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html', // 配置輸出檔名和路徑
template: './public/index.html', // 配置要被編譯的html檔案
hash: true,
// 壓縮 => production 模式使用
minify: {
removeAttributeQuotes: true, //刪除雙引號
collapseWhitespace: true //摺疊 html 為一行
}
})
]
}
複製程式碼
- clean-webpack-plugin: 打包器清理源目錄檔案,在webpack打包器清理dist目錄
npm install clean-webpack-plugin -D
// 修改webpack.config.js
const cleanWebpackPlugin=require('clean-webpack-plugin')
module.exports = {
plugins: [new cleanWebpackPlugin(['dist'])]
}
複製程式碼
webpack中babel的實現
安裝 npm i -D @babel-preset-env @babel-core babel-loader
- @babel-preset-env:可以讓我們靈活設定程式碼目標執行環境
- @babel-core: babel核心庫
- babel-loader: webpack的babel外掛,讓我們可以在webpack中執行babel
配置.babelrc
{
"presets": ['@babel/preset-env']
}
複製程式碼
配置webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: {loader: 'babel-loader'}
}]
}
}
複製程式碼
提取公用程式碼
module.exports = {
optimization: {
splitChunks: {
common: {
// 抽離公共程式碼
chunks: 'initial',
name: 'common', // 打包後的檔名
minChunks: 2, // 最小引用2次
minSize: 0 // 超出0位元組就生成一個新包
},
styles: {
// 抽離公用程式碼
name: 'styles',
test: /\.css$/,
chunks: 'all',
minChunks: 2,
enforce: true
},
vender: {
// 抽離第三方外掛
test: /node_modules/,
chunks: 'initial',
name: 'vendor', // 打包後的檔名
priority: 10 // 設定優先順序,防止與自定義公共程式碼提取時被覆蓋,不進行打包
}
}
}
}
複製程式碼
什麼是長快取?在webpack中如何做到長快取優化?
- 瀏覽器在使用者訪問頁面的時候,為了加快載入速度會對使用者訪問的靜態資源進行儲存,但是每一次程式碼升級或更新都需要瀏覽器下載新的程式碼,最簡單方便的方式就是引入新的檔名稱。
- webpack中可以在output中指定chunkhash,並且分離經常更新的程式碼和框架程式碼。通過NameModulesPlugin或HashedModuleIdsPlugin使再次打包檔名不變。
什麼是Tree-shaking?CSS可以Tree-shaking?
Tree-shaking是指在打包中取出那些引入了但在程式碼中沒有被用到的死程式碼。webpack中通過uglifysPlugin來Tree-shaking JS。CSS需要使用purify-CSS
繼承 8種
原型鏈繼承
- 重點:子的原型物件為new一個父的例項
Child.prototype = new Parent();
- 缺點:多個例項對引用型別的操作會被篡改
借用建構函式繼承
- 重點:在子建構函式內部呼叫父建構函式
Parent.call(this)
- 缺點:無法實現複用,不能繼承原型屬性/方法
組合繼承
- 重點:使用原型鏈繼承共享的屬性和方法,通過借用建構函式繼承例項屬性
function Child(name,age){
// 繼承屬性
Parent.call(this, name)
this.age=age
}
// 繼承方法
Child.prototype = new Parent()
Child.prototype.constructor = Child;
複製程式碼
- 缺點:無論在什麼情況都會呼叫兩次父建構函式,一次是建立子型別原型,另一次是在子建構函式內部
原型式繼承
- 重點:執行對給定物件的淺複製
function object(obj){
function F(){}
F.prototype=obj
return new F();
}
var person1=object(person);
複製程式碼
在ES5中Object.create()可替換上面的方法object()
var person1 = Object.create(person);
- 缺點:原型鏈繼承多個例項的引用型別屬性指向相同,存在篡改的可能;無法傳遞引數
寄生式繼承
- 重點:在原型式繼承的基礎上,增強物件,返回建構函式
function createAnother(obj){
var clone=object(obj);
// ES5中用這個
// var clone=Object.create(obj);
// 增強物件
clone.sayHi=function(){};
return clone;
}
var person1=createAnother(person)
複製程式碼
- 缺點:同原型式繼承
寄生組合式繼承
- 重點:結合建構函式傳遞引數和寄生模式實現繼承
// 借用建構函式增強子類例項屬性(支援傳參和避免篡改)
function Child(name,age){
// 繼承屬性
Parent.call(this, name)
this.age=age
}
function inheritPrototype(Child, Parent){
var prototype=Object.create(Parent.prototype);
prototype.constructor=Child;
Child.prototype=prototype;
}
// 將父類原型指向子類,這樣子類就能使用父類原型鏈的屬性/方法
inheritPrototype(Child, Parent);
複製程式碼
優點:只呼叫一次建構函式,原型鏈不變,是最成熟的
混入方式繼承多個方式
重點:利用Object.assign將父類原型上的方法拷貝到子類原型上,這樣子類例項例項就可以使用父類的方法
Object.assign(Child.prototype, Parent.prototype);
Child.prototype.constructor=Child;
複製程式碼
ES6類 extends
重點:使用extends表明繼承自哪個父類,並且在子類建構函式中必須使用super,可以看做是Parent.call(this,value)
class Parent{
constructor(value){
this.val=value
}
}
class Child extends Parent{
constructor(value){
super(value)
this.val = value
}
}
複製程式碼