webpack
是一個現代Javascript應用程序的靜態模塊打包器,指的是webpack
在不進行特殊配置時,就只能處理JavaScript
這一種語言,打包指的就是多個js文件不須要人爲的去理清其的依賴關係,並且還能將其合成爲一個文件。css
爲何要打包呢?由於前端項目中的邏輯多了,文件多了,複雜度提升了(好比一個項目依賴多個模塊),因而提出多種模塊化的標準,webpack
就是這麼一種優秀的模塊化方案。
webpack
不只強大,並且靈活(每一個功能可插拔)。html
webpack
除了打包還能幹什麼?前端
loader
,把代碼翻譯成瀏覽器看的懂的代碼。plugin
裏。下面會解釋loader和plugin
。node
babel-loader
,文件中引入css文件就須要css-loader
,style-loader
。webpack
的能力,其機制就是強調一個事件監聽的能力,在項目裏監聽一些事件,而且改變一些文件打包輸出的結果。好比使用一個叫UglifyJSPlugin
的插件來對js文件進行壓縮,從而減少js
文件的大小,加速load速度。Loader負責文件轉換,那麼Plugin即是負責功能擴展。Loader和Plugin做爲Webpack的兩個重要組成部分,承擔着兩部分不一樣的職責。react
什麼是模塊呢? 舉個例子:一個公司須要正常運轉,就有市場部,技術部,人事部等等,這每一個部門就至關於一個模塊,在前端項目中也就有好比專門網絡請求的模塊,錯誤處理的模塊,專門渲染的模塊。webpack
瞭解模塊化以前瞭解下做用域的概念先。es6
傳統作法會引入多個js腳本,它們共處於全局做用域下,就容易致使全局做用域變量衝突(例如同名變量衝突),而發生一些不可預測的事情。 例如:web
/*moduleA.js裏*/
var a=10;
/*moduleB.js裏*/
var a=11;
/*index.html裏*/
<body>
<script src="./moduleA.js"></script>
<script src="./moduleB.js"></script>
<script src="./moduleC.js"></script>
</body>
複製代碼
當出現上面得衝突後,a的值還能肯定嗎?——不能!面試
而後就有人想出,每一個js腳本里都使用一個對象包裹,造成一個局部做用域。api
// 定義模塊內的局部做用域,以moduleA爲例
var Susan = {
name: "susan",
sex: "female",
tell: function(){
console.log("im susan")
}
}
複製代碼
可是這樣又有各嚴重的問題,就是對象裏值咱們能更改,沒法保證模塊屬性內部安全性,對於好比說用戶名密碼等數據的情景就很嚴重了。
因而又改進到了當即執行函數和閉包的形式。
// 定義模塊內的閉包做用域(模塊做用域),以moduleA爲例
var SusanModule = (function(){
var name = "susan"
var sex = "female"
functioon tell(){//這樣就不能更改其中的數據了
console.log("I'm ", this.name)
}
})()
複製代碼
咱們再改進下寫法,爲當即執行函數寫入參數爲window
。
// 定義模塊內的閉包做用域(模塊做用域),以moduleA爲例
(function(window){
var name = "susan"
var sex = "female"
functioon tell(){
console.log("I'm ", this.name)
}
window.susanModule = {tell}
})(window)// window做爲參數傳給
//////////////////////
//測試
window.susanModule.tell(); //im susan
複製代碼
這樣大概就是早期的模塊化的形式了。
如今的模塊化方案有:
//大概形式以下
//定義
define("mymodule", ["dep1", "dep2"], function(d1, d2) {
});
// 加載
require(["module", "../file"], function(module, file) {
});
複製代碼
// 經過require函數來引用
const math = require("./math");
// 經過exports將其導出
exports.getSum = function(a,b){
return a + b;
}
複製代碼
// 經過import函數來引用
import math from "./math";
// 經過export將其導出
export function sum(a, b){
return a + b;
}
複製代碼
此外說說ES6
模塊化和CommonJs
的模塊化的區別:
CommonJS
模塊輸出的是一個值的拷貝,ES6
模塊輸出的是值的引用。
注意:CommonJS
模塊輸出的是值的拷貝,也就是說,一旦輸出一個值,模塊內部的變化就影響不到這個值
ES6
模塊是動態引用,而且不會緩存值,模塊裏面的變量綁定其所在的模塊。
CommonJS
模塊是運行時加載,ES6
模塊是編譯時輸出接口。
緣由:CommonJS
加載的是一個對象(即module.exports
屬性),該對象只有在腳本運行完纔會生成。而 ES6 模塊
不是對象,它的對外接口只是一種靜態定義,在代碼靜態解析階段就會生成。
CommonJS
模塊的require()
是同步加載模塊,ES6
模塊的import
命令是異步加載,有一個獨立的模塊依賴的解析階段。
前端模塊化主要解決了兩個問題:「命名空間衝突」,「文件依賴管理」。
和介紹webpack又有什麼關係呢?
在webpack中,一切皆模塊。咱們在模塊化開發的時候,一般會使用ES Module
或者CommonJS
規範導出或引入依賴模塊,webpack打包編譯的時候,會統一替換成本身的__webpack_require__
來實現模塊的引入和導出,從而實現模塊緩存機制,以及抹平不一樣模塊規範之間的一些差別性。
Entry入口文件
出發,針對每一個 Module 串行調用對應的 Loader 去翻譯文件的內容,再找到該 Module 依賴的 Module,遞歸地進行編譯處理const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: path.resolve(__dirname, '../src/index.js'), //指定入口文件,程序從這裏開始編譯,__dirname當前所在目錄, ../表示上一級目錄, ./同級目錄
output: {
path: path.resolve(__dirname, '../dist'), // 輸出的路徑
filename: 'app/[name]_[hash:8].js' // 打包後文件
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react'],
}
},
exclude: /node_modules/
}
]
},
plugins: [//plugin下的插件
new HtmlWebpackPlugin({
template: path.resolve(__dirname, '../src/index.template.html'),
inject: true
})
]
複製代碼
loader下:
babel-loader
: babel加載器
babel-preset-es2015
: 支持es2015
babel-preset-react
: jsx
轉換成js
loader
是支持以數組的形式配置多個的,當Webpack在轉換該文件類型的時候,會按順序鏈式調用每個loader
,前一個loader
返回的內容會做爲下一個loader
的入參。
plugin下:
html-webapck-plugin
插件的兩個主要做用:
爲html
文件中引入的外部資源如script
、link
動態添加每次compile
後的hash
,防止引用緩存的外部文件問題
能夠生成建立html入口文件
,好比單頁面能夠生成一個html文件入口,配置N個html-webpack-plugin
能夠生成N個頁面入口
webpack基於發佈訂閱模式,在運行的生命週期中會廣播出許多事件,plugin插件
經過監聽這些事件,就能夠在特定的階段執行本身的插件任務,從而實現本身想要的功能。
一些常見的loader和plugin能夠看看這裏,最好對這些有個大概瞭解和記憶。。
到這裏就爲理解webpack
下一個簡單定義:webpack做用於模塊打包
,將不一樣模塊的文件打包整合在一塊兒,而且保證它們之間的引用正確,執行有序。而且經過其的loader機制
,讓webpack
可以去處理其餘類型的文件,並將它們轉換爲有效模塊,以供應用程序使用,以及被添加到依賴圖中。且再經過webpack的Plugin機制
,咱們還能夠進一步實現諸如按需加載,代碼壓縮等一系列擴展功能。
參考文章: