webpack打包

ESM存在環(huán)境兼容問題
模塊文件過多
網(wǎng)絡(luò)請求頻繁
所有的前端資源都需要模塊化

綜上所述熙暴,模塊化是必要的


散落的模塊文件打包到一起掂器,資源統(tǒng)合到一起

  • 新特性代碼編譯
  • 模塊化JavaScript打包
  • 支持不同類型的資源模塊

模塊打包工具

Webpack

  • 模塊打包器(Module bundler)解決模塊化JavaScript代碼打包的問題,可以將零散的模塊代碼統(tǒng)合到一個JS文件當(dāng)中
  • 模塊加載器(Lodar)將環(huán)境兼容問題的代碼進(jìn)行編譯轉(zhuǎn)換
  • 代碼拆分(Code Splitting)將應(yīng)用中所有的代碼按照需求打包乃摹,不用擔(dān)心代碼打包到一起峡懈,比如應(yīng)用加載過程中初次運行所必要的代碼打包到一塊肪康,在運行過程中,實現(xiàn)增量加載雾狈,不用擔(dān)心文件太大
  • 資源模塊(Asset Module)支持在JavaScript中以模塊化的方式去載入任意類型的資源文件善榛,比如在webpack當(dāng)中移盆,通過JavaScript import一個CSS文件咒循,最終通過style標(biāo)簽的形式工作叙甸,其他文件類似如此
    打包工具解決的是整個前端的模塊化熔萧,并非單指JavaScript

webpack初體驗

  • 步驟1:
    初始化項目
yarn init --yes
  • 步驟2:
    添加webpack依賴作為開發(fā)依賴
yarn add webpack webpack-cli --dev
  • 步驟3:
    檢驗webpack版本號
yarn webpack --version
  • 步驟4:
    使用webpack打包
yarn webpack
打包成功終端顯示信息

webpack會將文件打包為運行文件夾dist哪痰,并且將js代碼壓縮為main.js


  • 如果覺得每次都用指令

yarn webpack

很麻煩的話,可以在package.json里用script注冊build指令替換掉



再次進(jìn)行打包就是

yarn build

webpack 配置文件

webpack 4以后的版本支持0配置的方式直接啟動打包肋演,整個打包過程會按照約定爹殊,將src/index.js作為入口,存入dist/main.js中

  • 自定義打包配置
    項目根目錄創(chuàng)建webpack.config.js的文件反症。這個文件是運行在node環(huán)境中的JS文件铅碍,需要按照commonJS的方法編寫代碼
const path = require('path')

module.exports = {
  // 指定webpack打包入口文件的路徑  ./是不能省略的
  entry: './src/main.js',
  // 設(shè)置輸出文件的位置胞谈,要求是對象,通過對象的filename配紫,指定輸出名稱睹晒,
  output: {
    filename: 'bundle.js',
    // 指定輸出文件所在的目錄伪很,path必須要是絕對路徑锉试,載入path模塊呆盖,獲得路徑
    path: path.join(__dirname, 'output')
  }
}

webpack工作模式

不同環(huán)境的幾組預(yù)設(shè)配置
默認(rèn)的工作模式的production
修改工作模式的指令就是在運行webpack打包時的指令加上mode应又,例如

yarn webpack --mode 工作模式

工作模式分為三種:

  • production 生產(chǎn)模式,webpack會自動優(yōu)化打包結(jié)果洞就,這也是默認(rèn)的工作模式
  • development 開發(fā)模式旬蟋,webpack會自動優(yōu)化打包的速度倾贰,添加一些調(diào)試過程中的輔助
  • None模式,webpack就是運行最原始的打包架忌,不作任何的額外處理

差異可以在官方文檔找到:

https://webpack.js.org/configuration/mode/

也可以在配置文件里設(shè)置工作模式

  • 在webpack.config.js文件里聲明mode屬性的屬性值饰恕,就無需配置指令的參數(shù)了


