gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長(zhǎng)資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

手把手帶你從0開始創(chuàng)建并發(fā)布npm包

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

手把手帶你從0開始創(chuàng)建并發(fā)布npm包

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

背景

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

閱讀本文,你將收獲:

  • 從0開始創(chuàng)建并發(fā)布npm的全過程?!鞠嚓P(guān)教程推薦:nodejs視頻教程、編程教學(xué)】

  • 一個(gè)持續(xù)迭代且簡(jiǎn)單實(shí)用的axios請(qǐng)求去重工具庫(kù)。

工具庫(kù)準(zhǔn)備

創(chuàng)建一個(gè)新項(xiàng)目,包含package.json

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

功能實(shí)現(xiàn) /src/index.js

npm i qs axios

主要思路是用請(qǐng)求的url和參數(shù)作為key記錄請(qǐng)求隊(duì)列,當(dāng)出現(xiàn)重復(fù)請(qǐng)求時(shí),打斷后面的請(qǐng)求,將前面的請(qǐng)求結(jié)果返回時(shí)共享給后面的請(qǐng)求。

import qs from "qs"; import axios from "axios";  let pending = []; //用于存儲(chǔ)每個(gè)ajax請(qǐng)求的取消函數(shù)和ajax標(biāo)識(shí) let task = {}; //用于存儲(chǔ)每個(gè)ajax請(qǐng)求的處理函數(shù),通過請(qǐng)求結(jié)果調(diào)用,以ajax標(biāo)識(shí)為key  //請(qǐng)求開始前推入pending const pushPending = (item) => {     pending.push(item); }; //請(qǐng)求完成后取消該請(qǐng)求,從列表刪除 const removePending = (key) => {     for (let p in pending) {         if (pending[p].key === key) {             //當(dāng)前請(qǐng)求在列表中存在時(shí)             pending[p].cancelToken(); //執(zhí)行取消操作             pending.splice(p, 1); //把這條記錄從列表中移除         }     } }; //請(qǐng)求前判斷是否已存在該請(qǐng)求 const existInPending = (key) => {     return pending.some((e) => e.key === key); };  // 創(chuàng)建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) => {                         // 判斷是否存在請(qǐng)求中的當(dāng)前請(qǐng)求 如果有取消當(dāng)前請(qǐng)求                         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);             }         );          // 請(qǐng)求執(zhí)行前加入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 };
登錄后復(fù)制

新增示例代碼文件夾/example

示例入口index.js

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

api列表api.js

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

全局請(qǐng)求封裝request.js

import drrq from '../src/index.js'; const baseURL = 'https://xxx';  // 處理請(qǐng)求數(shù)據(jù)  (拼接url,data添加token等) 請(qǐng)根據(jù)實(shí)際情況調(diào)整 const paramsHandler = (url, data) => {     url = baseURL + url;     data.token = 'xxxx';     return { url, data }; };  // 處理全局接口返回的全局處理相關(guān)邏輯  請(qǐng)根據(jù)實(shí)際情況調(diào)整 const resHandler = (res) => {     // TODO 未授權(quán)跳轉(zhuǎn)登錄,狀態(tài)碼異常報(bào)錯(cuò)等     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); };
登錄后復(fù)制

測(cè)試功能

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

    "scripts": {         "test": "node example"     },
登錄后復(fù)制

執(zhí)行npm run test

手把手帶你從0開始創(chuàng)建并發(fā)布npm包

功能正常,工具庫(kù)準(zhǔn)備完畢。

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

打包

一般項(xiàng)目的打包使用webpack,而工具庫(kù)的打包則使用rollup

安裝 Rollup

通過下面的命令安裝 Rollup:

npm install --save-dev rollup
登錄后復(fù)制

創(chuàng)建配置文件

在根目錄創(chuàng)建一個(gè)新文件 rollup.config.js

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

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

安裝babel

如果要使用 es6 的語法進(jìn)行開發(fā),還需要使用 babel 將代碼編譯成 es5。因?yàn)閞ollup的模塊機(jī)制是 ES6 Modules,但并不會(huì)對(duì) es6 其他的語法進(jìn)行編譯。

安裝模塊

rollup-plugin-babel 將 rollup 和 babel 進(jìn)行了完美結(jié)合。

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

根目錄創(chuàng)建 .babelrc

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

兼容 commonjs

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

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

安裝模塊

npm install --save-dev rollup-plugin-commonjs rollup-plugin-node-resolve
登錄后復(fù)制

壓縮 bundle

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

安裝插件

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

npm install --save-dev rollup-plugin-uglify
登錄后復(fù)制

