成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

手把手帶你從0開始創建并發布npm包

都2202年了,不會有人還不會發布npm包吧?下面本篇文章給大家分享一下從0開始創建并發布npm的全過程,希望對大家有所幫助!

手把手帶你從0開始創建并發布npm包

前端(vue)入門到精通課程,老師在線輔導:聯系老師
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API調試工具:點擊使用

背景

4月發布了一篇文章,快來升級你項目內的axios封裝,向重復請求say goodbye,介紹了axios的二次封裝用于支持常規請求及自定義請求,并對同一時間內的相同請求做攔截處理(如果您沒有閱讀過這篇文章,建議您花費3分鐘大致了解)。恰逢最近準備寫一個跨框架組件庫(工作量很大,前端三個小伙伴利用空閑時間在卷,待組件庫完善后會分享給大家,敬請期待),需要學習發布npm包,昨天就想著利用空閑時間把之前寫的去除重復請求的axios封裝發布為npm包,便于代碼復用,回饋社區的同時也能學以致用。

閱讀本文,你將收獲:

  • 從0開始創建并發布npm的全過程?!鞠嚓P教程推薦:nodejs視頻教程、編程教學】

  • 一個持續迭代且簡單實用的axios請求去重工具庫。

工具庫準備

創建一個新項目,包含package.json

{     "name": "drrq",     "type": "module",     "version": "1.0.0" }
登錄后復制

功能實現 /src/index.js

npm i qs axios

主要思路是用請求的url和參數作為key記錄請求隊列,當出現重復請求時,打斷后面的請求,將前面的請求結果返回時共享給后面的請求。

import qs from "qs"; import axios from "axios";  let pending = []; //用于存儲每個ajax請求的取消函數和ajax標識 let task = {}; //用于存儲每個ajax請求的處理函數,通過請求結果調用,以ajax標識為key  //請求開始前推入pending const pushPending = (item) => {     pending.push(item); }; //請求完成后取消該請求,從列表刪除 const removePending = (key) => {     for (let p in pending) {         if (pending[p].key === key) {             //當前請求在列表中存在時             pending[p].cancelToken(); //執行取消操作             pending.splice(p, 1); //把這條記錄從列表中移除         }     } }; //請求前判斷是否已存在該請求 const existInPending = (key) => {     return pending.some((e) => e.key === key); };  // 創建task const createTask = (key, resolve) => {     let callback = (response) => {         resolve(response.data);     };     if (!task[key]) task[key] = [];     task[key].push(callback); }; // 處理task const handleTask = (key, response) => {     for (let i = 0; task[key] && i < task[key].length; i++) {         task[key][i](response);     }     task[key] = undefined; };  const getHeaders = { 'Content-Type': 'application/json' }; const postHeaders = { 'Content-Type': 'application/x-www-form-urlencoded' }; const fileHeaders = { 'Content-Type': 'multipart/form-data' };  const request = (method, url, params, headers, preventRepeat = true, uploadFile = false) => {     let key = url + '?' + qs.stringify(params);     return new Promise((resolve, reject) => {         const instance = axios.create({             baseURL: url,             headers,             timeout: 30 * 1000,         });          instance.interceptors.request.use(             (config) => {                 if (preventRepeat) {                     config.cancelToken = new axios.CancelToken((cancelToken) => {                         // 判斷是否存在請求中的當前請求 如果有取消當前請求                         if (existInPending(key)) {                             cancelToken();                         } else {                             pushPending({ key, cancelToken });                         }                     });                 }                 return config;             },             (err) => {                 return Promise.reject(err);             }         );          instance.interceptors.response.use(             (response) => {                 if (preventRepeat) {                     removePending(key);                 }                 return response;             },             (error) => {                 return Promise.reject(error);             }         );          // 請求執行前加入task         createTask(key, resolve);          instance(Object.assign({}, { method }, method === 'post' || method === 'put' ? { data: !uploadFile ? qs.stringify(params) : params } : { params }))             .then((response) => {                 // 處理task                 handleTask(key, response);             })             .catch(() => {});     }); };  export const get = (url, data = {}, preventRepeat = true) => {     return request('get', url, data, getHeaders, preventRepeat, false); };  export const post = (url, data = {}, preventRepeat = true) => {      return request('post', url, data, postHeaders, preventRepeat, false);  };  export const file = (url, data = {}, preventRepeat = true) => {      return request('post', url, data, fileHeaders, preventRepeat, true);  }; export default { request, get, post, file };
登錄后復制

