webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序須要的每一個模塊,而後將全部這些模塊打包成一個或多個 bundle。
須要先理解四個核心概念:css
入口指 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
該屬性設置 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 可使你在 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的三種方式:
module.rules 容許你在 webpack 配置中指定多個 loader。 這是展現 loader 的一種簡明方式,而且有助於使代碼變得簡潔。同時讓你對各個 loader 有個全局概覽:
module: { rules: [ { test: /\.css$/, use: [ { loader: 'style-loader' }, { loader: 'css-loader', options: { modules: true } } ] } ] }
使用 ! 將資源中的 loader 分開。分開的每一個部分都相對於當前目錄解析。
import Styles from 'style-loader!css-loader?modules!./styles.css';
經過前置全部規則及使用 !,能夠對應覆蓋到配置中的任意 loader。選項能夠傳遞查詢參數,例如 ?key=value&foo=bar,或者一個 JSON 對象,例如 ?{"key":"value","foo":"bar"}。
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;
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 _模塊_可以以各類方式表達它們的依賴關係
resolver 是一個庫(library),用於幫助找到模塊的絕對路徑。一個模塊能夠做爲另外一個模塊的依賴模塊,而後被後者引用,以下:
import foo from 'path/to/module' // 或者 require('path/to/module')
所依賴的模塊能夠是來自應用程序代碼或第三方的庫(library)。resolver 幫助 webpack 找到 bundle 中須要引入的模塊代碼,這些代碼在包含在每一個 require/import 語句中。 當打包模塊時,webpack 使用 enhanced-resolve 來解析文件路徑
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)爲這些選項提供了合理的默認配置。