From 21c404aa0701acf75542fd9c4b1c77866dfa744b Mon Sep 17 00:00:00 2001 From: winixt Date: Sat, 1 Apr 2023 15:59:37 +0800 Subject: [PATCH] feat: change request to fetch --- docs/reference/plugin/plugins/request.md | 88 +++++--- packages/fes-plugin-request/package.json | 10 +- .../src/template/cacheControl.js | 201 ------------------ .../src/template/genRequestKey.js | 22 -- .../src/template/helpers.js | 84 -------- .../src/template/paramsProcess.js | 11 - .../src/template/preventRepeatReq.js | 64 ------ .../src/template/request.js | 127 ++--------- .../src/template/scheduler.js | 32 --- packages/fes-plugin-request/types.d.ts | 35 +-- pnpm-lock.yaml | 164 +++++++++----- scripts/release.mjs | 9 +- 12 files changed, 198 insertions(+), 649 deletions(-) delete mode 100644 packages/fes-plugin-request/src/template/cacheControl.js delete mode 100644 packages/fes-plugin-request/src/template/genRequestKey.js delete mode 100644 packages/fes-plugin-request/src/template/helpers.js delete mode 100644 packages/fes-plugin-request/src/template/paramsProcess.js delete mode 100644 packages/fes-plugin-request/src/template/preventRepeatReq.js delete mode 100644 packages/fes-plugin-request/src/template/scheduler.js diff --git a/docs/reference/plugin/plugins/request.md b/docs/reference/plugin/plugins/request.md index 1d688db1..9d037401 100644 --- a/docs/reference/plugin/plugins/request.md +++ b/docs/reference/plugin/plugins/request.md @@ -1,6 +1,6 @@ # @fesjs/plugin-request -基于 axios 封装的 request,内置防止重复请求、请求缓存、错误处理等功能。 +基于 fetch 封装的 request,内置防止重复请求、请求缓存、错误处理等功能。 ## 启用方式 @@ -10,35 +10,39 @@ { "dependencies": { "@fesjs/fes": "^3.0.0", - "@fesjs/plugin-request": "^3.0.0" + "@fesjs/plugin-request": "^4.0.0-beta.0" } } ``` ## 运行时配置 -入口文件的全局配置,具体请求的配置参数会覆盖全局配置,支持 [axios](https://axios-http.com/zh/docs/req_config) 所有的参数。 +入口文件的全局配置,具体请求的配置参数会覆盖全局配置,支持 [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#sending_a_request_with_credentials_included) 所有的参数。 ```js import { defineRuntimeConfig } from '@fesjs/fes'; export default defineRuntimeConfig({ request: { - // API 前缀 baseURL: '', - dataHandler(data, response) { + timeout: 10000, // 默认 10s + method: 'POST', // 默认 post + mergeRequest: false, // 是否合并请求 + responseType: null, // 可选 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData',默认根据 content-type 处理 + credentials: 'include', // 默认 include, 'include' | 'same-origin' | 'omit' + headers: {}, // 传给服务器的 header + cacheData: false, // 是否缓存 + requestInterceptor: (config: Config) => Config, + responseInterceptor: (response: RequestResponse) => RequestResponse, + transformData(data, response) { // 处理响应内容异常 - if (data.code !== '0') { + if (isPlainObject(data)) { if (data.code === '10000') { - FMesseage.error('hello world'); + return Promise.reject(data); } - if (data.code === '20000') { - FMesseage.error('hello world'); - } - throw new Error(response); + return data?.result ? data.result : data; } - // 响应数据格式化 - return data?.result ? data.result : data; + return data; }, // http 异常,和插件异常 errorHandler(error) { @@ -47,13 +51,7 @@ export default defineRuntimeConfig({ console.log(error.response.data); console.log(error.response.status); console.log(error.response.headers); - } else if (error.request) { - // 请求已经成功发起,但没有收到响应 - // `error.request` 在浏览器中是 XMLHttpRequest 的实例, - // 而在node.js中是 http.ClientRequest 的实例 - console.log(error.request); - } else if (error.type) { - // 插件异常 + } else if (error.msg) { console.log(error.msg); } else { // 发送请求时出了点问题 @@ -61,11 +59,7 @@ export default defineRuntimeConfig({ } console.log(error.config); }, - // 请求拦截器 - requestInterceptors: [], - // 响应拦截器 - responseInterceptors: [], - // 支持其他 axios 配置 + // 支持其他 fetch 配置 ...otherConfigs, }, }); @@ -82,7 +76,7 @@ export default defineRuntimeConfig({ - url: 后端接口 url - data: 参数 - - options: 配置支持 [axios](https://axios-http.com/zh/docs/req_config) 所有的参数,和插件扩展参数。 + - options: 配置支持 [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#sending_a_request_with_credentials_included) 所有的参数,和插件扩展参数。 - **返回值**: Promise @@ -148,7 +142,7 @@ request( password: '123456', }, { - cache: { + cacheData: { cacheType: 'ram', // ram: 内存,session: sessionStorage,local:localStorage cacheTime: 1000 * 60 * 3, // 缓存时间:默认3min }, @@ -162,7 +156,37 @@ request( }); ``` -若 `cache` 传 `true`,则默认使用 `ram` 缓存类型,缓存时间 3min。 +若 `cacheData` 传 `true`,则默认使用 `ram` 缓存类型,缓存时间 3min。 + +### 请求 abort + +```javascript +import { request } from '@fesjs/fes'; + +const controller = new AbortController(); +request('/url/abort', null, { + signal: controller.signal, +}).then((response) => { + console.log('process response: ' + response); +}); +// cancel the request +controller.abort(); +``` + +### 获取 response headers + +```javascript +import { rawRequest } from '@fesjs/fes'; + +const controller = new AbortController(); +rawRequest('/url/abort', null, { + signal: controller.signal, +}).then((response) => { + console.log('process headers: ' + response.headers); +}); +// cancel the request +controller.abort(); +``` ### 结合 use 使用 @@ -184,3 +208,11 @@ export default { }, }; ``` + +## 3.x 升级到 4.x + +1. 缓存参数 cache 改成 cacheData(避免与 fetch 原本的 cache 冲突) +2. dataHandler 改成 transformData +3. requestInterceptors 改为 requestInterceptor,不在支持数组,只支持函数 +4. responseInterceptors 改为 responseInterceptor,不在支持数组,只支持函数 +5. 其他 axios 特有的配置不在支持 diff --git a/packages/fes-plugin-request/package.json b/packages/fes-plugin-request/package.json index 87ece0df..a2ab2eda 100644 --- a/packages/fes-plugin-request/package.json +++ b/packages/fes-plugin-request/package.json @@ -28,12 +28,12 @@ "access": "public" }, "peerDependencies": { - "@fesjs/fes": "^3.0.0", - "vue": "^3.2.47" + "@fesjs/fes": "3.0.0-rc.5", + "vue": "^3.2.37" }, "dependencies": { - "@fesjs/utils": "^3.0.0", - "axios": "^1.0.0-alpha.1" + "@fesjs/utils": "3.0.0-rc.2", + "@qlin/request": "^0.1.2" }, "typings": "./types.d.ts" -} +} \ No newline at end of file diff --git a/packages/fes-plugin-request/src/template/cacheControl.js b/packages/fes-plugin-request/src/template/cacheControl.js deleted file mode 100644 index fafb4439..00000000 --- a/packages/fes-plugin-request/src/template/cacheControl.js +++ /dev/null @@ -1,201 +0,0 @@ -import { isObject, isString, isURLSearchParams, checkHttpRequestHasBody } from './helpers'; -/** - * 缓存实现的功能 - * 1. 唯一定位一个请求(url, data | params, method) - * 其中请求参数根据请求方法使用其中一个就够了 - * 一个请求同时包含 data | params 参数的设计本身不合理 - * 不对这种情况进行兼容 - * 2. 控制缓存内容的大小,localStorage 只有5M - * 3. 控制缓存时间 - * session(存在内存中) - * expireTime 存在localStoreage 中 - * 4. 成功的、且响应内容为json的请求进行缓存 - */ - -/** - * 配置数据 - * type: 'ram' | 'sessionStorage' | 'localStorage' - * cacheTime: '' - */ - -/** - * 缓存数据结构 - * cache: { - * url: 'url', // 缓存 url - * data: data, // 数据 - * expire: '' // 缓存时间 - * } - */ - -/** - * 请求参数可以为如下类型 - * - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams - * - Browser only: FormData, File, Blob - * 只缓存参数类型为: string、plain object、URLSearchParams 或者无参数的 请求 - */ - -const CACHE_KEY_PREFIX = '__FES_REQUEST_CACHE:'; -const CACHE_TYPE = { - ram: 'ram', - session: 'sessionStorage', - local: 'localStorage', -}; - -const CACHE_DATA_MAP = new Map(); - -function genInnerKey(key, cacheType = 'ram') { - if (cacheType !== CACHE_TYPE.ram) { - return `${CACHE_KEY_PREFIX}${key}`; - } - return key; -} - -function canCache(data) { - return !data || isObject(data) || isString(data) || Array.isArray(data) || isURLSearchParams(data); -} - -function setCacheData({ key, cacheType = 'ram', data, cacheTime = 1000 * 60 * 3 }) { - const _key = genInnerKey(key, cacheType); - - const currentCacheData = { - cacheType, - data, - cacheTime, - expire: Date.now() + cacheTime, - }; - if (cacheType !== CACHE_TYPE.ram) { - const cacheInstance = window[CACHE_TYPE[cacheType]]; - try { - cacheInstance.setItem(_key, JSON.stringify(currentCacheData)); - } catch (e) { - // setItem 出现异常,清理缓存 - for (const item in cacheInstance) { - if (item.startsWith(CACHE_KEY_PREFIX) && Object.prototype.hasOwnProperty.call(cacheInstance, item)) { - cacheInstance.removeItem(item); - } - } - } - } else { - CACHE_DATA_MAP.set(_key, currentCacheData); - } -} - -function isExpire({ expire, cacheTime }) { - if (!cacheTime || expire >= Date.now()) { - return false; - } - return true; -} - -function getCacheData({ key, cacheType = 'ram' }) { - const _key = genInnerKey(key, cacheType); - if (cacheType !== CACHE_TYPE.ram) { - const cacheInstance = window[CACHE_TYPE[cacheType]]; - const text = cacheInstance.getItem(_key) || null; - try { - const currentCacheData = JSON.parse(text); - if (currentCacheData && !isExpire(currentCacheData)) { - return currentCacheData.data; - } - cacheInstance.removeItem(_key); - return null; - } catch (e) { - cacheInstance.removeItem(_key); - return null; - } - } else { - const currentCacheData = CACHE_DATA_MAP.get(_key); - if (currentCacheData && !isExpire(currentCacheData)) { - return currentCacheData.data; - } - CACHE_DATA_MAP.delete(_key); - return null; - } -} - -// 存储缓存队列 -const cacheStartFlag = new Map(); -const cachingQueue = new Map(); - -/** - * 等上一次请求结果 - * 1. 如果上一次请求成功,直接使用上一次的请求结果 - * 2. 如果上一次请求失败,重启本次请求 - */ -function handleCachingStart(ctx, config) { - const _key = genInnerKey(ctx.key, config.cache.cacheType); - const caching = cacheStartFlag.get(_key); - if (caching) { - return new Promise((resolve) => { - const queue = cachingQueue.get(_key) || []; - cachingQueue.set(_key, queue.concat(resolve)); - }); - } - cacheStartFlag.set(_key, true); -} - -// 有请求成功的 -function handleCachingQueueSuccess(ctx, config) { - // 移除首次缓存 flag - const _key = genInnerKey(ctx.key, config.cache.cacheType); - const queue = cachingQueue.get(_key); - if (queue && queue.length > 0) { - queue.forEach((resolve) => { - resolve({ - response: ctx.response, - }); - }); - } - cachingQueue.delete(_key); - cacheStartFlag.delete(_key); -} - -// 处理请求失败 -function handleCachingQueueError(ctx, config) { - const _key = genInnerKey(ctx.key, config.cache.cacheType); - const queue = cachingQueue.get(_key); - if (queue && queue.length > 0) { - const firstResolve = queue.shift(); - firstResolve(); - cachingQueue.set(_key, queue); - } else { - cachingQueue.delete(_key); - cacheStartFlag.delete(_key); - } -} - -export default async (ctx, next) => { - const { config } = ctx; - if (config.cache) { - const cacheData = getCacheData({ key: ctx.key, cacheType: config.cache.cacheType }); - if (cacheData) { - ctx.response = { - data: cacheData, - }; - return; - } - const result = await handleCachingStart(ctx, config); - if (result) { - Object.keys(result).forEach((key) => { - ctx[key] = result[key]; - }); - return; - } - } - await next(); - - if (config.cache) { - const requestdata = checkHttpRequestHasBody(config.method) ? config.data : config.params; - if (!ctx.error && ctx.response && canCache(requestdata) && canCache(ctx.response.data)) { - handleCachingQueueSuccess(ctx, config); - - setCacheData({ - key: ctx.key, - data: ctx.response.data, - ...config.cache, - }); - } else { - handleCachingQueueError(ctx, config); - } - } -}; diff --git a/packages/fes-plugin-request/src/template/genRequestKey.js b/packages/fes-plugin-request/src/template/genRequestKey.js deleted file mode 100644 index 27bbbd95..00000000 --- a/packages/fes-plugin-request/src/template/genRequestKey.js +++ /dev/null @@ -1,22 +0,0 @@ -import { isURLSearchParams } from './helpers'; -/** - * 唯一定位一个请求(url, data | params, method) - * 其中请求参数(data, params)根据请求方法,只使用其中一个 - * 一个请求同时包含 data | params 参数的设计本身不合理 - * 不对这种情况进行兼容 - */ - -const getQueryString = (data) => { - if (isURLSearchParams(data)) { - return data.toString(); - } - return data ? JSON.stringify(data) : ''; -}; - -export default async function genRequestKey(ctx, next) { - const { url, data, params, method } = ctx.config; - - ctx.key = `${url}${getQueryString(data)}${getQueryString(params)}${method}`; - - await next(); -} diff --git a/packages/fes-plugin-request/src/template/helpers.js b/packages/fes-plugin-request/src/template/helpers.js deleted file mode 100644 index 97cdef0f..00000000 --- a/packages/fes-plugin-request/src/template/helpers.js +++ /dev/null @@ -1,84 +0,0 @@ -/** - *判断类型 - * @param {*} obj 需要判断的对象 - */ -export function typeOf(obj) { - const map = { - '[object Boolean]': 'boolean', - '[object Number]': 'number', - '[object String]': 'string', - '[object Function]': 'function', - '[object Array]': 'array', - '[object Date]': 'date', - '[object RegExp]': 'regExp', - '[object Undefined]': 'undefined', - '[object Null]': 'null', - '[object Object]': 'object', - '[object URLSearchParams]': 'URLSearchParams', - }; - return map[Object.prototype.toString.call(obj)]; -} - -export function isFunction(obj) { - return typeOf(obj) === 'function'; -} - -export function isDate(obj) { - return typeOf(obj) === 'date'; -} - -export function isString(obj) { - return typeOf(obj) === 'string'; -} - -export function isArray(obj) { - return typeOf(obj) === 'array'; -} - -export function isObject(obj) { - return typeOf(obj) === 'object'; -} - -export function isURLSearchParams(obj) { - return typeOf(obj) === 'URLSearchParams'; -} - -export function checkHttpRequestHasBody(method) { - method = method.toUpperCase(); - const HTTP_METHOD = { - GET: { - request_body: false, - }, - POST: { - request_body: true, - }, - PUT: { - request_body: true, - }, - DELETE: { - request_body: true, - }, - HEAD: { - request_body: false, - }, - OPTIONS: { - request_body: false, - }, - PATCH: { - request_body: true, - }, - }; - return HTTP_METHOD[method].request_body; -} - -export function trimObj(obj) { - if (isObject(obj)) { - Object.entries(obj).forEach(([key, value]) => { - if (isString(value)) { - obj[key] = value.trim(); - } else if (isObject(value)) { - trimObj(value); - } - }); - } -} diff --git a/packages/fes-plugin-request/src/template/paramsProcess.js b/packages/fes-plugin-request/src/template/paramsProcess.js deleted file mode 100644 index 06864044..00000000 --- a/packages/fes-plugin-request/src/template/paramsProcess.js +++ /dev/null @@ -1,11 +0,0 @@ -import { checkHttpRequestHasBody, trimObj } from './helpers'; - -export default async (ctx, next) => { - const config = ctx.config; - if (checkHttpRequestHasBody(config.method)) { - trimObj(config.data); - } else { - trimObj(config.params); - } - await next(); -}; diff --git a/packages/fes-plugin-request/src/template/preventRepeatReq.js b/packages/fes-plugin-request/src/template/preventRepeatReq.js deleted file mode 100644 index 0b1505af..00000000 --- a/packages/fes-plugin-request/src/template/preventRepeatReq.js +++ /dev/null @@ -1,64 +0,0 @@ -const requestMap = new Map(); - -const mergeRequestMap = new Map(); -const requestQueue = new Map(); - -function handleCachingStart(ctx) { - const isRequesting = mergeRequestMap.get(ctx.key); - if (isRequesting) { - return new Promise((resolve) => { - const queue = requestQueue.get(ctx.key) || []; - requestQueue.set(ctx.key, queue.concat(resolve)); - }); - } - mergeRequestMap.set(ctx.key, true); -} - -function handleRepeatRequest(ctx) { - const queue = requestQueue.get(ctx.key); - if (queue && queue.length > 0) { - queue.forEach((resolve) => { - if (ctx.error) { - resolve({ - error: ctx.error, - }); - } else { - resolve({ - response: ctx.response, - }); - } - }); - } - requestQueue.delete(ctx.key); - mergeRequestMap.delete(ctx.key); -} - -export default async (ctx, next) => { - if (ctx.config.mergeRequest) { - const result = await handleCachingStart(ctx); - if (result) { - Object.keys(result).forEach((key) => { - ctx[key] = result[key]; - }); - return; - } - } else { - if (requestMap.get(ctx.key) && !ctx.config.mergeRequest) { - ctx.error = { - type: 'REPEAT', - msg: '重复请求', - config: ctx.config, - }; - return; - } - requestMap.set(ctx.key, true); - } - - await next(); - - if (ctx.config.mergeRequest) { - handleRepeatRequest(ctx); - } else { - requestMap.delete(ctx.key); - } -}; diff --git a/packages/fes-plugin-request/src/template/request.js b/packages/fes-plugin-request/src/template/request.js index a0a69193..c98683ad 100644 --- a/packages/fes-plugin-request/src/template/request.js +++ b/packages/fes-plugin-request/src/template/request.js @@ -1,131 +1,34 @@ -import axios from 'axios'; import { ApplyPluginsType, plugin } from '@fesjs/fes'; -import { ref } from 'vue'; -import scheduler from './scheduler'; -import { checkHttpRequestHasBody, isFunction } from './helpers'; +import { ref, shallowRef } from 'vue'; -import paramsProcess from './paramsProcess'; -import genRequestKey from './genRequestKey'; -import preventRepeatReq from './preventRepeatReq'; -import cacheControl from './cacheControl'; - -function addInterceptors(instance, interceptors, type = 'request') { - interceptors.forEach((fn) => { - if (Array.isArray(fn)) { - instance.interceptors[type].use(...fn); - } else if (isFunction(fn)) { - instance.interceptors[type].use(fn); - } - }); -} - -function addRequestInterceptors(instance, interceptors) { - addInterceptors(instance, interceptors, 'request'); -} - -function addResponseInterceptors(instance, interceptors) { - addInterceptors(instance, interceptors, 'response'); -} - -async function axiosMiddleware(context, next) { - try { - context.response = await context.instance.request(context.config); - } catch (error) { - context.error = error; - } - await next(); -} +import { createRequest } from '@qlin/request'; function getRequestInstance() { - const { - dataHandler, - errorHandler, - requestInterceptors = [], - responseInterceptors = [], - ...otherConfigs - } = plugin.applyPlugins({ + const defaultConfig = plugin.applyPlugins({ key: 'request', type: ApplyPluginsType.modify, - initialValue: {}, + initialValue: { + timeout: 10000, + }, }); - const defaultConfig = Object.assign( - { - timeout: 10000, - withCredentials: true, - }, - otherConfigs, - ); - const instance = axios.create(defaultConfig); - - addRequestInterceptors(instance, requestInterceptors); - addResponseInterceptors(instance, responseInterceptors); - - // 洋葱模型内部应该这是对数据的处理,避免有副作用调用 - scheduler.use(paramsProcess).use(genRequestKey).use(cacheControl).use(preventRepeatReq).use(axiosMiddleware); - - return { - context: { - errorHandler, - dataHandler: dataHandler || ((data) => data), - instance, - defaultConfig, - }, - request: scheduler.compose(), - }; + return createRequest(defaultConfig); } -function userConfigHandler(url, data, options = {}) { - options.url = url; - options.method = (options.method || 'post').toUpperCase(); - if (checkHttpRequestHasBody(options.method)) { - options.data = data; - } else { - options.params = data; - } - return options; -} +const currentRequest = getRequestInstance(); -let currentRequestInstance = null; - -function createContext(userConfig) { - return { - ...currentRequestInstance.context, - config: { - ...currentRequestInstance.context.defaultConfig, - ...userConfig, - }, - }; -} - -function getCustomerHandler(ctx, options = {}) { - const { dataHandler, errorHandler } = ctx; - return { - dataHandler: options.dataHandler || dataHandler, - errorHandler: options.errorHandler || errorHandler, - }; -} - -export const request = (url, data, options = {}) => { +export const rawRequest = (url, data, options = {}) => { if (typeof options === 'string') { options = { method: options, }; } - if (!currentRequestInstance) { - currentRequestInstance = getRequestInstance(); - } - const userConfig = userConfigHandler(url, data, options); - const context = createContext(userConfig); - const { dataHandler, errorHandler } = getCustomerHandler(context, options); + return currentRequest(url, data, options); +}; - return currentRequestInstance.request(context).then(async () => { - if (!context.error) { - return dataHandler(context.response.data, context.response); - } - errorHandler && errorHandler(context.error); - return Promise.reject(context.error); - }); +export const request = async (url, data, options = {}) => { + const response = await rawRequest(url, data, options); + return response.data; }; function isPromiseLike(obj) { @@ -135,7 +38,7 @@ function isPromiseLike(obj) { export const useRequest = (url, data, options = {}) => { const loadingRef = ref(true); const errorRef = ref(null); - const dataRef = ref(null); + const dataRef = shallowRef(null); let promise; if (isPromiseLike(url)) { promise = url; diff --git a/packages/fes-plugin-request/src/template/scheduler.js b/packages/fes-plugin-request/src/template/scheduler.js deleted file mode 100644 index bcecd266..00000000 --- a/packages/fes-plugin-request/src/template/scheduler.js +++ /dev/null @@ -1,32 +0,0 @@ -class Scheduler { - constructor() { - this.middlewares = []; - } - - use(fn) { - if (typeof fn !== 'function') throw new TypeError('middleware must be a function!'); - this.middlewares.push(fn); - return this; - } - - compose() { - return (context, next) => { - let index = -1; - const dispatch = (i) => { - if (i <= index) return Promise.reject(new Error('next() called multiple times')); - index = i; - let fn = this.middlewares[i]; - if (index === this.middlewares.length) fn = next; - if (!fn) return Promise.resolve(); - try { - return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); - } catch (e) { - return Promise.reject(e); - } - }; - return dispatch(0); - }; - } -} - -export default new Scheduler(); diff --git a/packages/fes-plugin-request/types.d.ts b/packages/fes-plugin-request/types.d.ts index 2c2b40c0..fb8c9604 100644 --- a/packages/fes-plugin-request/types.d.ts +++ b/packages/fes-plugin-request/types.d.ts @@ -1,39 +1,18 @@ -import { AxiosRequestConfig, AxiosResponse, AxiosError } from 'axios'; +import type { Config, ParamsType } from '@qlin/request/dist/interface'; import { Ref } from 'vue'; -type RequestInterceptor = (value: AxiosRequestConfig) => AxiosRequestConfig | [(value: AxiosRequestConfig) => AxiosRequestConfig, (error: any) => any]; -type ResponseInterceptor = (value: AxiosResponse) => AxiosResponse | [(value: AxiosResponse) => AxiosResponse, (error: any) => any]; +export * from '@qlin/request'; -export type RequestResponse = AxiosResponse; -export type RequestError = AxiosError & { type: string; msg: string; [key: string]: any }; -interface RequestPluginOption { - mergeRequest?: boolean; - dataHandler?(data: any, response: AxiosResponse): any; - errorHandler?(error: RequestError): void; - cache?: - | boolean - | { - cacheType?: 'ram' | 'sessionStorage' | 'localStorage'; - cacheTime?: number; - }; -} - -export type RequestOptions = AxiosRequestConfig & RequestPluginOption; - -export function request(url: string, data?: null | Record, options?: AxiosRequestConfig & RequestPluginOption): Promise; +export function request(url: string, data?: ParamsType | null, options?: Partial): Promise; +export function rawRequest(url: string, data?: ParamsType | null, options?: Partial): Promise; export function useRequest( url: string, - data?: null | Record, - options?: AxiosRequestConfig & RequestPluginOption, + data?: null | ParamsType, + options?: Partial, ): { loadingRef: Ref; errorRef: Ref; dataRef: Ref }; declare module '@fesjs/fes' { interface PluginRuntimeConfig { - request?: { - dataHandler?(data: any, response: AxiosResponse): any; - errorHandler?(error: RequestError): void; - requestInterceptors?: RequestInterceptor[]; - responseInterceptors?: ResponseInterceptor[]; - } & AxiosRequestConfig; + request?: Partial; } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 90c54e43..fb1cb884 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -613,16 +613,16 @@ importers: packages/fes-plugin-request: dependencies: '@fesjs/fes': - specifier: ^3.0.0 - version: link:../fes + specifier: 3.0.0-rc.5 + version: 3.0.0-rc.5(vue@3.2.47) '@fesjs/utils': - specifier: ^3.0.0 - version: link:../fes-utils - axios: - specifier: ^1.0.0-alpha.1 - version: 1.0.0-alpha.1 + specifier: 3.0.0-rc.2 + version: 3.0.0-rc.2 + '@qlin/request': + specifier: ^0.1.2 + version: 0.1.2 vue: - specifier: ^3.2.47 + specifier: ^3.2.37 version: 3.2.47 packages/fes-plugin-sass: @@ -2827,7 +2827,7 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.3.2 + debug: 4.3.4 espree: 9.5.1 globals: 13.20.0 ignore: 5.2.4 @@ -2844,6 +2844,23 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@fesjs/compiler@3.0.0-rc.3: + resolution: {integrity: sha512-LlrvEl+4ylfdW5+35JtJ+2IipLEH1YqKo29wWG6ZrMy9vyW9i0u/j12C3PqLlzKa7LikMGYTMv4k4KdjX6ie7w==} + dependencies: + '@babel/core': 7.21.3 + '@babel/preset-env': 7.20.2(@babel/core@7.21.3) + '@babel/register': 7.21.0(@babel/core@7.21.3) + '@fesjs/utils': 3.0.0-rc.2 + commander: 7.2.0 + dotenv: 8.2.0 + joi: 17.3.0 + readline: 1.3.0 + set-value: 3.0.2 + tapable: 2.2.0 + transitivePeerDependencies: + - supports-color + dev: false + /@fesjs/fes-design@0.7.20(vue@3.2.47): resolution: {integrity: sha512-XEyi1GLOLwCuGi2S0MGnwMGHoSDQ2XXjOgnzxrRz+z7XmC4jA/P+5Z2Q82J1F1D4lRxNAzzRjFQlfM+hNoLblA==} peerDependencies: @@ -2867,6 +2884,23 @@ packages: - '@vue/composition-api' dev: false + /@fesjs/fes@3.0.0-rc.5(vue@3.2.47): + resolution: {integrity: sha512-dtNeVruuNgaJktjiZFkRDzVes3JfZu/7NetukkGCdrYY3eubuXz5Z7aNvbhQqHMsAWLsevy+YCy3qrjdiG5thw==} + engines: {node: ^10.12.0 || ^12.0.0 || >= 14.0.0} + hasBin: true + dependencies: + '@fesjs/compiler': 3.0.0-rc.3 + '@fesjs/preset-built-in': 3.0.0-rc.5(vue@3.2.47) + '@fesjs/runtime': 3.0.0-rc.2(vue@3.2.47) + '@fesjs/utils': 3.0.0-rc.2 + pirates: 4.0.5 + resolve-cwd: 3.0.0 + vue-router: 4.1.6(vue@3.2.47) + transitivePeerDependencies: + - supports-color + - vue + dev: false + /@fesjs/plugin-qiankun@3.0.0-rc.0(@fesjs/fes-design@0.7.20)(@fesjs/fes@packages+fes)(vue@3.2.47): resolution: {integrity: sha512-qFQ3cDBmGJYZPbc8Mu4ZVodm+/Q8g1rIPRAg24cxVybVc1taA0YbGo8FefQayyaUTxFLtYp921TYWytzGDNJRg==} peerDependencies: @@ -2899,6 +2933,31 @@ packages: - supports-color dev: false + /@fesjs/preset-built-in@3.0.0-rc.5(vue@3.2.47): + resolution: {integrity: sha512-PK4l66aCwPGthUQNRL+btmEejynTIW0jztWTQFtOEHuyTbfZvQSq0FEiVBdANSSnFC8iHsjlBx2f0WpUjbUKMw==} + peerDependencies: + vue: ^3.2.37 + dependencies: + '@fesjs/compiler': 3.0.0-rc.3 + '@fesjs/utils': 3.0.0-rc.2 + '@vue/compiler-sfc': 3.2.47 + envinfo: 7.8.1 + express: 4.17.3 + mockjs: 1.1.0 + vue: 3.2.47 + transitivePeerDependencies: + - supports-color + dev: false + + /@fesjs/runtime@3.0.0-rc.2(vue@3.2.47): + resolution: {integrity: sha512-dvV9+eQ6bfDaeTLhDI7P7hTd3uCswze4Wa866dJEHzXfkR31W7oog7Q/CSX+mo++5UHVa2kuHamm1MFaPvkijw==} + peerDependencies: + vue: ^3.2.37 + dependencies: + vue: 3.2.47 + vue-router: 4.1.6(vue@3.2.47) + dev: false + /@fesjs/utils@3.0.0-rc.2: resolution: {integrity: sha512-kZlFvKZtuw77Xd4gru0uHMWB13lTWvpSQzMhfD4UnPBQQhtpGZrDWX/7ik/qafdxPkZ3ovwPbirScrCMHdPvNw==} dependencies: @@ -2949,7 +3008,7 @@ packages: engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.2 + debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -3401,6 +3460,13 @@ packages: resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} dev: false + /@qlin/request@0.1.2: + resolution: {integrity: sha512-iHkkFQjNuutRIEatYcfWpSimQO9SumOvM5mcDJ6zLr4zLyXTqMlWaRXvORmvlt+DCbc/k8m2fi9DDXaUQb2TqQ==} + dependencies: + '@types/lodash-es': 4.17.7 + lodash-es: 4.17.21 + dev: false + /@rollup/plugin-babel@5.3.1(@babel/core@7.21.3)(rollup@2.79.1): resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} engines: {node: '>= 10.0.0'} @@ -3429,7 +3495,7 @@ packages: builtin-modules: 3.3.0 deepmerge: 4.2.2 is-module: 1.0.0 - resolve: 1.20.0 + resolve: 1.22.1 rollup: 2.79.1 dev: true @@ -4802,7 +4868,7 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.3.2 + debug: 4.3.4 transitivePeerDependencies: - supports-color dev: false @@ -5081,16 +5147,6 @@ packages: engines: {node: '>= 0.4'} dev: true - /axios@1.0.0-alpha.1: - resolution: {integrity: sha512-p+meG161943WT+K7sJYquHR46xxi/z0tk7vnSmEf/LrfEAyiP+0uTMMYk1OEo1IRF18oGRhnFxN1y8fLcXaTMw==} - dependencies: - follow-redirects: 1.15.2 - form-data: 4.0.0 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: false - /babel-jest@27.0.6(@babel/core@7.21.3): resolution: {integrity: sha512-iTJyYLNc4wRofASmofpOc5NK9QunwMk+TLFgGXsTFS8uEqmd8wdI7sga0FPe2oVH3b5Agt/EAK1QjPEuKL8VfA==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} @@ -5505,6 +5561,7 @@ packages: /chalk@5.0.1: resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false /chalk@5.2.0: resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} @@ -5851,7 +5908,7 @@ packages: dev: false /concat-map@0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=, tarball: https://registry.npmmirror.com/concat-map/download/concat-map-0.0.1.tgz} + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} /confusing-browser-globals@1.0.11: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} @@ -7367,7 +7424,7 @@ packages: dependencies: eslint-plugin-import: 2.25.3(eslint@8.37.0) glob-parent: 5.1.2 - resolve: 1.20.0 + resolve: 1.22.1 dev: true /eslint-import-resolver-node@0.3.7: @@ -7451,7 +7508,7 @@ packages: is-glob: 4.0.3 minimatch: 3.1.2 object.values: 1.1.6 - resolve: 1.20.0 + resolve: 1.22.1 tsconfig-paths: 3.14.2 transitivePeerDependencies: - eslint-import-resolver-typescript @@ -7470,7 +7527,7 @@ packages: eslint-utils: 2.1.0 ignore: 5.2.4 minimatch: 3.1.2 - resolve: 1.20.0 + resolve: 1.22.1 semver: 6.3.0 dev: true @@ -7502,7 +7559,7 @@ packages: natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.11 - semver: 7.3.6 + semver: 7.3.8 vue-eslint-parser: 8.3.0(eslint@8.37.0) transitivePeerDependencies: - supports-color @@ -7570,7 +7627,7 @@ packages: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 - debug: 4.3.2 + debug: 4.3.4 doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.1.1 @@ -8040,17 +8097,8 @@ packages: mime-types: 2.1.35 dev: false - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: false - /forwarded@0.2.0: - resolution: {integrity: sha1-ImmTZCiq1MFcfr6XeahL8LKoGBE=, tarball: https://registry.npmmirror.com/forwarded/download/forwarded-0.2.0.tgz} + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} dev: false @@ -8621,7 +8669,7 @@ packages: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.2 + debug: 4.3.4 transitivePeerDependencies: - supports-color dev: false @@ -8661,7 +8709,7 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.3.2 + debug: 4.3.4 transitivePeerDependencies: - supports-color dev: false @@ -9191,7 +9239,7 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} dependencies: - debug: 4.3.2 + debug: 4.3.4 istanbul-lib-coverage: 3.2.0 source-map: 0.6.1 transitivePeerDependencies: @@ -9535,7 +9583,7 @@ packages: jest-pnp-resolver: 1.2.3(jest-resolve@27.5.1) jest-util: 27.5.1 jest-validate: 27.5.1 - resolve: 1.20.0 + resolve: 1.22.1 resolve.exports: 1.1.1 slash: 3.0.0 dev: false @@ -9635,7 +9683,7 @@ packages: jest-util: 27.5.1 natural-compare: 1.4.0 pretty-format: 27.5.1 - semver: 7.3.6 + semver: 7.3.8 transitivePeerDependencies: - supports-color dev: false @@ -10167,7 +10215,7 @@ packages: resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} engines: {node: '>=12'} dependencies: - chalk: 5.0.1 + chalk: 5.2.0 is-unicode-supported: 1.3.0 /log-update@4.0.0: @@ -10205,6 +10253,7 @@ packages: /lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} + dev: false /magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} @@ -10300,7 +10349,7 @@ packages: resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} /media-typer@0.3.0: - resolution: {integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=, tarball: https://registry.npmmirror.com/media-typer/download/media-typer-0.3.0.tgz} + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} dev: false @@ -10653,7 +10702,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.20.0 + resolve: 1.22.1 semver: 5.7.1 validate-npm-package-license: 3.0.4 @@ -10663,7 +10712,7 @@ packages: dependencies: hosted-git-info: 4.1.0 is-core-module: 2.11.0 - semver: 7.3.6 + semver: 7.3.8 validate-npm-package-license: 3.0.4 /normalize-path@3.0.0: @@ -10855,7 +10904,7 @@ packages: resolution: {integrity: sha512-1/D8uRFY0ay2kgBpmAwmSA404w4OoPVhHMqRqtjvrcK/dnzcEZxMJ+V4DUbyICu8IIVRclHcOf5wlD1tMY4GUQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: - chalk: 5.0.1 + chalk: 5.2.0 cli-cursor: 4.0.0 cli-spinners: 2.7.0 is-interactive: 2.0.0 @@ -11648,10 +11697,6 @@ packages: ipaddr.js: 1.9.1 dev: false - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: false - /prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} dev: false @@ -12134,7 +12179,7 @@ packages: engines: {node: '>=12.0.0'} hasBin: true dependencies: - chokidar: 3.5.2 + chokidar: 3.5.3 immutable: 4.3.0 source-map-js: 1.0.2 dev: false @@ -12207,6 +12252,7 @@ packages: hasBin: true dependencies: lru-cache: 7.18.3 + dev: false /semver@7.3.8: resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} @@ -12295,7 +12341,7 @@ packages: dev: false /setprototypeof@1.1.0: - resolution: {integrity: sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=, tarball: https://registry.npmmirror.com/setprototypeof/download/setprototypeof-1.1.0.tgz} + resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} dev: false /setprototypeof@1.2.0: @@ -12513,7 +12559,7 @@ packages: /spdy-transport@3.0.0: resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} dependencies: - debug: 4.3.2 + debug: 4.3.4 detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -12527,7 +12573,7 @@ packages: resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} engines: {node: '>=6.0.0'} dependencies: - debug: 4.3.2 + debug: 4.3.4 handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 @@ -13028,7 +13074,7 @@ packages: dev: true /toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==, tarball: https://registry.npmmirror.com/toidentifier/download/toidentifier-1.0.1.tgz} + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} dev: false @@ -13563,14 +13609,14 @@ packages: peerDependencies: eslint: '>=6.0.0' dependencies: - debug: 4.3.2 + debug: 4.3.4 eslint: 8.37.0 eslint-scope: 7.1.1 eslint-visitor-keys: 3.4.0 espree: 9.5.1 esquery: 1.5.0 lodash: 4.17.21 - semver: 7.3.6 + semver: 7.3.8 transitivePeerDependencies: - supports-color dev: true diff --git a/scripts/release.mjs b/scripts/release.mjs index 32d4c202..af437521 100644 --- a/scripts/release.mjs +++ b/scripts/release.mjs @@ -13,14 +13,17 @@ import buildConfig from '../build.config.js'; const { prompt } = enquirer; const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); -const { preid, dry: isDryRun } = minimist(process.argv.slice(2)); +const { preid: preId, dry: isDryRun } = minimist(process.argv.slice(2)); const packages = buildConfig.pkgs; const versionIncrements = ['patch', 'minor', 'major', 'prepatch', 'preminor', 'premajor', 'prerelease']; const incVersion = (version, i) => { - const preId = preid || semver.prerelease(version)[0]; - return semver.inc(version, i, preId); + let _preId = preId || semver.prerelease(version)?.[0]; + if (!_preId && /pre/.test(i)) { + _preId = 'beta'; + } + return semver.inc(version, i, _preId); }; const autoIncVersion = (version) => { if (version.includes('-')) {