webpack打包結(jié)果運行原理

小知識:VScode快捷折疊代碼的快捷鍵是ctrl+k+ctrl+0
將所有的模塊放入一個文件埋嵌,并且構(gòu)造成為一個立即執(zhí)行函數(shù)范舀,可以通過打斷點的方式進(jìn)行一步步調(diào)試锭环,將各個模塊通過互相調(diào)用聯(lián)系起來

webpack 資源模塊加載

通過webpack引入前端項目中的任意文件

  • webpack內(nèi)部默認(rèn)只處理JavaScript文件
  • 要想讓webpack處理其他類型的文件例如css等等就需要新的loader
  • CSS需要的新loader有:
    • css-loader
    • style-loader
yarn add style-loader --dev
yarm add css-style --dev

另外安裝了loader之后還需要在webpack.config.js文件里進(jìn)行設(shè)置


設(shè)置module下的rules
test:表示的是匹配打包過程中的文件路徑
use:匹配到的文件需要使用的loader,多個loader的話執(zhí)行順序是從后往前執(zhí)行
Loader是webpack的核心特性
通過不同的Loader可以實現(xiàn)加載任何類型的資源

webpack 導(dǎo)入資源模塊

打包入口=>運行入口
JavaScript驅(qū)動整個前端應(yīng)用的業(yè)務(wù)

JS代碼通過import引入CSS文件才是正確的做法

例如:
在js引入css文件要使用import

因為是單獨的類名玫锋,所以還需要使用element.classList.add來添加標(biāo)簽的類名實現(xiàn)選擇器

  • 邏輯合理,JS確實需要資源文件
  • 保證上線資源不缺失悦屏,都是必要的

webpack 文件資源加載器

導(dǎo)入一個png資源


同理散劫,也是需要import導(dǎo)入的获搏,這里需要接收資源模塊的默認(rèn)導(dǎo)出常熙,也就是資源路徑,使用路徑設(shè)置為src

這個時候同樣是需要新的Loader墓贿,因為導(dǎo)入了webpack默認(rèn)不能識別的資源類型

yarn add file-loader --dev

同樣聋袋,需要在webpack配置文件設(shè)置


rules下的多個數(shù)組

webpack會默認(rèn)的認(rèn)為打包的內(nèi)容會放在網(wǎng)站的根目錄下面幽勒,可能會造成路徑問題
更改問題:
通過配置文件告知webpack

    publicPath: 'dist/'

publicPath是默認(rèn)空字符串的啥容,所以要記得修改

運行原理

webpack Data URLs 與 url-loader

  • 特殊的URL協(xié)議咪惠,當(dāng)前的url就可以直接表示文件內(nèi)容的方式



    例子

    圖片或者是字體這一類無法通過文本表示的二進(jìn)制文件姨拥,就可以通過base64編碼結(jié)果為字符串來標(biāo)示內(nèi)容

yarn add url-loader --dev

然后將rules下的圖片類改成url-loader

          loader: 'url-loader',

url-load 適合小文件的使用,小文件使用Data URLs徽缚,可以減少請求次數(shù)凿试。大文件單獨提取存放那婉,使用file-loader,提高加載速度

  • use作為類寞奸,loader指定url-loader隐岛,options的limit則是指定范圍大小內(nèi)的文件進(jìn)行url處理聚凹,之外的進(jìn)行file-loader處理妒牙,前提是必須要添加file-loader的依賴
use: {
          loader: 'url-loader',
          // 添加配置選項
          options: {
            // 只將10KB以下的文件進(jìn)行url-loader的處理单旁,以上的依然使用file-loader
            limit: 10 * 1024 // 10 KB
          }
        }

