Loader 入門【Webpack Book 翻譯】

原文連接: https://survivejs.com/webpack...
翻譯計劃: https://segmentfault.com/a/11...

附言:由於發現書中一些內容單獨放出來會比較尷尬,因此會跳過部分章節,固然完整版會所有翻譯,已經正在研究原版的網站搭建工程了
clipboard.pngjavascript

Webpack 提供了多種配置模塊 loader 的方法。 Webpack 2 開始經過引入 use 字段,簡化了 loader 使用。在這裏使用絕對路徑是一個好主意,由於它們容許你在不影響構建的狀況下移動配置。css

另外一種方法是設置 context 字段,由於這會產生相似的效果並影響 entry 和 loader 的路徑解析。可是它對輸出沒有影響,你仍然須要使用絕對路徑或 /java

即便你設置了 includeexclude 規則,從 node_modules 加載的包仍然能夠正常工做,由於它們已經被編譯爲開箱即用的代碼。若是它們沒這麼作,那麼你必須應用 Consuming Packages 章節中涵蓋的技術。node

T> include/exclude 在處理 node_modules 問題時很是方便,由於當你將 JavaScript 文件導入項目時,webpack 會默認處理並遍歷已安裝的包。爲了讓 webpack 不處理 node_modules,你須要使用 exclude。其餘文件類型不會遇到此問題。webpack

剖析 Loader

Webpack 經過 loader 支持多種格式的文件。此外,它支持一些開箱即用的 JavaScript 模塊規範。文件格式不一樣,但思路都是一致的,你必須設置一個或多個 loader,並將它們與你的目錄結構鏈接起來。git

{pagebreak}github

下例中 webpack 經過 Babel 處理 JavaScript:web

webpack.config.jsnpm

module.exports = {
  ...
  module: {
    rules: [
      {
        // **Conditions** to match files using RegExp, function.
        test: /\.js$/,

        // **Restrictions**
        // Restrict matching to a directory. This
        // also accepts an array of paths or a function.
        // The same applies to `exclude`.
        include: path.join(__dirname, "app"),
        exclude(path) {
          // You can perform more complicated checks  as well.
          return path.match(/node_modules/);
        },

        // **Actions** to apply loaders to the matched files.
        use: "babel-loader",
      },
    ],
  },
};

T> 若是你對 RegExp 的匹配不熟悉,可使用在線工具,例如 regex101RegExrRegexpersegmentfault

Loader 的運算順序

必定要記住 loader 老是從右到左,從下到上(拆開寫的時候)進行運算的。把它當作函數比較容易理解所謂「從右到左運行」。你能夠把 use: ["style-loader", "css-loader"] 看做 style(css(input))

要查看規則,請看如下示例:

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

根據從右到左的規則,能夠等效拆分爲:

{
  test: /\.css$/,
  use: "style-loader",
},
{
  test: /\.css$/,
  use: "css-loader",
},

強制執行順序

儘管可使用上述規則配置,可是也能夠強制在常規規則以前以後應用特定規則。enforce 字段在這裏能夠派上用場。把他設置爲 pre or post 以在其餘 loader 以前或以後進行處理。

Lint 是一個很好的例子,由於 Lint 必須先於任何其餘行爲。enforce: "post" 卻是不多用到,這可能是你想對構建結果進行檢查時使用的。

{pagebreak}

基本語法以下:

{
  // Conditions
  test: /\.js$/,
  enforce: "pre", // "post" too

  // Actions
  use: "eslint-loader",
},

若是你能夠保證 test 中的 loader 順序無誤,那麼能夠不使用 enforce。不過使用 enforce 方便你把不一樣步驟的 loader 分離開來,更容易組織。

Loader 的傳參

可經過 query 把參數傳到 loader:

{
  // Conditions
  test: /\.js$/,
  include: PATHS.app,

  // Actions
  use: "babel-loader?presets[]=env",
},

這種配置風格也適用於 entry 和 import,webpack 會處理他們。在某些個別狀況下,這個寫法能派上用場,但一般狀況下最好使用如下更具可讀性的方案。

{pagebreak}

傳入對象到 use

{
  // Conditions
  test: /\.js$/,
  include: PATHS.app,

  // Actions
  use: {
    loader: "babel-loader",
    options: {
      presets: ["env"],
    },
  },
},

若是你想使用多個 loader,你能夠將一個對象數組傳遞給 use

{
  test: /\.js$/,
  include: PATHS.app,

  use: [
    {
      loader: "babel-loader",
      options: {
        presets: ["env"],
      },
    },
    // Add more loaders here
  ],
},

{pagebreak}

使用函數在 use 字段添加分支

