1规个、webpack和webpack-dev-server區(qū)別
webpack 每次會(huì)生成一個(gè)bundle.js文件岭皂,webpack-dev-server不會(huì)存捺,只是將打包結(jié)果放在內(nèi)存中贼邓,并不會(huì)寫(xiě)入實(shí)際的bundle.js,在每次webpack-dev-server接收到請(qǐng)求時(shí)热鞍,都將內(nèi)存中的打包結(jié)果返回給瀏覽器葫慎。
2、webpack-cli安裝后可以直接在控制臺(tái)調(diào)用webpack
命令
3薇宠、url-loader 和 file-loader
url-loader
和file-loader
都可以用來(lái)作為打包圖片的loader
-
url-loader
不會(huì)生成一個(gè)具體的圖片文件偷办,而是直接在需要這個(gè)圖片src地址的地方給出圖片的base64地址,這樣比較適合幾k大小的小圖澄港,減少http請(qǐng)求椒涯;url-loader
有個(gè)limit設(shè)置一個(gè)numer,單位是bytes回梧,如果圖片大于這個(gè)limit值废岂,則默認(rèn)使用file-loader
, 如果小于則使用url-loader
-
file-loader
會(huì)生成一個(gè)圖片文件,適合大點(diǎn)的圖片
4狱意、style-loader
作用主要是將css放到dom中
官方英文解釋很到位:Adds CSS to the DOM by injecting a <style> tag
如果配置style-loader/url
湖苞,則會(huì)生成一個(gè)類(lèi)似<link rel="stylesheet" href="path/to/file.css">
這樣的內(nèi)聯(lián)css。
5详囤、postcss-loader與Autoprefixer一起财骨,用來(lái)適配各大瀏覽器廠(chǎng)商css前綴
- 需要配置
postcss.config.js
,和安裝autoprefixer
6藏姐、resolve配置
-
resolve.alias
設(shè)置別名來(lái)替換某個(gè)路徑隆箩,如:
resolve:{
alias:{
@: './src/components/'
}
}
當(dāng)需要引入import './src/components/header'
時(shí),可以寫(xiě)成import '@/header'
-
resolve.extensions
設(shè)置引入文件的擴(kuò)展格式羔杨,當(dāng)引入文件省略了后綴名時(shí)候捌臊,會(huì)按照設(shè)置的resolve.extensions
去相應(yīng)路徑匹配對(duì)應(yīng)格式的文件,默認(rèn)是['js', 'json']问畅,如果是react項(xiàng)目可以設(shè)置:extensions: ['.jsx', '.js', '.json']
7娃属、模塊樣化處理
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: true,
},
},
如上在配置css-loader
時(shí)候,配置modules: true
但一般出路antd
的樣式時(shí)候护姆,需要做兩手處理:
{
test: /\.less$/,
include: /node_modules\/antd/,
use: [
'style-loader',
{ loader: 'css-loader', options: {modules: false} },
'less-loader'
]
},
{
test: /\.less$/,
exclude: /node_modules\/antd/,
use: [
'style-loader',
{ loader: 'css-loader', options: {modules: true} },
'less-loader'
]
}
這樣避免了 css-modules 對(duì) antd 的樣式進(jìn)行處理矾端,否則會(huì)造成antd 的樣式的不匹配。
8卵皂、iconfont字體打包
{
test: /\.(eot|ttf|svg|woff)$/,
use: {
loader: 'file-loader',
},
}
如上示例秩铆,打包.eot, .ttf等字體文件
9、html-webpack-plugin
- 會(huì)在打包完成后灯变,自動(dòng)生成一個(gè)html文件殴玛,并把打包生成的js自動(dòng)引入到這個(gè)html中
- 如果希望打包出來(lái)的html是按照要求配置的,如加上
<div id="root"></div>
添祸,那么就可以在HtmlWebpackPlugin
配置中加入template
指定一個(gè)模板文件
10滚粟、clean-webpack-plugin
- 清除打包數(shù)據(jù)
-
clean-webpack-plugin
v3.0以上版本,不需要添加額外配置項(xiàng)刃泌,默認(rèn)清除的文件是output.path
指定的路徑文件夾內(nèi)容
11凡壤、output.publicPath
- 在
output
中配置publicPath
,如一個(gè)路徑或者一個(gè)cdn地址耙替,然后打包出來(lái)的資源會(huì)自動(dòng)加上這個(gè)publicPath前綴亚侠,如加上一個(gè)cdn的host后,打包出來(lái)的script的src會(huì)在文件名前加上這個(gè)cdn地址俗扇。
12硝烂、source-map
-
souce-map
是源代碼和打包后的代碼的一個(gè)映射關(guān)系,對(duì)應(yīng)的webpack配置是devtool
铜幽,可以快速定位錯(cuò)誤行代碼滞谢。 -
devtool
在mode=development
中一般配置,devtool:cheap-module-eval-source-map
除抛,這樣既可以定位錯(cuò)誤正確的位置爹凹,同時(shí)打包速度也不會(huì)太受影響。 -
devtool
在mode=production
中一般配置镶殷,devtool:cheap-module-source-map
禾酱。 -
devtool
設(shè)置了source-map
會(huì)生成一個(gè).map
映射文件; - 設(shè)置了帶
inline
绘趋,則會(huì)將映射文件內(nèi)容放到打包文件里颤陶,不會(huì)單獨(dú)生成.map
映射文件; - 設(shè)置了帶
cheap
的配置只會(huì)提示行不提示列錯(cuò)誤陷遮,同時(shí)只提示業(yè)務(wù)代碼滓走,不管loader的打包代碼; - 設(shè)置了帶
module
的是除了核心業(yè)務(wù)代碼帽馋,loader打包文件代碼也會(huì)提示錯(cuò)誤位置 - 設(shè)置了帶
eval
的會(huì)提高打包速度搅方。
13比吭、devServer
- 主要用于快速開(kāi)發(fā)應(yīng)用,提高開(kāi)發(fā)效率
- 通過(guò)設(shè)置
package.json
中的stripts姨涡,"watch": "webpack --watch"
衩藤,可以實(shí)現(xiàn)修改頁(yè)面代碼后自動(dòng)打包,但是沒(méi)法開(kāi)啟一個(gè)服務(wù)涛漂,這就不能滿(mǎn)足ajax(ajax必須在一個(gè)http服務(wù)里才能使用)調(diào)用服務(wù)等開(kāi)發(fā)需求了赏表,此時(shí)需要webpack-dev-server
了 -
webpack-dev-server
打包出來(lái)的文件不會(huì)放到原先的dist或者配置好的output路徑,而是放到了本地電腦內(nèi)存中匈仗,這樣提升打包速度 - 配置
contentBase
瓢剿,告訴服務(wù)器從哪個(gè)目錄中提供內(nèi)容,填寫(xiě)output的path就可以了 - 配置
open
悠轩,設(shè)為true時(shí)devserver啟動(dòng)后自動(dòng)打開(kāi)瀏覽器 - 配置
port
间狂,可以修改開(kāi)啟服務(wù)的端口號(hào) - 配置
proxy
,如果現(xiàn)在在http://localhost:3000
上有服務(wù)端的話(huà)火架,可以設(shè)置proxy: {'/api': 'http://localhost:3000'}
前标,這樣在本地的非3000端口host上請(qǐng)求/api/info
接口,實(shí)際是請(qǐng)求了http://localhost:3000/api/info
距潘,否則會(huì)報(bào)跨域錯(cuò)誤 - 如果不用
webpack-dev-server
炼列,可以通過(guò)webpack-dev-middleware
和express/koa2寫(xiě)一個(gè)server.js的服務(wù),然后啟動(dòng)這個(gè)服務(wù)音比,可以達(dá)到和webpack-dev-server
一樣的修改后自動(dòng)更新等效果
14俭尖、hot-module-replacement
- 當(dāng)添加了
webpack-dev-server
之后,那么每次有代碼修改時(shí)洞翩,就會(huì)重新請(qǐng)求頁(yè)面稽犁,然后刷新頁(yè)面,但這有個(gè)小問(wèn)題骚亿,就是即便一個(gè)css顏色值修改了已亥,頁(yè)面也會(huì)重新刷新,加入hot-module-replacement
可以簡(jiǎn)化這個(gè)請(qǐng)求過(guò)程来屠。 - 首先在
devServer
中加入hot:true
虑椎,然后在plugins
中加入new webpack.HotModuleReplacementPlugin()
配置,這樣僅僅只能做到css樣式的無(wú)刷新修改 - 如果需要js也能無(wú)刷新修改俱笛,則需要在js中加入
module.hot
的判斷捆姜,判斷的對(duì)應(yīng)結(jié)果中需要更新代碼,使用module.hot.accept
將其綁定到新的函數(shù)執(zhí)行中迎膜,詳見(jiàn)https://webpack.docschina.org/guides/hot-module-replacement/#%E5%90%AF%E7%94%A8-hmr - 具體針對(duì)前端不同框架泥技,社區(qū)有不同loader可以支持HMR,React Hot Loader磕仅,Vue loader等
15珊豹、配置Babel
- Babel主要是將es6+代碼轉(zhuǎn)換為es5代碼簸呈,讓低版本瀏覽器也能加載代碼
- ① 最基本的設(shè)置是:
npm install --save-dev babel-loader @babel/core
webpack 設(shè)置:
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader"
}
]
}
.babelrc
文件設(shè)置如下:
npm install @babel/preset-env --save-dev
{
"presets": ["@babel/preset-env"]
}
但面對(duì)更低版本的瀏覽器的時(shí)候,像promise還需要轉(zhuǎn)化注入店茶,就需要引入babel/polyfill
- ②
npm install --save @babel/polyfill
在對(duì)應(yīng)業(yè)務(wù)js代碼文件開(kāi)頭引入polyfill import "@babel/polyfill";
但是這樣有個(gè)缺點(diǎn)蜕便,就是會(huì)把所有es6轉(zhuǎn)es5的需要的語(yǔ)法都給打包到對(duì)應(yīng)文件,造成打包文件過(guò)大忽妒。
如果需要按需去打包polyfill語(yǔ)法,根據(jù)代碼需要兼贸,可以設(shè)置文件 .babelrc
:
{
"presets": [["@babel/preset-env", {
"targets": {
chrome: "67"
},
"useBuiltIns": "usage",
}]],
}
上面配置中的 targets
中配置的瀏覽器版本段直,是指大于該版本的瀏覽器,根據(jù)該瀏覽器對(duì)es6的支持情況去有針對(duì)性的打包polyfill代碼溶诞,這樣可以讓打包文件變得更小一點(diǎn)鸯檬,比如如果chrome67以上的版本瀏覽器對(duì)promise支持很好,那么就不需要打包promise的語(yǔ)法了螺垢,更不需要對(duì)promise去轉(zhuǎn)碼喧务。
總的來(lái)說(shuō),polyfill修改了全局作用域枉圃,瀏覽器下是window功茴,node下是global。
babel-polyfill主要由兩部分組成孽亲,core-js和regenerator runtime坎穿。
core-js
:提供了如ES5、ES6返劲、ES7等規(guī)范中 中新定義的各種對(duì)象玲昧、方法的模擬實(shí)現(xiàn)。
regenerator
:提供generator支持篮绿,如果應(yīng)用代碼中用到generator孵延、async函數(shù)的話(huà)用到。
引入babel-polyfill全量包后文件會(huì)變得非常大亲配。
- ③ 以上方式需要在對(duì)應(yīng)入口js文件開(kāi)頭引入polyfill
import "@babel/polyfill";
這種方式會(huì)產(chǎn)生一些全局變量尘应,代碼量大了之后如寫(xiě)一個(gè)大型庫(kù)或者ui組件庫(kù)等全局變量會(huì)產(chǎn)生變量污染全局。這樣就需要用到transform-runtime
吼虎,它不會(huì)污染全局環(huán)境:
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime @babel/runtime-corejs2
刪除對(duì)應(yīng)文件開(kāi)頭的引入 import "@babel/polyfill";
.babelrc
文件設(shè)置如下:
{
"plugins": [["@babel/plugin-transform-runtime",
{
"absoluteRuntime": false,
"corejs": 2,
"helpers": true,
"regenerator": true,
"useESModules": false,
}]],
}
@babel/plugin-transform-runtime
會(huì)以閉包的形式
16菩收、Tree Shaking
- Tree Shaking 用來(lái)檢測(cè)項(xiàng)目中沒(méi)有被引用的代碼(dead-code),Webpack會(huì)對(duì)這部分代碼進(jìn)行標(biāo)記鲸睛,然后在資源壓縮打包的時(shí)候娜饵,從打包出來(lái)的文件中去掉友绝,如下示例:
// outer.js
export const foo = () => {
console.log('Fucked Up');
};
export const bar = () => {
console.log('Beyond All Repair');
};
// index.js
import { foo } from './outer';
foo();
然后配置webpack.config.js
文件橄唬,添加如下mode
和optimization
2個(gè)配置:
// webpack.config.js
mode: 'development',
optimization: {
usedExports: true,
},
然后打包,打開(kāi)打包好的文件,可以看到如下部分:
/***/ "./src/outer.js":
/*!**********************!*\
!*** ./src/outer.js ***!
\**********************/
/*! exports provided: foo, bar */
/*! exports used: foo */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return foo; });\n/* unused harmony export bar */\nvar foo = function foo() {\n console.log('Fucked Up');\n};\nvar bar = function bar() {\n console.log('Beyond All Repair');\n};//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9zcmMvb3V0ZXIuanMuanMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9zcmMvb3V0ZXIuanM/NGJlZiJdLCJzb3VyY2VzQ29udGVudCI6WyJleHBvcnQgY29uc3QgZm9vID0gKCkgPT4ge1xuICBjb25zb2xlLmxvZygnRnVja2VkIFVwJyk7XG59O1xuXG5leHBvcnQgY29uc3QgYmFyID0gKCkgPT4ge1xuICBjb25zb2xlLmxvZygnQmV5b25kIEFsbCBSZXBhaXInKTtcbn07XG4iXSwibWFwcGluZ3MiOiJBQUFBO0FBQUE7QUFBQTtBQUNBO0FBQ0E7QUFFQTtBQUNBO0FBQ0EiLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./src/outer.js\n");
/***/ })
其中有2行注釋說(shuō)明了:
/*! exports provided: foo, bar */
/*! exports used: foo */
就是打包文件中還是導(dǎo)出了foo
和bar
兩個(gè)方法铐然,但只用到了foo
,這說(shuō)明在development
中代碼的tree shaking
只是找出來(lái)了并告知了羽峰,但并沒(méi)有真的去刪除這部分沒(méi)用到的代碼踊赠,webpack4新增了mode
,將其設(shè)置為production
后电湘,不用設(shè)置optimization
隔节,就會(huì)真實(shí)執(zhí)行tree shaking
:
// webpack.config.js
mode: 'production',
因?yàn)樵O(shè)置了mode: 'production'
后代碼被作了minify(壓縮)
和 mangle(混淆破壞)
,foo
和bar
方法已經(jīng)搜不到了寂呛,但是方法體中的console內(nèi)容還是可以搜的怎诫,可以發(fā)現(xiàn),foo
中的console內(nèi)容Fucked Up
還可以搜到贷痪,而bar
中的console內(nèi)容Beyond All Repair
已經(jīng)搜不到了幻妓,因?yàn)橐呀?jīng)被刪除了。
webpack4新增了一個(gè)例外處理的口子劫拢,就是在package.json
中配置一個(gè)sideEffects
屬性肉津,來(lái)設(shè)置哪些文件是永遠(yuǎn)都不會(huì)被刪除掉的,如果設(shè)置了sideEffects: false
舱沧,那么則會(huì)正常的刪除未被用到的代碼妹沙。如果設(shè)置了sideEffects: ["@babel/polly-fill"]
則表明,即便@babel/polly-fill
沒(méi)被直接應(yīng)用熟吏,但還是會(huì)在打包時(shí)初烘,將它打包進(jìn)來(lái)。
- Tree Shaking的注意事項(xiàng)(來(lái)至官網(wǎng)):
- 使用
ES2015
模塊語(yǔ)法(即 import 和 export)分俯。 - 確保沒(méi)有 compiler 將 ES2015 模塊語(yǔ)法轉(zhuǎn)換為
CommonJS
模塊(這也是流行的Babel preset
中 @babel/preset-env 的默認(rèn)行為)肾筐。 - 在項(xiàng)目
package.json
文件中,添加一個(gè)"sideEffects"
屬性缸剪。 - 通過(guò)將
mode
選項(xiàng)設(shè)置為production
吗铐,啟用minification
(代碼壓縮) 和tree shaking
。
- 使用
17杏节、Mode: development/production
wenpack4新增了mode
配置:
- 設(shè)置
mode: 'development'
- 會(huì)將
process.env.NODE_ENV
的值設(shè)為development
- 啟用
NamedChunksPlugin
和NamedModulesPlugin
唬渗。
- 會(huì)將
- 設(shè)置
mode: 'production'
- 會(huì)將
process.env.NODE_ENV
的值設(shè)為production
- 啟用
FlagDependencyUsagePlugin
FlagIncludedChunksPlugin
ModuleConcatenationPlugin
NoEmitOnErrorsPlugin
OccurrenceOrderPlugin
SideEffectsFlagPlugin
UglifyJsPlugin
- 會(huì)將