你知道如何使用 Webpack 工具打包類庫嗎?

2021-09-13 23:24:11 字數 3865 閱讀 4408

在編寫庫的時候,我們有時候會希望按需載入某些依賴,例如如果**的執行環境不支援某些功能的話,就載入相關的 polyfill 。

webpack 作為當前最流行的打包工具,早已支援動態載入的功能了。

本文將討論一種用 webpack 打包含動態載入的類庫的方法。

注意,本文是寫給類庫作者看的,如果讀者寫的是應用,那就沒有必要往下看了。

示例類庫

// my-lib.jsclass mylib  else 

});}

initialize() }

這個類庫中有個 loaddeps 方法,會根據執行環境檢測 textdecoder 是否存在,如果不存在就會去載入依賴,這些依賴是在本地目錄中。

當我們把類庫發布到 npm 之後,我們就會這麼使用它:

constructor() ,

// ...};然後輸出了這些檔案:

// webpack outputbuilt at: 02/19/2019 5:08:41 pm

asset      size  chunks             chunk names

1.js  79 bytes       1  [emitted]

2.js  79 bytes       2  [emitted]

3.js  79 bytes       3  [emitted]

index.js   144 kib       0  [emitted]  main

entrypoint main = index.js

/1.js/2.js/3.js
但是結果呢?當然是 404 了。因為**的根目錄沒有這些檔案呀,除非你把這些檔案複製到**根目錄。

同樣道理,如果 publicpath 是相對路徑的話(假設是 『』),那麼請求依賴的路徑就會相對於當前的 url 了,即如果當前 url 是 /topics/:uid,那請求的路徑就會是 /topics/:uid/1.js。除非當前目錄下有這些依賴,不然結果還是 404。

當然,我們還可以修改服務端配置,把 /1.js 和 **/1.js 都指向 /path/to/project/node_modules/my-lib/dist/1.js。

對應用層來說,為了乙個庫而改伺服器配置就顯得太麻煩了。

對乙個類庫來說,它應該管理好自己的依賴,不應該讓應用層甚至是伺服器端來配合。

解決方案

我們需要解決這個路徑問題,既要保證結果正確,又要方便開發。

很明顯,這個問題是因為 webpack 打包的時候處理了 import() 導致的,如果我們不在編譯時處理,而是執行時處理,這不就可以達到目的了嗎?

先來準備一下 dist/ 的目錄結構, 修改 webpack 的配置:

const copywebpackplugin = require('copy-webpack-plugin');module.exports = ,

plugins: [

new copywebpackplugin()

]}

copywebpackplugin 會把 src/deps/ 中的檔案複製到 dist/ 目錄中,這時候 dist/ 就會變成:

dist

├── 1.js├── 2.js├── 3.js├── text-encoding.js

├── other-dep.js

├── another-dep.js

└── index.js

方案一:由應用層處理

這個方案很容易實現,只需要讓應用層來呼叫 import() 就可以了。

// my-lib.jsclass mylib 

loaddeps() else

} else

});constructor() );

}}

這種做法非常簡單,而且在開發環境下也不需要任何處理就能正常執行了。

不足之處是如果有多個專案都引用了這個類庫的話,那麼當類庫新增了新的依賴時,所有引用了這個類庫的專案都要改動原始碼。這會是乙個比較繁瑣的事情。

對於這個解決方案,其實還有乙個變種,相對來說更加方便:

// my-lib.jsclass mylib 

loaddeps() else

});constructor() );

}}

注意:這個變種方案有可能會出現 critical dependency: the request of a dependency is an expression 的報錯。

方案二:由類庫處理

這個方案稍微複雜一點點。

想要 webpack 不處理 import(),那麼就不能讓 webpack 去解析含有 import() 的檔案,即需要把含有載入依賴的部分分離到另乙個檔案中。

// runtime.jsmodule.exports = }
注意:因為 webpack 不會解析這個檔案,loader 就不會處理這個檔案,所以這個檔案裡面最好使用 node.js 原生支援的語法。

// my-lib.jsimport runtime from './runtime';class mylib  else 

});}}

然後修改 webpack 配置:

module.exports = ,

module: ,

plugins: [ ... ]

}

這樣,webpack 在處理 my-lib.js 的時候會把 runtime.js 載入進來,但不會去解析它。所以會得到以下的結果:

// dist/index.js/******/ ([/* 0 *//***/ (function(module, exports) };/***/ }),/* 1 *//***/ (function(module, __webpack_exports__, __webpack_require__) 

var _proto = mylib.prototype;

_proto.loaddeps = function loaddeps() else

});};

_proto.initialize = function initialize() ;

return mylib;}();// ...

如果應用層引用了這個類庫,那麼 webpack 打包應用的時候就會處理類庫中的 import(),這樣就和應用層平時的動態載入一樣了,上面的問題也就解決了。

最後剩下乙個問題,那就是在開發環境下,我們也需要測試 runtime.js,但這時候它是 import(『my-lib/dist/***』) 的,這個肯定會報 error: cannot find module 的錯誤。

這時候可以像方案一那樣,用 import(importprefix + 『/text-encoding』) 的方式來解決,也可以利用 normalmodulereplacementplugin 來解決。

// webpack.dev.jsmodule.exports = ),

]}

這個外掛程式可以改變重定向資源,上面的配置是把 my-lib/dist/* 裡面的資源都重定向到 ../src/deps。

更多詳細的用法,可以參考下官方文件 normalmodulereplacementplugin。

注意:這個外掛程式最好只用在開發環境中。

這個方案雖然有些繁瑣,但最大的優點是可以把依賴管理都交給類庫自己處理,不需要應用層干預。就算類庫日後改變打包位置(不再是 dist/) 也無需讓應用層知道。

軟工文件你知道嗎?

前言 從軟體開發周期來看 從文件型別來看 通過以上這兩個導圖,我們大致可以分清在什麼階段需要寫什麼文件,這對於我們以後的工作是很有幫助的。需要注意的是我們是根據文件來開發軟體,而不是開發完軟體之後根據你所開發的詳情寫文件。那我們編寫文件的作用是什麼呢?文件名稱 文件的作用 可行性研究報告 從經濟 技...

Apple 如何知道你使用了私有API

寫在開頭 ios開發者 群532084214 給大家提供乙個交流技術 也可以聊天打屁的平台 otool l 這個工具可以清晰的列出你鏈結所有的庫 像io.kit是不允許使用的 nm u 這個工具可以清晰的列出你所有鏈結符號 如 c方法 oc方法 檢查所有selecter的字串 occlass sel...

如何使用webpack打包JS

我們在命令列中輸入 webpack h看看webpack的命令列大全 usage webpack cli options webpack cli options entry output webpack cli options outputwebpack告訴我們,用webpack進行打包有三種方法 ...