蛋糕分割整合工具——Webpack-前端工程化

歡迎關注個人我的博客分享一些前端技術、面試題、面試技巧等css

歷史情況

Web 前端開發這幾年發展很是迅速,很是多的開發框架和構建工具的涌現,敬愛的前端攻城獅,可能你昨天還在用的工具、插件,到了今天可能就過期了。到了今天,外面的世界已經變了。html

當你在遇到一個 Bug 須要修復時,沒有比工程化推廣更迫切的事情了前端

須要解決的問題

工具和語言雖然差別大,可是解決的都是類似的問題,大概有如下幾點node

  • 擴展 JavaScript、HTML、Css 自己的語言能力
  • 解決重複工做
  • 模板化、模塊化
  • 解決功能複用和變動的問題
  • 解決開發和產品環境差別問題
  • 解決發佈流程問題

什麼是前端工程化

所謂工程化,能夠簡單認爲是將框架的職責拓寬再拓寬,主旨是幫業務團隊更好的完成需求,工程化會預測一些常碰到的問題,將之扼殺在搖籃,而這種路徑是可重用的,是具備可持續性。webpack

好比第一個優化去除冗餘,是在屢次去除冗餘代碼,思考冗餘出現的緣由而最終思考得出一個避免冗餘的方案。git

nOI3pF.jpg

自動化構建工具

說到構建工具,咱們每每會在前面加上(自動化)三個字,由於構建工具就是用來讓咱們再也不作機械重複的事情,解放咱們的雙手。github

要完成前端工程化,少不了工程構建工具,requireJSgrunt的出現,改變了業界前端代碼的編寫習慣,同時他們也是推進前端工程化的一個基礎web

requireJS是一偉大的模塊加載器,他的出現讓 JavaScript 製做多人維護的大型項目成爲可能。 grunt是一款 JavaScript 構建工具,主要完成編譯、壓縮、合併等一系列工做,後續又出了GulpWebPack等構建工具。面試

WebPack 具備Gulpgrunt對於靜態資源自動化構建的能力,但更重要的是,WebPack 彌補了requireJS在模塊化方面的缺陷,同時兼容 AMD 與 CMD 的模塊加載規範,具備更強大的 JS 模塊化功能。npm

兩種模式

開發模式

開發模式比較簡單,主要就是監聽文件變化,自動進行打包、合併的操做

生產模式

參考咱們得技術棧與需求,咱們的靜態文件都要發佈到 cdn 上,並且必須有 md5 版本號,方便快速發佈(cdn 更新極其緩慢,因此更新必須使用新的文件名)

生產模式主要增長了文件壓縮、文件 md5 名修改、替換 HTML 等操做

這樣的好處是上線很是方便,一個命令便可更新線上,並且不存在緩存問題

什麼是 CDN

CDN 是構建在網絡之上的內容分發網絡,依靠部署在各地的邊緣服務器,經過中心平臺的負載均衡、內容分發、調度等功能模塊,使用戶就近獲取所需內容,下降網絡擁塞,提升用戶訪問響應速度和命中率。CDN 的關鍵技術主要有內容存儲和分發技術。

CDN 的基本原理是普遍採用各類緩存服務器,將這些緩存服務器分佈到用戶訪問相對集中的地區或網絡中,在用戶訪問網站時,利用全局負載技術將用戶的訪問指向距離最近的工做正常的緩存服務器上,由緩存服務器直接響應用戶請求。

CDN 網絡是在用戶和服務器之間增長 Cache 層,如何將用戶的請求引導到 Cache 上得到源服務器的數據,主要是經過接管 DNS 實現,這就是 CDN 的最基本的原理

請求流程

nOoauj.png

  1. 用戶向瀏覽器輸入www.web.com這個域名,瀏覽器第一次發現本地沒有 dns 緩存,則向網站的 dns 服務器請求
  2. 網站的 dns 域名解析設置了 Cname,指向了wwww.web.51cdn.com,請求指向了 CDN 網絡中的智能 DNS 負載均衡系統
  3. 智能 DNS 負載均衡系統解析域名,把對用戶響應速度最快的 IP 節點返回給用戶
  4. 用戶向該節點(CDN 服務器)發出請求
  5. 因爲是第一次訪問,CDN 服務器會向原 Web 站點請求,並緩存內容
  6. 請求結果發送給用戶

爲何要用 WebPack

nOT1sJ.png

前端須要模塊化:JS 模塊化不只僅是爲了提升代碼複用性,多人協做開發項目,更是爲了讓資源文件更合理的進行緩存

當在 WebPack 處理後,輸出的靜態文件只剩下 JS、png、Css、jpg

