Compare commits

..

No commits in common. "master" and "v3.1.6" have entirely different histories.

107 changed files with 2091 additions and 6656 deletions

4
.eslintignore Normal file
View File

@ -0,0 +1,4 @@
**/*.ts
lib
node_modules

View File

@ -31,8 +31,5 @@
"source": "./fixtures/output/**/*.*",
"target": "./fixtures/input/<base>"
}
],
"cSpell.words": [
"unref"
]
}

File diff suppressed because it is too large Load Diff

View File

@ -97,17 +97,15 @@ npm install
npm run dev
```
## Project Demo
## Start On Cloud IDE
| Project | Description |
|----------------------------------------- | ----------------------------------------- |
| <img src="https://docs.icegl.cn/logo.png" width="100px"> | [threejs webgl three three.js tres.js tvt.js](https://gitee.com/ice-gl/icegl-three-vue-tres) |
[https://idegithub.com/WeBankFinTech/fes.js](https://idegithub.com/WeBankFinTech/fes.js)
## Feedback
| Github Issue | WeChat group | Fes.js 开源运营小助手 |
| ------------------------------------ | --------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
| [@fesjs/fes.js/issues](../../issues) | <img src="https://wanchun-1252303708.cos.ap-nanjing.myqcloud.com/WeChatb7bcfb33e47b8949ced831b8e79ffb0b.jpg" height="250"/> |
| [@fesjs/fes.js/issues](../../issues) | <img src="https://i.loli.net/2020/09/11/2XhKtPZd6NFVbDE.png" width="250" /> | <img src="https://i.loli.net/2020/09/16/sxwr62CKhmYOUyV.jpg" height="250"/> |
## Contributing
@ -129,4 +127,4 @@ In order for the Fes.js open source project to run better, and to give back to t
The output of experience can also help your system accumulate your own projects, sort out your work ideas, and also help your technology blog to promote. Good practice cases will have the opportunity to be invited to participate in the project community technical meeting to share, hurry up and participate.
Please stamp: <https://mp.weixin.qq.com/s/nV4NG_OUUrdgtft8g_IW4g>
Please stamp: https://mp.weixin.qq.com/s/nV4NG_OUUrdgtft8g_IW4g

View File

@ -8,7 +8,7 @@
<div align="center">
一个好用的前端应用解决方案
一个优秀的前端解决方案
[![GitHub issues](https://img.shields.io/github/issues/WeBankFinTech/fes.js.svg?style=flat-square)](../../issues)
[![MIT](https://img.shields.io/dub/l/vibe-d.svg?style=flat-square)](http://opensource.org/licenses/MIT)
@ -99,19 +99,15 @@ npm install
npm run dev
```
## 项目样例
## 在 Cloud IDE 中预览
使用 fes.js 构建的优秀项目,欢迎联系。
| 项目 | 描述 |
|----------------------------------------- | ----------------------------------------- |
| <img src="https://docs.icegl.cn/logo.png" width="100px"> | [三维可视化项目快速落地の开源框架](https://gitee.com/ice-gl/icegl-three-vue-tres) |
[https://idegithub.com/WeBankFinTech/fes.js](https://idegithub.com/WeBankFinTech/fes.js)
## 反馈
| Github Issue | Fes.js 开源运营小助手 |
| ------------------------------------ | ------------------------------------------------------------------------------------------------ |
| [@fesjs/fes.js/issues](../../issues) | <img src="https://wanchun-1252303708.cos.ap-nanjing.myqcloud.com/WeChatb7bcfb33e47b8949ced831b8e79ffb0b.jpg" height="250"/> |
| [@fesjs/fes.js/issues](../../issues) | <img src="https://cos-1254145788.cos.ap-guangzhou.myqcloud.com/WechatIMG104.jpeg" height="250"/> |
## 参与共建
@ -132,4 +128,4 @@ npm run dev
为了 Fes.js 开源项目更好的运转,同时回馈开源社区,社区推出有奖征文活动!欢迎大家投递实践经验,给社区用户,更广泛的开发者提供借鉴。
经验输出也可以帮助到你系统沉淀自有项目,梳理工作思路,也能够帮助你的技术博客做宣传。优秀的实践案例将有机会邀请参与项目社区技术会议分享,赶快来参与吧。
请戳:<https://mp.weixin.qq.com/s/nV4NG_OUUrdgtft8g_IW4g>
请戳https://mp.weixin.qq.com/s/nV4NG_OUUrdgtft8g_IW4g

View File

@ -1,3 +1,4 @@
export const zh = {
'/guide/': [
{
@ -5,12 +6,12 @@ export const zh = {
items: [
{
text: '介绍',
link: '/guide/index.md',
link: '/guide/index.md'
},
{
text: '快速上手',
link: '/guide/getting-started.md',
},
link: '/guide/getting-started.md'
}
],
},
{
@ -18,44 +19,35 @@ export const zh = {
items: [
{
text: '目录结构',
link: '/guide/directory-structure.md',
},
{
link: '/guide/directory-structure.md'
},{
text: 'Vite 和 Webpack 双构建',
link: '/guide/builder.md',
},
{
link: '/guide/builder.md'
},{
text: '编译时配置',
link: '/guide/config.md',
},
{
link: '/guide/config.md'
},{
text: '运行时配置',
link: '/guide/runtime-config.md',
},
{
link: '/guide/runtime-config.md'
},{
text: '环境变量',
link: '/guide/env.md',
},
{
link: '/guide/env.md'
},{
text: '路由',
link: '/guide/route.md',
},
{
link: '/guide/route.md'
},{
text: '插件',
link: '/guide/plugin.md',
},
{
link: '/guide/plugin.md'
},{
text: 'HTML 模板',
link: '/guide/template.md',
},
{
link: '/guide/template.md'
},{
text: 'Mock 数据',
link: '/guide/mock.md',
},
{
text: '从 2.x 迁移到 3.x',
link: '/guide/upgrade3.md',
},
link: '/guide/mock.md'
},{
text: '从 2.0.x 迁移到 3.0.x',
link: '/guide/upgrade3.md'
}
],
},
{
@ -63,102 +55,102 @@ export const zh = {
items: [
{
text: '使用图片',
link: '/guide/image.md',
link: '/guide/image.md'
},
{
text: '使用 css',
link: '/guide/css.md',
link: '/guide/css.md'
},
{
text: '静态资源',
link: '/guide/public.md',
},
link: '/guide/public.md'
}
],
},
{
text: '贡献指南',
link: '/guide/contributing.md',
link: '/guide/contributing.md'
},
{
text: '常见问题',
link: '/guide/faq.md',
link: '/guide/faq.md'
},
],
'/reference/plugin/': [
{
text: '介绍',
link: '/reference/plugin/index.md',
link: '/reference/plugin/index.md'
},
{
text: 'Plugins',
items: [
{
text: '@fesjs/plugin-access',
link: '/reference/plugin/plugins/access.md',
link: '/reference/plugin/plugins/access.md'
},
{
text: '@fesjs/plugin-enums',
link: '/reference/plugin/plugins/enums.md',
link: '/reference/plugin/plugins/enums.md'
},
{
text: '@fesjs/plugin-icon',
link: '/reference/plugin/plugins/icon.md',
link: '/reference/plugin/plugins/icon.md'
},
{
text: '@fesjs/plugin-jest',
link: '/reference/plugin/plugins/jest.md',
link: '/reference/plugin/plugins/jest.md'
},
{
text: '@fesjs/plugin-layout',
link: '/reference/plugin/plugins/layout.md',
link: '/reference/plugin/plugins/layout.md'
},
{
text: '@fesjs/plugin-locale',
link: '/reference/plugin/plugins/locale.md',
link: '/reference/plugin/plugins/locale.md'
},
{
text: '@fesjs/plugin-model',
link: '/reference/plugin/plugins/model.md',
link: '/reference/plugin/plugins/model.md'
},
{
text: '@fesjs/plugin-request',
link: '/reference/plugin/plugins/request.md',
link: '/reference/plugin/plugins/request.md'
},
{
text: '@fesjs/plugin-vuex',
link: '/reference/plugin/plugins/vuex.md',
link: '/reference/plugin/plugins/vuex.md'
},
{
text: '@fesjs/plugin-qiankun',
link: '/reference/plugin/plugins/qiankun.md',
link: '/reference/plugin/plugins/qiankun.md'
},
{
text: '@fesjs/plugin-windicss',
link: '/reference/plugin/plugins/windicss.md',
link: '/reference/plugin/plugins/windicss.md'
},
{
text: '@fesjs/plugin-sass',
link: '/reference/plugin/plugins/sass.md',
link: '/reference/plugin/plugins/sass.md'
},
{
text: '@fesjs/plugin-editor',
link: '/reference/plugin/plugins/editor.md',
link: '/reference/plugin/plugins/editor.md'
},
{
text: '@fesjs/plugin-pinia',
link: '/reference/plugin/plugins/pinia.md',
link: '/reference/plugin/plugins/pinia.md'
},
{
text: '@fesjs/plugin-watermark',
link: '/reference/plugin/plugins/watermark.md',
link: '/reference/plugin/plugins/watermark.md'
},
{
text: '@fesjs/plugin-login',
link: '/reference/plugin/plugins/login.md',
link: '/reference/plugin/plugins/login.md'
},
{
text: '@fesjs/plugin-swc',
link: '/reference/plugin/plugins/swc.md',
link: '/reference/plugin/plugins/swc.md'
},
],
},
@ -166,10 +158,10 @@ export const zh = {
text: '插件开发',
items: [{
text: '插件介绍',
link: '/reference/plugin/dev/index.md',
link: '/reference/plugin/dev/index.md'
}, {
text: '插件API',
link: '/reference/plugin/dev/api.md',
link: '/reference/plugin/dev/api.md'
}],
},
],

View File

@ -6,12 +6,12 @@ import { withBase } from 'vitepress'
## 依赖环境
首先得有 [Node.js](https://nodejs.org/),并确保 node 版本是 `v18.12.0` 或以上。
首先得有 [Node.js](https://nodejs.org/),并确保 node 版本是 12.13 或以上。
```bash
# 打印 node 版本
node -v
v18.12.0
v12.13.0
```
推荐使用 [pnpm](https://pnpm.io/installation) 管理 npm 依赖

View File

@ -1,29 +1,28 @@
# 从 2.x 迁移到 3.x
# 从 2.0.x 迁移到 3.0.x
## 版本 3.x 的 break
## 版本 3.0.x 的 break
1. 环境要求 `node >= v18.12.0`
2. 编译时的 [base](../reference/config/index.md/#base) 配置,移到了 [router.base](../reference/config/index.md/#router) 下
3. [webpack-dev-server](https://github.com/webpack/webpack-dev-server) 从 `v3.x` 升级到了 `v5.x`,如果遇到配置不兼容,可以查看[webpack-dev-server 3.x 升级 4.x](https://github.com/webpack/webpack-dev-server/blob/master/migration-v4.md)、[webpack-dev-server 4.x 升级 5.x](https://github.com/webpack/webpack-dev-server/blob/master/migration-v5.md)
4. [layout 插件](../reference/plugin/plugins/layout.md#_4-x-升级到-5-x) 有一些属性变更
5. [request 插件](../reference/plugin/plugins/request.md#_2-x-升级到-3-x) 有一些参数变更,升级请使用最新版本
1. 编译时的 [base](../reference/config/index.md/#base) 配置,移到了 [router.base](../reference/config/index.md/#router) 下。
2. [webpack-dev-server](https://github.com/webpack/webpack-dev-server) 从 `v3.x` 升级到了 `v4.x`,如果遇到配置不兼容,可以查看[webpack-dev-server 3.x 升级 4.x](https://github.com/webpack/webpack-dev-server/blob/master/migration-v4.md)。
3. [layout 插件](../reference/plugin/plugins/layout.md#_4-x-升级到-5-x) 有一些属性变更
3. [request 插件](../reference/plugin/plugins/request.md#_2-x-升级到-3-x) 有一些参数变更
## 继续使用 Webpack
1. 添加 Webpack 构建依赖包: `npm i @fesjs/builder-webpack -D`
2. `dev``publicPath` 配置不能为 `./`,请更改为 `auto`
3. 将 html 模版文件从 `public/index.html` 挪到项目根目录,移除 [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) 相关配置,具体模版变量使用请查看[HTML 模版](../guide/template.html)
1. 添加 Webpack 构建依赖包: `npm i @fesjs/builder-webpack -D`
2. 如果设置了 `publicPath: './'`,请更改为 `publicPath: ''`
3. 如果有,`public/index.html` 文件挪到项目根目录,移除 [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) 相关配置,具体模版变量使用请查看[HTML 模版](../guide/template.html)
## 换成 Vite
1. 安装依赖包 `npm i @fesjs/builder-vite`
2. 将 Webpack 相关的配置换成 Vite具体可查看[配置](../reference/config/index.md)
3. 将 html 模版文件从 `public/index.html` 挪到项目根目录,如果有相应的 [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) 配置,需要改成 [vite-plugin-html](https://github.com/vbenjs/vite-plugin-html) 的写法
4. 将 `require` 等 Vite 不支持的代码,改写成 Vite 支持的方式
1. 安装依赖包 `npm i @fesjs/builder-vite`
2. 将 Webpack 相关的配置换成 Vite具体可查看[配置](../reference/config/index.md)
3. 将 html 模版文件从 `public/index.html` 挪到项目根目录,如果有相应的 [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) 配置,需要改成 [vite-plugin-html](https://github.com/vbenjs/vite-plugin-html) 的写法
4. 将 `require` 等 Vite 不支持的代码,改写成 Vite 支持的方式
## 插件
插件都需要升级到 `3.x` 版本,新版添加了兼容`builder`的逻辑,但是提供的接口和配置没有变化,只需要升级版本即可使用。
插件都需要升级到 `3.0.x` 版本,新版添加了兼容`builder`的逻辑,但是提供的接口和配置没有变化,只需要升级版本即可使用。
- [@fesjs/plugin-layout](../reference/plugin/plugins/layout.md) 需要升级到`5.0.x`版本。
- [@fesjs/plugin-locale](../reference/plugin/plugins/locale.md) 需要升级到`4.0.x`版本。

View File

@ -64,6 +64,6 @@ npm run dev
| Github Issue | Fes.js 开源运营小助手 |
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| [@fesjs/fes.js/issues](https://github.com/WeBankFinTech/fes.js/issues) | <img src="https://wanchun-1252303708.cos.ap-nanjing.myqcloud.com/WeChatb7bcfb33e47b8949ced831b8e79ffb0b.jpg" height="250"/> |
| [@fesjs/fes.js/issues](https://github.com/WeBankFinTech/fes.js/issues) | <img src="https://cos-1254145788.cos.ap-guangzhou.myqcloud.com/WechatIMG104.jpeg" height="250"/> |
</HomeContent>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

View File

@ -93,22 +93,6 @@ export default {
};
```
### console
- 类型: `object`
- 默认值:`{}`
- 详情:
用于控制应用启动的时候在 console 中打印的信息,目前仅支持 version
- 示例:
```js
export default {
console: {
version: true
}
};
```
### define
- 类型: `object`

View File

@ -9,7 +9,7 @@ import { withBase } from 'vitepress'
为了进一步降低研发成本,我们将布局利用 `fes.js` 插件的方式内置,只需通过简单的配置即可拥有布局,包括导航以及侧边栏。从而做到用户无需关心布局。
- 侧边栏菜单数据根据路由中的配置自动生成。
- 布局,提供 `side``top``mixin``left-right``top-left-right`种布局。
- 布局,提供 `side``top``mixin``left-right`种布局。
- 主题,提供 `light``dark` 两种主题。
- 默认实现对路由的 404、403 处理。
- 搭配 [@fesjs/plugin-access](./access.html) 插件使用,可以完成对路由的权限控制。
@ -34,7 +34,7 @@ import { withBase } from 'vitepress'
## 布局类型
配置参数是 `navigation`, 布局有五种类型 `side``mixin``top``left-right``top-left-right` 默认是 `side`
配置参数是 `navigation`, 布局有三种类型 `side``mixin``top``left-right` 默认是 `side`
### side
@ -53,12 +53,9 @@ import { withBase } from 'vitepress'
### left-right
<!-- ![mixin](/left-right.png) -->
<!-- ![mixin](/mixin.png) -->
<img :src="withBase('left-right.png')" alt="left-right">
<!-- ![mixin](/top-left-right.png) -->
<img :src="withBase('top-left-right.png')" alt="top-left-right">
### 页面个性化
可以为页面单独设置布局类型:
@ -130,14 +127,7 @@ export default {
}, {
name: 'simpleList'
}],
// 403 页面配置
403: {
title: '没有访问权限,请联系管理人员',
},
// 404 页面配置
404: {
title: '哎呀!这个页面找不到了',
}
},
};
```
@ -233,7 +223,7 @@ export function layout(layoutConfig, { initialState }) {
- **类型**`String`
- **默认值**:默认为 [编译时配置 title](../../../reference/config/#title)
- **详情**:产品名,当配置为"$"开头时,开启国际化,使用`$`后面的内容去匹配语言设置
- **详情**:产品名。
### logo
@ -253,7 +243,7 @@ export const layout = {
- **类型**`boolean`
- **默认值**`false`
- **详情**:是否开启多页。可通过 tabReload: false 控制标签页是否重新加载。
- **详情**:是否开启多页。
### menus
@ -268,10 +258,6 @@ export const layout = {
- **path**:菜单的路径,可配置第三方地址。
- **query**:同 vue-router 的 query 参数。
- **params**:同 vue-router 的 params 参数。
- **match (v4.0.0+**:额外匹配的路径,当前路由命中匹配规则时,此菜单高亮。
```
@ -300,7 +286,6 @@ export const layout = {
```
- **children**:子菜单配置。
- **_blank**:是否在新的窗口打开页面,默认 http 开头的链接在新窗口打开
:::tip
函数类型仅在运行时可用,可以实现动态变更菜单。
@ -391,7 +376,7 @@ export const layout = {
## API
### useTabTitle建议使用useLayout
### useTabTitle
类型定义如下:
@ -412,18 +397,6 @@ titleRef.value = 'changed';
</script>
```
### useLayout
类型定义如下:
```ts
function useLayout(options: { title?: string }): { title: Ref<string>; reloadTab: () => void; closeTab: () => void };
```
- title: 更新当前页签的标题
- reloadTab重载当前页签
- closeTab关闭当前页签
## 4.x 升级到 5.x
1. 个性化 layout 配置改为使用传入 navigation

View File

@ -69,9 +69,11 @@ export default {
想了解更多语言信息配置、匹配规则,请参考 [Vue I18n](https://vue-i18n.intlify.dev/guide/essentials/syntax.html) 文档。
### 多层配置
### 多层配置
如果国际化内容较多,希望模块化配置,则可以这样:
```
src
├── locales
│ ├── zh-CN.js
@ -82,7 +84,6 @@ src
└── pages
│ └── index.vue
└── app.js
```
插件会把相同语言的配置合并在一起!
@ -144,19 +145,7 @@ export default {
### 运行时配置
## onLocaleChange
当语言环境发生变化时,会触发此函数。
```js
import { defineRuntimeConfig } from '@fesjs/fes';
export default defineRuntimeConfig({
onLocaleChange: ({ t, locale }) => {
}
});
```
暂无。
## API

View File

@ -2,6 +2,7 @@
import antfu from '@antfu/eslint-config';
export default await antfu({
files: ['**/*.js', '**/*.jsx', '**/*.vue', '**/*.ts'],
// TODO: 使用 ignore 代替 cli 命令中的配置
stylistic: {
indent: 4,

View File

@ -1,9 +1,8 @@
{
"name": "fes.js",
"type": "module",
"version": "3.4.11",
"version": "3.1.6",
"private": true,
"packageManager": "pnpm@8.6.6",
"description": "一个好用的前端管理台快速开发框架",
"preferGlobal": true,
"workspaces": [
@ -40,18 +39,18 @@
"semver": "^7.3.6"
},
"devDependencies": {
"@antfu/eslint-config": "^3.8.0",
"@antfu/eslint-config": "^2.6.2",
"@commitlint/cli": "^18.4.4",
"@commitlint/config-conventional": "^18.4.4",
"chokidar": "^3.5.3",
"commitizen": "^4.3.1",
"commitizen": "^4.3.0",
"cz-conventional-changelog": "^3.3.0",
"deepmerge": "^4.2.2",
"eslint": "^9.13.0",
"eslint": "^8.56.0",
"fs-extra": "^11.1.1",
"lint-staged": "^15.2.0",
"simple-git-hooks": "^2.9.0",
"typescript": "^5.6.3",
"typescript": "^5.0.4",
"vitepress": "1.0.0-alpha.73",
"vue": "^3.3.4",
"yargs-parser": "^21.1.1"

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/create-fes-app",
"version": "3.0.6",
"version": "3.0.2",
"description": "create a app base on fes.js",
"main": "lib/index.js",
"files": [
@ -30,7 +30,7 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"fs-extra": "^11.1.1",
"inquirer": "^7.3.3",
"readline": "^1.3.0",

View File

@ -17,8 +17,8 @@
},
"dependencies": {
"@fesjs/fes": "^3.0.0",
"@fesjs/plugin-access": "^3.1.9",
"@fesjs/plugin-layout": "^5.4.3",
"@fesjs/plugin-access": "^3.0.0",
"@fesjs/plugin-layout": "^5.0.0",
"@fesjs/plugin-model": "^3.0.0",
"@fesjs/plugin-enums": "^3.0.0",
"@fesjs/fes-design": "^0.8.0",

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/builder-vite",
"version": "4.0.5",
"version": "4.0.2",
"description": "@fesjs/builder-vite",
"author": "qlin",
"license": "MIT",
@ -25,12 +25,12 @@
"access": "public"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.12",
"@fesjs/fes": "^3.1.8",
"core-js": "^3.29.1"
},
"dependencies": {
"@babel/core": "^7.23.3",
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"@rollup/pluginutils": "^5.1.0",
"@vitejs/plugin-basic-ssl": "^1.0.2",
"@vitejs/plugin-legacy": "^5.2.0",

View File

@ -25,7 +25,7 @@ export default async (api, args) => {
args: {},
});
const isHTTPS = !!(process.env.HTTPS || args.https || api.config.viteOption.server?.https);
const isHTTPS = !!(process.env.HTTPS || args.https);
const bundleConfig = deepmerge(getInnerCommonConfig(api), {
mode: 'development',

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/builder-webpack",
"version": "3.1.0",
"version": "3.0.12",
"description": "@fesjs/builder-webpack",
"author": "qlin",
"license": "MIT",
@ -26,7 +26,7 @@
"access": "public"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.17",
"@fesjs/fes": "^3.1.10",
"core-js": "^3.29.1"
},
"dependencies": {
@ -38,7 +38,7 @@
"@babel/plugin-transform-runtime": "^7.23.2",
"@babel/preset-env": "^7.23.2",
"@babel/preset-typescript": "^7.23.2",
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"@vue/babel-plugin-jsx": "^1.2.2",
"ajv": "^8.12.0",
"autoprefixer": "^10.4.14",
@ -52,7 +52,7 @@
"fs-extra": "^11.1.1",
"get-folder-size": "^2.0.1",
"html-webpack-plugin": "^5.5.0",
"html-webpack-tags-plugin": "^3.0.2",
"html-webpack-tags-plugin": "^3.0.0",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.8.1",
@ -66,7 +66,7 @@
"webpack": "^5.90.3",
"webpack-5-chain": "^8.0.1",
"webpack-bundle-analyzer": "^4.4.0",
"webpack-dev-server": "^5.1.0",
"webpackbar": "^7.0.0"
"webpack-dev-server": "^4.15.1",
"webpackbar": "^5.0.2"
}
}

View File

@ -1,21 +1,13 @@
import { extname } from 'node:path';
import { extname } from 'path';
import historyFallback from 'connect-history-api-fallback';
const ASSET_EXT_NAMES = ['.ico', '.png', '.jpg', '.jpeg', '.gif', '.svg'];
function proxyMiddleware(api) {
return (req, res, next) => {
const proxyMiddleware = (api) => (req, res, next) => {
const proxyConfig = api.config.proxy;
if (proxyConfig) {
if (Array.isArray(proxyConfig)) {
if (proxyConfig.some(item => item.context.some(path => path && req.url.startsWith(path)))) {
if (proxyConfig && Object.keys(proxyConfig).some((path) => req.url.startsWith(path))) {
return next();
}
}
else if (Object.keys(proxyConfig).some(path => req.url.startsWith(path))) {
return next();
}
}
if (ASSET_EXT_NAMES.includes(extname(req.url))) {
return next();
}
@ -23,6 +15,5 @@ function proxyMiddleware(api) {
const history = historyFallback();
history(req, res, next);
};
}
export default proxyMiddleware;

View File

@ -1,23 +1,6 @@
import { chalk } from '@fesjs/utils';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';
function formatProxy(proxy) {
if (!proxy) {
return [];
}
if (Array.isArray(proxy)) {
return proxy;
}
return Object.keys(proxy).map((apiPath) => {
return {
context: [apiPath],
...proxy[apiPath],
};
});
}
import webpack from 'webpack';
import { chalk } from '@fesjs/utils';
export function startDevServer({ webpackConfig, host, port, proxy, https, beforeMiddlewares, afterMiddlewares, customerDevServerConfig }) {
const options = {
@ -27,7 +10,6 @@ export function startDevServer({ webpackConfig, host, port, proxy, https, before
client: {
logging: 'error',
overlay: false,
progress: true,
webSocketURL: {
hostname: host,
port,
@ -45,20 +27,12 @@ export function startDevServer({ webpackConfig, host, port, proxy, https, before
...(customerDevServerConfig || {}),
port,
host,
proxy: formatProxy(proxy),
proxy,
};
const compiler = webpack(webpackConfig);
const server = new WebpackDevServer(options, compiler);
if (options.host === '0.0.0.0') {
// eslint-disable-next-line no-console
console.log(chalk.green(' ➜ Local: '), chalk.cyan(`${options.server}://127.0.0.1:${options.port}`));
// eslint-disable-next-line no-console
console.log(chalk.gray(' ➜ Network: '), chalk.gray(`${options.server}://${options.host}:${options.port}`));
}
else {
// eslint-disable-next-line no-console
console.log(chalk.green(' ➜ :Local: '), chalk.cyan(`${options.server}://${options.host}:${options.port}`));
}
console.log(chalk.green('Server: '), chalk.blue(`${options.server}://${options.host}:${options.port}`));
server.startCallback((err) => {
if (err) {
console.error(err);

View File

@ -1,6 +1,5 @@
import fs from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import path from 'path';
import fs from 'fs';
import { cleanTmpPathExceptCache, getBundleAndConfigs } from '../../common/buildDevUtils';
import connectHistoryMiddleware from './connectHistoryMiddleware';

View File

@ -1,13 +1,13 @@
import { existsSync } from 'node:fs';
import { join } from 'node:path';
import webpack from 'webpack';
import { existsSync } from 'node:fs';
import Config from 'webpack-5-chain';
import webpack from 'webpack';
import createCssWebpackConfig from './css';
import createDefineWebpackConfig from './define';
import getBabelOpts from './getBabelOpts';
import createHtmlWebpackConfig from './html';
import createMinimizerWebpackConfig from './minimizer';
import createVueWebpackConfig from './vue';
import createDefineWebpackConfig from './define';
import createMinimizerWebpackConfig from './minimizer';
import createHtmlWebpackConfig from './html';
const DEFAULT_EXCLUDE_NODE_MODULES = [
'vue',
@ -124,14 +124,12 @@ export default async function getConfig({ api, cwd, config, env, entry = {}, mod
webpackConfig.module
.rule('esm')
.test(/\.m?jsx?$/)
.resolve
.set('fullySpecified', false);
.resolve.set('fullySpecified', false);
webpackConfig.module
.rule('js')
.test(/\.(js|mjs|jsx|ts|tsx)$/)
.exclude
.add((filepath) => {
.exclude.add((filepath) => {
// always transpile js in vue files
if (/(\.vue|\.jsx)$/.test(filepath)) { return false; }
@ -149,11 +147,9 @@ export default async function getConfig({ api, cwd, config, env, entry = {}, mod
webpackConfig.module
.rule('js-in-node_modules')
.test(/\.(js|mjs)$/)
.include
.add(/node_modules/)
.include.add(/node_modules/)
.end()
.exclude
.add((filepath) => {
.exclude.add((filepath) => {
if (transpileDepRegex && transpileDepRegex.test(filepath)) { return true; }
return false;

View File

@ -1,25 +1,25 @@
{
"name": "@fesjs/compiler",
"version": "3.0.6",
"version": "3.0.2",
"description": "@fesjs/compiler",
"author": "qlin",
"license": "MIT",
"homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"main": "lib/index.js",
"files": [
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-compiler"
},
"bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues"
},
"keywords": [
"fes"
],
"main": "lib/index.js",
"files": [
"lib"
],
"author": "qlin",
"license": "MIT",
"bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues"
},
"homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": {
"access": "public"
},
@ -27,10 +27,11 @@
"@babel/core": "^7.23.2",
"@babel/preset-env": "^7.23.2",
"@babel/register": "^7.22.15",
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"commander": "^7.0.0",
"dotenv": "8.2.0",
"joi": "17.3.0",
"set-value": "3.0.2",
"tapable": "^2.2.0"
}
}

View File

@ -1,16 +1,17 @@
import { lodash } from '@fesjs/utils';
import set from 'set-value';
export function updateUserConfigWithKey({
key,
value,
userConfig,
userConfig
}) {
lodash.set(userConfig, key, value);
set(userConfig, key, value);
}
export function getUserConfigWithKey({
key,
userConfig,
userConfig
}) {
return lodash.get(userConfig, key);
}

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-access",
"version": "3.1.9",
"version": "3.1.4",
"description": "@fesjs/plugin-access",
"main": "lib/index.js",
"files": [
@ -28,11 +28,11 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"lodash-es": "^4.17.21"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.13",
"@fesjs/fes": "^3.1.9",
"vue": "^3.2.47",
"vue-router": "^4.0.1"
},

View File

@ -1,7 +1,7 @@
import { computed, reactive, unref } from "vue";
import { isPlainObject } from "{{{ lodashPath }}}";
import createComponent from "./createComponent";
import { reactive, unref, computed, inject } from "vue";
import createDirective from "./createDirective";
import createComponent from "./createComponent";
import {isPlainObject} from "{{{ lodashPath }}}";
function isPromise(obj) {
return (
@ -20,23 +20,12 @@ const state = reactive({
const rolePromiseList = [];
const accessPromiseList = [];
// 预设的 accessId且不会被移除
const presetAccessIds = []
const setPresetAccess = (access) => {
const accessIds = Array.isArray(access) ? access : [access];
presetAccessIds.push(...accessIds.filter(id => !presetAccessIds.includes(id)));
}
const getAllowAccessIds = () => {
const result = [...presetAccessIds, ...state.currentAccessIds];
const roleAccessIds = state.roles[state.currentRoleId];
if (Array.isArray(roleAccessIds) && roleAccessIds.length > 0) {
result.push(...roleAccessIds);
return state.currentAccessIds.concat(roleAccessIds);
}
return result;
return state.currentAccessIds;
};
const _syncSetAccessIds = (promise) => {
@ -145,13 +134,8 @@ export const install = (app) => {
app.component("Access", createComponent(useAccess));
};
export const hasAccessSync = (path) => {
return match(unref(path), getAllowAccessIds());
}
export const access = {
hasAccess,
hasAccessSync,
isDataReady,
setRole,
getRole: () => {
@ -160,9 +144,12 @@ export const access = {
setAccess,
match,
getAccess: getAllowAccessIds,
setPresetAccess,
};
export const hasAccessSync = (path) => {
return match(unref(path), getAllowAccessIds());
}
export const useAccess = (path) => {
const allowPageIds = computed(getAllowAccessIds);
const result = computed(() => {

View File

@ -13,10 +13,7 @@ export default function createDirective(useAccess) {
beforeMount(el) {
const ctx = {};
ctx.watch = (path) => {
// el._display = el._display || el.style.display; // 这种只能获取到行内样式 会导致保存不了组件加载时的初始display
if (!el._display) {
el._display = window.getComputedStyle(el).display
}
el._display = el._display || el.style.display;
const access = useAccess(path);
setDisplay(el, access);
return watch(access, () => {

View File

@ -3,14 +3,10 @@ import type { Ref } from 'vue';
export const access: {
hasAccess: (accessId: string | number) => Promise<boolean>;
hasAccessSync: (accessId: string | number) => boolean;
isDataReady: () => boolean;
setRole: (roleId: string | Promise<string>) => void;
getRole: () => string;
setAccess: (accessIds: Array<string | number> | Promise<Array<string | number>>) => void;
getAccess: () => string[];
match: (path: string, accessIds: string[]) => boolean;
setPresetAccess: (accessId: string | string[]) => void;
};
export function useAccess(accessId: string | number): Ref<boolean>;

View File

@ -1,21 +1,7 @@
{
"name": "@fesjs/plugin-icon",
"version": "4.0.0",
"version": "3.0.0",
"description": "@fesjs/plugin-icon",
"author": "qlin",
"license": "MIT",
"homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-icon"
},
"bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues"
},
"keywords": [
"fes"
],
"main": "lib/index.js",
"files": [
"lib",
@ -24,6 +10,20 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-icon"
},
"keywords": [
"fes"
],
"author": "qlin",
"license": "MIT",
"bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues"
},
"homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": {
"access": "public"
},

View File

@ -1,5 +1,5 @@
import { basename, extname } from 'node:path';
import { readFileSync, statSync } from 'node:fs';
import { extname, basename } from 'path';
import { statSync, readFileSync } from 'fs';
import { optimize } from 'svgo';
const presetDefault = [
@ -15,7 +15,7 @@ const presetDefault = [
{
name: 'removeAttrs',
params: {
attrs: '(class)',
attrs: '(fill|stroke|class)',
},
},
];

View File

@ -1,8 +1,8 @@
import { computed } from 'vue';
// eslint-disable-next-line
import icons from '../icons';
function noop() {}
const noop = () => {};
export default {
name: 'FesIcon',

View File

@ -29,7 +29,6 @@
&[tabindex] {
cursor: pointer;
}
&--spin {
display: inline-block;
animation: loadingCircle 1s infinite linear;

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-layout",
"version": "5.4.6",
"version": "5.1.10",
"description": "@fesjs/plugin-layout",
"author": "harrywan",
"license": "MIT",
@ -28,15 +28,14 @@
"access": "public"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.17",
"@fesjs/fes": "^3.1.9",
"@fesjs/fes-design": ">=0.7.0",
"vue": "^3.2.47",
"vue-router": "^4.0.1"
},
"dependencies": {
"@fesjs/utils": "^3.0.3",
"@vueuse/core": "^10.7.0",
"dompurify": "^3.1.7"
"@fesjs/utils": "^3.0.1",
"@vueuse/core": "^10.7.0"
},
"typings": "./types.d.ts"
}

View File

@ -30,13 +30,6 @@ export default (api) => {
const absRuntimeFilePath = join(namespace, 'runtime.js');
api.register({
key: 'addExtraLocales',
fn: () => [
join(api.paths.absTmpPath, namespace, 'locales'),
],
});
api.onGenerateFiles(async () => {
// .fes配置
const userConfig = {
@ -122,7 +115,6 @@ export default (api) => {
return [
{
path: '/',
name: 'fesLayout',
component: winPath(join(api.paths.absTmpPath || '', absFilePath)),
children: routes,
},

View File

@ -1,4 +1,4 @@
function getMetaByName(config, name) {
const getMetaByName = (config, name) => {
let res = {};
if (Array.isArray(config)) {
for (let i = 0; i < config.length; i++) {
@ -17,9 +17,9 @@ function getMetaByName(config, name) {
}
}
return res;
}
};
function fillMenuByRoute(menuConfig, routeConfig, dep = 0) {
const fillMenuByRoute = (menuConfig, routeConfig, dep = 0) => {
dep += 1;
if (dep > 3) {
console.warn('[plugin-layout]: 菜单层级最好不要超出三层!');
@ -44,6 +44,6 @@ function fillMenuByRoute(menuConfig, routeConfig, dep = 0) {
});
}
return arr;
}
};
export default fillMenuByRoute;

View File

@ -1,6 +1,6 @@
import { plugin } from '@@/core/coreExports';
export function transTitle(name) {
export const transTitle = (name) => {
if (!/^\$\S+$/.test(name)) {
return name;
}
@ -10,10 +10,10 @@ export function transTitle(name) {
return t(name.slice(1));
}
return name;
}
};
export function transform(menus) {
return menus.map((menu) => {
export const transform = (menus) =>
menus.map((menu) => {
const copy = {
...menu,
label: transTitle(menu.label),
@ -23,4 +23,3 @@ export function transform(menus) {
}
return copy;
});
}

View File

@ -1,10 +1,8 @@
import DOMPurify from 'dompurify';
const isStr = function (str) {
return typeof str === 'string';
};
export function isValid(elm) {
export const isValid = (elm) => {
if (elm.nodeType === 1) {
if (elm.nodeName.toLowerCase() === 'script') {
return false;
@ -24,11 +22,11 @@ export function isValid(elm) {
}
}
return true;
}
};
export function validateContent(svgContent) {
export const validateContent = (svgContent) => {
const div = document.createElement('div');
div.innerHTML = DOMPurify.sanitize(svgContent);
div.innerHTML = svgContent;
// setup this way to ensure it works on our buddy IE
for (let i = div.childNodes.length - 1; i >= 0; i--) {
@ -48,4 +46,4 @@ export function validateContent(svgContent) {
}
}
return '';
}
};

View File

@ -1,9 +1,8 @@
export function flatNodes(nodes = []) {
return nodes.reduce((res, node) => {
export const flatNodes = (nodes = []) =>
nodes.reduce((res, node) => {
res.push(node);
if (node.children) {
res = res.concat(flatNodes(node.children));
}
return res;
}, []);
}

View File

@ -1,2 +1,3 @@
export { default as Page } from './views/page.vue';
export { useTabTitle } from './useTitle';
export * from './useLayout';

View File

@ -1,6 +0,0 @@
export default {
pluginLayout: {
closeOtherPage: 'Close Other Page',
reloadPage: 'Reload Page',
},
};

View File

@ -1,6 +0,0 @@
export default {
pluginLayout: {
closeOtherPage: '关闭其他页签',
reloadPage: '刷新当前页签',
},
};

View File

@ -8,8 +8,13 @@ if (!accessApi) {
export const access = (memo) => {
const runtimeConfig = getConfig();
accessApi.setPresetAccess(['/403', '/404']);
const accessIds = accessApi.getAccess();
if (!accessIds.includes('/403')) {
accessApi.setAccess(accessIds.concat('/403'));
}
if (!accessIds.includes('/404')) {
accessApi.setAccess(accessIds.concat('/404'));
}
return {
unAccessHandler({ router, to, from, next }) {
if (runtimeConfig.unAccessHandler && typeof runtimeConfig.unAccessHandler === 'function') {

View File

@ -1,31 +1,12 @@
import { inject, ref } from 'vue';
import { createSharedComposable } from '@vueuse/core';
import { shallowReactive } from 'vue';
import { useRoute } from '@@/core/coreExports';
function _useLayout() {
const state = shallowReactive({
closeTab: () => {},
});
export const PLUGIN_LAYOUT_TITLE_KEY = Symbol('PLUGIN_LAYOUT_TITLE_KEY');
export const PLUGIN_LAYOUT_KEY = Symbol('PLUGIN_LAYOUT_KEY');
export function useTabTitle(title) {
const titleMap = inject(PLUGIN_LAYOUT_TITLE_KEY);
if (!titleMap) {
console.warn('[plugin-layout]: 未正确获取到titleMap');
return;
}
const route = useRoute();
const titleRef = ref(title);
const path = route.path;
titleMap.set(path, titleRef);
return titleRef;
return state;
}
export function useLayout(options) {
const parent = inject(PLUGIN_LAYOUT_KEY, { reloadTab: () => void 0, closeTab: () => void 0 });
const titleRef = useTabTitle(options?.title);
return {
...parent,
title: titleRef,
};
}
export const useLayout = createSharedComposable(_useLayout);

View File

@ -0,0 +1,18 @@
import { reactive, ref } from 'vue';
import { useRoute } from '@@/core/coreExports';
const cache = reactive(new Map());
export const getTitle = path => cache.get(path);
export const deleteTitle = patch => cache.delete(patch);
export function useTabTitle(title) {
const route = useRoute();
const titleRef = ref(title);
const path = route.path;
cache.set(path, titleRef);
return titleRef;
}

View File

@ -1,10 +1,8 @@
<template>
<Wrapper :icon-src="img403" :title="title" sub-title="" />
<Wrapper :iconSrc="img403" title="没有访问权限,请联系管理人员" subTitle="" />
</template>
<script>
import { computed, defineComponent } from 'vue';
import getConfig from '../helpers/getConfig';
import { defineComponent } from 'vue';
import img403 from '../assets/403.png';
import Wrapper from './components/Wrapper.vue';
@ -13,13 +11,8 @@ export default defineComponent({
Wrapper,
},
setup() {
const config = getConfig();
const title = computed(() => {
return config['403']?.title || '没有访问权限,请联系管理人员';
});
return {
img403,
title,
};
},
});

View File

@ -1,11 +1,9 @@
<template>
<Wrapper :icon-src="img404" :title="title" sub-title="" />
<Wrapper :iconSrc="img404" title="哎呀!这个页面找不到了" subTitle="" />
</template>
<script>
import { computed, defineComponent } from 'vue';
import { defineComponent } from 'vue';
import img404 from '../assets/404.png';
import getConfig from '../helpers/getConfig';
import Wrapper from './components/Wrapper.vue';
export default defineComponent({
@ -13,14 +11,8 @@ export default defineComponent({
Wrapper,
},
setup() {
const config = getConfig();
const title = computed(() => {
return config['404']?.title || '哎呀!这个页面找不到了';
});
return {
img404,
title,
};
},
});

View File

@ -11,8 +11,8 @@
>
<div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img">
<div v-if="transformedTitle" class="logo-name">
{{ transformedTitle }}
<div v-if="title" class="logo-name">
{{ title }}
</div>
</div>
<LayoutMenu
@ -58,8 +58,8 @@
<div>
<div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img">
<div v-if="transformedTitle" class="logo-name">
{{ transformedTitle }}
<div v-if="title" class="logo-name">
{{ title }}
</div>
</div>
<LayoutMenu
@ -98,8 +98,8 @@
<FHeader ref="headerRef" class="layout-header" :inverted="theme === 'dark'" :fixed="currentFixedHeaderRef">
<div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img">
<div v-if="transformedTitle" class="logo-name">
{{ transformedTitle }}
<div v-if="title" class="logo-name">
{{ title }}
</div>
</div>
<LayoutMenu
@ -127,65 +127,12 @@
</FFooter>
</FLayout>
</template>
<template v-else-if="currentNavigation === 'top-left-right'">
<FHeader ref="headerRef" class="layout-header" :inverted="theme === 'dark'" :fixed="currentFixedHeaderRef">
<div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img">
<div v-if="transformedTitle" class="logo-name">
{{ transformedTitle }}
</div>
</div>
<LayoutMenu
class="layout-menu"
:menus="rootMenus"
mode="horizontal"
:inverted="theme === 'dark'"
/>
<div class="layout-header-custom">
<slot name="renderCustom" :menus="menus" />
</div>
<template v-if="locale">
<slot name="locale" />
</template>
</FHeader>
<FLayout v-if="activeSubMenus.length" :embedded="!multiTabs" :fixed="currentFixedHeaderRef" :style="headerStyleRef">
<FAside v-model:collapsed="collapsedRef" :inverted="theme === 'dark'" :fixed="isFixedSidebar" :width="`${sideWidth}px`" collapsible class="layout-aside">
<LayoutMenu
class="layout-menu"
:menus="activeSubMenus"
:collapsed="collapsedRef"
mode="vertical"
:expanded-keys="menuProps?.expandedKeys"
:default-expand-all="menuProps?.defaultExpandAll"
:accordion="menuProps?.accordion"
:inverted="theme === 'dark'"
/>
</FAside>
<FLayout :embedded="!multiTabs" :fixed="isFixedSidebar" :style="sideStyleRef">
<FMain class="layout-main">
<MultiTabProvider :multi-tabs="multiTabs" />
</FMain>
<FFooter v-if="footer" class="layout-footer">
{{ footer }}
</FFooter>
</FLayout>
</FLayout>
<FLayout v-else :embedded="!multiTabs" :fixed="currentFixedHeaderRef" :style="headerStyleRef">
<FMain class="layout-main">
<MultiTabProvider :multi-tabs="multiTabs" />
</FMain>
<FFooter v-if="footer" class="layout-footer">
{{ footer }}
</FFooter>
</FLayout>
</template>
<template v-else-if="currentNavigation === 'mixin'">
<FHeader ref="headerRef" class="layout-header" :fixed="currentFixedHeaderRef" :inverted="theme === 'dark'">
<div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img">
<div v-if="transformedTitle" class="logo-name">
{{ transformedTitle }}
<div v-if="title" class="logo-name">
{{ title }}
</div>
</div>
<div class="layout-header-custom">
@ -230,8 +177,6 @@ import { useRoute, useRouter } from '@@/core/coreExports';
import { FAside, FFooter, FHeader, FLayout, FMain } from '@fesjs/fes-design';
import { computed, nextTick, ref, watch } from 'vue';
import defaultLogo from '../assets/logo.png';
import { flatNodes } from '../helpers/utils';
import { transTitle } from '../helpers/pluginLocale';
import LayoutMenu from './Menu.vue';
import MultiTabProvider from './MultiTabProvider.vue';
@ -270,7 +215,7 @@ export default {
},
navigation: {
type: String,
default: 'side', // side / top / mixin //top-left-right //
default: 'side', // side / top / mixin //
},
navigationOnError: {
type: [String, Function], // 403, 404 navigation
@ -303,10 +248,6 @@ export default {
const route = useRoute();
const router = useRouter();
const transformedTitle = computed(() => {
return transTitle(props.title);
});
const currentNavigation = computed(() => {
if (route.meta.layout && route.meta.layout.navigation !== undefined) {
return route.meta.layout.navigation;
@ -341,56 +282,6 @@ export default {
},
);
const rootMenus = computed(() => {
return props.menus.map((menu) => {
const { children, match, ...others } = menu;
let { path, query, params } = menu;
const flatChildren = flatNodes(children || []);
if (!menu.path) {
const firstChild = flatChildren.find(item => item.path);
if (firstChild) {
path = firstChild.path;
query = firstChild.query;
params = firstChild.params;
}
}
return {
...others,
path,
query,
params,
match: (match || [])
.concat(...flatChildren.map(item => []
.concat(item.match || [])
.concat(item.path)),
),
_children: children,
};
});
});
const activeRootMenu = computed(() => {
const matchRootMenus = rootMenus.value.filter((menu) => {
const match = menu.match;
if (!match || !Array.isArray(match)) {
return false;
}
return match.some((str) => {
const reg = new RegExp(str);
return reg.test(route.path);
});
});
return matchRootMenus[0] ?? null;
});
const activeSubMenus = computed(() => {
if (!activeRootMenu.value) {
return [];
}
return activeRootMenu.value._children || [];
});
return {
headerRef,
headerHeightRef,
@ -400,9 +291,6 @@ export default {
headerStyleRef,
sideStyleRef,
currentNavigation,
rootMenus,
activeSubMenus,
transformedTitle,
};
},
};

View File

@ -1,7 +1,7 @@
<template>
<FMenu
v-model:expanded-keys="expandedKeysRef"
v-model="activeMenu"
v-model:expandedKeys="expandedKeysRef"
:model-value="activePath"
:inverted="inverted"
:mode="mode"
:options="transformedMenus"
@ -12,9 +12,9 @@
</template>
<script>
import { useRoute, useRouter } from '@@/core/coreExports';
import { computed, h, ref, watch } from 'vue';
import { FMenu } from '@fesjs/fes-design';
import { computed, h, nextTick, ref, watch } from 'vue';
import { useRoute, useRouter } from '@@/core/coreExports';
import { transform as transformByAccess } from '../helpers/pluginAccess';
import { transform as transformByLocale } from '../helpers/pluginLocale';
import { flatNodes } from '../helpers/utils';
@ -79,7 +79,6 @@ export default {
const router = useRouter();
const transformedMenus = computed(() => transformByLocale(transformByAccess(transform(props.menus))));
const menuArray = computed(() => flatNodes(transformedMenus.value));
const activePath = computed(() => {
const matchMenus = menuArray.value.filter((menu) => {
const match = menu.match;
@ -97,12 +96,6 @@ export default {
return matchMenus[0].path;
});
const activeMenu = ref(activePath.value);
watch(activePath, () => {
activeMenu.value = activePath.value;
});
const expandedKeysRef = ref(props.expandedKeys);
watch(
@ -132,32 +125,11 @@ export default {
const onMenuClick = (e) => {
const path = e.value;
const currentMenu = menuArray.value.find(item => item.value === path);
if (currentMenu._blank) {
const resolved = router.resolve({
path,
query: currentMenu?.query || {},
params: currentMenu?.params || {},
});
// TODO
nextTick(() => {
activeMenu.value = activePath.value;
});
window.open(resolved.href, '_blank');
}
else if (/^https?:\/\//.test(path)) {
// TODO
nextTick(() => {
activeMenu.value = activePath.value;
});
if (/^https?:\/\//.test(path)) {
window.open(path, '_blank');
}
else if (/^\//.test(path)) {
router.push({
path,
query: currentMenu?.query || {},
params: currentMenu?.params || {},
});
router.push(path);
}
else {
console.warn('[plugin-layout]: 菜单的path只能是以http(s)开头的网址或者路由地址');
@ -165,7 +137,6 @@ export default {
};
return {
activeMenu,
activePath,
expandedKeysRef,
transformedMenus,

View File

@ -1,11 +1,11 @@
<script lang="jsx">
import { isVNode, onBeforeMount, ref } from 'vue';
import { ref, onBeforeMount, isVNode } from 'vue';
// eslint-disable-next-line import/extensions
import Icons from '../icons';
import { validateContent } from '../helpers/svg';
const urlReg = /^((https?|ftp|file):\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/;
const isUrlResource = name => urlReg.test(name) || name.includes('.svg');
const isUrlResource = (name) => urlReg.test(name) || name.includes('.svg');
export default {
props: {
@ -25,8 +25,7 @@ export default {
});
}
});
}
else {
} else {
AIconComponent.value = Icons[props.icon];
}
}
@ -40,14 +39,13 @@ export default {
return <AIconComponent.value />;
}
if (AText.value) {
return <span class="fes-layout-icon" innerHTML={AText.value}></span>;
return <span class={'fes-layout-icon'} innerHTML={AText.value}></span>;
}
return null;
};
},
};
</script>
<style>
.fes-layout-icon {
display: inline-block;

View File

@ -7,12 +7,12 @@
type="card"
class="layout-content-tabs"
@close="handleCloseTab"
@update:model-value="switchPage"
@update:modelValue="switchPage"
>
<FTabPane v-for="page in pageList" :key="page.path" :value="page.path" :closable="pageList.length > 1">
<template #tab>
{{ page.title }}
<ReloadOutlined v-if="page.tabReload" v-show="route.path === page.path" class="layout-tabs-close-icon" @click="reloadPage(page.path)" />
<ReloadOutlined v-show="route.path === page.path" class="layout-tabs-close-icon" @click="reloadPage(page.path)" />
</template>
</FTabPane>
<template #suffix>
@ -27,12 +27,13 @@
</template>
<script>
import { computed, provide, reactive, ref, unref } from 'vue';
import { computed, ref, unref } from 'vue';
import { FDropdown, FTabPane, FTabs } from '@fesjs/fes-design';
import { MoreOutlined, ReloadOutlined } from '@fesjs/fes-design/icon';
import { plugin, useRoute, useRouter } from '@@/core/coreExports';
import { useRoute, useRouter } from '@@/core/coreExports';
import { transTitle } from '../helpers/pluginLocale';
import { PLUGIN_LAYOUT_KEY, PLUGIN_LAYOUT_TITLE_KEY } from '../useLayout';
import { deleteTitle, getTitle } from '../useTitle';
import { useLayout } from '../useLayout';
import Page from './page.vue';
let i = 0;
@ -53,14 +54,7 @@ export default {
const pageRef = ref();
const route = useRoute();
const router = useRouter();
const titleCache = reactive(new Map());
provide(PLUGIN_LAYOUT_TITLE_KEY, titleCache);
const getTitle = path => titleCache.get(path);
const deleteTitle = patch => titleCache.delete(patch);
const layoutState = useLayout();
const createPage = (_route) => {
const computedTitle = computed(() => {
@ -73,28 +67,11 @@ export default {
name: _route.meta.name ?? _route.name,
title: computedTitle,
key: getKey(),
tabReload: _route.meta.tabReload ?? true,
};
};
const pageList = ref([createPage(router.currentRoute.value)]);
const actions = computed(() => {
const sharedLocale = plugin.getShared('locale');
if (sharedLocale) {
const { t } = sharedLocale.locale;
return [
{
value: 'closeOtherPage',
label: t('pluginLayout.closeOtherPage'),
},
{
value: 'reloadPage',
label: t('pluginLayout.reloadPage'),
},
];
}
return [
const actions = [
{
value: 'closeOtherPage',
label: '关闭其他页签',
@ -104,19 +81,16 @@ export default {
label: '刷新当前页签',
},
];
});
const findPage = path => pageList.value.find(item => unref(item.path) === unref(path));
router.beforeEach((to) => {
const page = findPage(to.path);
if (!page) {
if (!page)
pageList.value = [...pageList.value, createPage(to)];
}
else {
else
page.route = to;
}
return true;
});
@ -135,33 +109,28 @@ export default {
const handleCloseTab = async (targetKey) => {
targetKey = targetKey || route.path;
const selectedPage = findPage(targetKey);
if (!selectedPage) {
return;
}
const list = [...pageList.value];
const index = list.indexOf(selectedPage);
if (route.path === selectedPage.path) {
if (list.length > 1) {
if (list.length - 1 === index) {
if (list.length - 1 === index)
await switchPage(list[index - 1].path);
}
else {
else
await switchPage(list[index + 1].path);
}
}
}
list.splice(index, 1);
pageList.value = list;
pageRef.value.removeKeepAlive(selectedPage.name);
deleteTitle(selectedPage.path);
};
layoutState.closeTab = handleCloseTab;
const reloadPage = (path) => {
const selectedPage = findPage(path || unref(route.path));
if (selectedPage) {
if (selectedPage)
selectedPage.key = getKey();
}
};
const closeOtherPage = (path) => {
const selectedPage = findPage(path || unref(route.path));
@ -170,9 +139,8 @@ export default {
};
const getPageKey = (_route) => {
const selectedPage = findPage(_route.path);
if (selectedPage) {
if (selectedPage)
return selectedPage.key;
}
return '';
};
@ -188,11 +156,6 @@ export default {
}
};
provide(PLUGIN_LAYOUT_KEY, {
closeTab: handleCloseTab,
reloadTab: reloadPage,
});
return {
pageRef,
route,

View File

@ -22,14 +22,12 @@ interface Menu {
children?: Menu[];
}
type Navigation = 'side' | 'mixin' | 'top' | 'left-right' | 'top-left';
type Navigation = 'side' | 'mixin' | 'top' | 'left-right';
export const Page: Component;
export function useTabTitle(title: string | Ref<string>): void;
export function useLayout(options: { title?: string }): { title: Ref<string>; reloadTab: () => void; closeTab: () => void };
interface LayoutRuntimeConfig {
footer?: string;
theme?: 'dark' | 'light';

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-locale",
"version": "4.4.0",
"version": "4.2.2",
"description": "@fesjs/plugin-locale",
"main": "lib/index.js",
"files": [
@ -28,12 +28,12 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"vue-i18n": "^9.0.0",
"lodash-es": "^4.17.21"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.12",
"@fesjs/fes": "^3.1.9",
"@fesjs/fes-design": ">=0.7.0",
"vue": "^3.2.47"
},

View File

@ -1,5 +1,5 @@
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { readFileSync } from 'fs';
import { join } from 'path';
import { name } from '../package.json';
const namespace = 'plugin-locale';
@ -24,8 +24,6 @@ export default (api) => {
api.addRuntimePluginKey(() => 'locale');
api.addRuntimePluginKey(() => 'onLocaleChange');
const absoluteFilePath = join(namespace, 'core.js');
const absRuntimeFilePath = join(namespace, 'runtime.js');
@ -34,17 +32,10 @@ export default (api) => {
return join(api.paths.absSrcPath, api.config.singular ? 'locale' : 'locales');
}
api.register({
key: 'addExtraLocales',
fn: () => [
getLocaleFileBasePath(),
],
});
// 监听 locale 文件改变,重新生成文件
api.addTmpGenerateWatcherPaths(getLocaleFileBasePath);
api.onGenerateFiles(async () => {
api.onGenerateFiles(() => {
// .fes配置
const userConfig = {
locale: 'zh-CN', // default locale
@ -54,13 +45,9 @@ export default (api) => {
...api.config.locale,
};
const additionalLocales = await api.applyPlugins({
key: 'addExtraLocales',
type: api.ApplyPluginsType.add,
initialValue: [],
});
const localeConfigFileBasePath = getLocaleFileBasePath();
const { files, locales } = getLocales(additionalLocales);
const { files, locales } = getLocales(localeConfigFileBasePath);
const { baseNavigator, ...otherConfig } = userConfig;
@ -68,7 +55,7 @@ export default (api) => {
path: join(namespace, 'locales.js'),
content: Mustache.render(readFileSync(join(__dirname, 'runtime/locales.js.tpl'), 'utf-8'), {
REPLACE_IMPORTS: files,
REPLACE_LOCALES: locales.map(item => ({
REPLACE_LOCALES: locales.map((item) => ({
locale: item.locale,
importNames: item.importNames.join(', '),
})),

View File

@ -8,7 +8,7 @@
import { isRef, unref } from 'vue';
import { createI18n, useI18n } from '{{{ VUE_I18N_PATH }}}';
import locales from './locales'
import { plugin, ApplyPluginsType } from '@@/core/coreExports';
const defaultOptions = {{{REPLACE_DEFAULT_OPTIONS}}};
@ -19,22 +19,18 @@ const getDefaultLocale = () => {
if (fes_locale) {
return {
locale: fes_locale,
fallbackLocale: defaultOptions.fallbackLocale,
fallbackLocale: fes_locale,
};
}
if (BASE_NAVIGATOR) {
const keys = locales.map(item=> item.locale);
const findKey = keys.find(item=> item.includes(window.navigator.language))
if(findKey){
return {
locale: findKey,
fallbackLocale: defaultOptions.fallbackLocale,
locale: window.navigator.language,
fallbackLocale: window.navigator.language,
};
}
}
return {
locale: defaultOptions.locale,
fallbackLocale: defaultOptions.fallbackLocale,
locale: 'zh-CN',
fallbackLocale: 'zh-CN',
};
};
@ -51,8 +47,6 @@ const i18n = createI18n({
messages,
});
const t = i18n.global.t;
window.localStorage.setItem("fes_locale", unref(i18n.global.locale));
const setLocale = ({ locale }) => {
if (isRef(i18n.global.locale)) {
@ -61,11 +55,6 @@ const setLocale = ({ locale }) => {
i18n.global.locale = locale;
}
window.localStorage.setItem("fes_locale", locale);
plugin.applyPlugins({
key: 'onLocaleChange',
type: ApplyPluginsType.event,
args: { i18n, t, locale: unref(i18n.global.locale) },
});
};
const getLocale = () => {
@ -89,20 +78,19 @@ const getAllLocales = () => {
const install = (app) => {
app.use(i18n);
plugin.applyPlugins({
key: 'onLocaleChange',
type: ApplyPluginsType.event,
args: { i18n, t, locale: unref(i18n.global.locale) },
});
};
const t = (key) => {
return i18n.global.t(key)
}
const locale = {
setLocale,
getLocale,
addLocale,
getAllLocales,
messages,
t,
t
};
export { useI18n, locale, install };

View File

@ -126,7 +126,7 @@ export default {
title: 'Nyelv',
},
'hy-AM': {
lang: 'hy-AM',
lang: 'hu-HU',
label: 'Հայերեն',
icon: '🇦🇲',
title: 'Լեզու',
@ -162,7 +162,7 @@ export default {
title: 'Ziman',
},
'kn-IN': {
lang: 'kn-IN',
lang: 'zh-TW',
label: 'ಕನ್ನಡ',
icon: '🇮🇳',
title: 'ಭಾಷೆ',

View File

@ -1,6 +1,6 @@
import { plugin } from '@@/core/coreExports';
import { install, locale, useI18n } from './core';
// eslint-disable-next-line import/extensions
import { useI18n, locale, install } from './core';
import SelectLang from './views/SelectLang.vue';
// 共享出去

View File

@ -1,11 +1,11 @@
<template>
<FTooltip v-model="isOpened" popper-class="lang-popper" mode="popover">
<FTooltip v-model="isOpened" popperClass="lang-popper" mode="popover">
<div class="lang-icon">
<LanguageOutlined />
</div>
<template #content>
<FScrollbar height="274" class="lang-container">
<div v-for="item in configs" :key="item.lang" class="lang-option" :class="[item.lang === locale && 'is-selected']" @click="handleSelect(item)">
<div v-for="item in configs" :key="item.lang" :class="['lang-option', item.lang === locale && 'is-selected']" @click="handleSelect(item)">
<span>{{ item.icon }}</span>
<span>{{ item.label }}</span>
</div>
@ -15,12 +15,12 @@
</template>
<script>
import { FScrollbar, FTooltip } from '@fesjs/fes-design';
import { FTooltip, FScrollbar } from '@fesjs/fes-design';
import { LanguageOutlined } from '@fesjs/fes-design/icon';
import { useI18n } from 'vue-i18n';
import { computed, ref } from 'vue';
import langUConfigMap from '../langUConfigMap';
// eslint-disable-next-line import/extensions
import { locale as _locale } from '../core';
export default {
@ -55,13 +55,11 @@ export default {
},
};
</script>
<style>
.fes-tooltip.fes-tooltip-popover.lang-popper {
padding: 0;
}
</style>
<style lang="less" scoped>
.lang-icon {
display: flex;

View File

@ -1,4 +1,4 @@
import { basename, join } from 'node:path';
import { join, basename } from 'path';
import { glob, winPath } from '@fesjs/utils';
const ignore = /\.(d\.ts|\.test\.(js|ts))$/;
@ -15,14 +15,13 @@ const getRouteName = function (path) {
.replace(/\[...([a-zA-Z]*)\]/, 'FUZZYMATCH-$1');
};
export function getLocales(cwdArray) {
export function getLocales(cwd) {
const map = {};
const files = [];
cwdArray.forEach((cwd) => {
glob.sync('**/*.js', {
cwd,
})
.filter(file => !ignore.test(file))
.filter((file) => !ignore.test(file))
.forEach((fileName) => {
const locale = basename(fileName, '.js');
const importName = getRouteName(fileName).replace('.js', '');
@ -37,10 +36,9 @@ export function getLocales(cwdArray) {
}
map[locale].push(importName);
});
});
return {
locales: Object.keys(map).map(key => ({ locale: key, importNames: map[key] })),
locales: Object.keys(map).map((key) => ({ locale: key, importNames: map[key] })),
files,
};
}

View File

@ -1,5 +1,3 @@
import type { VueI18n } from 'vue-i18n';
export { useI18n } from 'vue-i18n';
export const locale: {
@ -7,7 +5,6 @@ export const locale: {
addLocale: ({ locale, messages }: { locale: string; messages: object }) => void;
getAllLocales: () => string[];
messages: Record<string, object>;
t: VueI18n['t'];
};
declare module '@fesjs/fes' {
@ -21,7 +18,4 @@ declare module '@fesjs/fes' {
}
| false;
}
interface PluginRuntimeConfig {
onLocaleChange: (params: { t: VueI18n['t']; locale: string }) => void;
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-login",
"version": "3.0.2",
"version": "3.0.0",
"description": "@fesjs/plugin-login",
"main": "lib/index.js",
"files": [
@ -29,7 +29,7 @@
},
"peerDependencies": {
"@fesjs/fes": "^3.0.0",
"@fesjs/plugin-request": "^4.0.0-rc.3",
"@fesjs/plugin-request": "^3.0.0",
"vue": "^3.2.47"
},
"typings": "./types.d.ts"

View File

@ -1,12 +1,8 @@
import { request } from '@@/core/pluginExports';
import { ApplyPluginsType, getRouter, plugin } from '@fesjs/fes';
let config;
function getLoginConfig() {
if (config) {
return config;
}
if (config) return config;
config = plugin.applyPlugins({
key: 'login',
type: ApplyPluginsType.modify,
@ -18,8 +14,27 @@ function getLoginConfig() {
return config;
}
const defaultExport = {
onRouterCreated({ router }) {
// ACCESS
export function request(memo) {
if (!memo.responseInterceptors) {
memo.responseInterceptors = [];
}
memo.responseInterceptors.push([
(response) => response,
(error) => {
if (error?.response?.status === 401) {
const router = getRouter();
const { loginPath } = getLoginConfig();
router.push({ path: loginPath });
}
throw error;
},
]);
return memo;
}
export function onRouterCreated({ router }) {
const { hasLogin, loginPath } = getLoginConfig();
if (hasLogin && loginPath) {
let isAuthenticated;
@ -33,52 +48,4 @@ const defaultExport = {
next();
});
}
},
};
// ACCESS
if (request.version) {
defaultExport.request = (memo) => {
const config = getLoginConfig();
if (config.ignore401Redirect) {
return memo;
}
const errorHandler = memo.errorHandler;
memo.errorHandler = (error) => {
if (error?.response?.status === 401) {
const router = getRouter();
const { loginPath } = getLoginConfig();
router.push({ path: loginPath });
}
errorHandler && errorHandler(error);
};
return memo;
};
}
else {
defaultExport.request = (memo) => {
const config = getLoginConfig();
if (config.ignore401Redirect) {
return memo;
}
if (!memo.responseInterceptors) {
memo.responseInterceptors = [];
}
memo.responseInterceptors.push([
response => response,
(error) => {
if (error?.response?.status === 401) {
const router = getRouter();
const { loginPath } = getLoginConfig();
router.push({ path: loginPath });
}
throw error;
},
]);
return memo;
};
}
export default defaultExport;

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-model",
"version": "3.0.3",
"version": "3.0.1",
"description": "@fesjs/plugin-model",
"main": "lib/index.js",
"files": [
@ -28,10 +28,10 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3"
"@fesjs/utils": "^3.0.1"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.12",
"@fesjs/fes": "^3.1.4",
"vue": "^3.2.47"
},
"typings": "./types.d.ts"

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-monaco-editor",
"version": "3.0.3",
"version": "3.0.1",
"description": "@fesjs/plugin-monaco-editor",
"main": "lib/index.js",
"files": [
@ -26,14 +26,14 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"lodash-es": "^4.17.21",
"monaco-editor": "^0.36.1",
"monaco-editor-webpack-plugin": "^7.0.1",
"vite-plugin-monaco-editor": "^1.1.0"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.12",
"@fesjs/fes": "^3.1.4",
"vue": "^3.2.47"
},
"typings": "./types.d.ts"

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-pinia",
"version": "3.0.3",
"version": "3.0.1",
"description": "@fesjs/plugin-pinia",
"main": "lib/index.js",
"files": [
@ -28,10 +28,10 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3"
"@fesjs/utils": "^3.0.1"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.12",
"@fesjs/fes": "^3.1.4",
"pinia": "^2.0.11",
"vue": "^3.2.47"
},

View File

@ -1,2 +1 @@
PORT=9000
HOST=127.0.0.1

View File

@ -1,2 +1 @@
PORT=9001
HOST=127.0.0.1

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-qiankun",
"version": "3.1.6",
"version": "3.1.1",
"description": "@fesjs/plugin-qiankun",
"main": "lib/index.js",
"files": [
@ -32,7 +32,7 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"address": "^1.1.2",
"lodash-es": "^4.17.21",
"qiankun": "^2.7.0",
@ -42,7 +42,7 @@
"npm-run-all": "^4.1.5"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.13",
"@fesjs/fes": "^3.1.4",
"@fesjs/fes-design": ">=0.7.20",
"vue": "^3.2.47"
},

View File

@ -9,7 +9,7 @@ import {
shallowRef,
} from "vue";
import { loadMicroApp } from "{{{QIANKUN}}}";
import { mergeWith, cloneDeep, isEqual, concat } from "{{{LODASH_ES}}}";
import { mergeWith, cloneDeep, isEqual } from "{{{LODASH_ES}}}";
// eslint-disable-next-line import/extensions
import { getMasterOptions } from "./masterOptions";

View File

@ -3,9 +3,6 @@ import { cloneDeep } from 'lodash-es'
let initState = reactive({});
const setModelState = (props) => {
// 使用深拷贝去掉主应用数据和子应用数据的引用关系,避免出现副作用。
Object.keys(initState).forEach(p=>{
delete initState[p]
})
Object.assign(initState, cloneDeep(props))
};

View File

@ -1,21 +1,7 @@
{
"name": "@fesjs/plugin-request",
"version": "4.0.1",
"version": "4.0.0-rc.1",
"description": "@fesjs/plugin-request",
"author": "qlin",
"license": "MIT",
"homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-request"
},
"bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues"
},
"keywords": [
"fes"
],
"main": "lib/index.js",
"files": [
"lib",
@ -24,16 +10,30 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-request"
},
"keywords": [
"fes"
],
"author": "qlin",
"license": "MIT",
"bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues"
},
"homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.12",
"@fesjs/fes": "^3.1.4",
"vue": "^3.2.37"
},
"dependencies": {
"@fesjs/utils": "^3.0.3",
"@qlin/request": "^0.3.1"
"@fesjs/utils": "^3.0.1",
"@qlin/request": "^0.1.2"
},
"typings": "./types.d.ts"
}

View File

@ -1,4 +1,4 @@
import { join } from 'node:path';
import { join } from 'path';
import { name } from '../package.json';
export default (api) => {
@ -9,9 +9,7 @@ export default (api) => {
let generatedOnce = false;
api.onGenerateFiles(() => {
if (generatedOnce) {
return;
}
if (generatedOnce) return;
generatedOnce = true;
api.copyTmpFiles({
namespace,

View File

@ -1,44 +1,39 @@
import { ApplyPluginsType, plugin } from '@fesjs/fes';
import { createRequest } from '@qlin/request';
import { ref, shallowRef } from 'vue';
import { createRequest } from '@qlin/request';
function getRequestInstance() {
const defaultConfig = plugin.applyPlugins({
key: 'request',
type: ApplyPluginsType.modify,
initialValue: {
timeout: 10000,
responseType: 'json',
},
});
return createRequest(defaultConfig);
}
// 不能立马初始化,用户配置可能还没准备好
let currentRequest;
function _rawRequest(url, data, options = {}) {
export const rawRequest = (url, data, options = {}) => {
if (typeof options === 'string') {
options = {
method: options,
};
}
if (!currentRequest) {
currentRequest = getRequestInstance();
}
return currentRequest(url, data, options);
}
};
// 代理 request 上的属性
export const rawRequest = new Proxy(_rawRequest, {
get(_, key) {
if (!currentRequest) {
currentRequest = getRequestInstance();
}
return currentRequest[key];
},
});
export async function request(url, data, options = {}) {
export const request = async (url, data, options = {}) => {
const response = await rawRequest(url, data, options);
return response.data;
}
};
request.version = '4.0.0';
@ -46,15 +41,14 @@ function isPromiseLike(obj) {
return !!obj && typeof obj === 'object' && typeof obj.then === 'function';
}
export function useRequest(url, data, options = {}) {
export const useRequest = (url, data, options = {}) => {
const loadingRef = ref(true);
const errorRef = ref(null);
const dataRef = shallowRef(null);
let promise;
if (isPromiseLike(url)) {
promise = url;
}
else {
} else {
promise = request(url, data, options);
}
promise
@ -72,4 +66,4 @@ export function useRequest(url, data, options = {}) {
error: errorRef,
data: dataRef,
};
}
};

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-swc",
"version": "3.0.5",
"version": "3.0.3",
"description": "@fesjs/plugin-swc",
"main": "lib/index.js",
"types": "types.d.ts",
@ -26,7 +26,7 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"@swc/core": "^1.3.49",
"@swc/css": "^0.0.20",
"css-minimizer-webpack-plugin": "^5.0.0",
@ -35,6 +35,6 @@
"terser-webpack-plugin": "^5.3.7"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.12"
"@fesjs/fes": "^3.1.4"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-vuex",
"version": "3.0.3",
"version": "3.0.1",
"description": "@fesjs/plugin-vuex",
"main": "lib/index.js",
"files": [
@ -28,10 +28,10 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3"
"@fesjs/utils": "^3.0.1"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.12",
"@fesjs/fes": "^3.1.4",
"vue": "^3.2.47",
"vuex": "^4.0.0"
},

View File

@ -1,15 +1,12 @@
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
import { join } from 'node:path';
import { parser, winPath } from '@fesjs/utils';
import { readdirSync, readFileSync, statSync } from 'fs';
import { join } from 'path';
/**
* 获取文件夹所有JS文件路径
* @param {string} dir
*/
function getDirFilePaths(dir) {
if (!existsSync(dir)) {
return [];
}
const dirs = readdirSync(dir);
let pathList = [];
for (const name of dirs) {
@ -17,8 +14,7 @@ function getDirFilePaths(dir) {
const info = statSync(path);
if (info.isDirectory()) {
pathList = pathList.concat(getDirFilePaths(path));
}
else if (path.endsWith('.js')) {
} else if (path.endsWith('.js')) {
pathList.push(path);
}
}
@ -33,8 +29,8 @@ function pathToHump(path, root) {
return path
.replace(root, '')
.replace('.js', '')
.replace(RegExp('(/|\\.|-|_)\\S', 'g'), text => text[1].toUpperCase())
.replace(/\S/, text => text.toLowerCase());
.replace(RegExp('(/|\\.|-|_)\\S', 'g'), (text) => text[1].toUpperCase())
.replace(/\S/, (text) => text.toLowerCase());
}
/**
@ -49,7 +45,7 @@ function getModelTypes(ast, name, namespace = '') {
getters: {},
};
let namespaced = false;
if (ast.type !== 'ObjectExpression') { return types; }
if (ast.type !== 'ObjectExpression') return types;
ast.properties.forEach((node) => {
if (node.key.name === 'namespaced' && node.value.value) {
namespaced = true;
@ -60,6 +56,7 @@ function getModelTypes(ast, name, namespace = '') {
if (namespaced) {
type = types[node.key.name][name];
if (!type) {
// eslint-disable-next-line no-multi-assign
type = types[node.key.name][name] = {};
}
}
@ -80,8 +77,7 @@ function getModelTypes(ast, name, namespace = '') {
...subTypes[key],
...types[key][name],
};
}
else {
} else {
types[key] = {
...subTypes[key],
...types[key],
@ -116,9 +112,8 @@ function parseModel(paths = [], root) {
sourceType: 'module',
plugins: ['jsx', 'typescript'],
});
ast = ast.program.body.filter(body => body.type === 'ExportDefaultDeclaration')[0];
}
catch (err) { }
ast = ast.program.body.filter((body) => body.type === 'ExportDefaultDeclaration')[0];
} catch (err) { }
if (ast) {
const { mutations, actions, getters } = getModelTypes(ast.declaration, moduleName);
MUTATION_TYPES = {
@ -160,10 +155,9 @@ export function parseStore(root) {
const modelPaths = [];
const pluginPaths = [];
paths.forEach((path) => {
if (path.includes('plugin')) {
if (path.indexOf('plugin') > -1) {
pluginPaths.push(path);
}
else {
} else {
modelPaths.push(path);
}
});

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/plugin-watermark",
"version": "3.0.3",
"version": "3.0.1",
"description": "@fesjs/plugin-watermark",
"main": "lib/index.js",
"files": [
@ -28,11 +28,11 @@
"access": "public"
},
"dependencies": {
"@fesjs/utils": "^3.0.3",
"@fesjs/utils": "^3.0.1",
"lodash-es": "^4.17.21"
},
"peerDependencies": {
"@fesjs/fes": "^3.1.12",
"@fesjs/fes": "^3.1.4",
"vue": "^3.2.47"
},
"typings": "./types.d.ts"

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/preset-built-in",
"version": "3.1.14",
"version": "3.1.8",
"description": "@fesjs/preset-built-in",
"author": "qlin",
"license": "MIT",
@ -29,13 +29,13 @@
"vue": "^3.2.47"
},
"dependencies": {
"@fesjs/compiler": "^3.0.6",
"@fesjs/runtime": "^3.0.1",
"@fesjs/utils": "^3.0.3",
"@fesjs/compiler": "^3.0.2",
"@fesjs/runtime": "^3.0.0",
"@fesjs/utils": "^3.0.1",
"@vue/compiler-sfc": "^3.3.4",
"@wll8/better-mock": "0.3.3-alpha",
"envinfo": "^7.7.3",
"express": "^4.17.3"
"express": "^4.17.3",
"mockjs": "^1.1.0"
},
"typings": "./types.d.ts"
}

View File

@ -16,7 +16,6 @@ export default function () {
require.resolve('./plugins/features/alias'),
require.resolve('./plugins/features/autoprefixer'),
require.resolve('./plugins/features/define'),
require.resolve('./plugins/features/console'),
require.resolve('./plugins/features/dynamicImport'),
require.resolve('./plugins/features/globalCSS'),
require.resolve('./plugins/features/inlineLimit'),

View File

@ -12,8 +12,6 @@ import DefaultContainer from './defaultContainer.vue';
{{{ entryCodeAhead }}}
{{{ CONSOLE }}}
const renderClient = (opts = {}) => {
const { plugin, routes, rootElement } = opts;
const rootContainer = plugin.applyPlugins({

View File

@ -13,15 +13,6 @@ export function importsToStr(imports) {
});
}
function getConsoleInfo(config, pkg) {
if (config.console?.version) {
return `
console.log('%c[${pkg.name}]%c${pkg.version}', 'background-color: #1677ff; border-top-left-radius: 6px; border-bottom-left-radius: 6px; color: white; padding: 4px', 'background-color: #42b983; border-top-right-radius: 6px; border-bottom-right-radius: 6px; color: white; padding: 4px');
`;
}
return '';
}
export default function (api) {
const {
utils: { Mustache },
@ -33,7 +24,6 @@ export default function (api) {
path: 'fes.js',
content: Mustache.render(fesTpl, {
enableTitle: api.config.title !== false,
CONSOLE: getConsoleInfo(api.config, api.pkg),
defaultTitle: api.config.title || 'fes.js',
runtimePath,
rootElement: `#${api.config.mountElementId || 'app'}`,

View File

@ -1,13 +0,0 @@
export default (api) => {
api.describe({
key: 'console',
config: {
default: {
version: false,
},
schema(joi) {
return joi.object().description('output info in console, default version');
},
},
});
};

View File

@ -122,7 +122,7 @@ export default (api) => {
api.logger.info('mock.js should export Function');
return;
}
const mockjs = require('@wll8/better-mock');
const mockjs = require('mockjs');
initFunction({ cgiMock, mockjs, utils });
} catch (err) {
api.logger.error('mock.js run fail!');

View File

@ -1,8 +1,8 @@
import type { App, Component, DefineComponent } from 'vue';
import type { createMemoryHistory, createWebHashHistory, createWebHistory, Router, RouteRecordRaw, RouterHistory } from 'vue-router';
import { Component, DefineComponent, Component, App } from 'vue';
import { RouteRecordRaw, Router, RouterHistory, createMemoryHistory, createWebHashHistory, createWebHistory } from 'vue-router';
// @ts-ignore
import type { Plugin } from '@fesjs/runtime';
import { Plugin } from '@fesjs/runtime';
interface BeforeRenderConfig {
loading: Component;
@ -44,9 +44,6 @@ declare module '@fesjs/fes' {
interface PluginBuildConfig {
globalCSS?: 'beforeImports' | 'afterImports';
alias?: Record<string, string>;
console?: {
version?: boolean;
};
autoprefixer?: {
/** environment for `Browserslist` */
env?: string;

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/runtime",
"version": "3.0.1",
"version": "3.0.0",
"description": "@fesjs/runtime",
"main": "es/index.js",
"module": "es/index.js",

View File

@ -1,4 +1,4 @@
export { Plugin } from './es/index';
export { Plugin } from './es/index'
export {
useRoute,
@ -15,7 +15,7 @@ export {
} from 'vue-router';
export interface ApplyPluginsType {
compose: 'compose';
event: 'event';
modify: 'modify';
compose: 'compose',
event: 'event',
modify: 'modify'
};

View File

@ -54,7 +54,6 @@ export default defineBuildConfig({
{
title: '子菜单',
path: '/menuTest',
query: { id: 1 },
},
],
},

View File

@ -23,9 +23,8 @@ export const beforeRender = {
};
export const layout = {
// eslint-disable-next-line node/prefer-global/process
logo: `${process.env.BASE_URL}logo.png`,
renderCustom: () => {
logo: `${process.env.BASE_URL}wine-outline.svg`,
renderCustom: (props) => {
return <UserCenter />;
},
};

View File

@ -8,9 +8,6 @@ export default defineBuildConfig({
define: {
__DEV__: false,
},
console: {
version: true,
},
html: {
title: '海贼王',
},
@ -36,7 +33,7 @@ export default defineBuildConfig({
},
},
layout: {
title: '$home',
title: 'Fes.js',
footer: 'Created by MumbleFE',
multiTabs: true,
navigation: 'mixin',
@ -50,7 +47,6 @@ export default defineBuildConfig({
{
name: 'editor',
icon: '/wine-outline.svg',
_blank: true,
},
{
title: '$externalLink',
@ -74,7 +70,6 @@ export default defineBuildConfig({
},
{
name: 'pinia',
_blank: true,
},
],
menuProps: {

View File

@ -3,11 +3,6 @@ import { ref, watch } from 'vue';
import PageLoading from '@/components/pageLoading.vue';
import UserCenter from '@/components/userCenter.vue';
export function onLocaleChange({ locale, t }) {
//
console.log(locale, t);
}
export const beforeRender = {
loading: <PageLoading />,
action() {
@ -25,12 +20,8 @@ export const beforeRender = {
},
};
export function layout(layoutConfig, { initialState }) {
return {
export const layout = (layoutConfig, { initialState }) => ({
...layoutConfig,
403: {
title: 'hello word',
},
renderCustom: (props) => {
console.log(props);
return <UserCenter />;
@ -49,5 +40,4 @@ export function layout(layoutConfig, { initialState }) {
);
return menusRef;
},
};
}
});

View File

@ -5,5 +5,5 @@ html, body {
.page {
height: 1000px;
background: url("@/images/hello.png");
background-image: url('~@/images/hello.png');
}

View File

@ -4,6 +4,6 @@ export default {
externalLink: 'externalLink',
mock: 'mock',
test: {
test: 'test',
b: 1,
},
};

View File

@ -4,6 +4,6 @@ export default {
externalLink: '外部链接',
mock: '代理',
test: {
test: '测试',
b: 1,
},
};

View File

@ -13,7 +13,7 @@ import { FButton } from '@fesjs/fes-design';
defineRouteMeta({
name: 'index',
title: '$test.test',
title: '$home',
});
console.log('123123'.replaceAll('123', '234'));
@ -27,5 +27,6 @@ function go() {
<style lang="less">
.page {
height: 1000px;
background-image: url('@/images/hello.png');
}
</style>

View File

@ -1,23 +1,19 @@
<template>
<div class="page">
menuTest: {{ route.params }} <input style="border: 1px solid red">
</div>
<div class="page">menuTest: {{ route.params }} <input style="border: 1px solid red" /></div>
</template>
<config>
{
"title": "menuTest-详情"
}
</config>
<script>
import { useLayout, useRoute } from '@fesjs/fes';
import { useRoute, useTabTitle } from '@fesjs/fes';
export default {
components: {},
setup() {
const route = useRoute();
const { title } = useLayout({ title: `详情-${route.params?.id}` });
const title = useTabTitle(`详情-${route.params?.id}`);
setTimeout(() => {
title.value = `详情-${route.params?.id}-changed`;

View File

@ -2,25 +2,17 @@
<div class="page">
menuTest-index
<div style="display: flex; flex-direction: column">
<router-link to="/menuTest/1">
Go to 1
</router-link>
<router-link to="/menuTest/2">
Go to 2
</router-link>
<router-link to="/menuTest/3">
Go to 3
</router-link>
<router-link to="/menuTest/1">Go to 1</router-link>
<router-link to="/menuTest/2">Go to 2</router-link>
<router-link to="/menuTest/3">Go to 3</router-link>
</div>
</div>
</template>
<config>
{
"title": "menuTest"
}
</config>
<script>
export default {
components: {},

View File

@ -1,10 +1,7 @@
<template>
<div>{{ store.counter }}</div>
<FButton class="m-2" @click="store.increment">
Button
</FButton>
<FButton class="m-2" @click="store.increment">Button</FButton>
</template>
<config>
{
"name": "pinia",
@ -14,7 +11,6 @@
}
}
</config>
<script>
import { FButton } from '@fesjs/fes-design';
import { useStore } from '@/store/main';

View File

@ -1,25 +1,26 @@
{
"compilerOptions": {
"target": "esnext",
"jsx": "preserve",
"lib": ["esnext", "dom"],
"experimentalDecorators": true,
"baseUrl": ".",
"outDir": "build/dist",
"module": "esnext",
"target": "esnext",
"lib": ["esnext", "dom"],
"sourceMap": true,
"baseUrl": ".",
"jsx": "preserve",
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"allowJs": true,
"skipLibCheck": true,
"experimentalDecorators": true,
"strict": true,
"paths": {
"@/*": ["./src/*"],
"@@/*": ["./src/.fes/*"]
},
"allowJs": true,
"strict": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "build/dist",
"sourceMap": true,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true
}
},
"include": [
"src/**/*",

View File

@ -1,6 +1,6 @@
{
"name": "@fesjs/utils",
"version": "3.0.3",
"version": "3.0.1",
"description": "@fesjs/utils",
"main": "lib/index.js",
"files": [

Some files were not shown because too many files have changed in this diff Show More