webpack 常用加載器分類

  • 編譯轉(zhuǎn)換類
    加載到的資源模塊轉(zhuǎn)換為JavaScript代碼蔫饰,比如css-loader
  • 文件操作類
    加載到的資源模塊拷貝到輸出目錄篓吁,導(dǎo)出訪問路徑杖剪,比如file-loader
  • 代碼檢查類
    統(tǒng)一代碼風(fēng)格盛嘿,提高代碼質(zhì)量次兆,比如eslint-loader


webpack 處理ES2015

因為模塊打包需要,所以處理import园蝠,export彪薛,并不能處理ES6的其他特性
如果需要webpack打包過程中同時處理其他的ES6特性的轉(zhuǎn)換陪汽,需要為JS文件配置一個額外的編譯器loader挚冤。比如babel-loader

yarn add babel-loader @babel/core @babel/preset-env --dev

修改webpack.config.js文件

{
        test: /.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      },
  • webpack只是打包工具
  • 加載器可以用來轉(zhuǎn)換編譯代碼

webpack 模塊加載方式

  • 遵循ESM 標(biāo)準(zhǔn)的import聲明
  • 遵循CommonJS標(biāo)準(zhǔn)的require函數(shù)
  • 遵循AMD標(biāo)準(zhǔn)的define函數(shù)和require函數(shù)
    不要混合使用,不方便統(tǒng)一標(biāo)準(zhǔn)的實施
  • Loader加載的非JavaScript也會觸發(fā)資源加載
    • 樣式代碼中的@import屬性和url函數(shù)


    • HTML代碼中圖片標(biāo)簽的src屬性


      要使用html還得添加html-loader


      html-loader只會處理img標(biāo)簽的src屬性,如果其他屬性也想要觸發(fā)打包的話肤京,添加attrs屬性的規(guī)則就行了

webpack核心工作原理

loader機(jī)制是webpack的核心
先找到一個.js文件作為入口忘分,就猶如樹狀一樣妒峦,每個支點找到對應(yīng)的資源文件肯骇,最后整合到一起寫入bundle.js文件


webpack Loader的工作原理

loader就是負(fù)責(zé)資源文件從輸入到輸出的轉(zhuǎn)換
對于同一個資源可以依次使用多個loader
比如:
css-loader->style-loader

webpack 插件機(jī)制

增強webpack自動化能力
Loader專注實現(xiàn)資源模塊加載
Plugin解決其他自動化工作
比如:清除dist目錄,拷貝靜態(tài)文件到輸出目錄漾脂,壓縮輸出代碼

webpack 自動清除輸出目錄插件

yarn add clean-webpack-plugin --dev

使用

const { CleanWebpackPlugin } = require('clean-webpack-plugin')

  plugins: [
    new CleanWebpackPlugin()
  ]

webpack 自動生成HTML插件

通過webpack輸出HTML文件
插件:html-webpack-plugin
不需要解構(gòu):

const HtmlWebpackPlugin = require('html-webpack-plugin')

與上述自動清除目錄插件的導(dǎo)入與使用基本是一致的
生成模板符相,以供webpack生成html參照結(jié)構(gòu)


titie表示標(biāo)題,meta內(nèi)部可以設(shè)置viewport等等傲须,template就是指定的模板文件

模板文件內(nèi)部也可以通過調(diào)用內(nèi)容來寫入

同時輸出多個頁面文件



以后如果要添加多個HTML文件就寫多個實例對象就可以了

webpack常用插件使用總結(jié)&copy-webpack-plugin

以下這個插件最好不要在開發(fā)階段使用,一般都是留在上線前的那一次打包中使用

  • copy-webpack-plugin的作用就是將指定文件夾下面的文件拷貝到輸出目錄
    用法與導(dǎo)入導(dǎo)出都與上述一致已卸,不需要贅述
    之后在 官方說明多看看特別用法累澡,社區(qū)還提供了更多的插件
    需求->關(guān)鍵詞->搜索

webpack 開發(fā)一個插件

相比于loader愧哟,plugin擁有更寬的能力范圍
plugin通過鉤子機(jī)制實現(xiàn)

