【webpack學習筆記(一)】流行的前端模塊化工具webpack初探

来源:http://www.cnblogs.com/penghuwan/archive/2017/04/04/6665140.html
-Advertisement-
Play Games

簡介:講解webpack如何實現模塊編程,以及為什麼我們需要打包,壓縮js文件,實現sass/less編譯以及JSX等模版的轉換(版本控制),然後用實例說明如何用webpack實現SPA和MPA(單頁面應用程式和多頁面應用程式,包含詳細圖解)(在以後的文章中還將介紹如何實現js壓縮和sass/les... ...


從開發文件到生產文件

  有一天我突然意識到一個問題,在使用react框架搭建應用時,我使用到了sass/less,JSX模版以及ES6的語法在編輯器下進行開發,使用這些寫法是可以提高開發的效率。可是瀏覽器它本身是並不能夠“理解”這些語法的呀。就像下麵這張圖:       在開發代碼文件 --> 生產代碼文件的轉換過程中,我們到底需要做些什麼呢?沒錯,這一切都和webpack(或gulp)有關:       轉一張webpack官網的圖,webpack能把less/sass文件,json文件,乃至css文件,全都打包成js文件和靜態資源文件(圖片)  

 

webpack和gulp的共同作用及兩者的區別:   webpack和gulp本質上並不是同一類型工具,但它們都能完成以下任務:

 

webpack:一個模塊化工具(a module bundle) gulp:一個任務運行器(a Task Runner)   在用react/vue/angular搭建單頁面應用時,我們可以用webpack代替gulp的工作,方便而快捷。兩者具體的區別,在這裡不多贅述,大家自行查閱資料。下麵我主要介紹一下webpack的使用   除了利用webpack實現開發代碼 --> 生產代碼的轉換,我們為什麼要用它做其他一些工作,比如文件打包(文件合併),JS/css壓縮呢?   為什麼要用webpack實現文件打包?   為什麼我們要做文件打包的工作,這樣做有什麼意義嗎?這要從我們曾經喜聞樂見的<script>標簽說起。對於許多初學者來說,在每個HTML頁面里寫入大量的<script>標簽是再正常不過的事情。然後在部署上線時就會生成這樣的HTML文件  
<html>
  <body>
    <script src = 'http:// ...  a.js' />
    <script src = 'http:// ...  b.js' />
    <script src = 'http:// ...  c.js' />
    <script src = 'http:// ...  d.js' />
  </body>
</html>
  咋看一下似乎也沒什麼不對,但是仔細想想,每個頁面都發起如此多的http請求,大量的頁面疊加在一起,這將極大降低頁面的性能,使頁面載入得很慢。那麼我們想,能不能將無數個script文件合為一個(或幾個)文件,這樣請求數不就大大減少了嗎?沒錯,webpack打包做的就是這樣的作用   為什麼要用webpack實現JS壓縮?   和打包一樣,壓縮文件也是為了提高頁面性能,(大家可結合自己對那些打開極慢的網站的體驗感受一下頁面性能的重要性)。使用webpack壓縮文件時,它會做以下操作:
  • 刪除註釋
  • 刪除空格 (所以我們偶爾會看到沒有間隔或只有一行的JS代碼)
  • 縮短變數名,函數名和函數參數名(var myName = '彭湖灣')-->var  a = '彭湖灣'
這樣做的好處:
  • 減少文件體積,加快傳輸速度,提高頁面性能
  • 實現代碼混淆,破壞其可讀性,保護創作者的知識產權
 (註:這一過程不可逆!需要事先做好備份工作) 為什麼要用webpack實現sass,less的編譯和JSX模版文件的轉換?   也就是上文提到的,通過webpack的轉換,從瀏覽器無法“理解”的開發代碼生成一份瀏覽器能夠“理解”的生產代碼   commonJS和AMD規範   從大量<script>的寫法到webpack的廣泛使用,實際上就是前端模塊化發展的過程,而其間有兩個主要的模塊化標準commonJS和AMD,webpack是基於commonJS的,(當然也相容寫AMD,不過不推薦)下麵是commonJS 的模塊寫法:   const moduleInput = require('moduleInpu') //輸入模塊 module.exports = { //輸出模塊   ... }   下麵我就一一來介紹如何用webpack實現上述三種功能:   首先你得創建一個文件webpackTest,在終端進入目錄,寫入$ npm install webpack -g,安裝成功   1文件打包(SPA-單頁面應用程式)   1-1安裝好webpack後創建這樣一個目錄:     1-2:向component各文件和dist/index.html文件寫入內容   dist表示的是生產目錄,component是開發目錄,我們平時開發時只在component目錄下完成。dist/index.html是我們手動創建的,內容如下:  
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
  </head>
  <body>
  <script type="text/javascript" src="bundle.js"></script></body>
</html>

 

我們希望通過webpack的文件打包,將component中的所有文件合併到dist/ab.js中來然後dist/index.html就可以引用dist/ab.js文件了。 component/a.js內容:
console.log('我是a.js文件');
component/b.js內容:
console.log("我是b.js文件");
component/ab.js內容:
require('./a')
require('./b')
console.log('我是ab.js,我require了a.js文件和b.js文件');
  1-3向webpack.config.js中寫入內容:  
var path = require('path')
 
module.exports = {
    entry:{
       ab:'./component/ab.js',
    },
    output:{
        filename:'bundle.js',
        path:path.resolve(__dirname,'dist'),
    },
}

 

webpack要求webpack.config.js的輸出模塊為一個對象,且包含兩大基本屬性:entry和output。entry,顧名思義,入口文件,上面代碼表示component/ab.js是入口文件,output/bundle.js是輸出文件。由於component/ab.js引入(require)了a.js文件和b.js文件,這三個文件會被一起打包dist/bundle.js中,(註:entry中可以寫入相對路徑)  
var path = require('path')
path.resolve(__dirname,'dist')
    這段代碼什麼意思?path是node的內置模塊,resolve是它的一個方法,__dirname表示當前目錄在磁碟中的絕對路徑,path.resolve(__dirname,'dist') = __dirname + '/dist' ,在我的mac里它相當於Users/penghuwan/myprogram/webpackTest/dist(註意:必須為絕對路徑,不能為相對路徑!)   1- 4 OK!該寫的都寫好了,接下來,在終端進入目錄,寫入webpack回車     component下的三個文件都被打包好了,再回來看看我們的目錄  

 

多了一個dist/bundle.js的文件!讓我們看看裡面有什麼:  

 

就是我們獨立寫的a.js,b.js和ab.js打包後的dist/ab.js。   與此同時,我們之前在dist/index.html里的 <script type="text/javascript" src="ab.js"></script></body>不就可以起到作用了嗎?讓我們在磁碟里找到該文件打開,發現控制台輸出了:  

 

用圖解描述上述過程,,webpack 遞歸地構建一個依賴樹,這個依賴樹包括你應用所需的每個模塊,然後將所有模塊打包為少量的包(bundle) - 通常只有一個包 - 可由瀏覽器載入     2多入口文件   2-1上述例子中,我們只在entry中寫入了一個入口文件,那我們能不能一次寫入多個入口文件呢?這當然是可以的,首先修改我們在component的文件結構:  

 

c.js/d.js/cd.js和a.js/b.js/ab.js結構上完全一致,只是輸出的文本不同,這裡不多贅述,然後修改我們的webpack.config.js  
var path = require('path')
module.exports = {
    entry:{
       ab:'./component/ab.js',
       cd:'./component/cd.js'
    },
    output:{
        filename:'[name].js',
        path:path.resolve(__dirname,'dist'),
    },
}
  這裡的name是占位符[name]分別對應entry中寫入的[ab]和[cd],這表示,在dist下生成的將不再是上文提到的bundle.js,而是ab.js和cd.js兩個JS文件   2-2再修改一下我們的dist/index.html:  

 

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
  </head>
  <body>
  <script type="text/javascript" src="./ab.js"></script></body>
  <script type="text/javascript" src="./cd.js"></script></body>
</html>
2-3然後同樣是進入終端,寫入webpack再回車,回到目錄,此時已經生成了dist/ab.js和dist/cd.js兩個文件  

  

2-4在瀏覽器中打開dist/index.html,輸出:       用圖解描述上述過程如下,由於引用關係建立的依賴書,a/b/ab和c/d/cd分別被打包為兩個bundle並被引入dist/index.html  

 

3為輸出文件添加哈希值標記,避免相同文件重新載入   在前後兩次在終端輸入webpack打包時,即使component中的所有文件都沒有變化,資源是要重新載入一遍的。同理,在生產中,每次需要在代碼中更新內容時,伺服器都必須重新部署,然後再由所有客戶端重新下載。 這顯然是低效的,因為通過網路獲取資源可能會很慢。 那麼我們怎麼才能避免這個問題呢———給output中的bundle文件提供hash值標記:   每次構建輸出文件時,如果代碼發生變化,輸出的文件將生成不同的hash值,這時將重新載入資源,但如果代碼無變化,輸出文件hash值也不變化,系統就會預設使用原來緩存的輸出文件   3-1修改我們的webpack.config.js:  
var path = require('path')
 
module.exports = {
    entry:{
       ab:'./component/ab.js',
       cd:'./component/cd.js'
    },
    output:{
        filename:'[name]-[hash].js',
        path:path.resolve(__dirname,'dist'),
    },
}

 

打包後dist目錄:(上個例子中的dist/ab.js和dist/cd.js已刪掉)  

 

寫入hash值帶來的新問題——每次都要更改dist/index.html中JS的src   因為我們生成的hash是不斷變化的,與此同時index.html必須不斷更改<script>標簽中的src的值   4解決hash值帶來的新問題   4-1使用html-webpack-plugin插件,webpack.config.js的輸出模塊對象有一個plugins屬性,它是一個數組,數組項是創建的plugin對象 在終端寫入npm install html-webpack-plugin --save-dev,安裝完畢後修改webpack.config.js的配置:  
var path = require('path')
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry:{
       ab:'./component/ab.js',
       cd:'./component/cd.js'
    },
    output:{
        filename:'[name]-[hash].js',
        path:path.resolve(__dirname,'dist'),
    },
    plugins:[
      new HtmlWebpackPlugin()
    ]
}

 

  4-2在終端里輸入webpack回車,打開我們的dist/index,居然已經自動寫入了src帶hash值的script標簽!  

  