完整配置

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(),     ], };
登錄后復(fù)制

在package.json中加上

"scripts": {     "build": "rollup -c" },
登錄后復(fù)制

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

發(fā)包前的準(zhǔn)備

準(zhǔn)備npm賬號(hào),通過npm login或npm adduser。這里有一個(gè)坑,終端內(nèi)連接不上npm源,需要在上網(wǎng)工具內(nèi)復(fù)制終端代理命令后到終端執(zhí)行才能正常連接。

手把手帶你從0開始創(chuàng)建并發(fā)布npm包

準(zhǔn)備一個(gè)簡(jiǎn)單清晰的readme.md

手把手帶你從0開始創(chuàng)建并發(fā)布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": "能自動(dòng)取消重復(fù)請(qǐng)求的axios封裝",     "type": "module",     "keywords": [         "取消重復(fù)請(qǐng)求",     ],     "dependencies": {         "axios": "^1.2.0",         "qs": "^6.11.0"     },     "scripts": {         "test": "node example",         "build": "rollup -c"     },     "devDependencies": {        ...     } }
登錄后復(fù)制

  • name 包名稱 一定不能與npm已有的包名重復(fù),想一個(gè)簡(jiǎn)單易記的
  • private 是否為私有
  • version 版本
  • main 入口文件位置
  • repository git倉(cāng)庫(kù)地址
  • author 作者
  • license 協(xié)議
  • description 描述
  • keywords 關(guān)鍵詞,便于檢索

每個(gè) npm 包都需要一個(gè)版本,以便開發(fā)人員在安全地更新包版本的同時(shí)不會(huì)破壞其余的代碼。npm 使用的版本系統(tǒng)被叫做 SemVer,是 Semantic Versioning 的縮寫。

不要過分擔(dān)心理解不了相較復(fù)雜的版本名稱,下面是他們對(duì)基本版本命名的總結(jié): 給定版本號(hào) MAJOR.MINOR.PATCH,增量規(guī)則如下:

  • MAJOR 版本號(hào)的變更說明新版本產(chǎn)生了不兼容低版本的 API 等,

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

  • PATCH 版本號(hào)的變更說明你在新版本中做了向后兼容的 bug 修復(fù)。

表示預(yù)發(fā)布和構(gòu)建元數(shù)據(jù)的附加標(biāo)簽可作為 MAJOR.MINOR.PATCH 格式的擴(kuò)展。

最后,執(zhí)行npm publish就搞定啦

手把手帶你從0開始創(chuàng)建并發(fā)布npm包

手把手帶你從0開始創(chuàng)建并發(fā)布npm包

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

轉(zhuǎn)載地址:https://juejin.cn/post/7172240485778456606

