自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

怎樣寫一個能同時用于Node和瀏覽器的JavaScript包?

開發(fā) 前端
我在這個問題上見過很多困惑,即使是很有經(jīng)驗(yàn)的 JavaScript 開發(fā)者也可能難以把握其中的巧妙之處。因此我認(rèn)為值得為它書寫一小段教程。

我在這個問題上見過很多困惑,即使是很有經(jīng)驗(yàn)的 JavaScript 開發(fā)者也可能難以把握其中的巧妙之處。因此我認(rèn)為值得為它書寫一小段教程。

[[184498]]

我在這個問題上見過很多困惑,即使是很有經(jīng)驗(yàn)的 JavaScript 開發(fā)者也可能難以把握其中的巧妙之處。因此我認(rèn)為值得為它書寫一小段教程。

假設(shè)你有一個 JavaScript 的模塊想要發(fā)布到 npm 上,它是同時適用于 Node 和瀏覽器的。但是請注意!這個特殊的模塊在 Node 版本和瀏覽器版本上的實(shí)現(xiàn)有著細(xì)微的區(qū)別。

這種情況出現(xiàn)得實(shí)在頻繁,因?yàn)樵?Node 和瀏覽器間有著很多微小的環(huán)境差別。在這種情況下,可以用比較巧妙的方法來正確地實(shí)現(xiàn),尤其是當(dāng)你在嘗試著使用最小的 browser 包(bundle)來優(yōu)化的時候。

讓我們構(gòu)建一個 JS 包

因此讓我們來寫一個小的 JavaScript 包,叫做 base64-encode-string。它所做的只是接收一個字符串作為輸入,輸出其 base64 編碼的版本。

對于瀏覽器來說,這很簡單:我們只需要使用自帶的 btoa 函數(shù):

  1. module.exports = function (string) { 
  2.   return btoa(string); 
  3. }; 

然而在 Node 里并沒有 btoa 函數(shù)。因此,作為替代,我們需要自己創(chuàng)建一個 Buffer,然后在上面調(diào)用 buffer.toString()

  1. module.exports = function (string) { 
  2.   return Buffer.from(string, 'binary').toString('base64'); 
  3. }; 

對于一個字符串,這兩者都應(yīng)提供其正確的 base64 編碼版本,比如:

  1. var b64encode = require('base64-encode-string'); 
  2. b64encode('foo');    // Zm9v 
  3. b64encode('foobar'); // Zm9vYmFy 

現(xiàn)在我們只需要一些方法來檢測我們究竟是在瀏覽器上運(yùn)行還是在 Node 上,好讓我們能保證使用正確的版本。Browserify 和 Webpack 都定義了一個叫 process.browser 的字段,它會返回 true(譯者注:即瀏覽器環(huán)境下),然而在 Node 上這個字段返回 false。所以我們只需要簡單地:

  1. if (process.browser) { 
  2.   module.exports = function (string) { 
  3.     return btoa(string); 
  4.   }; 
  5. else { 
  6.   module.exports = function (string) { 
  7.     return Buffer.from(string, 'binary').toString('base64'); 
  8.   }; 

現(xiàn)在我們只需要把我們的文件命名為 index.js,鍵入 npm publish,我們就完成了,對不對?好的吧,這個方法有效,但不幸的是,這種實(shí)現(xiàn)有一個巨大的性能問題。

因?yàn)槲覀兊?index.js 文件包含了對 Node 自帶的 processBuffer 模塊的引用,Browserify 和 Webpack 都會自動引入 polyfill,來將它們打包進(jìn)這些模塊。

對于這個簡單的九行模塊,我算了一下, Browserify 和 Webpack 會創(chuàng)建 一個壓縮后有 24.7KB 的包 (7.6KB min+gz)。對于這種東西,用掉的空間實(shí)在是太多,因?yàn)樵跒g覽器里,只需要 btoa 就能表示這個。

“browser” 字段,我該如何愛你

如果你在 Browserify 或者 Webpack 文檔里找解決這個問題的提示,你可能最后會發(fā)現(xiàn) node-browser-resolve。這是一個對于 package.json 內(nèi) "browser" 字段的規(guī)范,可以被用于定義在瀏覽器版本構(gòu)建時需要被換掉的東西。

使用這種技術(shù),我們可以將接下來這段加入我們的 package.json

  1.   /* ... */ 
  2.   "browser": { 
  3.     "./index.js""./browser.js" 
  4.   } 

然后將函數(shù)分割成兩個不同的文件:index.jsbrowser.js

  1. // index.js 
  2. module.exports = function (string) { 
  3.   return Buffer.from(string, 'binary').toString('base64'); 
  4. }; 
  5.  
  6. // browser.js 
  7. module.exports = function (string) { 
  8.   return btoa(string); 
  9. }; 

有了這次改進(jìn)以后,Browserify 和 Webpack 會給出 更加合理的包:Browserify 的包壓縮后是 511 字節(jié)(315 min+gz),Webpack 的包壓縮后是 550 字節(jié)(297 min+gz)。

當(dāng)我們將我們的包發(fā)布到 npm 時,在 Node 里運(yùn)行 require('base64-encode-string') 的人將得到 Node 版的代碼,在 Browserfy 和 Webpack 里跑的人會得到瀏覽器版的代碼。

對于 Rollup 來說,這就有點(diǎn)復(fù)雜了,但也不需要太多額外的工作。Rollup 用戶需要使用 rollup-plugin-node-resolve 并在選項里將 browser 設(shè)置為 true

對 jspm 來說,很不幸地,沒有對 “browser” 字段的支持,但是 jspm 用戶可以通過 require('base64-encode-string/browser') 或者 jspm install npm:base64-encode-string -o "{main:'browser.js'}" 來迂回地解決問題。另一種方法是,包的作者可以在他們的 package.json指定一個 “jspm” 字段。