class MyPlugin {
  apply (compiler) {
    console.log('MyPlugin 啟動')

    compiler.hooks.emit.tap('MyPlugin', compilation => {
      // compilation => 可以理解為此次打包的上下文
      for (const name in compilation.assets) {
        // console.log(name)
        // console.log(compilation.assets[name].source())
        if (name.endsWith('.js')) {
          const contents = compilation.assets[name].source()
          const withoutComments = contents.replace(/\/\*\*+\*\//g, '')
          compilation.assets[name] = {
            source: () => withoutComments,
            size: () => withoutComments.length
          }
        }
      }
    })
  }
}

插件通過在生命周期的鉤子中掛載函數(shù)實現(xiàn)拓展

webpack 開發(fā)體驗的設(shè)想

過于原始的方式

理想的開發(fā)環(huán)境

  • 以HTTP server 運行
  • 自動編譯+自動刷新
  • 提供Source Map支持

實現(xiàn)自動編譯

監(jiān)聽文件變化,自動重新打包
啟動命令后面加個watch參數(shù)肥矢,啟動監(jiān)聽模式

yarn webpack --watch

自動刷新瀏覽器

browserSync工具甘改,以前有過介紹

browser-sync dist --files "**/*"

弊端:
操作麻煩楼誓,要開兩個終端主守,效率上降低了

webpack Dev Server

集成了自動編譯和自動刷新瀏覽器等功能

yarn add webpack-dev-server --dev

運行

yarn webpack-dev-server

打包結(jié)果不會存放在磁盤上参淫,而是存放在內(nèi)存當(dāng)中涎才,所以不會有dist文件夾耍铜,可以減少磁盤讀寫操作棕兼,大大提高效率
自動喚醒瀏覽器

yarn webpack-dev-server --open

webpack Dev Server靜態(tài)資源訪問

Dev Server默認(rèn)只會serve打包輸出文件
只要是webpack輸出的文件伴挚,都可被直接訪問到
靜態(tài)資源文件也需要serve

devServer: {
    // 指定額外的靜態(tài)資源路徑,可以為字符串或者數(shù)組蜈出,也就是一個或者多個
    contentBase: './public',
  }

webpack Dev Server 代理API

回到開發(fā)環(huán)境會造成跨域請求問題

并不是任何情況下API都應(yīng)該支持CORS同源策略
如果是同源部署皱蹦,根本沒必要開啟CORS
出現(xiàn)問題:開發(fā)階段接口跨域問題
解決問題:配置代理沪哺,把接口服務(wù)代理到本地的開發(fā)地址

webpack Dev Server支持配置代理
目標(biāo):將Github的API代理到本地開發(fā)服務(wù)器
在devServer當(dāng)中添加一個proxy屬性辜妓,這個屬性就是添加代理服務(wù)配置的

