webpack面試題

發表於2019-02-23

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
    }
}
複製程式碼

參考文獻:

相關文章