新增示例代碼文件夾/example

示例入口index.js

import { exampleRequestGet } from './api.js'; const example = async () => {     let res = await exampleRequestGet();     console.log('請求成功 '); }; example();
登錄后復制

api列表api.js

import { request } from './request.js'; // 示例請求Get export const exampleRequestGet = (data) => request('get', '/xxxx', data);  // 示例請求Post export const exampleRequestPost = (data) => request('post', '/xxxx', data);  // 示例請求Post 不去重 export const exampleRequestPost2 = (data) => request('post', '/xxxx', data, false);  // 示例請求Post 不去重 export const exampleRequestFile = (data) => request('file', '/xxxx', data, false);
登錄后復制

全局請求封裝request.js

import drrq from '../src/index.js'; const baseURL = 'https://xxx';  // 處理請求數據  (拼接url,data添加token等) 請根據實際情況調整 const paramsHandler = (url, data) => {     url = baseURL + url;     data.token = 'xxxx';     return { url, data }; };  // 處理全局接口返回的全局處理相關邏輯  請根據實際情況調整 const resHandler = (res) => {     // TODO 未授權跳轉登錄,狀態碼異常報錯等     return res; };  export const request = async (method, _url, _data = {}, preventRepeat = true) => {     let { url, data } = paramsHandler(_url, _data);     let res = null;     if (method == 'get' || method == 'GET' || method == 'Get') {         res = await drrq.get(url, data, preventRepeat);     }     if (method == 'post' || method == 'POST' || method == 'Post') {         res = await drrq.post(url, data, preventRepeat);     }     if (method == 'file' || method == 'FILE' || method == 'file') {         res = await drrq.file(url, data, preventRepeat);     }     return resHandler(res); };
登錄后復制

測試功能

代碼寫完后,我們需要驗證功能是否正常,package.json加上

    "scripts": {         "test": "node example"     },
登錄后復制

執行npm run test

手把手帶你從0開始創建并發布npm包

功能正常,工具庫準備完畢。

(eslint和prettier讀者可視情況選用)

打包

一般項目的打包使用webpack,而工具庫的打包則使用rollup

安裝 Rollup

通過下面的命令安裝 Rollup:

npm install --save-dev rollup
登錄后復制

創建配置文件

在根目錄創建一個新文件 rollup.config.js

export default {   input: "src/index.js",   output: {     file: "dist/drrp.js",     format: "esm",     name: 'drrp'   } };
登錄后復制

  • input —— 要打包的文件
  • output.file —— 輸出的文件 (如果沒有這個參數,則直接輸出到控制臺)
  • output.format —— Rollup 輸出的文件類型

安裝babel

如果要使用 es6 的語法進行開發,還需要使用 babel 將代碼編譯成 es5。因為rollup的模塊機制是 ES6 Modules,但并不會對 es6 其他的語法進行編譯。

安裝模塊

rollup-plugin-babel 將 rollup 和 babel 進行了完美結合。

npm install --save-dev rollup-plugin-babel@latest npm install --save-dev @babel/core  npm install --save-dev @babel/preset-env
登錄后復制

根目錄創建 .babelrc

{     "presets": [       [         "@babel/preset-env",         {           "modules": false         }       ]     ] }
登錄后復制

兼容 commonjs

rollup 提供了插件 rollup-plugin-commonjs,以便于在 rollup 中引用 commonjs 規范的包。該插件的作用是將 commonjs 模塊轉成 es6 模塊。

rollup-plugin-commonjs 通常與 rollup-plugin-node-resolve 一同使用,后者用來解析依賴的模塊路徑。

安裝模塊

