經過核心概念瞭解webpack工做機制

webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。
須要先理解四個核心概念:css

  • 入口(entry)
  • 輸出(output)
  • loader
  • 插件(plugins)

入口(entry)

入口指 webpack 構建其內部依賴圖開始的模塊。進入入口後,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的。
在 webpack 配置中有多種方式定義 entry 屬性。
用法:html

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


單個入口可簡寫成以下:前端

const config = {
entry: './path/to/my/entry/file.js'
};

如下是兩種實際用例:
1.分離應用程序和第三方庫入口,vue-cli中是這樣作的:vue

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

webpack 從 app.js 和 vendors.js 開始建立依賴圖。這些依賴圖是彼此徹底分離、互相獨立的。這種方式比較常見於,只有一個入口起點(不包括 vendor)的單頁應用程序(single page application)中。node

2.多頁面應用程序webpack

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

在多頁應用中,頁面跳轉時服務器將爲你獲取一個新的 HTML 文檔。頁面從新加載新文檔,而且資源被從新下載。因爲入口起點增多,多頁應用可以複用入口起點之間的大量代碼/模塊.web

輸出(Output)

該屬性設置 webpack 在輸出它所建立的 bundles的路徑以及命名。
注意: 即便能夠存在多個入口起點,但只指定一個輸出配置。vue-cli

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

filename 用於輸出文件的文件名。
目標輸出目錄 path 的絕對路徑。編程

const config = {
output: {
filename: 'bundle.js',
path: '/home/proj/public/assets'
}
};

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

多個入口時:
若是配置建立了多個單獨的 "chunk"(例如,使用多個入口起點或使用像 CommonsChunkPlugin 這樣的插件),則應該使用佔位符(substitutions)來確保每一個文件具備惟一的名稱。

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

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

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

 

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

__webpack_public_path__ = myRuntimePublicPath

// 剩餘的應用程序入口

loader

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

示例:
使用loader加載 CSS 文件 和 將 TypeScript 轉爲 JavaScript。
首先安裝對應的loader

npm install --save-dev css-loader
npm install --save-dev ts-loader

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

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


以上配置,對一個 module 對象定義了 rules 屬性,裏面包含兩個必須屬性:test 和 use。
test 屬性,用於標識出應該被對應的 loader 進行轉換的某個或某些文件。
use 屬性,表示進行轉換時,應該使用哪一個 loader。
上面的配置表明, 當webpack編譯器解析時, 遇到 require()/import 語句有'.css'路徑時,在打包以前先用 css-loader 轉換一下;遇到 require()/import 語句有'.ts'路徑時,在打包以前先用 ts-loader 轉換一下

使用Loader的三種方式:

1.配置: 在 webpack.config.js 文件中指定 loader。

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

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

2.內聯: 在 import 語句或任何等效於 "import" 的方式中指定 loader。

使用 ! 將資源中的 loader 分開。分開的每一個部分都相對於當前目錄解析。

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


經過前置全部規則及使用 !,能夠對應覆蓋到配置中的任意 loader。選項能夠傳遞查詢參數,例如 ?key=value&foo=bar,或者一個 JSON 對象,例如 ?{"key":"value","foo":"bar"}。

3.經過 CLI 使用 loader:

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

loader 經過(loader)預處理函數,爲 JavaScript 生態系統提供了更多能力。 用戶如今能夠更加靈活地引入細粒度邏輯,例如壓縮、打包、語言翻譯等loader 遵循標準的模塊解析。多數狀況下,loader 將從模塊路徑(一般將模塊路徑認爲是 npm install, node_modules)解析。loader 模塊須要導出爲一個函數,而且使用 Node.js 兼容的 JavaScript 編寫。一般使用 npm 進行管理,可是也能夠將自定義 loader 做爲應用程序中的文件。按照約定,loader 一般被命名爲 xxx-loader(例如 json-loader)。

用法:
因爲插件能夠攜帶參數/選項,你必須在 webpack 配置中,向 plugins 屬性傳入 new 實例。
根據你的 webpack 用法,這裏有多種方式使用插件。

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: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        use: 'babel-loader'
      }
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;

 

插件(plugins)

loader 被用於轉換某些類型的模塊,而插件的使用範圍包括,從打包優化和壓縮,一直到從新定義環境中的變量。能夠用來處理各類任務.
使用某個插件,只須要require(),而後添加到 plugins 數組中.多數插件能夠經過選項(option)自定義,也能夠在一個配置文件中由於不一樣目的而屢次使用同一個插件,這時須要經過使用 new 操做符來建立它的一個實例。

示例:

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

const config = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'), //生成文件(emit)的路徑
    filename: 'yq-webpack.bundle.js' // webpack bundle 的名稱
  },
  module: {
    rules: [
      {test: /\.txt$/, use: 'raw-loader'}
    ]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new HtmlWebpackPlugin({template: './src/index.html'})
  ]
};

module.exports = config;

 模塊

  在模塊化編程中,開發者將程序分解成離散功能塊(discrete chunks of functionality),並稱之爲_模塊_。

每一個模塊具備比完整程序更小的接觸面,使得校驗、調試、測試垂手可得。 精心編寫的_模塊_提供了可靠的抽象和封裝界限,使得應用程序中每一個模塊都具備條理清楚的設計和明確的目的。
對比 Node.js 模塊,webpack _模塊_可以以各類方式表達它們的依賴關係

  • ES2015 import 語句
  • CommonJS require() 語句
  • AMD define 和 require 語句
  • css/sass/less 文件中的 @import 語句。
  • 樣式(url(...))或 HTML 文件(<img src=...>)中的圖片連接(image url)

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

import foo from 'path/to/module'
// 或者
require('path/to/module')

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

webpack 中的解析規則

webpack 可以解析三種文件路徑:
絕對路徑:

import "/home/me/file";

import "C:\\Users\\me\\file";

相對路徑

import "/home/me/file";

import "C:\\Users\\me\\file";

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

模塊路徑

import "module";


import "module/lib/file";

 

模塊將在 resolve.modules 中指定的全部目錄內搜索。

一旦根據上述規則解析路徑後,解析器(resolver)將檢查路徑是否指向文件或目錄。若是路徑指向一個文件:
若是路徑具備文件擴展名,則被直接將文件打包。
不然,將使用 [resolve.extensions] 選項做爲文件擴展名來解析,此選項告訴解析器在解析中可以接受哪些擴展名(例如 .js, .jsx)。

若是路徑指向一個文件夾,則採起如下步驟找到具備正確擴展名的正確文件:

若是文件夾中包含 package.json 文件,則按照順序查找 resolve.mainFields 配置選項中指定的字段。而且 package.json 中的第一個這樣的字段肯定文件路徑。
若是 package.json 文件不存在或者 package.json 文件中的 main 字段沒有返回一個有效路徑,則按照順序查找 resolve.mainFiles 配置選項中指定的文件名,看是否能在 import/require 目錄下匹配到一個存在的文件名。
文件擴展名經過 resolve.extensions 選項採用相似的方法進行解析。
webpack 根據構建目標(build target)爲這些選項提供了合理的默認配置。
相關文章
相關標籤/搜索