前端(vue)入門到精通課程,老師線上輔導:聯絡老師
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:
4月釋出了一篇文章,,介紹了axios的二次封裝用於支援常規請求及自定義請求,並對同一時間內的相同請求做攔截處理(如果您沒有閱讀過這篇文章,建議您花費3分鐘大致瞭解)。恰逢最近準備寫一個跨框架元件庫(工作量很大,前端三個小夥伴利用空閒時間在卷,待元件庫完善後會分享給大家,敬請期待),需要學習釋出npm包,昨天就想著利用空閒時間把之前寫的去除重複請求的axios封裝釋出為npm包,便於程式碼複用,回饋社群的同時也能學以致用。
閱讀本文,你將收穫:
從0開始建立並行布npm的全過程。【相關教學推薦:、】
一個持續迭代且簡單實用的axios請求去重工具庫。
建立一個新專案,包含package.json
{
"name": "drrq",
"type": "module",
"version": "1.0.0"
}
登入後複製
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 };
登入後複製
範例入口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
功能正常,工具庫準備完畢。
(eslint和prettier讀者可視情況選用)
一般專案的打包使用webpack,而工具庫的打包則使用rollup
通過下面的命令安裝 :
npm install --save-dev rollup
登入後複製
建立組態檔
在根目錄建立一個新檔案 rollup.config.js
export default {
input: "src/index.js",
output: {
file: "dist/drrp.js",
format: "esm",
name: 'drrp'
}
};
登入後複製
如果要使用 es6 的語法進行開發,還需要使用 babel 將程式碼編譯成 es5。因為rollup的模組機制是 ES6 Modules,但並不會對 es6 其他的語法進行編譯。
將 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
}
]
]
}
登入後複製
rollup 提供了外掛 ,以便於在 rollup 中參照 commonjs 規範的包。該外掛的作用是將 commonjs 模組轉成 es6 模組。
rollup-plugin-commonjs 通常與 一同使用,後者用來解析依賴的模組路徑。
安裝模組
npm install --save-dev rollup-plugin-commonjs rollup-plugin-node-resolve
登入後複製
新增 UglifyJS 可以通過移除註上釋、縮短變數名、重整程式碼來極大程度的減少 bundle 的體積大小 —— 這樣在一定程度降低了程式碼的可讀性,但是在網路通訊上變得更有效率。
安裝外掛
用下面的命令來安裝 :
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源,需要在上網工具內複製終端代理命令後到終端執行才能正常連線。
完整的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": {
...
}
}
登入後複製
每個 npm 包都需要一個版本,以便開發人員在安全地更新包版本的同時不會破壞其餘的程式碼。npm 使用的版本系統被叫做 ,是 Semantic Versioning 的縮寫。
不要過分擔心理解不了相較複雜的版本名稱,下面是他們對基本版本命名的總結: 給定版本號 MAJOR.MINOR.PATCH,增量規則如下:
MAJOR 版本號的變更說明新版本產生了不相容低版本的 API 等,
MINOR 版本號的變更說明你在以向後相容的方式新增功能,接下來
PATCH 版本號的變更說明你在新版本中做了向後相容的 bug 修復。
表示預釋出和構建後設資料的附加標籤可作為 MAJOR.MINOR.PATCH 格式的擴充套件。
最後,執行npm publish就搞定啦
本文的完整程式碼已開源至 ,感興趣的讀者歡迎fork和star!
轉載地址:https://juejin.cn/post/7172240485778456606
更多node相關知識,請存取:!
以上就是手把手帶你從0開始建立並行布npm包的詳細內容,更多請關注TW511.COM其它相關文章!