Webpack 是什麼,有什麼好處

  • WebPack 能夠看作是模塊打包機:它作的事情是,分析你的項目結構,找到 JavaScript 模塊以及其它的一些瀏覽器不能直接運行的拓展語言(Sass,TypeScript 等),並將其打包爲合適的格式以供瀏覽器使用。
  • 爲了簡化開發的複雜度
  • 模塊化,讓咱們能夠把複雜的程序細化爲小的文件;
  • CSS modules
  • sass,less 等 CSS 預處理器
  • webpack-plugins
  • 插件(Plugins)是用來拓展 Webpack 功能的,它們會在整個構建過程當中生效,執行相關的任務。

WebPack 功能特性

  • 支持 CommonJS 和 AMD 模塊,意思就是咱們基本能夠無痛遷移舊項目
  • 支持模塊加載器和插件機制,可對模塊靈活定製
  • 能夠經過配置打包多個文件,有利於瀏覽器的緩存功能提高性能
  • 將樣式文件和圖片等靜態資源也可視爲模塊進行打包
  • 內置有source map,即便打包在一塊兒依舊方便調試

任何靜態資源均可以視做模塊,而後模塊之間也能夠相互依賴,經過 WebPack 對模塊進行處理後,能夠打包咱們想要的靜態資源

使用 WebPack

  • 新建 WebPackDemo 文件夾,使用npm init命令生成package.json文件。

  • 使用npm install webpack -D安裝 webpack

nOqPkn.png

  • 在文件夾下建立webpack.config.js文件,編寫配置文件
    • entry: 是頁面入口文件配置(HTML 文件引入的惟一的 js 文件)
    • output: 對應輸出項配置(path: 入口文件最終要輸出到哪裏,filename: 輸出文件的名稱,publicPath: 公共資源路徑)

nOXj4s.png

項目結構

webpack-demo
|-- node_modules
|-- src
  |-- index.js
| index.html
| package.json
| webpack.config.js
複製代碼
  • webpack 打包當前項目操做指令 npx webpack

會在項目文件夾中生成一個 out 文件夾,裏邊會有編譯後的 index.js。

Webpack loader 加載器

loader 意義 這些加載器主要作一些預處理的工做,好比 less 等,這裏咱們以 css 和 babel 編譯 E2015 爲例

安裝 loader 咱們第一步就是先要安裝好各個須要使用的 loader。 運行如下命令進行安裝npm install babel-loader babel babel-core css-loader style-loader -D

添加 css 文件,在 js 文件中引用以後使用 WebPack 打包

nXS9JJ.png

若是編譯過程當中出現報錯 Error: Cannot find module '@babel/core' babel-loader@8 requires Babel 7.x (the package '@babel/core'). If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7'. 使用命令 npm install babel-loader@7

編譯完成後查看index.html,查看源碼後發現head標籤裏多出了style標籤,裏面正是咱們想要的樣式。

nXpZXq.png

圖片打包

咱們以前也說過,WebPack 對於靜態資源來講,也是看作模塊來加載的,Css 咱們是已經看過了。那麼圖片是怎麼做爲模塊打包加載進來的呢?這裏咱們能夠想到,圖片咱們是url-loader加載的,咱們在 Css 文件裏的 url 屬性,其實就是一種封裝處理過的 require 操做,固然咱們還有一種方式就是直接對元素的 src 屬性進行 require 賦值。

npm install url-loader file-loader
複製代碼
div {
  background-image: url("./1.jpg");
}
複製代碼
let img = document.createElement("img");
img.src = require("./image/xxx.png");
document.body.appendChild(img);
複製代碼

上述兩種方法都會對符合要求的圖片進行處理。而要求就是在 url-loader 後面經過 query 參數的方式實現的,這裏就是說只有不大於8kb的圖片纔會打包處理成 Base64 格式的圖片。

{
  test: /.jpg|png|gif|svg$/,
  use: ['url-loader?limit=8192&name=./[name].[ext]']
}
複製代碼

publicPath 是像圖片這種靜態資源打包後的根路徑,當瀏覽器須要引用輸入靜態資源文件時,這個配置項指定輸入文件的公共 URL 地址。在 loader 中它被嵌入到 script 或者 link 標籤或者對靜態資源的引用裏。當文件的 href 或者 url()與它在磁盤上的路徑不一致時就應當用 publicPath,當你想定義一些或者全部文件放在不一樣的主機或 CDN 上時會有用。

nXm2b4.png

編譯後實現效果

nXMHfA.png

打包多個文件

WebPack 不只適用於 SPA 開發,對於多頁面,多站點,WebPack 支持的很好,經過更改配置文件爲多入口