 devServer: {
    proxy: {
      // 請求路徑前綴
      '/api': {
        // http://localhost:8080/api/users -> https://api.github.com/api/users
        // 代理目標(biāo)
        target: 'https://api.github.com',
        // http://localhost:8080/api/users -> https://api.github.com/users
        // 實現(xiàn)代理路徑的重寫
        pathRewrite: {
          // 替換為空,^為開頭
          '^/api': ''
        },
        // 不能使用 localhost:8080 作為請求 GitHub 的主機(jī)名
        // 默認(rèn)使用的就是用戶的localhost:8080
        // changeOrigin:true就會以實際代理的主機(jī)名去請求酪夷,就是api.github.com
        changeOrigin: true
      }
    }
  },
代理效果

Source Map

運行代碼和源代碼之間完全不同,如果需要調(diào)試應(yīng)用坦报,錯誤信息沒法定位片择,調(diào)試或者報錯都是基于運行代碼字管,Source Map就是解決這類問題的辦法(源代碼地圖)
用于映射源代碼和轉(zhuǎn)換代碼之間的關(guān)系

version屬性:記錄Source Map版本號
sources屬性:轉(zhuǎn)換之前源文件的名稱嘲叔,可能是多個文件借跪,所以是數(shù)組
name屬性:源代碼成員名稱
mapping屬性:轉(zhuǎn)換之后的代碼的字符與轉(zhuǎn)換之前對應(yīng)的映射關(guān)系
最新版jQuery已經(jīng)去除了引入source map的注釋

引入

可以調(diào)試未壓縮的代碼了

source map 解決了源代碼和運行代碼不一致所產(chǎn)生的問題

webpack 配置 Source Map

在webpack配置文件里有一個屬性叫做devtool
卵牍,配置開發(fā)過程中的輔助工具
webpack 支持12種不同的方式
每種方式的效率和效果不同


生成了map文件糊昙,在開發(fā)者工具內(nèi)也可以直接定位到出問題的文件

eval模式下的Source Map

構(gòu)建速度,重新打包速度没咙,是否在生產(chǎn)環(huán)境下使用祭刚,所生成的map質(zhì)量

這種模式下不會生成source-map文件涡驮,只能定位源代碼名稱捉捅,不知道行列信息

不同devtool之間的差異

所有的不同模式下的devtool測試:

const HtmlWebpackPlugin = require('html-webpack-plugin')

const allModes = [
    'eval',
    'cheap-eval-source-map',
    'cheap-module-eval-source-map',
    'eval-source-map',
    'cheap-source-map',
    'cheap-module-source-map',
    'inline-cheap-source-map',
    'inline-cheap-module-source-map',
    'source-map',
    'inline-source-map',
    'hidden-source-map',
    'nosources-source-map'
]

module.exports = allModes.map(item => {
    return {
        devtool: item,
        mode: 'none',
        entry: './src/main.js',
        output: {
            filename: `js/${item}.js`
        },
        module: {
            rules: [
                {
                    test: /\.js$/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            presets: ['@babel/preset-env']
                        }
                    }
                }
            ]
        },
        plugins: [
            new HtmlWebpackPlugin({
                filename: `${item}.html`
            })
        ]
    }
})

// module.exports = [
//  {
//      entry: './src/main.js',
//      output: {
//          filename: 'a.js'
//      }
//  },
//  {
//      entry: './src/main.js',
//      output: {
//          filename: 'b.js'
//      }
//  }
// ]

運行之后可以慢慢觀察各個模式的差距

  • eval:是否使用eval執(zhí)行模塊代碼
  • cheap:Source Map是否包含行信息
  • module:是否能夠得到Loader處理之前的源代碼
  • inline:使用dataURL的方式嵌入到url當(dāng)中(最少用到的)
  • hidden:看不到source-map的效果即碗,但是確實生成了map文件剥懒,跟jquery是一樣的初橘,代碼中并沒有引入保檐,開發(fā)第三方包比較有用
  • nosources:能看到錯誤出現(xiàn)的位置夜只,但是點擊錯誤信息扔亥,看不到源代碼的旅挤,可以找到錯誤,確保源代碼不會被暴露的情況

webpack選擇合適的 Source Map模式

來自師傅的個人開發(fā)經(jīng)驗之談:
選擇cheap-module-eval-source-map

  • 代碼每行不超過80個字符(定位到行就可以了)
  • 經(jīng)過Loader轉(zhuǎn)換過后的差異較大秕脓,頻繁使用框架(需要查閱轉(zhuǎn)換之前的代碼)
  • 首次打包速度比較慢芙贫,但是重寫打包相對較快

生產(chǎn)環(huán)境下
選擇None

  • Source Map會暴露源代碼
  • 調(diào)試是開發(fā)階段的事情屹培,在開發(fā)階段盡可能找到所有的bug
    再不濟(jì)也要選擇nosources-source-map
  • 不要暴露源代碼的內(nèi)容

沒有選擇的差異,理解不同模式的差異蓄诽,適配不同的環(huán)境

