What is webpack
webpack是一個static module bundler(靜態(tài)模塊打包器)。當(dāng)webpack處理你app的時候,webpack會在內(nèi)部創(chuàng)建一個dependency graph, 這個graph中會列出app中所有的module,以及module之間的依賴關(guān)系。使用這個graph創(chuàng)建出來一個或者多個bundles
What is module
通常我們可以將一個文件理解成是一個module。但是module通俗的解釋就是:
module指的是獨立的可重用的最小代碼單元,module中的代碼可以被export出去,module也可以引用其他的module。
簡而言之,module中包含三個概念:
- 獨立的代碼單元module
- module可以被暴露
- module也可以引用其他module
ES6 module
在ES6之前,雖然JS也有module,但是module的實現(xiàn)(import、export)都是使用第三方庫實現(xiàn)的,JS并沒有內(nèi)置的module feature。
因此當(dāng)不使用第三方庫的時候(requirejs),我們根本沒有辦法在一個module(JS文件)中引用另外一個module(js文件),因此只能使用多個<script> tag, 這樣會發(fā)送很多請求不利于頁面的perfermance。
因此ES6終于引入了module,俗稱ES6 module,支持module的import/export,相當(dāng)于以后可以直接使用import export不需要借助其他任何工具,但是并不是所有的瀏覽器都實現(xiàn)了ES6 module,所以。。。
通常的兼容做法就是借助transpiler(babel), 將你的ES6 import編譯成ES5。
- 例子
// ES6
import Lodash from 'Lodash';
// Babel compile
"use strict";
var _Lodash = _interopRequireDefault(require("Lodash"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
Why we need bunlder
現(xiàn)代的Web肯定需要很多和用戶交互的地方,因此純HTML已經(jīng)不能夠滿足我們的需求了,需要在HTML中加JS,那么通常通過script tag, 將你的JS文件加入到HTML中。
如果你的JS文件只有50行,還好,但是隨著APP的功能越來越多,JS的代碼量肯定越來越大,如果最后這個JS文件需要包含幾十萬行代碼,就太可怕了。。
那么你肯定會說,不如果我們將這些代碼分散在多個JS文件里,在HTML中多引入幾個script就OK不是?如果這么做
- 首先頁面需要加載這么多的文件,perfermance肯定會受影響
- 除此之外,你還得合理安排你的script標(biāo)簽的順序,如果B import scriptA,那么script A必須在scriptB之前
更好的方法是,如果每個文件都能以某種方式告訴我們它還需要什么其他文件,然后我們就可以利用這個來安排文件引入的先后順序
webpack就會使用這種方式構(gòu)建dependency graph(描述所有的文件和他們的依賴),然后將這些文件全部bundle起來。
How does webpack work
當(dāng)你定義一個webpack的入口文件,webpack就會從這里開始開始處理.我們俗稱為compile過程
- 遞歸地遍歷每個文件的依賴關(guān)系,并解析每個依賴關(guān)系,直到遍歷完成為止。
webpack的resolver會首先check所有依賴的文件是否存在,如果都存在,然后將每一個文件都轉(zhuǎn)換成一個module,然后為這些module創(chuàng)建dependency graph
將所有的module都bundle在一個文件中,這個文件就是output
同時webpack會創(chuàng)建并保留所有module的注冊表,其中可能包含module所在的位置,因此可以在需要時正確調(diào)用/執(zhí)行它們。
Loader
webpack的目的是將你所有的dependency全部bundle在一起,那么你的dependency可能是JS文件,也可能是一些assets(picture)。
本身bundler只是用來bundle JS文件的,那么對于其他類型的文件和assets, webpack需要在他們被bundler處理之前做一些預(yù)處理工作,將這些文件翻譯成bundler能夠處理的類型。
這個預(yù)處理工作就由loader完成,因為有l(wèi)oader,所以webpack可以支持bundle多種多樣的文件。
Loader可以將各種其他類型的文件翻譯成JS或者data URLs
Plugins
plugins可以截取webpack的runtime events, 因為webpack給所有的runtime events都提供了hook,我們可以利用hook去實現(xiàn)plugin的功能。
Plugin實現(xiàn)
每一個plugin必須有一個apply方法,這個apply方法會被webpack compiler調(diào)用,就可以幫助plugin獲取entire compilation lifecycle
const pluginName = 'ConsoleLogOnBuildWebpackPlugin';
class ConsoleLogOnBuildWebpackPlugin {
apply(compiler) {
compiler.hooks.run.tap(pluginName, compilation => {
console.log('The webpack build process is starting!!!');
});
}
}
module.exports = ConsoleLogOnBuildWebpackPlugin;
Plugin使用
我們可以在webpack的config文件中配置插件,webpack的config對象中有一個參數(shù)plugins,他的類型是數(shù)組,每一個元素必須是plugin的new instance
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');
module.exports = {
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.ProgressPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};