webpack是一個(gè)模塊打包器(module bundler),提供了一個(gè)核心犬钢,核心提供了很多開(kāi)箱即用的功能,同時(shí)它可以用loader和plugin來(lái)擴(kuò)展。webpack本身結(jié)構(gòu)精巧耘戚,基于tapable的插件架構(gòu),擴(kuò)展性強(qiáng)操漠,眾多的loader或者plugin讓webpack顯得很復(fù)雜收津。
webpack常用配置包括:devtool、entry浊伙、 output撞秋、module、resolve嚣鄙、plugins吻贿、externals等,本文主要介紹下webpack常用的loader和plugin
webpack允許我們使用loader來(lái)處理文件哑子,loader是一個(gè)導(dǎo)出為function的node模塊舅列。可以將匹配到的文件進(jìn)行一次轉(zhuǎn)換卧蜓,同時(shí)loader可以鏈?zhǔn)絺鬟f剧蹂。
loader的使用方式
一般loader的使用方式分為三種:
1:在配置文件webpack.config.js中配置
module.exports = {
module: {
rules: [
{
test: /\.txt$/,
use: 'raw-loader'
}
]
}
}復(fù)制代碼
2:通過(guò)命令行參數(shù)方式
webpack --module-bind 'txt=raw-loader'復(fù)制代碼
3:通過(guò)內(nèi)聯(lián)使用
import txt from 'raw-loader!./file.txt';復(fù)制代碼
webpack常用的loader
- 樣式:style-loader、css-loader烦却、less-loader宠叼、sass-loader等
- 文件:raw-loader、file-loader 其爵、url-loader等
- 編譯:babel-loader冒冬、coffee-loader 、ts-loader等
- 校驗(yàn)測(cè)試:mocha-loader摩渺、jshint-loader 简烤、eslint-loader等
比如下面配置,可以匹配.scss的文件摇幻,分別經(jīng)過(guò)sass-loader横侦、css-loader、style-loader的處理绰姻。
sass-loader
轉(zhuǎn)化sass為css文件枉侧,并且包一層module.exports成為一個(gè)js module。style-loader
將創(chuàng)建一個(gè)style標(biāo)簽將css文件嵌入到html中狂芋。css-loader
則處理其中的@import和url()榨馁。
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
use:[
{loader:'style-loader'},
{loader:'css-loader',options:{sourceMap:true,modules:true}},
{loader:'sass-loader',options:{sourceMap:true}}
],
exclude:/node_modules/
}
]
}
}復(fù)制代碼
vue-loader、coffee-loader帜矾、babel-loader
等可以將特定文件格式轉(zhuǎn)成js模塊翼虫、將其他語(yǔ)言轉(zhuǎn)化為js語(yǔ)言和編譯下一代js語(yǔ)言file-loader屑柔、url-loader
等可以處理資源,file-loader可以復(fù)制和放置資源位置珍剑,并可以指定文件名模板掸宛,用hash命名更好利用緩存。url-loader
可以將小于配置limit大小的文件轉(zhuǎn)換成內(nèi)斂Data Url的方式招拙,減少請(qǐng)求旁涤。raw-loader
可以將文件已字符串的形式返回imports-loader、exports-loader
等可以向模塊注入變量或者提供導(dǎo)出模塊功能迫像,常見(jiàn)場(chǎng)景是:
1:jquery插件注入=jquery
2:禁用AMD劈愚,imports-loader?define=false
等同于:var $ = require("jquery") 和 var define = false;-
expose-loader
:暴露對(duì)象為全局變量
如何寫一個(gè)loader:官網(wǎng)介紹how to write a loader
下面是一個(gè)簡(jiǎn)單的raw-loader,它可以將文本類文件轉(zhuǎn)成字符串到j(luò)s文件中。其中this.cacheable闻妓、this.value等是loader的api菌羽,分別是將結(jié)果標(biāo)記為可緩存和把值傳遞給下一個(gè)loader。module.exports = function(content) { this.cacheable && this.cacheable(); this.value = content; return "module.exports = " + JSON.stringify(content); }復(fù)制代碼
webpack的plugin比loader強(qiáng)大由缆,通過(guò)鉤子可以涉及整個(gè)構(gòu)建流程注祖,可以做一些在構(gòu)建范圍內(nèi)的事情。
webpack常用的plugin
官網(wǎng)介紹plugins
第三方插件awesome-webpack
首先webpack內(nèi)置
UglifyJsPlugin
均唉,壓縮和混淆代碼是晨。webpack內(nèi)置
CommonsChunkPlugin
,提高打包效率舔箭,將第三方庫(kù)和業(yè)務(wù)代碼分開(kāi)打包罩缴。-
ProvidePlugin
:自動(dòng)加載模塊,代替require和importnew webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' })復(fù)制代碼
html-webpack-plugin
可以根據(jù)模板自動(dòng)生成html代碼层扶,并自動(dòng)引用css和js文件extract-text-webpack-plugin
將js文件中引用的樣式單獨(dú)抽離成css文件-
DefinePlugin
編譯時(shí)配置全局變量箫章,這對(duì)開(kāi)發(fā)模式和發(fā)布模式的構(gòu)建允許不同的行為非常有用。new webpack.DefinePlugin({ PRODUCTION: JSON.stringify(true), VERSION: JSON.stringify("5fa3b9"), BROWSER_SUPPORTS_HTML5: true, TWO: "1+1", "typeof window": JSON.stringify("object") })復(fù)制代碼
-
HotModuleReplacementPlugin
熱更新- 添加HotModuleReplacementPlugin
- entry中添加 "webpack-dev-server/client?http://localhost:8080/",
- entry中添加 "webpack/hot/dev-server"
- (熱更新還可以直接用webpack_dev_server --hot --inline,原理也是在entry中添加了上述代碼)
webpack 內(nèi)置的
DllPlugin
和DllReferencePlugin
相互配合镜会,前置第三方包的構(gòu)建檬寂,只構(gòu)建業(yè)務(wù)代碼,同時(shí)能解決Externals多次引用問(wèn)題戳表。DllReferencePlugin引用DllPlugin配置生成的manifest.json文件,manifest.json包含了依賴模塊和module id的映射關(guān)系-
babili-webpack-plugin桶至、transform-runtime 、transform-object-rest-spread
- babili-webpack-plugin:構(gòu)建在babel之上 why
- transform-runtime :解決了babel在每個(gè)文件都插入了輔助代碼匾旭,代碼體積過(guò)大的問(wèn)題镣屹。
- transform-object-rest-spread:
Transform rest properties for object destructuring assignment and spread properties for object literals
為對(duì)象字面量添加解構(gòu)賦值和spread屬性
optimize-css-assets-webpack-plugin
不同組件中重復(fù)的css可以快速去重webpack-bundle-analyzer
一個(gè)webpack的bundle文件分析工具,將bundle文件以可交互縮放的treemap的形式展示季率。compression-webpack-plugin
生產(chǎn)環(huán)境可采用gzip壓縮JS和CSS-
happypack
:通過(guò)多進(jìn)程模型野瘦,來(lái)加速代碼構(gòu)建const os = require('os'); let HappyPack = require('happypack'); let happyThreadPool = HappyPack.ThreadPool({size: os.cpus().length}); exports.plugins = [ new HappyPack({ id: 'jsx', threadPool: happyThreadPool, loaders: [ 'babel-loader' ] }), new HappyPack({ id: 'coffeescripts', threadPool: happyThreadPool, loaders: [ 'coffee-loader' ] }) ]; exports.module.loaders = [ { test: /\.js$/, loaders: [ 'happypack/loader?id=jsx' ] }, { test: /\.coffee$/, loaders: [ 'happypack/loader?id=coffeescripts' ] }, ]復(fù)制代碼
寫一個(gè)webpack插件:
官網(wǎng)介紹:how to write a plugin
主要的步驟如下:
- 編寫一個(gè)JavaScript命名函數(shù)描沟。
- 在它的原型上定義一個(gè)apply方法飒泻。
- 指定掛載的webpack事件鉤子鞭光。
- 處理webpack內(nèi)部實(shí)例的特定數(shù)據(jù)。
- 功能完成后調(diào)用webpack提供的回調(diào)泞遗。
編寫插件之前要理解compiler和compilation兩個(gè)對(duì)象惰许,以及webpack生命周期的各個(gè)階段和鉤子,plugin比loader強(qiáng)大史辙,通過(guò)plugin你可以訪問(wèn)compliler和compilation過(guò)程汹买,通過(guò)鉤子攔截webpack的執(zhí)行。
比如我們可以在構(gòu)建生成文件時(shí)聊倔,將所有生成的文件名生成到filelist.md的文件中
webpack會(huì)將compilation.assets的內(nèi)容生成文件晦毙,所以可以在構(gòu)建中利用它生成我們想要的文件。
function FileListPlugin(options) {}
FileListPlugin.prototype.apply = function(compiler) {
compiler.plugin('emit', function(compilation, callback) {
var filelist = 'In this build:\n\n';
for (var filename in compilation.assets) {
filelist += ('- '+ filename +'\n');
}
compilation.assets['filelist.md'] = {
source: function() {
return filelist;
},
size: function() {
return filelist.length;
}
};
callback();
});
};
module.exports = FileListPlugin;復(fù)制代碼
比如我們可以在html-webpack-plugin生成文件后刷新頁(yè)面耙蔑,完成熱更新效果见妒。
var webpack = require('webpack')
var webpackConfig = require('./webpack.config')
var compiler = webpack(webpackConfig)
var hotMiddleware = require('webpack-hot-middleware')(compiler, {
log: () => {}
})
compiler.plugin('compilation', function (compilation) {
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
hotMiddleware.publish({ action: 'reload' })
cb()
})
})復(fù)制代碼
比如我們可以在構(gòu)建完成后,打開(kāi)一個(gè)提示窗口甸陌。
class Notifier {
apply(compiler) {
compiler.plugin("done", (stats) => {
const pkg = require("./package.json");
const notifier = require("node-notifier");
const time = ((stats.endTime - stats.startTime) / 1000).toFixed(2);
notifier.notify({
title: pkg.name,
message: `WebPack is done!\n${stats.compilation.errors.length} errors in ${time}s`,
contentImage: "https://path/to/your/logo.png",
});
});
}
}
module.exports = Notifier;