如何發布一個 npm 包


一 背景

在工作時,突然接到經理的一個要求,需要將一個react的高階組件函數封裝成一個npm包。之前從沒弄過,當場還是有些懵逼的,但是這畢竟是工作,不能推脫。於是開始了學習、湯坑之旅。最終包發布,線上項目成功使用,雖然導致了一次線上故障,但還是快速地fix掉。吃一塹長一智,記錄一下整個發布的過程和遇到的一些問題。

二 流程

npm 包可以將可復用邏輯封裝成一個工具庫,依賴 npm 的強大生態,可以在項目中引入,讓代碼變得更加簡潔,提高效率。

  1. 在 npm 官網注冊一個賬號。
  2. 在本地登錄 npm 賬號。
  3. 編寫 npm 包內容。
  4. 發布包。

三 開發過程

1 注冊npm賬號。

附錄網站: https://www.npmjs.com/

2 在本地登錄npm賬號。

npm login

輸入在npm官網注冊的賬號密碼即可。

3 編寫npm包

3.1 執行以下命令,創建一個npm模塊

mkdir npmDir
cd npmDir
npm init -y

3.2 安裝webpack

npm install webpack webpack-ci -D

在本地開發時,通常考慮更多的是代碼的可讀性,以便於在邏輯出錯時,可debug其源碼找到問題。然而發至線上時,則考慮更多的是包的體積,越小即代表着更快的載入。
同時,一個強大的包應該支持多種方式導入,例如es module的import,commonjs的require以及amd的古老方式。
為做到以上兩點,選擇了webpack作為構建工具。雖然用webpack個人感覺稍微有點重,但是它可擴展性強,日后利用loader以及plugin可以實現更多的編譯以及優化需求。

3.3 梳理項目目錄


src下的index.js對應着包的內容。
最外層index.js為所暴露的出口文件。
dist目錄存放webpack打包后的文件。

3.4 編寫對應內容

3.4.1 webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
   mode: 'none',
   entry: {
       'add': './src/index.js',
       'add.min': './src/index.js'
   },
   output: {
       filename: '[name].js',
       library: 'add',
       libraryTarget: 'umd',
       libraryExport: 'default',
       globalObject: 'this'
   },
   optimization: {
       minimize: true,
       minimizer: [
           new TerserPlugin({
               include: /\.min\.js$/,
           })
       ]
   }
}
  1. mode: 支持開發版代碼不壓縮,線上版本壓縮。此處將mode設置為'none',默認全不壓縮,然后自己用插件來配置壓縮代碼文件。

  2. entry: 兩個入口,add為在開發時導入,add.min文件為在線上時導入。

  3. output:

    • filename: 設置占位符。默認為entry入口文件名字
    • library: 庫的返回值賦值給變量或者屬性 add。例如script引入方式,則可以全局使用add函數。此屬性和library配合使用
    • libraryTarget: 變量暴露的方式。設置為umd即可支持es module、cmd以及script引入腳本的方式使用。
    • libraryExport: 配置要導出的模塊中那些子模塊需要被導出。只有output.libraryTarget被設置成commonjs或者commonjs2的時候才有效。我的導出方式是export default,因此我將其直接導出。如果不填此項,則默認引入的是module對象。調用方式會是 .default形式。
  4. optimization: 利用TerserPlugin插件進行壓縮代碼,默認只壓縮.min結尾的輸出文件。

3.4.2 模塊主要內容 src/index.js

  const add = (...rest) => {
    console.log(rest)
    alert('哈哈')
  }

  export default add

簡單的一個測試函數

3.4.3 main入口文件index.js

  if (process.env.NODE_ENV === 'production') {
    module.exports = require('./dist/add.min.js');
  } else {
    module.exports = require('./dist/add.js')
  }

根據環境變量自動引入相關版本。

3.4.4 構建命令。package.json

  "scripts": {
    "test": "npm test",
    "build": "webpack",
    "prepublish": "webpack"
  },

發布包時可以手動執行build命令后后發布,也可通過prepublish鈎子自動編譯然后發布。

4 發布包

修改 package.json 中的name字段,即包在npm中的名字。小提示,想好名字之后,最好到npm官網上搜索一下這個包有沒有被別人注冊,有的話就要換一個了。
修改版本號,可手動修改,也可通過npm version命令進行更換。個人習慣於后面。

# 修改版本號
npm version major | minorr | patch
# 發布包到npm
npm publish

然后在npm官網上搜索一下,便可以找到你發布的包了。開心。

四 遇到的問題

4.1 在服務端渲染(ssr)的項目中引入該包時,會報錯誤 ”window is not defined“

本以為是包中代碼邏輯錯誤,把項目中所有引入到window的地方全都用typeof兼容了一遍,本想完事大吉,結果還是報這個錯誤。上網搜索各種帖子無效之后,我感覺是webpack編譯打包后出了問題,於是報着試一試的心態去看編譯后的未壓縮版本代碼,果然發現了問題。

如圖所示,打包后的文件為一個自運行匿名函數,函數第一個實參竟然是window。
於是去webpack官網查看相關文檔,看其是否能配置。果然找到了
-w728
修改globalObject屬性,將第一個參數設置為this,解決問題。

附錄
gihub: https://github.com/ShengGaoW/shenggao-test-npm


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM