嗯,webpack配置工程師誕生了……

概念

webpack 是一個現代的靜態模塊打包器(module bundler);css

四大概念

1. 入口(entry)
2. 輸出(output)
3. loader
4. 插件(plugins)
複製代碼

入口(entry)

簡言之: 就是編譯的起點html

從該起點開始,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的,能夠有一個入口起點(或多個入口起點)node

默認值爲 ./srcwebpack

webpack.config.jsweb

module.exports = {
  entry: './path/to/my/entry/file.js'
};
複製代碼

出口(output)

簡言之: 就是編譯的輸出正則表達式

告訴 webpack 在哪裏輸出它所建立的 bundles,以及如何命名這些文件,整個應用程序結構,都會被編譯到你指定的輸出路徑的文件夾中shell

默認值爲 ./distnpm

webpack.config.jsjson

const path = require('path');

module.exports = {
  entry: './path/to/my/entry/file.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js'
  }
};
複製代碼

loader(加載器)

簡言之: 處理非js的模塊數組

本質上,webpack loader 將全部類型的文件,轉換爲應用程序的依賴圖(和最終的 bundle)能夠直接引用的模塊。

在 webpack 的配置中 loader 有兩個目標:

  1. test 屬性,用於標識出應該被對應的 loader 進行轉換的某個或某些文件。(正則表達式去匹配相關文件);

  2. use 屬性,表示進行轉換時,應該使用哪一個 loader。

    webpack.config.js

const path = require('path');

const config = {
  output: {
    filename: 'my-first-webpack.bundle.js'
  },
  module: {
    rules: [
      { 
        test: /\.txt$/, 
        use: 'raw-loader' 
      }
    ]
  }
};

module.exports = config;
複製代碼

插件(plugins)

簡言之: 更強大的loader擴展,或者或者叫自定義loader

loader 被用於轉換某些類型的模塊,而插件則能夠用於執行範圍更廣的任務。插件的範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量。插件接口功能極其強大,能夠用來處理各類各樣的任務。

想要使用一個插件,操做

  1. require() 它,

  2. 添加到 plugins 數組中。

  3. 自定義選項(option)。

  4. 在一個配置文件中由於不一樣目的而屢次使用同一個插件,經過使用 new 操做符來建立它的一個實例;

    webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 經過 npm 安裝
const webpack = require('webpack'); // 用於訪問內置插件

const config = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;
複製代碼

模式

簡言之: 定義development 或 production的環境

經過選擇 development 或 production 之中的一個,來設置 mode 參數,你能夠啓用相應模式下的 webpack 內置的優化

webpack.config.js

module.exports = {
  mode: 'production'
};
複製代碼

 接下來就是詳細的用法

入口起點(entry points)

單個入口(簡寫)語法
用法:entry: string|Array

webpack.config.js

entry 屬性的單個入口語法,是下面的簡寫:

const config = {
  entry: {
    main: './path/to/my/entry/file.js'
  }
};
複製代碼

對象語法
用法:entry: {[entryChunkName: string]: string|Array}

webpack.config.js

const config = {
  entry: {
    app: './src/app.js',
    vendors: './src/vendors.js'
  }
};
複製代碼

多頁面應用程序 webpack.config.js

const config = {
  entry: {
    pageOne: './src/pageOne/index.js',
    pageTwo: './src/pageTwo/index.js',
    pageThree: './src/pageThree/index.js'
  }
};
複製代碼

使用 CommonsChunkPlugin 爲每一個頁面間的應用程序共享代碼建立 bundle。
最合適的方法:每一個 HTML 文檔只使用一個入口起點。

輸出(output)

用法(Usage) 在 webpack 中配置 output 屬性的最低要求是,將它的值設置爲一個對象,包括如下兩點:

  1. filename 用於輸出文件的文件名。
  2. 目標輸出目錄 path 的絕對路徑。

webpack.config.js

const config = {
  output: {
    filename: 'bundle.js',
    path: '/home/proj/public/assets'
  }
};
module.exports = config;
複製代碼

此配置將一個單獨的 bundle.js 文件輸出到 /home/proj/public/assets 目錄中

多個入口起點

{
  entry: {
    app: './src/app.js',
    search: './src/search.js'
  },
  output: {
    filename: '[name].js',
    path: __dirname + '/dist'
  }
}
複製代碼