npm install --save-dev rollup-plugin-commonjs rollup-plugin-node-resolve
登錄后復制

壓縮 bundle

添加 UglifyJS 可以通過移除注上釋、縮短變量名、重整代碼來極大程度的減少 bundle 的體積大小 —— 這樣在一定程度降低了代碼的可讀性,但是在網絡通信上變得更有效率。

安裝插件

用下面的命令來安裝 rollup-plugin-uglify:

npm install --save-dev rollup-plugin-uglify
登錄后復制

完整配置

rollup.config.js 最終配置如下

import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import babel from 'rollup-plugin-babel'; import { uglify } from 'rollup-plugin-uglify'; import json from '@rollup/plugin-json'  const paths = {     input: {         root:  'src/index.js',     },     output: {         root:  'dist/',     }, };  const fileName = `drrq.js`;  export default {     input: `${paths.input.root}`,     output: {         file: `${paths.output.root}${fileName}`,         format: 'esm',         name: 'drrq',     },     plugins: [         json(),         resolve(),         commonjs(),         babel({             exclude: 'node_modules/**',             runtimeHelpers: true,         }),         uglify(),     ], };
登錄后復制

在package.json中加上

"scripts": {     "build": "rollup -c" },
登錄后復制

即可執行npm run build將/src/index.js打包為/dist/drrq.js

發包前的準備

準備npm賬號,通過npm login或npm adduser。這里有一個坑,終端內連接不上npm源,需要在上網工具內復制終端代理命令后到終端執行才能正常連接。

手把手帶你從0開始創建并發布npm包

準備一個簡單清晰的readme.md

手把手帶你從0開始創建并發布npm包

修改package.json

完整的package.json如下

{     "name": "drrq",     "private": false,     "version": "1.3.5",     "main": "/dist/drrq.js",     "repository": "https://gitee.com/yuanying-11/drrq.git",     "author": "it_yuanying",     "license": "MIT",     "description": "能自動取消重復請求的axios封裝",     "type": "module",     "keywords": [         "取消重復請求",     ],     "dependencies": {         "axios": "^1.2.0",         "qs": "^6.11.0"     },     "scripts": {         "test": "node example",         "build": "rollup -c"     },     "devDependencies": {        ...     } }
登錄后復制

  • name 包名稱 一定不能與npm已有的包名重復,想一個簡單易記的
  • private 是否為私有
  • version 版本
  • main 入口文件位置
  • repository git倉庫地址
  • author 作者
  • license 協議
  • description 描述
  • keywords 關鍵詞,便于檢索

每個 npm 包都需要一個版本,以便開發人員在安全地更新包版本的同時不會破壞其余的代碼。npm 使用的版本系統被叫做 SemVer,是 Semantic Versioning 的縮寫。

不要過分擔心理解不了相較復雜的版本名稱,下面是他們對基本版本命名的總結: 給定版本號 MAJOR.MINOR.PATCH,增量規則如下:

  • MAJOR 版本號的變更說明新版本產生了不兼容低版本的 API 等,

  • MINOR 版本號的變更說明你在以向后兼容的方式添加功能,接下來

  • PATCH 版本號的變更說明你在新版本中做了向后兼容的 bug 修復。

表示預發布和構建元數據的附加標簽可作為 MAJOR.MINOR.PATCH 格式的擴展。

最后,執行npm publish就搞定啦

手把手帶你從0開始創建并發布npm包

手把手帶你從0開始創建并發布npm包

本文的完整代碼已開源至gitee.com/yuanying-11… ,感興趣的讀者歡迎fork和star!

