webpack源碼之loader機制

loader概念

loader是用來加載處理各類形式的資源,本質上是一個函數, 接受文件做爲參數,返回轉化後的結構。css

loader 用於對模塊的源代碼進行轉換。loader 可使你在 import 或"加載"模塊時預處理文件。所以,loader 相似於其餘構建工具中「任務(task)」,並提供了處理前端構建步驟的強大方法。loader 能夠將文件從不一樣的語言(如 TypeScript)轉換爲 JavaScript,或將內聯圖像轉換爲 data URL。loader 甚至容許你直接在 JavaScript 模塊中 import CSS文件!

loader和plugin區別

以前一篇文章中介紹了plugin機制,和今天研究的對象loader,他們二者在一塊兒極大的拓展了webpack的功能。它們的區別就是loader是用來對模塊的源代碼進行轉換,而插件目的在於解決 loader 沒法實現的其餘事。爲何這麼多說呢?由於plugin能夠在任何階段調用,可以跨Loader進一步加工Loader的輸出,執行預先註冊的回調,使用compilation對象作一些更底層的事情。前端

loader用法

配置

module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: 'style-loader' },
          {
            loader: 'css-loader'
          }
        ]
      }
    ]
  }

內聯

import Styles from 'style-loader!css-loader?modules!./styles.css';

CLI

webpack --module-bind 'css=style-loader!css-loader'

說明 上面三種使用方法做用都是將一組鏈式的 loader, 按照從右往左的順序執行,loader 鏈中的第一個 loader 返回值給下一個 loader。先使用css-loader解析 @import 和 url()路徑中指定的css內容,而後用style-loader 會把原來的 CSS 代碼插入頁面中的一個 style 標籤中。node

loader實現

//將css插入到head標籤內部
module.exports = function (source) {
    let script = (`
      let style = document.createElement("style");
      style.innerText = ${JSON.stringify(source)};
      document.head.appendChild(style);
   `);
    return script;
}
//使用方式1
resolveLoader: {
   modules: [path.resolve('node_modules'), path.resolve(__dirname, 'src', 'loaders')]
},
{
    test: /\.css$/,
    use: ['style-loader']
},
//使用方式2
將本身寫的loaders發佈到npm倉庫,而後添加到依賴,按照方式1中的配置方式使用便可

說明 上面是一個簡單的loader實現,同步的方式執行,至關於實現了style-loader的功能。webpack

loader原理

function iteratePitchingLoaders(options, loaderContext, callback) {
    var currentLoaderObject = loaderContext.loaders[loaderContext.loaderIndex];
    // load loader module
    loadLoader(currentLoaderObject, function(err) {
        var fn = currentLoaderObject.pitch;
        runSyncOrAsync(
            fn,
            loaderContext, [loaderContext.remainingRequest, loaderContext.previousRequest, currentLoaderObject.data = {}],
            function(err) {
                if(err) return callback(err);
                var args = Array.prototype.slice.call(arguments, 1);
                if(args.length > 0) {
                    loaderContext.loaderIndex--;
                    iterateNormalLoaders(options, loaderContext, args, callback);
                } else {
                    iteratePitchingLoaders(options, loaderContext, callback);
                }
            }
        );
    });
}

說明 上面是webpack源碼中loader執行關鍵步驟,遞歸的方式執行loader,執行機流程似於express中間件機制web

參考源碼
webpack: "4.4.1"
webpack-cli: "2.0.13"
參考文檔
https://webpack.js.org/concep...express

相關文章
相關標籤/搜索