高級進階 如下是使用 CDN 和資源 hash 的複雜示例:

config.js

output: {
  path: "/home/proj/cdn/assets/[hash]",
  publicPath: "http://cdn.example.com/assets/[hash]/"
}
複製代碼

在編譯時不知道最終輸出文件的 publicPath 的狀況下,publicPath 能夠留空,而且在入口起點文件運行時動態設置。若是你在編譯時不知道 publicPath,你能夠先忽略它,而且在入口起點設置 webpack_public_path

__webpack_public_path__ = myRuntimePublicPath

// 剩餘的應用程序入口
複製代碼

模式(mode)

區分開發環境和生產環境,方便開發調試和上線部署

mode: development

// webpack.development.config.js
module.exports = {
+ mode: 'development'
- plugins: [
-   new webpack.NamedModulesPlugin(),
-   new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
- ]
}
複製代碼

mode: production

// webpack.production.config.js
module.exports = {
+  mode: 'production',
-  plugins: [
-    new UglifyJsPlugin(/* ... */),
-    new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
-    new webpack.optimize.ModuleConcatenationPlugin(),
-    new webpack.NoEmitOnErrorsPlugin()
-  ]
}
複製代碼

使用環境變量

要在開發和生產構建之間,消除 webpack.config.js 的差別,須要環境變量。

webpack 命令行環境配置中,經過設置 --env 可使你根據須要,傳入儘量多的環境變量。在 webpack.config.js 文件中能夠訪問到這些環境變量。例如,--env.production 或 --env.NODE_ENV=local(NODE_ENV 一般約定用於定義環境類型,查看這裏)。

webpack --env.NODE_ENV=local --env.production --progress
複製代碼

module.exports 指向配置對象。
要使用 env 變量,你必須將 module.exports 轉換成一個函數:

webpack.config.js

module.exports = env => {
  // Use env.<YOUR VARIABLE> here:
  console.log('NODE_ENV: ', env.NODE_ENV) // 'local'
  console.log('Production: ', env.production) // true

  return {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  }
}
複製代碼

loader

loader 用於對模塊的源代碼進行轉換。
loader 可使你在 import 或"加載"模塊時預處理文件。
loader 能夠將文件從不一樣的語言(如 TypeScript)轉換爲 JavaScript,或將內聯圖像轉換爲 data URL。
loader 甚至容許你直接在 JavaScript 模塊中 import CSS文件!

示例 例如,你可使用 loader 告訴 webpack 加載 CSS 文件,或者將 TypeScript 轉爲 JavaScript。爲此,首先安裝相對應的 loader:

npm install --save-dev css-loader
npm install --save-dev ts-loader
複製代碼

而後指示 webpack 對每一個 .css 使用 css-loader,以及對全部 .ts 文件使用 ts-loader:

webpack.config.js

module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' },
      { test: /\.ts$/, use: 'ts-loader' }
    ]
  }
};
複製代碼

使用 loader

在你的應用程序中,有三種使用 loader 的方式:

  1. 配置(推薦):在 webpack.config.js 文件中指定 loader。
  2. 內聯:在每一個 import 語句中顯式指定 loader。
  3. CLI:在 shell 命令中指定它們。

配置[Configuration]

module.rules 容許你在 webpack 配置中指定多個 loader。 這是展現 loader 的一種簡明方式,而且有助於使代碼變得簡潔。同時讓你對各個 loader 有個全局概覽:

module: {
  rules: [
    {
      test: /\.css$/,
      use: [
        { loader: 'style-loader' },
        {
          loader: 'css-loader',
          options: {
            modules: true
          }
        }
      ]
    }
  ]
}
複製代碼

內聯

能夠在 import 語句或任何等效於 "import" 的方式中指定 loader。使用 ! 將資源中的 loader 分開。分開的每一個部分都相對於當前目錄解析。

import Styles from 'style-loader!css-loader?modules!./styles.css';
複製代碼

經過前置全部規則及使用 !,能夠對應覆蓋到配置中的任意 loader。

選項能夠傳遞查詢參數,例如 ?key=value&foo=bar,或者一個 JSON 對象,例如 ?{"key":"value","foo":"bar"}。

儘量使用 module.rules,由於這樣能夠減小源碼中的代碼量,而且能夠在出錯時,更快地調試和定位 loader 中的問題。

