面試官:你使用webpack時手寫過loader,分離過模塊嗎?

前言


你們好,以前出了一篇面試篇webpack入門,這篇文章繼續介紹接下來更深刻東西。javascript

概覽

  • 如何載入本身的loader
  • 使用loader-utils,schema-utils
  • 編寫本身的loader
  • 擴展

如何載入本身的loader

講道理你們都是直接import一個loader或者使用webpack內置的loader的。css

若是調試本身的loader,應該以下寫法:vue

//webpack.config.js
const path = require("path");
module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: path.resolve("loader.js"),
                        options: {
                            test: 'apple'
                        }
                    }
                ]
            }
        ]
    }
};
複製代碼

其實和正常載入loader同樣,只是這裏指向的是本地文件的路徑。java

path.resolve('loader.js') 得出路徑node

/Users/kev1nzh/Desktop/my/webpack/loader.jsreact

使用單個loader
在使用一個loader的時候,loader會接收你正則匹配的資源文件(如上,全部js文件)的字符串。

loader經過代碼轉化模塊後,最後返回傳遞出去。
複製代碼
使用多個loader
  • 當使用多個loader的時候,從傳入loader數組的最後一個開始反向傳入資源文件字符串。webpack

  • 最後一個loader接收最原始的資源文件字符串,轉化後傳入下一個lodaer。ios

  • 中間的loader接收上一個loader,轉化後傳入下一個。es6

  • 第一個loader最後接收轉化,並傳出全部loader處理完的資源文件字符串。web

{
     test: /\.css$/,
     use: [
         {
             loader: 'css-loader'
         },
         {
             loader: 'style-loader'
         },
     ]
}
//style-loader接收全部css的文件,轉化完再傳給css-loader,轉化完後再懟出來。
複製代碼

使用loader-utils,schema-utils

loader-utils, schema-utils是webpack的loader工具庫,有不少便捷的方法能夠調用。

const { getOptions,stringifyRequest, parseQuery  } = require("loader-utils");
const validateOptions = require("schema-utils");
const schema = {
    type: "object",
    properties: {
        test: {
            type: "string"
        }
    }
};
module.exports = function(source) {
    //getOptions 用於在loader裏獲取傳入的options,返回的是對象值。
    const options = getOptions(this);
    
    // stringifyRequest轉換路徑,避免require()或impot時使用的絕對路徑
    stringifyRequest(this, "./test.js"); // Result => "\"./test.js\""
    
    //parseQuery獲取query參數的,這個很簡單就不說啦
    parseQuery('?name=kev&age=14') // Result => {name: 'kev', age: '14'}
    
    //驗證參數的類型是否正確。
    validateOptions(schema, options, "loader");
};
複製代碼

編寫本身的loader

總算到手寫環節了!!!!

//webapck.config.js
const path = require("path");

module.exports = {
    entry: "./src",
    output: {
        path: path.resolve(__dirname, "dist"),
        filename: "package.js"
    },
    mode: "production",
    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    {
                        loader: path.resolve("loader.js"),
                        options: {
                            work: '996',
                            sick: 'ICU',
                        }
                    }
                ]
            }
        ]
    }
};
複製代碼

首先載入工具庫,爲了後續使用。

第一步先驗證options是否符合類型,

第二步獲取參數,而後替換傳入的資源文件字符串。

//loader.js
const { getOptions } = require("loader-utils");
const validateOptions = require("schema-utils");

const schema = {
    type: "object",
    properties: {
        work: {
            type: 'String'
        },
        sick: {
            type: 'String'
        }
    }
};

module.exports = function(source) {

    const options = getOptions(this);
    validateOptions(schema, options, 'loader');

    const  {work, sick} = options;
    source = source.replace(/\[work\]/g, work).replace(/\[sick\]/g, sick);

    return `export default ${JSON.stringify(source)}`;
};
複製代碼

展現下要轉換的js。

// src/index.js
console.log('工做[work] 生病[sick] 加班不規範 親人兩行淚');
複製代碼

最後在命令行,webpack!!!!!


擴展

webpack是如何運行的?
const index = require('./index');
const console = require('./console');

//index.js
const axios = require('./scripts/debounce.js'');
const moment = require('moment');
// do something
複製代碼
  1. webpack會解析全部模塊,若是模塊中有依賴其餘文件,那就繼續解析依賴的模塊。直到文件沒有依賴爲止。
  2. 解析結束後,webpack會把全部模塊封裝在一個函數裏,並放入一個名爲modules的數組裏。
  3. 將modules傳入一個自執行函數中,自執行函數包含一個installedModules對象,已經執行的代碼模塊會保存在此對象中。
  4. 最後自執行函數中加載函數(webpack__require)載入模塊。

分離代碼

// ./src/moment.js
const moment = require('moment');
console.log(moment().format('MMMM Do YYYY, h:mm:ss a'))

// ./index.js
const momentJs = require('./src/moment');
console.log(123);
複製代碼

如上代碼,咱們打包一下試試看。

兩個文件有依賴關係,因此打包後,都會把moment模塊打包進去。

SplitChunksPlugin

webpack4.x的分離代碼方法,以前的CommonsChunkPlugin插件已被移除。 此模塊開箱即用,默認狀況下,它僅影響按需塊,由於更改初始塊會影響HTML文件應包含的腳本標記以運行項目。

webpack將根據如下條件自動拆分塊:

  • 能夠共享新塊或來自該node_modules文件夾的模塊
  • 新塊將大於30kb(在min + gz以前)
  • 根據須要加載塊時的最大並行請求數將小於或等於5
  • 初始頁面加載時的最大並行請求數將小於或等於3
  • 當試圖知足最後兩個條件時,首選更大的塊。

讓咱們看下代碼如何實現!

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'initial',   //選擇哪些模塊須要優化, 參數爲 all、async、initial
      minSize: 30000,  // 要生成的塊的最小數
      maxSize: 0,  //要生成的塊的最大數
      minChunks: 2, // 分割前共享模塊的最小塊數
      maxAsyncRequests: 5, //按需加載時的最大並行請求數
      maxInitialRequests: 3, // 入口的最大並行請求數
      automaticNameDelimiter: '~',  //指定生成文件名當中的分隔符
      name: true, //拆分塊的名稱
      cacheGroups: { //緩存組
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          priority: -10
        },
        default: {
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true
        }
      }
    }
  }
};
複製代碼


好了這篇須要講的東西已經結束了。

面試系列第一篇: 面試官:你知道Callback Hell(回調地獄)嗎?

面試系列第二篇: 面試官:react和vue有什麼區別嗎?

面試系列第三篇: 面試官:你瞭解es6的知識嗎?

面試系列第四篇: 面試官:你瞭解Webpack嗎?

若是您有收穫或者疑問請在下方評論,求贊!謝謝觀看到這裏。

相關文章
相關標籤/搜索