webpack 自動刷新的問題

比如我測試一個文本輸入頁面仑氛,一旦有變化锯岖,文本會丟失出吹,又要重新輸入
頁面不刷新的前提下捶牢,模塊也可以及時更新

webpack HMR

HMR又名模塊熱替換(熱更新)
應(yīng)用程序運行過程中實時替換掉某個模塊秋麸,運行狀態(tài)不會改變灸蟆,以解決自動刷新導(dǎo)致頁面內(nèi)容丟失的問題炒考。
熱替換只是將修改的模塊實時替換到應(yīng)用中
HMR是webpack中最強大的功能之一
已經(jīng)集成到了webpack-dev-server中,不必要專門添加什么依賴
命令:

webpack-dev-server --hot

相對應(yīng)的也有可以在配置文件中添加相應(yīng)的配置打開HMR

  devServer: {
    hot: true
  },

然后載入webpack模塊

const webpack = require('webpack')

再在plugins里寫入實例

new webpack.HotModuleReplacementPlugin()

HMR還需要額外的操作才能正常工作

webpack中的HMR需要手動處理模塊熱替換邏輯

樣式文件熱更新開箱即用的原理:
經(jīng)過loader處理了,style-loader中已經(jīng)自動處理了熱更新
在框架下的開發(fā)测柠,每種文件都是有規(guī)律的谒主。所以JS就可以自動熱更新霎肯,通過腳手架創(chuàng)建的項目內(nèi)部都集成了HMR方案

HMR APIs

// ============ 以下用于處理 HMR,與業(yè)務(wù)代碼無關(guān) ============

// console.log(createEditor)

if (module.hot) {
  let lastEditor = editor
  module.hot.accept('./editor', () => {
    // console.log('editor 模塊更新了搂捧,需要這里手動處理熱替換邏輯')
    // console.log(createEditor)

    const value = lastEditor.innerHTML
    document.body.removeChild(lastEditor)
    const newEditor = createEditor()
    newEditor.innerHTML = value
    document.body.appendChild(newEditor)
    lastEditor = newEditor
  })

  module.hot.accept('./better.png', () => {
    img.src = background
    console.log(background)
  })
}

HMR注意事項

  • 處理HMR的代碼報錯會導(dǎo)致自動刷新
    解決方法:
    hotOnly: true // 只使用 HMR允跑,不會 fallback 到 live reloading
  • 沒啟用HMR的情況下聋丝,HMR API報錯
    缺失:
    new webpack.HotModuleReplacementPlugin()

解決:
添加控制條件

if(module.hot)
  • 代碼中多了一些與業(yè)務(wù)無關(guān)的代碼
    移除了熱更新的實例與導(dǎo)入代碼弱睦,業(yè)務(wù)模塊的相關(guān)代碼會自動移除

webpack 生產(chǎn)環(huán)境優(yōu)化

生產(chǎn)環(huán)境和開發(fā)環(huán)境有很大的差異
生產(chǎn)環(huán)境注重運行效率
開發(fā)環(huán)境注重開發(fā)效率
webpack 提供模式(mode) 為不同的工作環(huán)境創(chuàng)建不同的配置

webpack不同環(huán)境下的配置

  • 配置文件根據(jù)環(huán)境不同導(dǎo)出不同配置
    (中小型項目)
  • 一個環(huán)境對應(yīng)一個配置文件
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = (env, argv) => {
  const config = {
    mode: 'development',
    entry: './src/main.js',
    output: {
      filename: 'js/bundle.js'
    },
    devtool: 'cheap-eval-module-source-map',
    devServer: {
      hot: true,
      contentBase: 'public'
    },
    module: {
      rules: [
        {
          test: /\.css$/,
          use: [
            'style-loader',
            'css-loader'
          ]
        },
        {
          test: /\.(png|jpe?g|gif)$/,
          use: {
            loader: 'file-loader',
            options: {
              outputPath: 'img',
              name: '[name].[ext]'
            }
          }
        }
      ]
    },
    plugins: [
      new HtmlWebpackPlugin({
        title: 'Webpack Tutorial',
        template: './src/index.html'
      }),
      new webpack.HotModuleReplacementPlugin()
    ]
  }
// 判斷什么模式
  if (env === 'production') {
    config.mode = 'production'
    config.devtool = false
    config.plugins = [
      ...config.plugins,
      new CleanWebpackPlugin(),
      new CopyWebpackPlugin(['public'])
    ]
  }

  return config
}

  • 不同環(huán)境的配置文件


    公共端圈,開發(fā)環(huán)境,生產(chǎn)環(huán)境

    prod

    dev