本書中,你在更高級別上進行環境配置。實現相似結果的另外一個選擇是在 use 處使用分支,由於 webpack 的 loader 定義接受函數做爲參數,你能夠經過此函數區分環境:

{
  test: /\.css$/,

  // `resource` refers to the resource path matched.
  // `resourceQuery` contains possible query passed to it
  // `issuer` tells about match context path
  use: ({ resource, resourceQuery, issuer }) => {
    // You have to return something falsy, object, or a
    // string (i.e., "style-loader") from here.
    //
    // Returning an array fails! Nest rules instead.
    if (env === "development") {
      return {
        use: {
          loader: "css-loader", // css-loader first
          rules: [
            "style-loader", // style-loader after
          ],
        },
      };
    }
  },
},

用心感覺,這是組合配置的另外一種手段。

內聯式定義

儘管配置級 loader 定義更可取,但能夠內聯編寫 loader 定義:

// Process foo.png through url-loader and other
// possible matches.
import "url-loader!./foo.png";

// Override possible higher level match completely
import "!!url-loader!./bar.png";

這種方法的問題在你的源代碼會與 webpack 耦合。相同的機制還適用於 entry:

{
  entry: {
    app: "babel-loader!./app",
  },
},

匹配文件的備選方法

test 結合 includeexclude 是匹配文件的最經常使用方法。這些字段接受如下數據類型:

  • test——匹配 RegExp,字符串,函數,對象或數組。
  • include——同上。
  • exclude——同上,輸出與 include 相反。
  • resource: /inline/——匹配包含查詢內容的資源路徑。示例:/path/foo.inline.js, /path/bar.png?inline
  • issuer: /bar.js/——匹配從某處請求的資源。示例:若是 /path/foo.png/path/bar.js 請求,那麼 /path/foo.png 將匹配。
  • resourcePath: /inline/——匹配包含查詢內容的資源路徑(不包括 query)。示例:/path/foo.inline.png
  • resourceQuery: /inline/——匹配包含查詢內容的 query(不包括 query)。示例:/path/foo.png?inline

基於布爾值的字段可用於進一步進行約束:
Boolean based fields can be used to constrain these matchers further:

  • not——匹配給定條件(參見test表示接受的值)。
  • and——同時匹配一系列條件。
  • or——與數組中其中一個條件匹配。

基於 resourceQuery 加載

oneOf 字段能夠根據資源相關匹配將 webpack 路由到特定的 loader:

{
  test: /\.png$/,
  oneOf: [
    {
      resourceQuery: /inline/,
      use: "url-loader",
    },
    {
      resourceQuery: /external/,
      use: "file-loader",
    },
  ],
},

若是你須要在文件名中查詢,應該使用 resourcePath 而不是 resourceQuery

{pagebreak}

基於 issuer 加載

issuer 基於資源的導入位置進行操做。如下示例改編自 css-loader issue 287style-loader 將應用於 JavaScript 導入的 CSS 文件:

{
  test: /\.css$/,

  rules: [
    {
      issuer: /\.js$/,
      use: "style-loader",
    },
    {
      use: "css-loader",
    },
  ],
},

另外一種方法結合了 issuernot

{
  test: /\.css$/,

  rules: [
    // CSS imported from other modules is added to the DOM
    {
      issuer: { not: /\.css$/ },
      use: "style-loader",
    },
    // Apply css-loader against CSS imports to return CSS
    {
      use: "css-loader",
    },
  ],
}

瞭解 loader 行爲

經過觀察 loader 行爲能夠更深刻地理解它們。 loader-runner 容許你在沒有 webpack 的狀況下單獨運行它們。Webpack 在底層也是使用此軟件包,Extending with Loaders 章節將會詳細介紹它。

inspect-loader 能夠監視 loader 之間傳遞的內容。將此 loader 添加到你的配置便可檢查其中的數據流,而沒必要在 node_modules 中插入 console.log

總結

Webpack 提供了多種設置 loader 的方法,但在 webpack 4 中用好 use 就足夠了。注意 loader 的處理順序,這是不少常見的問題來源。

回顧一下:

  • Loaders 決定了 webpack 的模塊解析機制匹配到文件時應該做何處理。
  • loader 定義包括用於匹配的條件(conditions),以及匹配成功須要進行的動做(actions)
  • Webpack 2 引入了use字段。它將之前的 loaderloaders 字段結合到了一塊兒。
  • Webpack 4 提供了多種匹配和改變 loader 行爲的方法。例如,你能夠在匹配 loader 後進行 resource query 匹配,指引 loader 進行特定操做。

在下一章中,你將學習使用 webpack 加載圖片。

相關文章
相關標籤/搜索