大音希聲,大象無形,大智若愚,大巧若拙,越是“複雜”的東西,其原理越趨向“簡單”,大道至簡,繁在人心。
我們都知道,npm 是 JavaScript 世界的包管理工具,並且是 Node.js 平臺的預設包管理工具。通過 npm 可以安裝、共享、分發程式碼,管理專案依賴關係。雖然作為命令列工具的 npm 近年來逐漸式微,但是作為廣泛使用的儲存庫的 npm,卻依然如日中天,還是世界上最大的軟體登錄檔。
通常,我們通過npm install xxx
在 React、Vue、Angular 等現代前端專案中安裝依賴,但是前端專案在本質上還是執行在瀏覽器端的 HTML、JavaScript 和 CSS,那麼,我們有辦法在瀏覽器控制檯直接安裝 npm 包並使用嗎?
如果你對這個問題感興趣,不妨跟著我通過本文一探究竟,也許最終你會發現:越是“複雜”的東西,其原理越趨向“簡單”。
通過 <script />
引入 cdn 資源
在瀏覽器控制檯安裝 npm 包,看起來是個天馬行空的想法,讓人覺得不太切實際。如果我換一個方式進行提問:如何在瀏覽器/HTML 中引入 JavaScript 呢?也許你馬上就有了答案:<script />
標籤。沒錯,我們的第一步就是通過 <script />
標籤在 HTML 頁面上引入 cdn 資源。
那麼,又該如果在控制檯在頁面上插入<script />
標籤來引入 CDN 資源呢?這個問題可難不倒你:
// 在頁面中插入<script />標籤
const injectScript = (url) => {
const script = document.createElement('script');
script.src = url;
document.body.appendChild(script);
};
我們還得在資源引入後以及出現錯誤時,給使用者一些提示:
script.onload = () => {
console.log(pkg_name_origin, ' 安裝成功。');
};
script.onerror = () => {
console.log(pkg_name_origin, ' 安裝失敗。');
};
這麼以來,我們就可以直接在控制檯引入 cdn 資源了,你可以再額外補充一些善後工作的處理邏輯,比如把<script />
標籤移除。當然,你也完全可以通過建立<link />
標籤來引入css樣式庫,這裡不過多贅述。
根據包名安裝 npm 包
上面實現了通過<script />
引入 cdn 資源,但是我們安裝 npm 包一般都是通過npm install
後面直接跟包名來完成的,顯然單靠<script />
的方式難以達到我們的餓預期,那麼,有沒有一種方式,可以將我們的包名直接轉換成 cdn 資源地址呢?
答案當然是:有。否則我寫個屁啊 ?,cdnjs
就提供了這樣的能力。
cdnjs 提供了一個簡單的 API,允許任何人快速查詢 CDN 上的資源。具體使用讀者可參考官方連結,這裡給出一個根據包名查詢 CDN 資源連結的示例,可以直接在瀏覽器位址列開啟這個連結檢視:https://api.cdnjs.com/libraries?search=jquery
,這是一個 get 請求,你將看到類似下面的頁面,陣列的第一項為名稱/功能最相近的資源的最新 CDN 資源地址:
是以,根據包名搜尋 cdn 資源 URL 便有如下的實現:
const cdnjs = async (name) => {
const searchPromise = await fetch(
`https://api.cdnjs.com/libraries?search=${name}`,
// 不顯示referrer的任何資訊在請求頭中
{ referrerPolicy: 'no-referrer' }
);
const { results, total } = await searchPromise.json();
if (total === 0) {
console.error('Sorry, ', name, ' not found, please try another keyword.');
return;
}
// 取結果中最相關的一條
const { name: exactName, latest: url } = results[0];
if (name !== exactName) {
// 如果名稱和你傳進來的不一樣
console.log(name, ' not found, import ', exactName, ' instead.');
}
// 通過<script />標籤插入
injectScript(url);
};
安裝特定版本的 npm 包
我們在 npm 中還可以通過類似npm install jquery@3.5.1
的語法安裝特定版本的 npm 包,而 cdnjs 只能返回特定版本的詳細資訊(不含 cdn 資源連結)。
UNPKG在此時可以幫我們一個大忙。unpkg 是一個快速的全球內容分發網路,適用於 npm 上的所有內容。使用它可以使用以下 URL 快速輕鬆地從任何包載入任何檔案:unpkg.com/:package@:version/:file
。
例如,訪問https://unpkg.com/jquery@3.5.1
會自動重定向到https://unpkg.com/jquery@3.5.1/dist/jquery.js
,並返回v3.5.1
版本的jQuery
檔案內容(如果不帶版本號,會返回最新的資源):
也就是說,我們可以將https://unpkg.com/
➕包名
直接丟給<script />
標籤來載入資源:
const unpkg = (name) => {
injectScript(`https://unpkg.com/${name}`);
};
完整程式碼
將上面的程式碼簡單整理,並通過一個統一的入口方法npmInstall
進行呼叫:
// 儲存原始傳入的名稱
let pkg_name_origin = null;
const npmInstall = (originName) => {
// Trim string
const name = originName.trim();
pkg_name_origin = name;
// 三種引入方式
// 如果是一個有效的URL,直接通過<script />標籤插入
if (/^https?:\/\//.test(name)) return injectScript(name);
// 如果指定了版本,嘗試使用unpkg載入
if (name.indexOf('@') !== -1) return unpkg(name);
// 否則,嘗試使用cdnjs搜尋
return cdnjs(name);
};
// 在頁面中插入<script />標籤
const injectScript = (url) => {
const script = document.createElement('script');
script.src = url;
script.onload = () => {
console.log(pkg_name_origin, ' 安裝成功。');
};
script.onerror = () => {
console.log(pkg_name_origin, ' 安裝失敗。');
};
document.body.appendChild(script);
// document.body.removeChild(script);
};
const unpkg = (name) => {
injectScript(`https://unpkg.com/${name}`);
};
const cdnjs = async (name) => {
const searchPromise = await fetch(
`https://api.cdnjs.com/libraries?search=${name}`,
// 不顯示referrer的任何資訊在請求頭中
{ referrerPolicy: 'no-referrer' }
);
const { results, total } = await searchPromise.json();
if (total === 0) {
console.error('Sorry, ', name, ' not found, please try another keyword.');
return;
}
// 取結果中最相關的一條
const { name: exactName, latest: url } = results[0];
if (name !== exactName) {
console.log(name, ' not found, import ', exactName, ' instead.');
}
// 通過<script />標籤插入
injectScript(url);
};
我們可以使用類似npmInstall('moment')
的方式在控制檯進行呼叫:
下面這些呼叫方式自然也是支援的:
npmInstall('jquery'); // 直接引入
npmInstall('jquery@2'); // 指定版本
npmInstall('https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js'); // cdn地址
不每次都寫這些函式行不行
看了上面的操作,確實很簡單,但是也許你會說:每次要使用時,我都得在控制檯定義和呼叫函式,有些麻煩,不每次都寫這些函式行不行?那自然是行的啦,你完全可以自己寫一個瀏覽器外掛,將這些JS程式碼注入頁面,詳情可參考7分鐘學會寫一個瀏覽器外掛——突破某SDN未登入禁止複製的限制。
如果你實在不想寫,其實有人已經為你寫好了,那便是Console Importer
,它可以讓你的瀏覽器控制檯成為更強大的實驗場。
- 使用示例:
- 效果圖:
連結:Console Importer | Chrome 外掛地址
可以幹什麼
那麼,本文介紹的方法和工具到底有什麼用呢?
平時開發中,我們經常會想要在專案裡嘗試一些操作或者驗證一些庫的方法、列印結果,通過本文的學習,以後你完全可以直接在控制檯引入loadsh、moment、jQuery、React
等來進行使用和驗證,減少在專案中進行console.log
驗證後再刪除的頻次。
- 你可以通過引入
jQuery
方便的進行一些專案、頁面中的DOM操作; - 你可以通過引入
axios
進行一些簡單的介面請求; - 你可以通過引入
moment.js
來驗證一些時間格式化方法的使用; - 你可以通過引入
loadsh
並呼叫它的方法完成一些便捷的計算; - ...
可以學到什麼
unpkg
unpkg 是一個內容源自 npm 的前端常用全球快速 CDN,它能以快速、簡潔、優雅的方式提供任意包、任意檔案的訪問,在流行的類庫、框架文件中常常能看到它的身影。使用方式一般是unpkg.com/:package@:version/:file
。或者更簡潔一點:https://unpkg.com/
➕包名
,包名包含版本號時,你將獲得對應版本的js檔案,不包含版本號時,你將獲得這個庫的最新版js檔案。
cdnjs
cdnjs是一種免費的開源 CDN 服務,受到超過 12.5% 的網站的信任,每月處理超過 2000 億次請求,由 Cloudflare 提供支援。它類似 Google CDN 和微軟CDN服務,但是速度比這二者更加快。CDNJS 上提供了眾多 JavaScript 庫,你可以直接在網頁上引用這些 JS 檔案,實現使用者瀏覽網站的最佳速度體驗。
你還可以通過它的查詢APIhttps://api.cdnjs.com/libraries?search=xxx
進行特定庫的cdn地址的查詢,這個API還會給你返回一些你所查詢的庫的替代品。
大道至簡,繁在人心
越是“複雜”的東西,其原理也許越是趨向“簡單”,大道至簡,繁在人心,祝每一個努力攀登者,終能豁然開朗,釋然於心。