common.js:

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'js/bundle.js'
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'css-loader'
        ]
      },
      {
        test: /\.(png|jpe?g|gif)$/,
        use: {
          loader: 'file-loader',
          options: {
            outputPath: 'img',
            name: '[name].[ext]'
          }
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: 'Webpack Tutorial',
      template: './src/index.html'
    })
  ]
}

使用什么模式,就用這條指令:

yarn webpack --config 哪一個文件

webpack DefinePlugin

為代碼注入全局成員
這是webpack內(nèi)置的插件

  plugins: [
    new webpack.DefinePlugin({
      // 值要求的是一個代碼片段
      API_BASE_URL: JSON.stringify('https://api.example.com')
    })
  ]
直接替換一為設(shè)置的內(nèi)容

webpack Tree-shaking

  • [搖掉]代碼中沒有引用的部分张症,未引用代碼(dead-code)
  • Tree-shaking會在生產(chǎn)模式production下自動開啟
  • Tree-shaking不是某一個配置選項
  • 非生產(chǎn)模式下的配置:
// 集中配置webpack內(nèi)部的優(yōu)化功能
  optimization: {
    // 模塊只導(dǎo)出被使用的成員
    usedExports: true,
    // 盡可能合并每一個模塊到一個函數(shù)中
    concatenateModules: true,
    // 壓縮輸出結(jié)果
    minimize: true
  }

webpack Tree-shaking 與 babel

  • Tree Shaking的前提是ESM
  • 由webpack打包的代碼必須使用ESM
          options: {
            presets: [
              // 如果 Babel 加載模塊時已經(jīng)轉(zhuǎn)換了 ESM俗他,則會導(dǎo)致 Tree Shaking 失效
              // ['@babel/preset-env', { modules: 'commonjs' }]
              // ['@babel/preset-env', { modules: false }]
              // 也可以使用默認(rèn)配置兆衅,也就是 auto羡亩,這樣 babel-loader 會自動關(guān)閉 ESM 轉(zhuǎn)換
              ['@babel/preset-env', { modules: 'auto' }]
            ]
          }

Babel并不會讓Tree-shaking失效

webpack sideEffcts(副作用)

副作用:模塊執(zhí)行時除了導(dǎo)出成員之外所作的事情
一般用于npm包標(biāo)記是否有副作用

 optimization: {
    sideEffects: true,
  }

標(biāo)明代碼真的沒有副作用

確保你的代碼真的沒有副作用畏铆,否則會誤刪

  • 樣式文件屬于副作用模塊


    extend是寫的一個有副作用的模塊辞居,這樣設(shè)置不會誤刪

Code Splitting(代碼分割)

所有的代碼都會被打包到一起瓦灶,bundle體積過大
并不是每一個模塊在啟動的時候都是必要的
分包倚搬,按需加載

  • 多入口打包(多頁面應(yīng)用程序)
    一個頁面去對應(yīng)一個打包入口
    公共部分單獨提取


plugin部分

提取公共模塊
optimization中的splitChunks屬性

  • ESM動態(tài)導(dǎo)入
    按需加載:需要用到某個模塊時捅僵,再加載這個模塊
    動態(tài)導(dǎo)入的模塊會被自動分包(更為靈活)

