feat: request to fetch

This commit is contained in:
winixt 2023-03-18 13:03:16 +08:00
parent 828a58d885
commit 3c66904896
21 changed files with 126 additions and 629 deletions

View File

@ -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-rc.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;
},
// 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: sessionStoragelocallocalStorage
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 特有的配置不在支持

View File

@ -1,17 +1,22 @@
# @fesjs/plugin-windicss
::: warning 即将废弃
由于 windicss 不怎么维护了,本插件即将废弃,推荐使用 [tailwindcss](https://tailwindcss.com/)。
:::
## 介绍
`windicss` 支持
## 启用方式
`package.json` 中引入依赖:
```json
{
"devDependencies": {
"@fesjs/plugin-windicss": "^2.0.0"
},
}
}
```
@ -23,6 +28,6 @@
export default {
windicss: {
root: './',
}
}
},
};
```

View File

@ -46,7 +46,7 @@
"dependencies": {
"@fesjs/fes": "^3.0.0-rc.1",
"@fesjs/plugin-icon": "^3.0.0-rc.0",
"@fesjs/plugin-request": "^3.0.0-rc.3",
"@fesjs/plugin-request": "^4.0.0-rc.0",
"@fesjs/builder-webpack": "^3.0.0-rc.1",
"vue": "^3.2.37",
"core-js": "^3.27.0"

View File

@ -59,7 +59,7 @@
"style-loader": "^2.0.0",
"terser-webpack-plugin": "^5.3.6",
"vue-loader": "^16.1.2",
"webpack": "^5.69.0",
"webpack": "^5.76.2",
"webpack-bundle-analyzer": "^4.4.0",
"webpack-chain": "^6.5.1",
"webpack-dev-server": "^4.8.1",

View File

@ -93,8 +93,8 @@ export default function createCssWebpackConfig({ isDev, config, webpackConfig, b
if (!isDev) {
webpackConfig.plugin('extra-css').use(require.resolve('mini-css-extract-plugin'), [
{
filename: '[name].[contenthash:8].css',
chunkFilename: '[id].[contenthash:8].css',
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[id].[contenthash:8].css',
},
]);
webpackConfig.optimization.minimizer('css').use(require.resolve('css-minimizer-webpack-plugin'), [{}]);

View File

@ -77,8 +77,8 @@ export default async function getConfig({ api, cwd, config, env, entry = {}, mod
webpackConfig.output
.path(absoluteOutput)
.publicPath(publicPath || '/')
.filename('[name].[contenthash:8].js')
.chunkFilename('[name].[contenthash:8].chunk.js');
.filename('js/[name].[contenthash:8].js')
.chunkFilename('js/[name].[contenthash:8].chunk.js');
// --------------- resolve -----------
webpackConfig.resolve.extensions.merge(['.mjs', '.js', '.jsx', '.vue', '.ts', '.tsx', '.json', '.wasm']);

View File

@ -29,7 +29,7 @@
},
"peerDependencies": {
"@fesjs/fes": "3.0.0-rc.4",
"@fesjs/plugin-request": "3.0.0-rc.6",
"@fesjs/plugin-request": "^4.0.0-rc.0",
"vue": "^3.2.37"
},
"typings": "./types.d.ts"

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-request",
"version": "3.0.0-rc.5",
"version": "4.0.0-rc.0",
"description": "@fesjs/plugin-request",
"main": "lib/index.js",
"files": [
@ -33,7 +33,7 @@
},
"dependencies": {
"@fesjs/utils": "3.0.0-rc.2",
"axios": "^1.0.0-alpha.1"
"@qlin/request": "^0.1.1"
},
"typings": "./types.d.ts"
}

View File

@ -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
* 只缓存参数类型为: stringplain objectURLSearchParams 或者无参数的 请求
*/
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);
}
}
};

View File

@ -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();
}

View File

@ -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);
}
});
}
}

View File

@ -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();
};

View File

@ -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);
}
};

View File

@ -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 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) {

View File

@ -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();

View File

@ -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
| {
type?: 'ram' | 'sessionStorage' | 'localStorage';
cacheTime?: number;
};
}
export type RequestOptions = AxiosRequestConfig & RequestPluginOption;
export function request(url: string, data?: null | Record<string, any>, options?: AxiosRequestConfig & RequestPluginOption): Promise<any>;
export function request(url: string, data?: ParamsType | null, options?: Partial<Config>): Promise<any>;
export function rawRequest(url: string, data?: ParamsType | null, options?: Partial<Config>): Promise<any>;
export function useRequest(
url: string,
data?: null | Record<string, any>,
options?: AxiosRequestConfig & RequestPluginOption,
data?: null | ParamsType,
options?: Partial<Config>,
): { loadingRef: Ref<boolean>; errorRef: Ref<Error>; dataRef: Ref<any> };
declare module '@fesjs/fes' {
interface PluginRuntimeConfig {
request?: {
dataHandler?(data: any, response: AxiosResponse): any;
errorHandler?(error: RequestError): void;
requestInterceptors?: RequestInterceptor[];
responseInterceptors?: ResponseInterceptor[];
} & AxiosRequestConfig;
request?: Partial<Config>;
}
}

View File

@ -4,7 +4,7 @@ export default (api) => {
config: {
default: '/',
schema(joi) {
return joi.string().regex(/\/$/).error(new Error('config.publicPath must end with /.'));
return joi.string();
},
},
});

View File

@ -43,7 +43,7 @@
"@ttou/postcss-px-to-viewport": "1.1.4",
"@fesjs/fes": "^3.0.0-rc.0",
"@fesjs/plugin-icon": "^3.0.0-rc.0",
"@fesjs/plugin-request": "^3.0.0-rc.0",
"@fesjs/plugin-request": "^4.0.0-rc.0",
"@fesjs/builder-vite": "^3.0.0-rc.1",
"core-js": "^3.27.0",
"vue": "^3.2.37"

View File

@ -56,7 +56,7 @@
"@fesjs/plugin-model": "^3.0.0-rc.0",
"@fesjs/plugin-monaco-editor": "^3.0.0-rc.0",
"@fesjs/plugin-pinia": "^3.0.0-rc.0",
"@fesjs/plugin-request": "^3.0.0-rc.0",
"@fesjs/plugin-request": "^4.0.0-rc.0",
"@fesjs/plugin-sass": "^3.0.0-rc.0",
"@fesjs/plugin-windicss": "^3.0.0-rc.0",
"core-js": "^3.27.0",

View File

@ -56,7 +56,7 @@
"@fesjs/plugin-monaco-editor": "^3.0.0-rc.0",
"@fesjs/plugin-pinia": "^3.0.0-rc.0",
"@fesjs/plugin-qiankun": "^3.0.0-rc.0",
"@fesjs/plugin-request": "^3.0.0-rc.0",
"@fesjs/plugin-request": "^4.0.0-rc.0",
"@fesjs/plugin-sass": "^3.0.0-rc.0",
"@fesjs/plugin-watermark": "^3.0.0-rc.0",
"@fesjs/plugin-windicss": "^3.0.0-rc.0",

View File

@ -2103,6 +2103,14 @@
resolved "https://registry.npmmirror.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1"
integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==
"@qlin/request@^0.1.1":
version "0.1.1"
resolved "https://registry.npmmirror.com/@qlin/request/-/request-0.1.1.tgz#265026e2741208640522161eb9621077aae05487"
integrity sha512-3bQ3XaD4I4/EYZC15CR1TIHFCWQtZfYz0oleXlf4RS1xIW+7zna3OT5c0VKPiDn/aK1wZAH0mYODChIaRKSciA==
dependencies:
"@types/lodash-es" "^4.17.6"
lodash-es "^4.17.21"
"@rollup/plugin-babel@^5.2.0":
version "5.3.1"
resolved "https://registry.npmmirror.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283"
@ -2571,6 +2579,13 @@
dependencies:
"@types/lodash" "*"
"@types/lodash-es@^4.17.6":
version "4.17.7"
resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.7.tgz#22edcae9f44aff08546e71db8925f05b33c7cc40"
integrity sha512-z0ptr6UI10VlU6l5MYhGwS4mC8DZyYer2mCoyysZtSF7p26zOX8UpbrV0YpNYLGS8K4PUFIyEr62IMFFjveSiQ==
dependencies:
"@types/lodash" "*"
"@types/lodash@*":
version "4.14.191"
resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz#09511e7f7cba275acd8b419ddac8da9a6a79e2fa"
@ -3696,15 +3711,6 @@ aws4@^1.8.0:
resolved "https://registry.npmmirror.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3"
integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==
axios@^1.0.0-alpha.1:
version "1.3.4"
resolved "https://registry.npmmirror.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024"
integrity sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==
dependencies:
follow-redirects "^1.15.0"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
babel-jest@^27.0.6, babel-jest@^27.5.1:
version "27.5.1"
resolved "https://registry.npmmirror.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444"
@ -6156,7 +6162,7 @@ flatted@^3.1.0:
resolved "https://registry.npmmirror.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
follow-redirects@^1.0.0, follow-redirects@^1.15.0:
follow-redirects@^1.0.0:
version "1.15.2"
resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13"
integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==
@ -6182,15 +6188,6 @@ form-data@^3.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.npmmirror.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
@ -9588,11 +9585,6 @@ proxy-addr@~2.0.7:
forwarded "0.2.0"
ipaddr.js "1.9.1"
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.npmmirror.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@ -11609,10 +11601,10 @@ webpack-virtual-modules@^0.5.0:
resolved "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz#362f14738a56dae107937ab98ea7062e8bdd3b6c"
integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==
webpack@^5.69.0:
version "5.75.0"
resolved "https://registry.npmmirror.com/webpack/-/webpack-5.75.0.tgz#1e440468647b2505860e94c9ff3e44d5b582c152"
integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==
webpack@^5.76.2:
version "5.76.2"
resolved "https://registry.npmmirror.com/webpack/-/webpack-5.76.2.tgz#6f80d1c1d1e3bf704db571b2504a0461fac80230"
integrity sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==
dependencies:
"@types/eslint-scope" "^3.7.3"
"@types/estree" "^0.0.51"