轉載地址:https://juejin.cn/post/7172240485778456606

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
超鹏97国语在线| YY111111少妇无码理论片| 在线V观看免费国岛国片| 中国JAPANESE高潮尖叫| 99亚洲乱人伦AⅤ精品| 啊灬用力灬啊灬啊灬啊灬电子书| 厨房丝袜麻麻被进进出出| 高清一个人看WWW免费| 国产精品香港三级国产AV| 精品国精品国产自在久国产应用 | 成人无码区免费AⅤ片在线观看 | 欧美精品人人做人人爱视频| 日本精产国品一二三产品区别| 特级毛片内射WWW无码| 亚洲 欧美 中文 日韩AⅤ手机| 亚洲情A成黄在线观看动漫尤物| 中字年轻漂亮的儿媳BD| 巴西FREE性VIDEO极品| 国产SUV精品一区二区883| 黑人巨大精品欧美黑寡妇| 看国产黄大片在线观看| 人妻无码一区二区视频| 人妻含泪让粗大挺进| 人妻丰满妇岳av无码区HD| 凸凹人妻人人澡人人添医| 亚洲欧洲专线一区| Japanese日本护士XXXX18一19| 欧美成人综合久久精品| 欧美最婬乱婬爆婬牲视| 我被公么征服了HD中文字幕| 亚洲熟妇丰满美女XXXXX| 99亚洲国产精品精华液| 国产激情一区二区三区小说 | 少妇18p一区二区三区| 亚洲爆乳中文字幕无码专区网站| 中国熟妇毛多多裸交视频| 多毛freeoprn熟妇多毛y| 激情五月丁香六月综合AVXXXX | 999久久久免费精品国产| 国产成年无码AⅤ片在线观看| 精品亚洲自慰AV无码喷奶水| 人人妻人人澡人人爽人人精品电影| 性孕交大肚子孕妇| 337P日本大胆欧美裸体艺术| 国产精品久久久尹人香蕉| 裸体美女洗澡啪啪裸J网站| 水多的女人男人最上瘾| 影音先锋中文字幕人妻| 国产97色在线 | 亚洲| 久久久久亚洲AV无码专区喷水| 色欲av无码一区二区人妻精油| 无码人妻久久一区二区三区蜜桃| 亚洲色婷婷综合久久| А√天堂中文最新版在线种子| 国产亚洲成AⅤ人片在线观看| 少妇大叫太大太爽受不了| 亚洲人成影院在线无码按摩店 | 亚洲AV无码国产蜜桃麻豆| FREE MOVIES 日本护| 黑人精品XXX一区一二区| 人妻美妇疯狂迎合系列视频| 亚洲女久久久噜噜噜熟女| 成人欧美一区二区三区黑人牛| 久久WWW免费人成_看片中文| 日韩视频一二三区2021| 玉蒲团Ⅲ艳乳欲仙欲| 国产精品人人妻人色五月| 欧美极品小妇另类xXXX性| 亚洲AV永久无码精品无码一区二区| XXXXBBBB欧美残疾人| 久久精品国产亚洲AV蜜臀色欲 | 国产乱码字幕精品高清AV| 欧美交换配乱吟粗大| 亚洲人成网站18禁止大| 国产SUV精品一区二区88L| 免费无遮挡无码永久在线观看视频 | 久久久99久久久国产自输拍| 无码av无码免费一区二区毛片| H漫无码动漫AV动漫在线播放| 久久99精品久久只有精品| 我和公GONG在厨房日本电影| YOUJIZZ中国熟女| 久久亚洲AⅤ精品网站| 亚洲AV毛茸茸av成熟女人| 成码无人AV片在线电影网站| 蜜芽AⅤ色欲AV浪潮夜夜嗨| 亚洲AV一二三又爽又色又色| 国产AⅤ精品一区二区三理论片 | 成年免费A级毛片免费看| 另类小说激情婷婷久久| 亚洲成a人蜜臀AV在线播放| 国产成人精品免费午夜APP| 人妻妺妺窝人体色WWW聚色窝 | 亚洲爆乳无码一区二区三区| 国产精品国产亚洲精品看不卡| 日本H纯肉无遮掩3D动漫在线观| 中文天堂在线最新版在线WWW| 饥渴人妻被快递员玩弄的视频| 无码精品国产VA在线观看| 成人网站亚洲二区乱码| 欧美性猛交乱大交3| 真实的国产乱ⅩXXX66| 精品无码人妻被多人侵犯aⅴ| 午夜成人鲁丝片午夜精品| 丰满熟妇VIDEOSXXXX| 日本A级作爱免费观看在线| 99久热RE在线精品视频| 麻花豆传媒剧国产MV在线上-| 亚洲无人区一码二码三码区别| 果冻传媒一区二区天美传媒 | 国产强伦姧在线观看无码| 四川50岁熟妇大白屁股真爽| 波多野结衣一区二区三区高清| 年轻的嫂嫂2在线播放在线播放 | 国产777涩在线 | 美洲| 日韩人妻无码精品—专区| 波多野结衣迅雷种子| 人禽伦免费交视频播放| 啊轻点灬大JI巴太粗太长了欧美| 欧美男生射精高潮视频网站| 99久久综合狠狠综合久久| 男人猛躁进女人免费播放| 中国无码人妻丰满熟妇啪啪软件| 久久亚洲精品无码爱剪辑| 野花韩国高清免费神马| 久久欧美极品少妇XXXXⅩ| 亚洲综合成人婷婷五月在线观看| 久久ZYZ资源站无码中文动漫| 亚洲精品无码久久久影院相关影片 | 性色AV夜夜嗨AV浪潮牛牛| 国产无人区卡一卡二扰乱码| 亚洲AV成人一区二区三区天堂| 国产女主播喷水视频在线观看| 亚洲 暴爽 AV人人爽日日碰| 国语自产少妇精品视频蜜桃| 亚洲成AV人在线观看成年美女| 激情偷乱人伦小说视频| 亚洲人成色77777| 久久综合给合久久狠狠狠97色6| 在线无码VA中文字幕无码| 美女高潮黄又色高清视频免费| 制服 丝袜 亚洲 中文 综合| 激情男女高潮射精AV免费| 铜铜铜铜铜铜铜铜铜好大好深色 | 狠狠人妻久久久久久综合| 亚洲国产AV一区二区三区| 精品亚洲国产成人AV在线| 影音先锋女人AV女色资源| 欧美疯狂做受XXXX| 被义子侵犯的漂亮人妻中字| 色欲色AV免费观看| 国产亲子伦ⅩⅩⅩⅩX熟妇| 亚洲国产成人综合在线不卡| 久久久WWW免费人成精品| 中文字幕夫の上司に犯新沢平兰| 欧美人与禽ZOZZO| 大乳VIDEOS巨大吃奶| 无线乱码A区B区C区| 精品成人毛片一区二区| 永久免费AⅤ无码网站在线观看 | 性ⅩXXX搡XXXX搡| 久久97人妻无码一区二区三区| 中国娇小与黑人巨大交| 人妻 色综合网站| 国产成AV人片在线观看天堂无码 | 精品韩国AV无码一区二区三区| 一边摸一边叫床一边爽AV| 女人另类牲交ZOZOZO| 荡女小姿的YIN乱生活| 亚洲AV成人无码久久精品老人 | きょこんきょうしゃ在线| 少女のトゲ在线观看动漫| 狠狠人妻熟妇Av又粗又大| 中文精品久久久久人妻| 日韩无码av一区二区| 国内精自线一二三四2021| 岳今晚让我玩个够肥水一体探岳体| 全黄H全肉边做边吃奶| 国产清纯美女爆白浆视频| 伊人成年网站综合网| 日韩 无码 偷拍 中文字幕| 国产最好的高清播放机品牌| 在线观看免费AV网站| 日日狠狠久久8888偷偷色| 狠狠躁夜夜躁人人爽天天天天97| 中文字幕一区二区三区乱码| 少妇人妻14页_麻花色| 精品无码国产自产野外拍在线| CHINESE熟女熟妇1乱| 亚洲 国产 韩国 欧美 在线| 妺妺窝人体色www聚色窝图片 | 老根嫩草1一40淑媛全文| 成人特黄A级毛片免费视频| 亚洲插肏熟女人妇的屄网址| 欧美日本操逼视频| 国产亚洲欧美日韩在线一区二区三| 中文字幕AV无码一区二区蜜芽三| 四虎精品成人免费视频| 狂野欧美性猛XXXX乱大交| 国产成人AV一区二区三区无码|