如果你還沒有看第一篇 請(qǐng)先看下第一篇的基礎(chǔ)知識(shí):webpack開發(fā)配置
開發(fā)技巧
啟用source-map
現(xiàn)在的代碼是合并以后的代碼贺辰,不利于排錯(cuò)和定位逼裆,只需要在config中添加
...
devtool: 'eval-source-map',
...
這樣出錯(cuò)以后就會(huì)采用source-map的形式直接顯示你出錯(cuò)代碼的位置稽物。
配置webpack-dev-server代理
既然常用webpack做React一類的SPA巢价,那么一個(gè)典型的例子就是前后端分離倒得。后端是一個(gè)RESTful的server不管用什么寫的农渊。假定在本機(jī)他是類似[http://localhost:5000/api/@*
]這類的請(qǐng)求患蹂,現(xiàn)在添加配置讓ajax請(qǐng)求可以直接proxy過去。
devServer: {
hot: true,
inline: true,
//其實(shí)很簡(jiǎn)單的砸紊,只要配置這個(gè)參數(shù)就可以了
proxy: {
'/api/*': {
target: 'http://localhost:5000',
secure: false
}
}
},
更多的方法可以看官方文檔 Webpack dev server proxy
使用preLoaders和postLoaders
也許你想在寫代碼的時(shí)候檢查自己的js是否符合jshint的規(guī)范传于,那么隆重推薦preLoaders和postLoaders,上一節(jié)我們已經(jīng)非常了解loaders了醉顽,用它來處理各種類型的文件沼溜。perLoaders顧名思義就是在loaders執(zhí)行之前處理的,webpack的處理順序是perLoaders - loaders - postLoaders游添。
在config文件中配置
module: {
...
//和loaders一樣的語法系草,很簡(jiǎn)單
perLoaders: [
{
test: /\.jsx?$/,
include: APP_PATH,
loader: 'jshint-loader'
}
]
}
...
//配置jshint的選項(xiàng)通熄,支持es6的校驗(yàn)
jshint: {
"esnext": true
},
好了 現(xiàn)在每次npm run start的時(shí)候就可以看到j(luò)shint的提示信息啦
加載jQuery plugin或者其他legacy第三方庫
這個(gè)是非常有用的內(nèi)容!
你的項(xiàng)目有時(shí)候會(huì)要加載各種各樣的第三方庫,一些老的庫不支持AMD或者CommonJS等一些先進(jìn)的格式找都,比如一些jQuery的插件唇辨,它們都依賴jQuery,如果直接引用就會(huì)報(bào)錯(cuò) jQuery is not undefined這類的錯(cuò)誤檐嚣,有幾種方法解決
先創(chuàng)建一個(gè)jQuery plugin: plugin.js
(function ($) {
const shade = "#556b2f";
$.fn.greenify = function() {
this.css( "color", shade );
return this;
};
}(jQuery));
第一種方法 使用webpack.ProvidePlugin
...
plugins: [
new HtmlwebpackPlugin({
title: 'Hello World app'
}),
//provide $, jQuery and window.jQuery to every script
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
]
...
在js中引用
...
//這個(gè)也不需要了 因?yàn)?, jQuery, window.jQuery都可以直接使用了
//import $ from 'jquery';
import './plugin.js';
...
myPromise.then((number) => {
$('body').append('<p>promise result is ' + number + ' now is ' + moment().format() + '</p>');
//call our jquery plugin!
$('p').greenify();
});
...
發(fā)現(xiàn)我們插入的p里面的顏色已經(jīng)變成了綠色!
第二種方法 使用imports-loader
先安裝這個(gè)loader
npm install imports-loader --save-dev
然后在入口js中
//注意這種寫法 我們把jQuery這個(gè)變量直接插入到plugin.js里面了
//相當(dāng)于在這個(gè)文件的開始添加了 var jQuery = require('jquery');
import 'imports?jQuery=jquery!./plugin.js';
//后面的代碼一樣
myPromise.then((number) => {
$('body').append('<p>promise result is ' + number + ' now is ' + moment().format() + '</p>');
//call our jquery plugin!
$('p').greenify();
});
部署上線
剛才說的各種情況都是在開發(fā)時(shí)候的情況啰扛,那么假如項(xiàng)目已經(jīng)開發(fā)完了嚎京,需要部署上線了。我們應(yīng)該新創(chuàng)建一個(gè)單獨(dú)的config文件隐解,因?yàn)椴渴鹕暇€使用webpack的時(shí)候我們不需要一些dev-tools,dev-server和jshint校驗(yàn)等鞍帝。
復(fù)制我們現(xiàn)有的config文件,命名為 webpack.production.config.js煞茫,將里面關(guān)于 devServer等和開發(fā)有關(guān)的東西刪掉帕涌。
在package.json中添加一個(gè)命令。
"scripts": {
"start": "webpack-dev-server --hot --inline",
"build": "webpack --progress --profile --colors --config webpack.production.config.js"
},
當(dāng)要上線的時(shí)候,運(yùn)行
npm run build
可以發(fā)現(xiàn)build文件夾中生成了所有東西续徽。
分離app.js和第三方庫
現(xiàn)在我們build出來的只有一個(gè)bundle.js 如果第三方庫很多的話蚓曼,會(huì)造成這個(gè)文件非常大,減慢加載速度钦扭,現(xiàn)在我們要把第三方庫和我們app本身的代碼分成兩個(gè)文件纫版。
修改entry入口文件
entry: {
app: path.resolve(APP_PATH, 'index.js'),
//添加要打包在vendors里面的庫
vendors: ['jquery', 'moment']
},
添加CommonsChunkPlugin
plugins: [
//這個(gè)使用uglifyJs壓縮你的js代碼
new webpack.optimize.UglifyJsPlugin({minimize: true}),
//把入口文件里面的數(shù)組打包成verdors.js
new webpack.optimize.CommonsChunkPlugin('vendors', 'vendors.js'),
new HtmlwebpackPlugin({
title: 'Hello World app'
})
]
添加完畢 運(yùn)行npm run build
在build文件夾中發(fā)現(xiàn)如下結(jié)構(gòu)
- budle.js
- index.html
- vendors.js
生成多頁面
應(yīng)用不可能都是SPA,不可能只生成一個(gè)html文件客情,如果想生成多個(gè)html頁面這么玩其弊?其實(shí)也是很簡(jiǎn)單的: 現(xiàn)在的需求是這樣的,有兩個(gè)頁面膀斋,一個(gè)叫index.html 它需要引用vendors.js和app.js這兩個(gè)文件梭伐,還有一個(gè)mobile.html頁面他要引用vendors.js和mobile.js這兩個(gè)文件。
首先新建一個(gè)叫mobile.js的入口文件仰担,比app.js更簡(jiǎn)單一些
import './main.scss';
import $ from 'jquery';
import 'imports?jQuery=jquery!./plugin.js';
$(document).ready(function() {
let app = document.createElement('div');
app.innerHTML = '<h1>Hello World</h1>';
document.body.appendChild(app);
$('h1').greenify();
});
在config里面配置
entry: {
//三個(gè)入口文件糊识,app, mobile和 vendors
app: path.resolve(APP_PATH, 'index.js'),
mobile: path.resolve(APP_PATH, 'mobile.js'),
vendors: ['jquery', 'moment']
},
output: {
path: BUILD_PATH,
//注意 我們修改了bundle.js 用一個(gè)數(shù)組[name]來代替,他會(huì)根據(jù)entry的入口文件名稱生成多個(gè)js文件摔蓝,這里就是(app.js,mobile.js和vendors.js)
filename: '[name].js'
},
原來我們是沒有模版文件的技掏,原來利用的HtmlWebpackPlugin的默認(rèn)模版。誰想到這偉大的插件還可以自定義模版项鬼。 所以新建一個(gè)專門放模版的文件夾templates,在里面加兩個(gè)模版文件index.html 和 mobile.html
index.html
<!DOCTYPE html>
<html>
<head>
<title>{%= o.htmlWebpackPlugin.options.title %}</title>
</head>
<body>
<h3>Welcome to webpack</h3>
</body>
</html>
mobile.html
<!DOCTYPE html>
<html>
<head>
<title>{%= o.htmlWebpackPlugin.options.title %}</title>
</head>
<body>
<h3>Welcome to mobile page</h3>
</body>
</html>
繼續(xù)配置config.js,現(xiàn)在讓HtmlwebpackPlugin可以生成多個(gè)文件
...
//Template的文件夾路徑
var TEM_PATH = path.resolve(ROOT_PATH, 'templates');
...
plugins: [
...
//創(chuàng)建了兩個(gè)HtmlWebpackPlugin的實(shí)例哑梳,生成兩個(gè)頁面
new HtmlwebpackPlugin({
title: 'Hello World app',
template: path.resolve(TEM_PATH, 'index.html'),
filename: 'index.html',
//chunks這個(gè)參數(shù)告訴插件要引用entry里面的哪幾個(gè)入口
chunks: ['app', 'vendors'],
//要把script插入到標(biāo)簽里
inject: 'body'
}),
new HtmlwebpackPlugin({
title: 'Hello Mobile app',
template: path.resolve(TEM_PATH, 'mobile.html'),
filename: 'mobile.html',
chunks: ['mobile', 'vendors'],
inject: 'body'
})
...
]
然后運(yùn)行
npm run build
看看生成好的偉大的文件,沒問題绘盟!
- app.js
- mobile.js
- vendors.js
- index.html
- mobile.html
看看引用的對(duì)應(yīng)關(guān)系鸠真,完美C跸伞!
index.html
<body>
<h3>Welcome to webpack</h3>
<script src="vendors.js"></script><script src="app.js"></script>
</body>
mobile.html
<body>
<h3>Welcome to mobile page</h3>
<script src="vendors.js"></script><script src="mobile.js"></script>
</body>
生成Hash名稱的script來防止緩存
經(jīng)典問題,代碼更新了吠卷,但是瀏覽器有緩存锡垄,到時(shí)候就傻了。 怎么解決祭隔,換名字唄货岭。可以直接在后面加參數(shù),也可以直接換掉文件名字疾渴。 webpack提供給了我們非常簡(jiǎn)單的方法千贯,基于文件的md5,只要把
output: {
path: BUILD_PATH,
//只要再加上hash這個(gè)參數(shù)就可以了
filename: '[name].[hash].js'
},
運(yùn)行完build以后搞坝,看看生成的文件搔谴,很完美~
index.html
<body>
<h3>Welcome to webpack</h3>
<script src="vendors.js"></script><script src="app.b6641abee64c999d95c1.js"></script>
</body>
好了,你現(xiàn)在了解webpack作為一個(gè)module bundler的精髓了吧桩撮,把我們的例子做成一個(gè)圖敦第,幫助你理解一下。
文件壓縮
//使用插件html-webpack-plugin打包合并html
//使用插件extract-text-webpack-plugin打包獨(dú)立的css
//使用UglifyJsPlugin壓縮代碼
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var webpack = require("webpack");
module.exports = {
entry: {
bundle : './src/js/main.js'
},
output: {
filename: "[name]-[hash].js",
path: __dirname + '/dist'
},
module: {
rules: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
resolve:{
extensions:['.js','.css','.json'] //用于配置程序可以自行補(bǔ)全哪些文件后綴
},
plugins:[
new HtmlWebpackPlugin({
title: 'hello webpack',
template:'src/component/index.html',
inject:'body',
minify:{ //壓縮HTML文件
removeComments:true, //移除HTML中的注釋
collapseWhitespace:true //刪除空白符與換行符
}
}),
new ExtractTextPlugin("[name].[hash].css"),
new webpack.optimize.UglifyJsPlugin({
compress: { //壓縮代碼
dead_code: true, //移除沒被引用的代碼
},
except: ['$super', '$', 'exports', 'require'] //混淆,并排除關(guān)鍵字
})
]
};