【註意】這次的dist/index.html是webpack自動生成的,而以前的例子都是我們手動寫入的   5為生成的index.html指定模版   5-1但讓我們想一想另外一個問題,這個dist/html是自動生成的,我們能不能做一些改造,比如指定一個模版。用開發開發文件中的component/index.html為模版生成dist.html呢?先創建一個component/index.html文件,寫入:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>這是開發文件中的模版HTML</title>
  </head>
  <body>
</html>

 

  5-2修改我們的webpack.config.js:  
var path = require('path')
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry:{
       ab:'./component/ab.js',
       cd:'./component/cd.js'
    },
    output:{
        filename:'[name]-[hash].js',
        path:path.resolve(__dirname,'dist'),
    },
    plugins:[
      new HtmlWebpackPlugin({
        template:'./component/index.html'
      })
    ]
}

 

5-3在HtmlWebpackPlugin的參數對象中寫入template屬性,指定為component/index.js,回到終端,寫入webpack,然後讓我們看一看dist/index.html  

 

用圖解描述上述過程:     6用webpack打包多頁面應用程式(MPA) 談談SPA(sing page application)與MPA(mutiple page aplication),SPA和MPA 指的是單頁面應用程式和多頁面應用程式,之前我們打包的都是SPA,那麼怎麼打包MPA呢。很簡單,在plugins中寫入多個HtmlWebpackPlugin對象便可,這時候需要指明不同文件的filename屬性值,以及chunks屬性值——它們對應的bundle文件 6-1改寫一下我們的webpack.config.js文件:    
var path = require('path')
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry:{
       ab:'./component/ab.js',
       cd:'./component/cd.js'
    },
    output:{
        filename:'[name]-[hash].js',
        path:path.resolve(__dirname,'dist'),
    },
    plugins:[
      new HtmlWebpackPlugin({
        filename:'ab.html',
        template:'./component/index.html',
        chunks:['ab']
      }),
      new HtmlWebpackPlugin({
        filename:'cd.html',
        template:'./component/index.html',
        chunks:['cd']
      })
    ]
}

 