CLI

你也能夠經過 CLI 使用 loader:

webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
複製代碼

這會對 .jade 文件使用 jade-loader,對 .css 文件使用 style-loader 和 css-loader。

loader 特性

loader 支持鏈式傳遞。可以對資源使用流水線(pipeline)。一組鏈式的loader 將按照相反的順序執行。loader 鏈中的第一個 loader 返回值給下一個 loader。在最後一個 loader,返回 webpack 所預期的 JavaScript。
loader 能夠是同步的,也能夠是異步的。
loader 運行在 Node.js 中,而且可以執行任何可能的操做。
loader 接收查詢參數。用於對 loader 傳遞配置。
loader 也可以使用 options 對象進行配置。
除了使用 package.json 常見的 main 屬性,還能夠將普通的 npm 模塊導出爲 loader,作法是在 package.json 裏定義一個 loader 字段。
插件(plugin)能夠爲 loader 帶來更多特性。
loader 可以產生額外的任意文件。
loader 經過(loader)預處理函數,爲 JavaScript 生態系統提供了更多能力。 用戶如今能夠更加靈活地引入細粒度邏輯,例如壓縮、打包、語言翻譯和其餘更多。
複製代碼

解析 loader

loader 遵循標準的模塊解析。多數狀況下,loader 將從模塊路徑(一般將模塊路徑認爲是 npm install, node_modules)解析。

插件(plugins)

插件是 wepback 的支柱功能,是更強大的 loader。

剖析

webpack 插件是一個具備 apply 屬性的 JavaScript 對象。apply 屬性會被 webpack compiler(編譯器)調用,而且 compiler 對象可在整個編譯生命週期訪問。

eg: ConsoleLogOnBuildWebpackPlugin.js

const pluginName = 'ConsoleLogOnBuildWebpackPlugin';

class ConsoleLogOnBuildWebpackPlugin {
    apply(compiler) {
        compiler.hooks.run.tap(pluginName, compilation => {
            console.log("webpack 構建過程開始!");
        });
    }
}
複製代碼

compiler hook 的 tap 方法的第一個參數,應該是駝峯式命名的插件名稱。建議爲此使用一個常量,以便它能夠在全部 hook 中複用。

用法

因爲插件能夠攜帶參數/選項,你必須在 webpack 配置中,向 plugins 屬性傳入 new 實例。

根據你的 webpack 用法,這裏有多種方式使用插件。

配置

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin'); //經過 npm 安裝
const webpack = require('webpack'); //訪問內置的插件
const path = require('path');

const config = {
  entry: './path/to/my/entry/file.js',
  output: {
    filename: 'my-first-webpack.bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader'
      }
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;
複製代碼

模塊解析(module resolution)

resolver 是一個庫(library),用於幫助找到模塊的絕對路徑。一個模塊能夠做爲另外一個模塊的依賴模塊,而後被後者引用,以下:

import foo from 'path/to/module'
// 或者
require('path/to/module')
複製代碼

所依賴的模塊能夠是來自應用程序代碼或第三方的庫(library)。resolver 幫助 webpack 找到 bundle 中須要引入的模塊代碼,這些代碼在包含在每一個 require/import 語句中。 當打包模塊時,webpack 使用 enhanced-resolve 來解析文件路徑

webpack 中的解析規則 使用 enhanced-resolve,webpack 可以解析三種文件路徑:

絕對路徑
import "/home/me/file";

import "C:\\Users\\me\\file";
複製代碼

因爲咱們已經取得文件的絕對路徑,所以不須要進一步再作解析。

相對路徑
import "../src/file1";
import "./file2";
複製代碼

在這種狀況下,使用 import 或 require 的資源文件(resource file)所在的目錄被認爲是上下文目錄(context directory)。在 import/require 中給定的相對路徑,會添加此上下文路徑(context path),以產生模塊的絕對路徑(absolute path)。

模塊路徑
import "module";
import "module/lib/file";
複製代碼

模塊將在 resolve.modules 中指定的全部目錄內搜索。 你能夠替換初始模塊路徑,此替換路徑經過使用 resolve.alias 配置選項來建立一個別名。

未完待續…………

參考連接

  1. https://webpack.docschina.org/guides/getting-started/
  2. https://webpack.docschina.org/concepts/
相關文章
相關標籤/搜索