30分鐘快速過(guò)一遍Webpack4核心知識(shí)

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-loaderfile-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-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ò)誤行代碼。
  • devtoolmode=development中一般配置,devtool:cheap-module-eval-source-map,這樣既可以定位錯(cuò)誤正確的位置,同時(shí)打包速度也不會(huì)太受影響。
  • devtoolmode=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 LoaderVue 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文件開頭引入polyfillimport "@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文件,添加如下modeoptimization2個(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)出了foobar兩個(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(混淆破壞),foobar方法已經(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
    • 啟用 NamedChunksPluginNamedModulesPlugin。
  • 設(shè)置mode: 'production'
    • 會(huì)將 process.env.NODE_ENV 的值設(shè)為 production
    • 啟用 FlagDependencyUsagePlugin
    • FlagIncludedChunksPlugin
    • ModuleConcatenationPlugin
    • NoEmitOnErrorsPlugin
    • OccurrenceOrderPlugin
    • SideEffectsFlagPlugin
    • UglifyJsPlugin
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 如有好文, 請(qǐng)到此issue里提交文章,或者直接發(fā)pull request. ??webpack入門 ??webpac...
    Creoa閱讀 2,265評(píng)論 0 30
  • webpack 優(yōu)秀中文文章 轉(zhuǎn)載 如有好文, 請(qǐng)到此issue里提交文章,或者直接發(fā)pull request. ...
    果汁密碼閱讀 1,064評(píng)論 0 5
  • 目錄第1章 webpack簡(jiǎn)介 11.1 webpack是什么? 11.2 官網(wǎng)地址 21.3 為什么使用 web...
    lemonzoey閱讀 1,831評(píng)論 0 1
  • 搜羅一切webpack的好文章好工具 Webpack webpack 優(yōu)秀中文文章如有好文, 請(qǐng)到此issue里提...
    Lefter閱讀 1,534評(píng)論 0 29
  • 有人動(dòng)不動(dòng)就拿老祖宗的話說(shuō)事,今天就遇到了一位。 其實(shí)老祖宗經(jīng)常是黑白不分的,有人偏偏學(xué)會(huì)了這套把戲,我倒是覺得老...
    高手如林閱讀 636評(píng)論 0 3

友情鏈接更多精彩內(nèi)容