大道至簡,繁在人心:在瀏覽器控制檯安裝npm包是什麼操作?

獨釣寒江雪發表於2021-10-29
大音希聲,大象無形,大智若愚,大巧若拙,越是“複雜”的東西,其原理越趨向“簡單”,大道至簡,繁在人心

  我們都知道,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 資源地址

jquery

  是以,根據包名搜尋 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檔案內容(如果不帶版本號,會返回最新的資源):

jquery_unpkg

  也就是說,我們可以將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')的方式在控制檯進行呼叫:

console

  下面這些呼叫方式自然也是支援的:

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,它可以讓你的瀏覽器控制檯成為更強大的實驗場

  • 使用示例:

import

  • 效果圖:

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還會給你返回一些你所查詢的庫的替代品

大道至簡,繁在人心

  越是“複雜”的東西,其原理也許越是趨向“簡單”,大道至簡,繁在人心,祝每一個努力攀登者,終能豁然開朗,釋然於心。

參考資料

  本文首發於個人部落格,歡迎指正和star

相關文章