6-2打包後在dist中生成了dist/ab.html和dist/cd.html,瀏覽器打開ab.html,控制台輸出:     瀏覽器打開cd.html,控制台輸出:     圖解上述過程:  

 

 
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 類庫:.dll文件,使用類庫來封裝常用的功能,無法單獨運行。 abstact class Calculator類{欄位Num1,欄位Num2,abstract int GetResult()方法} Add類:Calculator類{override int GetResult()返回Num1+Num ...
  • 一、概述 提供一個創建一系列相關或相互依賴對象的介面,而無需指定它們具體的類。 二、模式中的角色 AbstarctProduct(IProduct):為一類產品對象聲明一個介面; ConcreteProduct(MySqlProduct、SqlServerProduct):定義一個將被相應的具體工廠 ...
  • JavasScript社區在創新的道路上開足了馬力,曾經流行過的也許一個月之後就過時了。2016已經結束了。你可能會想你是否錯過一些重要的東西?不用擔心,讓我們來回顧2016年前端有哪些主流。通過比較過去12個月里Github所增加的star數,我們依次來看看哪些項目吸引了大多數眼光。 ...
  • [1]前端架構 [2]版本管理 [3]命令行工具 [4]編輯器 [5]預處理器 ...
  • 原文鏈接:http://www.jianshu.com/p/42e11515c10f 什麼是WebPack,為什麼要使用它? 為什要使用WebPack 現今的很多網頁其實可以看做是功能豐富的應用,它們擁有著複雜的JavaScript代碼和一大堆依賴包。為了簡化開發的複雜度,前端社區涌現出了很多好的實 ...
  • 首先要瞭解何為跨域,(協議、功能變數名稱、埠任意一個不同)的web資源。如何解決跨域:1,jsonp 它只支持GET請求而不支持POST等其它類型的HTTP請求;例如angular 中,如下使用,$http.jsonp('some/trusted/url', {jsonpCallbackParam: 'c ...
  • 什麼是模板引擎 模板引擎是為了使用戶界面與業務數據(內容)分離而產生的,它可以生成特定格式的文檔,用於網站的模板引擎就會生成一個標準的HTML文檔.其本質是利用正則表達式,替換模板當中預先定義好的標簽. 常用模板引擎 "ArtTemplate" "BaiduTemplate" "velocity.j ...
  • 什麼是ajax Ajax(Asynchronous JavaScript and XML),是一種可以向伺服器請求額外的數據並且無需刷新頁面的技術,ajax的出現帶來了更好的用戶體驗. Ajax的核心就是XMLHttpRequest(XHR)對象.XHR為向伺服器發送請求和解析伺服器響應提供了流暢的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...