魔法注釋


靈活組織動態(tài)加載的模塊輸出的文件

MinCssExtraCtPlugin

提取CSS到單個文件

yarn add mini-css-extract-plugin --dev

在webpack配置文件中導(dǎo)入,再通過實例引用

const MiniCssExtractPlugin = require('mini-css-extract-plugin')

new MiniCssExtractPlugin()

會將樣式的CSS代碼單獨提取到一個文件中馒闷,再引用纳账,也就是說不需要style-loader了捺疼,取而代之的是

MiniCssExtractPlugin.loader

如果css文件體積大于150kb了啤呼,就考慮提取到單獨文件當(dāng)中

OptimizeCssAssetsWebpackPlugin

壓縮輸出的CSS文件
webpack內(nèi)置的壓縮插件只針對JS的壓縮官扣,CSS沒有壓縮,需要額外的插件


yarn add optimize-css-assets-webpack-plugin --dev

運行原理照舊蚯涮,有一點需要注意:配置在optimization的minimizer屬性當(dāng)中


如果在生產(chǎn)模式下就會自動進(jìn)行壓縮了

但是有一個缺點,如果配置了minimizer,編輯器就會自動認(rèn)為要使用配置的壓縮規(guī)則挟炬,那么JS就不會被壓縮了


內(nèi)置的JS壓縮為這個,配置回來就行了老速,這個插件也需要先下載依賴

輸出文件名Hash

生產(chǎn)模式下橘券,文件名使用Hash值
一旦資源發(fā)生改變卿吐,文件名也會發(fā)生改變嗡官,對于客戶端來說全新的文件名就是全新的請求衍腥,就沒有緩存的問題,不用擔(dān)心文件更新之后的問題

webpack中的filename屬性和絕大多數(shù)插件的filename屬性都支持通過占位符的方式為文件名設(shè)置Hash

  • [name]-[hash]:項目級別竹捉,有任何一個地方發(fā)生變化块差,hash值就全部發(fā)生變化了
  • [name]-[chunkhash]:同一路的打包憾儒,chunkhash都是同樣的hash,在同一路下的任意文件作出改動起趾,其他的同一路文件都會發(fā)生變化
  • [name]-[contenthash]:文件級別的hash
    (解決緩存問題最好的方式)
    可以通過:number的方式來指定hash長度


    八位hash是解決緩存最好的選擇
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末训裆,一起剝皮案震驚了整個濱河市边琉,隨后出現(xiàn)的幾起案子变姨,更是在濱河造成了極大的恐慌定欧,老刑警劉巖砍鸠,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爷辱,死亡現(xiàn)場離奇詭異饭弓,居然都是意外死亡示启,警方通過查閱死者的電腦和手機(jī)夫嗓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門舍咖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來排霉,“玉大人攻柠,你說我怎么就攤上這事」迮ィ” “怎么了冒滩?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長浪谴。 經(jīng)常有香客問我开睡,道長,這世上最難降的妖魔是什么苟耻? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任篇恒,我火速辦了婚禮,結(jié)果婚禮上凶杖,老公的妹妹穿的比我還像新娘。我一直安慰自己醋虏,他們只是感情好毛秘,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布艰匙。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪糖埋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機(jī)與錄音馆铁,去河邊找鬼。 笑死乖订,一個胖子當(dāng)著我的面吹牛乍构,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奥帘,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼扔茅,長吁一口氣:“原來是場噩夢啊……” “哼运褪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起嗦枢,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤殖演,失蹤者是張志新(化名)和其女友劉穎丸相,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弛作,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡萨西,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了年局。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脑溢。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡顶吮,死狀恐怖搏恤,靈堂內(nèi)的尸體忽然破棺而出熟空,到底是詐尸還是另有隱情,我是刑警寧澤息罗,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站油坝,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坤学,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一飞苇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至苗胀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人樟凄。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓瞎饲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容