今天凌晨兩點看了老大去世追悼會的直播,心裏說不出的滋味,今天狀態也沒有太好。如果有錯誤的地方歡迎指正
引言
webpack可以看做一個模塊打包工具,將各種靜態資源視爲模塊,它能夠對這些模塊進行解析、轉換等操作,最後打包在一起提供給瀏覽器。
優點
- 代碼轉換:
typeScript
編譯成JavaScript
、scss,less
編譯成css
- 文件優化:壓縮
JavaScript
、html
、css
文件,壓縮合並圖片等 - 代碼分割:提供多個頁面的公共代碼,抽離首屏不需要的代碼使其異步加載
- 模塊合併:模塊化的項目裏會有很多模塊和文件,構建狗能把模塊分類合併
- 自動刷新:監聽本地源代碼,自動重構刷新瀏覽器
- 擴展性好,插件機制完善
打包過程
- 利用babel完成代碼轉換,生成單個文件依賴
- 從入口開始分析,生成依賴圖譜
- 將引用模塊打包爲立即執行函數
- 把最終的bundle文件寫入bundle.js裏
四大核心
- entry:入口,即js入口源文件
- output:生成文件
- loader:文件處理
- plugins:插件
Entry
webpack應該用哪個模塊作爲入口文件,作爲構建內部依賴圖的開始,進入入口後,webpack會找到哪些庫和模塊是入口依賴的,並隨即被處理,最後輸出到bundle.js的文件中
//單入口:entry是一個字符串
module.exports = {
entry: './src/index.js'
}
//多入口:entry是一個對象
module.exports = {
entry: './src/index.js'
}
Output
告訴webpack在哪輸出bundles,以及怎麼命名他,在配置文件中均可搞定
//單入口配置項
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js’,
path: __dirname + '/dist'
}
};
//多入口配置項
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',//[name]佔位符確保文件名唯一
path: __dirname + '/dist'
}
}
Loader
loader
讓webpack能夠處理非javaScript
文件,因爲webpack自己只能看懂javaScript
。loader
能夠把所有類型的文件轉換成webpack能夠處理的模塊,然後利用打包能力對他進行處理
Loader的特點
- 每一個loader的職責都是單一的,只能完成一種轉換
- loader本質上是node.js模塊,這個模塊需要導出一個函數
- loader總是從右到左被調用
常用Loader
處理樣式
css-loader
加載css文件style-loader
使用style標籤把css-loader
內部樣式注入到html中less-loader,sass-loader
解析css預處理器
處理js
讓我們能夠使用最新的js代碼(ES6,ES7等)及讓我們能夠使用基於js進行了拓展的語言,比如JSX等
處理文件
通常使用的兩種loader是file-loader
和url-loader
,兩者主要的區別是url-loader
能夠設置圖片的大小限制,如果大小超過限制,則行爲等同於file-loader
,如果圖片大小不超過限制,那麼圖片會以base64的形式打包
處理vue單文件
vue-loader
是webpack的加載器魔鎧,它讓我們的隨心所欲的編寫.vue
格式的單文件組件。vue-loader
模塊允許 webpack
使用單獨的加載器模塊(例如 sass 或 scss 加載器
)提取和處理每個部分。該設置使我們可以使用 .vue
文件無縫編寫程序。
在文章最後,我們會嘗試開發一個簡易的loader來加深我們的理解
Plugin
專注於處理webpack在編譯過程裏某個特定任務的功能模塊
特點
-
是一個獨立的模塊
-
模塊對外暴露一個js函數
-
函數的原型
(prototype)
上定義了一個注入compiler
對象的apply
方法apply
函數中需要有通過compiler
對象掛載的webpack
事件鉤子,鉤子的回調中能拿到當前編譯的compilation
對象,如果是異步編譯插件的話可以拿到回調callback
-
完成自定義自編程流程並處理
complition
對象的內部數據 -
如果異步編譯插件的話,數據處理完成後執行
callback
回調
常用Plugin
HotModuleReplacementPlugin
代碼熱替換。因爲Hot-Module-Replacement
的熱更新是依賴於webpack-dev-server
,後者是在打包文件改變時更新打包文件或者 reload 刷新整個頁面,HRM
是隻更新修改的部分。HtmlWebpackPlugin
, 生成 html 文件。將 webpack 中entry
配置的相關入口 chunk 和extract-text-webpack-plugin
抽取的 css 樣式 插入到該插件提供的template
或者templateContent
配置項指定的內容基礎上生成一個 html 文件,具體插入方式是將樣式link
插入到head
元素中,script
插入到head
或者body
中。ExtractTextPlugin
, 將 css 成生文件,而非內聯 。該插件的主要是爲了抽離 css 樣式,防止將樣式打包在 js 中引起頁面樣式加載錯亂的現象。NoErrorsPlugin
報錯但不退出 webpack 進程UglifyJsPlugin
,代碼醜化,開發過程中不建議打開。uglifyJsPlugin
用來對 js 文件進行壓縮,從而減小 js 文件的大小,加速 load 速度。uglifyJsPlugin
會拖慢 webpack 的編譯速度,所有建議在開發簡單將其關閉,部署的時候再將其打開。多個 html 共用一個 js 文件(chunk),可用CommonsChunkPlugin
purifycss-webpack
。打包編譯時,可剔除頁面和 js 中未被使用的 css,這樣使用第三方的類庫時,只加載被使用的類,大大減小 css 體積optimize-css-assets-webpack-plugin
壓縮 css,優化 css 結構,利於網頁加載和渲染webpack-parallel-uglify-plugin
可以並行運行 UglifyJS 插件,這可以有效減少構建時間
同樣的,文章最後我們也會嘗試開發一個Plugin
番外
沒錯,文章最後了,現在我們開始開發一個loader
和plugin
開發一個loader
需求:開發一個loader
,將KobeBryant轉換爲
mamba forever`。
1.編寫loader
新建目錄my-loader
作爲名字,執行npm init -y
快速創建一個模塊化項目,然後新建index.js
module.exports = function(content) {
return content && content.replace(/KobeBryant/gi , 'mamba forever')
}
2.註冊模塊
一般情況下,我們需要的loader都是利用npm安裝,但是我們可以使用npm link
命令,以求在不發佈模塊的情況下,將本地的源碼鏈接到項目的node_modules
下。在項目的根目錄下執行以下命令
λ npm link my-loader
3.在webpack中配置loader
在webpack.base.config.js
中加上以下配置
{
test:/\.js/,
loader:'my-loader'
}
這樣我們js裏所有的字符串KobeBryant
就會替換爲mamba forever
了
4.配置參數
前面我們是寫死的替換,如果我們想要通過配置項來進行改變怎麼辦
// index.js
var utils = require('loader-utils')
module.exports = function (content) {
const options = utils.getOptions(this)
return content && content.replace(/KobeBryant/gi , options.name)
}
// webpack.base.conf.js
{
test:/\.js/,
use: {
loader: 'my-loader',
options: {
name: 'KobeBryant',
}
}
}
開發一個Plugin
- webpack在編譯中,會廣播很多事件
- webpack應用了觀察者模式,插件可以監聽webpack事件來觸發對應的處理邏輯
- 插件中可以使用webpack的api
1.編寫插件
創建目錄my-plugin
作爲編寫的插件,執行npm init -y
快速創建一個模塊化項目,然後新建index.js
class MyPlugin {
constructor(doneCakkback , failCallback) {
//保存在創建實例時候傳入的回調函數
this.doneCallback = doneCallback
this.failCallback = failCallback
}
apply(compiler) {
//成功完成一次完整的編譯和輸出時,會觸發done
compile.plugin('done' , stats => {
this.doneCallback(stats)
})
//出現異常的時候,觸發fail
compiler.plugin('fail' , err => {
this.failCallback(err)
})
}
}
module.exports = MyPlugin
2.註冊模塊
同樣的,我們link一下,以便於我們能直接使用本地的模塊
λ npm link my-plugin
3.配置插件
在webpack.base.conf.js
加上以下配置
plugins: [
new MyPlugin(
stats => {
console.log('編譯成功')
},
err => {
console.error('編譯失敗')
}
)
]