output 設置裏面[name]表明 entry 的每個鍵值,所以運行 WebPack 時候會輸出對應多個文件,out/page1.js,out/page2.js,在index.htmlindex2.html兩個頁面分別引用。

nvT4bQ.png

插件

代碼壓縮插件:uglifyjs-webpack-plugin

插件下載 npm install uglifyjs-webpack-plugin --save-dev

插件使用

const UglifyJsPlugin = require("uglifyjs-webpack-plugin");

module.exports = {
  optimization: {
    minimizer: [new UglifyJsPlugin()]
  }
};
複製代碼

具體配置請訪問:github.com/webpack-con…

**頁面分離:**前端工程一項就是減小 http 請求,這表示須要把多個 js 合併成一個,可是,單個 JS 文件過大會影響瀏覽器下載文件的速度,因爲如今瀏覽器併發 http 請求多達 6 個,能夠利用這個特性,將複用第三方資源庫奮力加載。

模塊分離插件:SplitChunksPlugin

Originally, chunks (and modules imported inside them) were connected by a parent-child relationship in the internal webpack graph. The CommonsChunkPlugin was used to avoid duplicated dependencies across them, but further optimizations where not possible

Since version 4 the CommonsChunkPlugin was removed in favor of optimization.splitChunks and optimization.runtimeChunk options.

經過將公共模塊拆出來,最終合成的文件可以在最開始的時候加載一次,便存起來到緩存中供後續使用。

咱們須要在webpack.config.js文件中添加下面的代碼

splitChunks: {
    chunks: "async", // initial、async和all
    minSize: 30000, // 造成一個新代碼塊最小的體積 默認是 3000
    minChunks: 1, // 在分割以前,這個代碼塊最小應該被引用的次數
    maxAsyncRequests: 5, // 按需加載時候最大的並行請求數。
    maxInitialRequests: 3, // 一個入口最大的並行請求數
    automaticNameDelimiter: '~',
    name: true, // 打包的chunks的名字 字符串或者函數(函數能夠根據條件自定義名字)
    cacheGroups: { // 這裏開始設置緩存的 chunks
        vendors: {
            test: /[\\/]node_modules[\\/]/,
            priority: -10
        },
    default: {
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true
        }
    }
}
複製代碼

具體配置請訪問:www.webpackjs.com/plugins/spl…

Css獨立打包

獨立出Css樣式,若是咱們但願樣式經過<link>引入,而不是放在<style>標籤中,即便這樣作會多一個請求。

安裝 npm install mini-css-extract-plugin --save-dev

nvbIVe.png

爲了區分開<link>連接和用<style>,咱們這裏以Css後綴結尾的模塊用插件。

WebPack 服務器

Use webpack with a development server that provides live reloading. This should be used for development only.

安裝:npm install webpack-dev-server --save-dev

Webpack 是如何打包的

WebPack 根據 webPack.config.js中的入口文件,在入口文件裏識別模塊依賴,無論這裏的模塊依賴是用CommonJS寫的,仍是用 ES6 Module 規範寫的,WebPack會自動進行分析,並經過轉換、編譯代碼、打包成最終的文件。(最終的文件是基於Webpack本身實現的ES5代碼,因此能夠跑在瀏覽器)

nvqCPs.png

Webpack 熱更新實現原理?

  • Webpack 編譯期,爲須要熱更新的 entry 注入熱更新代碼(EventSource 通訊)
  • 頁面首次打開後,服務端與客戶端經過 EventSource 創建通訊渠道,把下一次的 hash 返回前端
  • 客戶端獲取到 hash,這個 hash 將做爲下一次請求服務端 hot-update.js 和 hot-update.json 的 hash
  • 修改頁面代碼後,Webpack 監聽到文件修改後,開始編譯,編譯完成後,發送 build 消息給客戶端
  • 客戶端獲取到 hash,成功後客戶端構造 hot-update.js script 連接,而後插入主文檔
  • hot-update.js 插入成功後,執行 hotAPI 的 createRecord 和 reload 方法,獲取到 Vue 組件的 render 方法,從新 render 組件, 繼而實現 UI 無刷新更新。

但願對讀完本文的你有幫助、有啓發,若是有不足之處,歡迎批評指正交流!

歡迎關注個人我的博客分享一些前端技術、面試題、面試技巧等

辛苦整理良久,還望手動點贊鼓勵~


'摘抄'不是單純的「粘貼->複製」,而是眼到,手到,心到的一字一句敲打下來。

博客聲明:全部轉載的文章、圖片僅用於做者本人收藏學習目的,被要求或認爲適當時,將標註署名與來源。若不肯某一做品被轉用,請及時通知本站,本站將予以及時刪除。

相關文章
相關標籤/搜索