贊(0)
分享到: 更多 (0)
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
黄色免费视频大全| 五月天激情视频在线观看| 国产美女在线一区| 中文字幕制服丝袜在线| 狠狠干狠狠操视频| 日韩福利视频在线| 日韩成人三级视频| 久久av秘一区二区三区| 中文字幕免费高清在线| 韩国无码av片在线观看网站| 爱福利视频一区二区| 色婷婷一区二区三区在线观看| 97av中文字幕| 国产高清av片| 亚欧美在线观看| 91蝌蚪视频在线观看| 国产无色aaa| 黄色片免费网址| 国产精品12p| 国产精品自拍片| 久久久久国产精品熟女影院| 日韩肉感妇bbwbbwbbw| 91制片厂毛片| 天天综合五月天| 亚洲中文字幕无码中文字| xx欧美撒尿嘘撒尿xx| aaaaaaaa毛片| 妞干网在线视频观看| 成人在线观看a| 中文字幕22页| 精品少妇人妻av免费久久洗澡| 粉嫩虎白女毛片人体| 成年网站免费在线观看| av 日韩 人妻 黑人 综合 无码| 国产911在线观看| 国产精品网站免费| 日韩不卡一二三| 日韩国产成人无码av毛片| 992kp快乐看片永久免费网址| 成人性生交视频免费观看| 99在线免费视频观看| 日韩肉感妇bbwbbwbbw| 蜜臀av.com| 亚洲免费一级视频| 一女被多男玩喷潮视频| 久久久国产精华液999999 | 免费在线观看污网站| 国产精品一区在线免费观看| 国产美女网站在线观看| 欧美激情第四页| 亚洲爆乳无码专区| 茄子视频成人免费观看| 成人高清dvd| 日批视频在线免费看| 东京热加勒比无码少妇| 久艹视频在线免费观看| 美女福利视频在线| 人人妻人人澡人人爽精品欧美一区| 九九精品久久久| 国产伦精品一区二区三区四区视频_ | 欧美日韩成人免费视频| 熟妇人妻va精品中文字幕| 3d动漫一区二区三区| 丁香婷婷激情网| 性欧美大战久久久久久久| 黄瓜视频免费观看在线观看www| 五月天在线免费视频| 搡女人真爽免费午夜网站| 人人干人人视频| 亚洲黄色网址在线观看| 午夜视频在线瓜伦| 免费看黄色一级大片| 国产中文字幕二区| 中文字幕国内自拍| 艳母动漫在线免费观看| 国产裸体免费无遮挡| av日韩一区二区三区| 91制片厂免费观看| jizzjizz国产精品喷水| 2018日日夜夜| 欧美综合在线观看视频| 亚洲区成人777777精品| 成人亚洲精品777777大片| 三年中国国语在线播放免费| 中文字幕日本最新乱码视频| 2018日日夜夜| 免费观看日韩毛片| 亚洲视频在线a| 天天操狠狠操夜夜操| 中文字幕av不卡在线| 日本免费在线视频观看| 超碰在线播放91| 天堂av8在线| 国产奶头好大揉着好爽视频| 免费观看国产视频在线| 人妻av无码专区| 狠狠操精品视频| 国产一区二区在线观看免费视频| 亚洲成人手机在线观看| 男女超爽视频免费播放| 伊人成人222| 欧美狂野激情性xxxx在线观| 国产视频一区二区视频| 国产高潮呻吟久久久| 欧美成人免费高清视频| 天天做天天爱天天高潮| 免费日韩视频在线观看| 久久久成人精品一区二区三区| 国产精品国产亚洲精品看不卡| 国产精品人人爽人人爽| 中文字幕乱码免费| 日韩黄色片视频| 日韩精品综合在线| 亚洲第一狼人区| 丝袜老师办公室里做好紧好爽| 四虎成人在线播放| 蜜臀av免费观看| 97xxxxx| 日韩一级特黄毛片| 亚洲欧美日韩综合网| 99精品人妻少妇一区二区| 欧美 国产 精品| 91香蕉视频免费看| 欧美三级午夜理伦三级富婆| 国产成人黄色片| 免费超爽大片黄| 黄色成人在线免费观看| 欧美午夜精品理论片| 国产极品尤物在线| 99热自拍偷拍| 人妻少妇精品无码专区二区| 久久综合在线观看| 九九九九九九九九| 亚洲欧美日韩一二三区| 香港日本韩国三级网站| caopor在线视频| 亚洲爆乳无码专区| 免费大片在线观看| 青青草原成人网| 欧美日韩在线成人| 中文字幕在线观看日| 天天色综合社区| 亚洲视频在线不卡| 麻豆视频传媒入口| 国产av天堂无码一区二区三区| 国产亚洲精品久久久久久久| 日日噜噜夜夜狠狠久久丁香五月| 欧美午夜aaaaaa免费视频| 五月天激情播播| 黄色一级片国产| 免费观看日韩毛片| 国产日韩欧美久久| 六月婷婷激情网| 少妇av一区二区三区无码| 成人毛片视频网站| 91福利国产成人精品播放| 国产美女视频免费看| 日韩欧美一级在线| 国产视频一区二区三区在线播放| 亚洲激情在线观看视频| 免费国产成人看片在线| 免费无码不卡视频在线观看| 免费看a级黄色片| 亚洲av首页在线| 日韩美女爱爱视频| 北条麻妃av高潮尖叫在线观看| 九热视频在线观看| 成年人看的毛片| 国产又大又黄又粗又爽| 日本免费a视频| 国产高潮免费视频| 日韩精品在线中文字幕| 国产激情在线观看视频| 久久99国产精品一区| 亚洲五月天综合| 日本精品福利视频| www.久久91| 国产免费毛卡片| 人妻激情另类乱人伦人妻| 色多多视频在线播放| aa视频在线播放| 国产农村妇女精品久久| 久久久久免费精品| 免费一级淫片aaa片毛片a级| 女人高潮一级片| 欧美一级特黄a| 日韩免费毛片视频| 免费人成自慰网站| 91视频成人免费| 国产又大又长又粗又黄| 久久久精品麻豆| 成人一区二区三| 久久久精品在线视频| 国产午夜大地久久| 精品成在人线av无码免费看| 亚洲第一成肉网| 亚洲欧美自偷自拍另类| 免费看国产黄色片| 孩娇小videos精品| 午夜视频在线网站|