1、webpack和webpack-dev-server區(qū)別
webpack 每次會(huì)生成一個(gè)bundle.js文件,webpack-dev-server不會(huì),只是將打包結(jié)果放在內(nèi)存中,并不會(huì)寫入實(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è)類似<link rel="stylesheet" href="path/to/file.css">這樣的內(nèi)聯(lián)css。
5、postcss-loader與Autoprefixer一起,用來(lái)適配各大瀏覽器廠商css前綴
- 需要配置
postcss.config.js,和安裝autoprefixer
6、resolve配置
-
resolve.alias設(shè)置別名來(lái)替換某個(gè)路徑,如:
resolve:{
alias:{
@: './src/components/'
}
}
當(dāng)需要引入import './src/components/header'時(shí),可以寫成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-pluginv3.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
- 主要用于快速開發(fā)應(yīng)用,提高開發(fā)效率
- 通過(guò)設(shè)置
package.json中的stripts,"watch": "webpack --watch",可以實(shí)現(xiàn)修改頁(yè)面代碼后自動(dòng)打包,但是沒法開啟一個(gè)服務(wù),這就不能滿足ajax(ajax必須在一個(gè)http服務(wù)里才能使用)調(diào)用服務(wù)等開發(fā)需求了,此時(shí)需要webpack-dev-server了 -
webpack-dev-server打包出來(lái)的文件不會(huì)放到原先的dist或者配置好的output路徑,而是放到了本地電腦內(nèi)存中,這樣提升打包速度 - 配置
contentBase,告訴服務(wù)器從哪個(gè)目錄中提供內(nèi)容,填寫output的path就可以了 - 配置
open,設(shè)為true時(shí)devserver啟動(dòng)后自動(dòng)打開瀏覽器 - 配置
port,可以修改開啟服務(wù)的端口號(hào) - 配置
proxy,如果現(xiàn)在在http://localhost:3000上有服務(wù)端的話,可以設(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寫一個(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è)小問題,就是即便一個(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í)行中,詳見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代碼文件開頭引入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ù)的話用到。
引入babel-polyfill全量包后文件會(huì)變得非常大。
- ③ 以上方式需要在對(duì)應(yīng)入口js文件開頭引入polyfill
import "@babel/polyfill";
這種方式會(huì)產(chǎn)生一些全局變量,代碼量大了之后如寫一個(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)文件開頭的引入 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)目中沒有被引用的代碼(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和optimization2個(gè)配置:
// webpack.config.js
mode: 'development',
optimization: {
usedExports: true,
},
然后打包,打開打包好的文件,可以看到如下部分:
/***/ "./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)了并告知了,但并沒有真的去刪除這部分沒用到的代碼,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沒被直接應(yīng)用,但還是會(huì)在打包時(shí),將它打包進(jìn)來(lái)。
- Tree Shaking的注意事項(xiàng)(來(lái)至官網(wǎng)):
- 使用
ES2015模塊語(yǔ)法(即 import 和 export)。 - 確保沒有 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 FlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPluginOccurrenceOrderPluginSideEffectsFlagPluginUglifyJsPlugin
- 會(huì)將