進(jìn)階技巧

這種直接使用的 "browser" 方法可以工作得很好,但是對于大型項目來說,我發(fā)現(xiàn)它在 package.json 和代碼庫間引入了一種尷尬的耦合。比如說,我們的 package.json 會很快長成這樣:

  1.   /* ... */ 
  2.   "browser": { 
  3.     "./index.js""./browser.js"
  4.     "./widget.js""./widget-browser.js"
  5.     "./doodad.js""./doodad-browser.js"
  6.     /* etc. */ 
  7.   } 

在這種情況下,任何時候你想要一個適配于瀏覽器的模塊,都需要分別創(chuàng)建兩個文件,并且要記住在 "browser" 字段上添加額外行來將它們連接起來。還要注意不能拼錯任何東西!

并且,你會發(fā)現(xiàn)你在費(fèi)盡心機(jī)地將微小的代碼提取到分離的模塊里,僅僅是因?yàn)槟阆胍苊?if (process.browser) {} 檢查。當(dāng)這些 *-browser.js 文件積累起來的時候,它們會開始讓代碼庫變得很難跳轉(zhuǎn)。

如果這種情況變得實(shí)在太笨重了,有一些別的解決方案。我自己的偏好是使用 Rollup 作為構(gòu)建工具,來自動地將單個代碼庫分割到不同的 index.jsbrowser.js 文件里。這對于將你提供給用戶的代碼的解模塊化有額外的價值,節(jié)省了空間和時間。

要這樣做的話,先安裝 rolluprollup-plugin-replace,然后定義一個 rollup.config.js 文件:

  1. import replace from 'rollup-plugin-replace'
  2. export default { 
  3.   entry: 'src/index.js'
  4.   format: 'cjs'
  5.   plugins: [ 
  6.     replace({ 'process.browser': !!process.env.BROWSER }) 
  7.   ] 
  8. }; 

(我們將使用 process.env.BROWSER 作為一種方便地在瀏覽器構(gòu)建和 Node 構(gòu)建間切換的方式。)

接下來,我們可以創(chuàng)建一個帶有單個函數(shù)的 src/index.js 文件,使用普通的 process.browser 條件:

  1. export default function base64Encode(string) { 
  2.   if (process.browser) { 
  3.     return btoa(string); 
  4.   } else { 
  5.     return Buffer.from(string, 'binary').toString('base64'); 
  6.   } 

然后將 prepublish 步驟添加到 package.json 內(nèi),來生成文件:

  1.   /* ... */ 
  2.   "scripts": { 
  3.     "prepublish""rollup -c > index.js && BROWSER=true rollup -c > browser.js" 
  4.   } 

生成的文件都相當(dāng)直白易讀:

  1. // index.js 
  2. 'use strict'
  3.  
  4. function base64Encode(string) { 
  5.   { 
  6.     return Buffer.from(string, 'binary').toString('base64'); 
  7.   } 
  8.  
  9. module.exports = base64Encode; 
  10.  
  11. // browser.js 
  12. 'use strict'
  13.  
  14. function base64Encode(string) { 
  15.   { 
  16.     return btoa(string); 
  17.   } 
  18.  
  19. module.exports = base64Encode; 

你將注意到,Rollup 會按需自動地將 process.browser 轉(zhuǎn)換成 true 或者 false,然后去掉那些無用代碼。所以在生成的瀏覽器包里不會有對于 process 或者 Buffer 的引用。

使用這個技巧,在你的代碼庫里可以有任意個的 process.browser 切換,并且發(fā)布的結(jié)果是兩個小的集中的 index.jsbrowser.js 文件,其中對于 Node 只有 Node 相關(guān)的代碼,對于瀏覽器只有瀏覽器相關(guān)的代碼。

作為附帶的福利,你可以配置 Rollup 來生成 ES 模塊構(gòu)建,IIFE 構(gòu)建,或者 UMD 構(gòu)建。如果你想要示例的話,可以查看我的項目 marky,這是一個擁有多個 Rollup 構(gòu)建目標(biāo)的簡單庫。

在這篇文章里描述的實(shí)際項目(base64-encode-string)也同樣被 發(fā)布到 npm 上 ,你可以審視它,看看它是怎么做到的。源碼 在 GitHub 上。

 

責(zé)任編輯:張燕妮 來源: 開源中國社區(qū)
相關(guān)推薦

2012-08-14 10:44:52

解釋器編程

2017-12-14 15:45:02

2021-06-02 06:14:50

Nyxt瀏覽器

2012-09-03 10:24:16

果粉瀏覽器

2009-05-27 08:54:15

瀏覽器平臺Chrome

2019-12-02 13:46:35

瀏覽器前端開發(fā)

2017-01-05 09:07:25

JavaScript瀏覽器驅(qū)動

2011-04-14 15:55:35

WPF.NET

2022-06-20 09:01:56

Plasmo開源

2014-08-18 14:58:25

微軟IE

2020-07-06 08:23:11

開源瀏覽器操作系統(tǒng)

2022-06-13 06:33:04

瀏覽器瀏覽器插件

2016-10-09 08:38:01

JavaScript瀏覽器事件

2012-01-04 13:55:23

Canvas

2021-08-06 16:52:10

瀏覽器HTTPS通信

2012-04-25 14:06:45

HTML5

2023-01-18 14:16:16

lnavLinux瀏覽器

2020-03-12 11:29:51

JavaScript瀏覽器語言

2012-04-11 13:46:33

ibmdw

2014-02-14 09:37:01

JavascriptDOM
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號