教你用正確的方式在webpack裏引入jQuery、eCharts等lib

前注:

關於webpack的文檔全文(我本身寫的教程)請查看 根目錄的文檔說明html

若是能夠,請給本項目加【Star】和【Fork】持續關注。webpack

有疑義請點擊這裏,發【Issues】。git

點擊這裏查看DEMOgithub

九、外部擴展(Externals)

9.0、DEMO使用說明

安裝:web

npm i
複製代碼

運行:npm

npm run dev
複製代碼

打包(生產模式):緩存

npm run build
複製代碼

9.一、應用場景

當咱們加載一個外部庫,好比 jQuery,好比 echarts 等,爲了節約流量,咱們每每會使用 CDN 來加載這些東西。bash

這和咱們日常進行模塊化開發就有了必定的矛盾:服務器

  1. 需求:咱們須要引入一個全局變量(實質是引入一個模塊);
  2. 常規作法:因此正常來講,咱們應該經過 import 來引入這個模塊;
  3. 問題:但因爲經過CDN來加載,顯然咱們不能這麼作;

解決方案:

一、通常解決方案:app

咱們能夠直接經過使用這個全局變量來使用這個變量,例如:

// globalVariableName 經過CDN引入js文件,這個變量名其該js文件暴露出來的全局變量名(類型是一個函數)
document.getElementById("root").innerText = globalVariableName(1, 2, 3)
複製代碼

這個不是不行,但容易形成一個問題就是,容易在一不當心的狀況下,篡改了原有的變量。

而且,這種方式是高耦合度的,不推薦使用。

二、模塊化解決方案:

按照正常的開發方式,咱們一般是使用 外部擴展 來實現。

他具備如下特色:

示例代碼:

// ``webpack.config.js`` 文件裏的配置代碼

// 指定別名
externals: {
    // 後面是本來使用的全局變量名,前面的是引入的包名(就是import xx from 'echart'),而後咱們實際寫代碼時候,用的是xx這個變量名。
    "moduleName": 'globalVariableName'
}

// app.js 裏的業務代碼
import add from 'moduleName'
document.getElementById("root").innerText = add(1, 2, 3)
複製代碼
  1. webpack.config.js 裏進行配置;
  2. 一般使用 kv 模式,而且 v 通常是字符串(就像 "moduleName": 'globalVariableName' 這樣);
  3. 效果是當引入某個模塊時(k 決定),將不會像常規處理那樣去加載他,而是排除掉(就像 import add from 'moduleName' 這段代碼,不會去找 moduleName 這個模塊);
  4. 排除掉後怎麼處理呢,運行時從外部獲取這個擴展;
  5. 具體作法是(須要必定程度上知曉 webpack 打包後如何加載模塊,才能理解如下內容):獲取時,像正常導入一個模塊同樣,加載一個模塊;
  6. 但這個模塊作的事情,是將一個外部變量,經過 AMD 規範賦值給 module.exports(咱們使用 require 加載模塊時,獲取的值,就是 AMD 規範的模塊,經過這個屬性導出的值);
  7. 從而讓加載 moduleName 模塊時,實際加載到的是這個全局變量(5-7這個過程,實際體現的就是如下這段代碼)。
// 其餘代碼略
"moduleName": (function (module, exports) {
    module.exports = globalVariableName;
})
複製代碼

9.二、簡單來講(使用說明)

【需求】

假如我須要經過 CDN 加載一個我自定義的庫,示例我用的是:<script src="http://www.jianwangsan.cn/looksLikeCDN.js"></script>

這個庫就作了一件事情,暴露了一個全局變量 window.globalVariableName,這個變量是一個函數,他會將全部參數的和相加,並返回。(固然實際應用中,這個多是一個對象,有 N 個屬性,很是複雜,但原理是同樣的)

【第一步,修改html源文件】

我如今經過 CDN 來加載這個庫,所以個人 html 源文件是這樣的(固然實際上我不是CDN,所以用的是我我的服務器上的一個js文件,但道理也是同樣的):

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="http://www.jianwangsan.cn/looksLikeCDN.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
複製代碼

【第二步,配置webpack】

我如今須要使用這個方法,又不想經過模塊化引入(由於這個是固定不變的,沒有必要每次重複打包,這樣不利於緩存,就像 jQuery 庫同樣)。

因而我首先編輯 webpack.config.js 文件,給打包配置對象添加一個屬性,具體配置以下:

// 指定別名
externals: {
    // 後面是本來使用的全局變量名,前面的是引入的包名(就是import xx from 'echart'),而後咱們實際寫代碼時候,用的是xx這個變量名。
    "moduleName": 'globalVariableName'
}
複製代碼

將你想使用的全局變量,做爲 kv 鍵值對的 v,而 k 做爲在 js 文件中引入的模塊名使用(參考第三步)。

不想看解釋的跳過下面這段話,直接看第三步

以上配置意味着:

  1. moduleName 不會被正常加載:當我須要加載 import add from 'moduleName' 這個模塊時,webpack 不會像以前去找對應模塊那樣而處理(找到對應模塊,加載對應模塊,將模塊的返回值賦值給 add),而是採用一種新的機制來處理;
  2. 創造出的模塊:新的機制意味着,將創造一個 'moduleName' 模塊(注意,實際上這個模塊在工程裏並不存在);
  3. globalVariableName 全局變量:創造出來的模塊作了一件事情,他返回了一個值,這個值是 globalVariableName 這個全局變量的值。(想一想 AMD 規範中,module.exports = globalVariableName; 這段代碼表示什麼?);

因而體現的效果,就至關於如下代碼:

// app.js
import add from './moduleName'

// moduleName.js
export default window.globalVariableName
複製代碼

【第三步,在工程中引入】

上面咱們得到一個 k(moduleName),做爲模塊名,所以在 app.js 這個工程中查看:

// app.js
import add from 'moduleName'

// 這裏的 moduleName 模塊,返回 window.globalVariableName 這個值
// 因此就意味着 add 的值等同於 globalVariableName 的值
document.getElementById("root").innerText = add(1, 2, 3)
複製代碼

【結束】

這樣就能夠了,如今能夠嘗試進入命令行,輸入 npm run build 打包,並查看一下效果啦。

相關文章
相關標籤/搜索