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/**/*.*", "source": "./fixtures/output/**/*.*",
"target": "./fixtures/input/<base>" "target": "./fixtures/input/<base>"
} }
],
"cSpell.words": [
"unref"
] ]
} }

File diff suppressed because it is too large Load Diff

View File

@ -16,21 +16,21 @@ An excellent front-end solution
</div> </div>
- document - [http://fesjs.mumblefe.cn/](http://fesjs.mumblefe.cn/) - document - [http://fesjs.mumblefe.cn/](http://fesjs.mumblefe.cn/)
- changelog - [CHANGELOG.md](./CHANGELOG.md) - changelog - [CHANGELOG.md](./CHANGELOG.md)
# Pain points # Pain points
Before developing a front-end project, we may need to do the following preparations Before developing a front-end project, we may need to do the following preparations
- Set up a development environment - Set up a development environment
- Conventional code specification - Conventional code specification
- Encapsulate API requests - Encapsulate API requests
- Configure routing - Configure routing
- Realize layout, menu, navigation - Realize layout, menu, navigation
- Realize login - Realize login
- authority management - authority management
- ... - ...
In addition to the preparation work, there are many similar business types. For example, most of the middle and back-end applications are workbenches, additions, deletions, changes, permissions, charts, etc. If each project is completely processed manually, it will not only take time, but over time there may be multiple technology stacks and development specifications, leading to inconsistent development processes and making historical projects more and more difficult to maintain. So we need a complete solution to manage the entire process from development to deployment. In addition to the preparation work, there are many similar business types. For example, most of the middle and back-end applications are workbenches, additions, deletions, changes, permissions, charts, etc. If each project is completely processed manually, it will not only take time, but over time there may be multiple technology stacks and development specifications, leading to inconsistent development processes and making historical projects more and more difficult to maintain. So we need a complete solution to manage the entire process from development to deployment.
@ -40,14 +40,14 @@ Fes.js is an excellent front-end application solution. Fes.js is based on Vue 3.
It mainly has the following functions: It mainly has the following functions:
- 🚀 **fast** , Built-in routing, development, construction, etc., and provide plug-ins such as testing, layout, permissions, internationalization, state management, API requests, data dictionary, SvgIcon, etc., which can meet most of the daily development needs. - 🚀 **fast** , Built-in routing, development, construction, etc., and provide plug-ins such as testing, layout, permissions, internationalization, state management, API requests, data dictionary, SvgIcon, etc., which can meet most of the daily development needs.
- 🧨 **easy** , Based on Vue.js 3.0, easy to get started. Carry out the idea of "Convention is better than configuration", design plug-ins as much as possible to replace configuration with conventions, and provide a unified plug-in configuration entry, which is simple, concise and flexible. Provide a consistent API entry, a consistent experience, and easier learning. - 🧨 **easy** , Based on Vue.js 3.0, easy to get started. Carry out the idea of "Convention is better than configuration", design plug-ins as much as possible to replace configuration with conventions, and provide a unified plug-in configuration entry, which is simple, concise and flexible. Provide a consistent API entry, a consistent experience, and easier learning.
- 💪 **strong** , Only need to care about the content of the page, reduce the chance of writing BUG! Provide unit testing and coverage testing capabilities to ensure project quality. - 💪 **strong** , Only need to care about the content of the page, reduce the chance of writing BUG! Provide unit testing and coverage testing capabilities to ensure project quality.
- 📦 **expanded** , Drawing lessons from Umi, it implements a complete life cycle and plug-in mechanism. The plug-in can manage the compile time and runtime of the project, and the capabilities can be encapsulated through the plug-in, and run in an orderly manner in Fes.js. - 📦 **expanded** , Drawing lessons from Umi, it implements a complete life cycle and plug-in mechanism. The plug-in can manage the compile time and runtime of the project, and the capabilities can be encapsulated through the plug-in, and run in an orderly manner in Fes.js.
- 📡 **future** , While meeting demand, we will not stop exploring new technologies. Vue3.0 has been used to improve application performance, webpack5 has been used to improve construction performance and implement microservices, and new technologies such as vite will be explored in the future. - 📡 **future** , While meeting demand, we will not stop exploring new technologies. Vue3.0 has been used to improve application performance, webpack5 has been used to improve construction performance and implement microservices, and new technologies such as vite will be explored in the future.
## Plugins ## Plugins
@ -57,7 +57,7 @@ It mainly has the following functions:
| [@fesjs/plugin-enums](http://fesjs.mumblefe.cn/reference/plugin/plugins/enums.html#%E4%BB%8B%E7%BB%8D) | Provide unified enumeration access and rich functions to handle enumeration | | [@fesjs/plugin-enums](http://fesjs.mumblefe.cn/reference/plugin/plugins/enums.html#%E4%BB%8B%E7%BB%8D) | Provide unified enumeration access and rich functions to handle enumeration |
| [@fesjs/plugin-icon](http://fesjs.mumblefe.cn/reference/plugin/plugins/icon.html#%E4%BB%8B%E7%BB%8D) | svg file is automatically registered as a component | | [@fesjs/plugin-icon](http://fesjs.mumblefe.cn/reference/plugin/plugins/icon.html#%E4%BB%8B%E7%BB%8D) | svg file is automatically registered as a component |
| [@fesjs/plugin-jest](http://fesjs.mumblefe.cn/reference/plugin/plugins/jest.html#%E5%90%AF%E7%94%A8%E6%96%B9%E5%BC%8F) | Based on `Jest`, provide unit testing and coverage testing capabilities | | [@fesjs/plugin-jest](http://fesjs.mumblefe.cn/reference/plugin/plugins/jest.html#%E5%90%AF%E7%94%A8%E6%96%B9%E5%BC%8F) | Based on `Jest`, provide unit testing and coverage testing capabilities |
| [@fesjs/plugin-layout](http://fesjs.mumblefe.cn/reference/plugin/plugins/layout.html) | Simple configuration to have a layout, including navigation and sidebar | | [ @fesjs/plugin-layout](http://fesjs.mumblefe.cn/reference/plugin/plugins/layout.html) | Simple configuration to have a layout, including navigation and sidebar |
| [@fesjs/plugin-locale](http://fesjs.mumblefe.cn/reference/plugin/plugins/locale.html#%E4%BB%8B%E7%BB%8D) | Based on `Vue I18n`, providing internationalization capabilities | | [@fesjs/plugin-locale](http://fesjs.mumblefe.cn/reference/plugin/plugins/locale.html#%E4%BB%8B%E7%BB%8D) | Based on `Vue I18n`, providing internationalization capabilities |
| [@fesjs/plugin-model](http://fesjs.mumblefe.cn/reference/plugin/plugins/model.html#%E4%BB%8B%E7%BB%8D) | Simple data management solution | | [@fesjs/plugin-model](http://fesjs.mumblefe.cn/reference/plugin/plugins/model.html#%E4%BB%8B%E7%BB%8D) | Simple data management solution |
| [@fesjs/plugin-request](http://fesjs.mumblefe.cn/reference/plugin/plugins/request.html#%E5%90%AF%E7%94%A8%E6%96%B9%E5%BC%8F) | Based on the request encapsulated by `Axios`, built-in functions such as preventing repeated requests, request throttling, and error handling | | [@fesjs/plugin-request](http://fesjs.mumblefe.cn/reference/plugin/plugins/request.html#%E5%90%AF%E7%94%A8%E6%96%B9%E5%BC%8F) | Based on the request encapsulated by `Axios`, built-in functions such as preventing repeated requests, request throttling, and error handling |
@ -97,17 +97,15 @@ npm install
npm run dev npm run dev
``` ```
## Project Demo ## Start On Cloud IDE
| Project | Description | [https://idegithub.com/WeBankFinTech/fes.js](https://idegithub.com/WeBankFinTech/fes.js)
|----------------------------------------- | ----------------------------------------- |
| <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) |
## Feedback ## Feedback
| Github Issue | WeChat group | Fes.js 开源运营小助手 | | 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 ## 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. 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"> <div align="center">
一个好用的前端应用解决方案 一个优秀的前端解决方案
[![GitHub issues](https://img.shields.io/github/issues/WeBankFinTech/fes.js.svg?style=flat-square)](../../issues) [![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) [![MIT](https://img.shields.io/dub/l/vibe-d.svg?style=flat-square)](http://opensource.org/licenses/MIT)
@ -17,21 +17,21 @@
</div> </div>
- 使用文档 - [http://fesjs.mumblefe.cn/](http://fesjs.mumblefe.cn/) - 使用文档 - [http://fesjs.mumblefe.cn/](http://fesjs.mumblefe.cn/)
- 更新日志 - [CHANGELOG.md](./CHANGELOG.md) - 更新日志 - [CHANGELOG.md](./CHANGELOG.md)
# 痛点 # 痛点
在开发一个前端项目之前,我们可能需要做如下准备工作: 在开发一个前端项目之前,我们可能需要做如下准备工作:
- 搭建开发环境 - 搭建开发环境
- 约定代码规范 - 约定代码规范
- 封装 API 请求 - 封装 API 请求
- 配置路由 - 配置路由
- 实现布局、菜单、导航 - 实现布局、菜单、导航
- 实现登录 - 实现登录
- 权限管理 - 权限管理
- ... - ...
除了准备工作之外,还会遇到很多相似的业务类型,比如中后台应用大多都是工作台、增删改查、权限、图表等。如果每次项目都完全手动处理一遍,不仅耗费时间,久而久之可能会存在多种技术栈、开发规范,导致开发流程不统一,历史项目越来越难维护。所以我们需要一套完整的解决方案,管理开发到部署整个流程。 除了准备工作之外,还会遇到很多相似的业务类型,比如中后台应用大多都是工作台、增删改查、权限、图表等。如果每次项目都完全手动处理一遍,不仅耗费时间,久而久之可能会存在多种技术栈、开发规范,导致开发流程不统一,历史项目越来越难维护。所以我们需要一套完整的解决方案,管理开发到部署整个流程。
@ -41,14 +41,14 @@ Fes.js 是一个好用的前端应用解决方案。提供覆盖编译构建到
它主要具备以下功能: 它主要具备以下功能:
- 🚀 **快速** 内置了路由、开发、构建等并且提供测试、布局、权限、国际化、状态管理、API 请求、数据字典、SvgIcon 等插件,可以满足大部分日常开发需求。 - 🚀 **快速** 内置了路由、开发、构建等并且提供测试、布局、权限、国际化、状态管理、API 请求、数据字典、SvgIcon 等插件,可以满足大部分日常开发需求。
- 🧨 **简单** ,基于 Vue.js 3.0,上手简单。贯彻“约定优于配置”思想,设计插件上尽可能用约定替代配置,同时提供统一的插件配置入口,简单简洁又不失灵活。提供一致性的 API 入口,一致化的体验,学习起来更轻松。 - 🧨 **简单** ,基于 Vue.js 3.0,上手简单。贯彻“约定优于配置”思想,设计插件上尽可能用约定替代配置,同时提供统一的插件配置入口,简单简洁又不失灵活。提供一致性的 API 入口,一致化的体验,学习起来更轻松。
- 💪 **健壮** ,只需要关心页面内容,减少写 BUG 的机会!提供单元测试、覆盖测试能力保障项目质量。 - 💪 **健壮** ,只需要关心页面内容,减少写 BUG 的机会!提供单元测试、覆盖测试能力保障项目质量。
- 📦 **可扩展** ,借鉴 Umi 实现了完整的生命周期和插件化机制,插件可以管理项目的编译时和运行时,能力均可以通过插件封装进来,在 Fes.js 中协调有序的运行。 - 📦 **可扩展** ,借鉴 Umi 实现了完整的生命周期和插件化机制,插件可以管理项目的编译时和运行时,能力均可以通过插件封装进来,在 Fes.js 中协调有序的运行。
- 📡 **面向未来** ,在满足需求的同时,我们也不会停止对新技术的探索。已使用 Vue3.0 来提升应用性能,已使用 webpack5 和 vite 提升构建性能和实现微服务。 - 📡 **面向未来** ,在满足需求的同时,我们也不会停止对新技术的探索。已使用 Vue3.0 来提升应用性能,已使用 webpack5 和 vite 提升构建性能和实现微服务。
## 插件 ## 插件
@ -58,7 +58,7 @@ Fes.js 是一个好用的前端应用解决方案。提供覆盖编译构建到
| [@fesjs/plugin-enums](http://fesjs.mumblefe.cn/reference/plugin/plugins/enums.html#%E4%BB%8B%E7%BB%8D) | 提供统一的枚举存取及丰富的函数来处理枚举 | | [@fesjs/plugin-enums](http://fesjs.mumblefe.cn/reference/plugin/plugins/enums.html#%E4%BB%8B%E7%BB%8D) | 提供统一的枚举存取及丰富的函数来处理枚举 |
| [@fesjs/plugin-icon](http://fesjs.mumblefe.cn/reference/plugin/plugins/icon.html#%E4%BB%8B%E7%BB%8D) | svg 文件自动注册为组件 | | [@fesjs/plugin-icon](http://fesjs.mumblefe.cn/reference/plugin/plugins/icon.html#%E4%BB%8B%E7%BB%8D) | svg 文件自动注册为组件 |
| [@fesjs/plugin-jest](http://fesjs.mumblefe.cn/reference/plugin/plugins/jest.html#%E5%90%AF%E7%94%A8%E6%96%B9%E5%BC%8F) | 基于 `Jest`,提供单元测试、覆盖测试能力 | | [@fesjs/plugin-jest](http://fesjs.mumblefe.cn/reference/plugin/plugins/jest.html#%E5%90%AF%E7%94%A8%E6%96%B9%E5%BC%8F) | 基于 `Jest`,提供单元测试、覆盖测试能力 |
| [@fesjs/plugin-layout](http://fesjs.mumblefe.cn/reference/plugin/plugins/layout.html) | 简单的配置即可拥有布局,包括导航以及侧边栏 | | [ @fesjs/plugin-layout](http://fesjs.mumblefe.cn/reference/plugin/plugins/layout.html) | 简单的配置即可拥有布局,包括导航以及侧边栏 |
| [@fesjs/plugin-locale](http://fesjs.mumblefe.cn/reference/plugin/plugins/locale.html#%E4%BB%8B%E7%BB%8D) | 基于 `Vue I18n`,提供国际化能力 | | [@fesjs/plugin-locale](http://fesjs.mumblefe.cn/reference/plugin/plugins/locale.html#%E4%BB%8B%E7%BB%8D) | 基于 `Vue I18n`,提供国际化能力 |
| [@fesjs/plugin-model](http://fesjs.mumblefe.cn/reference/plugin/plugins/model.html#%E4%BB%8B%E7%BB%8D) | 简易的数据管理方案 | | [@fesjs/plugin-model](http://fesjs.mumblefe.cn/reference/plugin/plugins/model.html#%E4%BB%8B%E7%BB%8D) | 简易的数据管理方案 |
| [@fesjs/plugin-request](http://fesjs.mumblefe.cn/reference/plugin/plugins/request.html#%E5%90%AF%E7%94%A8%E6%96%B9%E5%BC%8F) | 基于 `Axios` 封装的 request内置防止重复请求、请求节流、错误处理等功能 | | [@fesjs/plugin-request](http://fesjs.mumblefe.cn/reference/plugin/plugins/request.html#%E5%90%AF%E7%94%A8%E6%96%B9%E5%BC%8F) | 基于 `Axios` 封装的 request内置防止重复请求、请求节流、错误处理等功能 |
@ -99,19 +99,15 @@ npm install
npm run dev npm run dev
``` ```
## 项目样例 ## 在 Cloud IDE 中预览
使用 fes.js 构建的优秀项目,欢迎联系。 [https://idegithub.com/WeBankFinTech/fes.js](https://idegithub.com/WeBankFinTech/fes.js)
| 项目 | 描述 |
|----------------------------------------- | ----------------------------------------- |
| <img src="https://docs.icegl.cn/logo.png" width="100px"> | [三维可视化项目快速落地の开源框架](https://gitee.com/ice-gl/icegl-three-vue-tres) |
## 反馈 ## 反馈
| Github Issue | 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 开源项目更好的运转,同时回馈开源社区,社区推出有奖征文活动!欢迎大家投递实践经验,给社区用户,更广泛的开发者提供借鉴。 为了 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 = { export const zh = {
'/guide/': [ '/guide/': [
{ {
@ -5,12 +6,12 @@ export const zh = {
items: [ items: [
{ {
text: '介绍', text: '介绍',
link: '/guide/index.md', link: '/guide/index.md'
}, },
{ {
text: '快速上手', text: '快速上手',
link: '/guide/getting-started.md', link: '/guide/getting-started.md'
}, }
], ],
}, },
{ {
@ -18,44 +19,35 @@ export const zh = {
items: [ items: [
{ {
text: '目录结构', text: '目录结构',
link: '/guide/directory-structure.md', link: '/guide/directory-structure.md'
}, },{
{
text: 'Vite 和 Webpack 双构建', text: 'Vite 和 Webpack 双构建',
link: '/guide/builder.md', link: '/guide/builder.md'
}, },{
{
text: '编译时配置', text: '编译时配置',
link: '/guide/config.md', link: '/guide/config.md'
}, },{
{
text: '运行时配置', text: '运行时配置',
link: '/guide/runtime-config.md', link: '/guide/runtime-config.md'
}, },{
{
text: '环境变量', text: '环境变量',
link: '/guide/env.md', link: '/guide/env.md'
}, },{
{
text: '路由', text: '路由',
link: '/guide/route.md', link: '/guide/route.md'
}, },{
{
text: '插件', text: '插件',
link: '/guide/plugin.md', link: '/guide/plugin.md'
}, },{
{
text: 'HTML 模板', text: 'HTML 模板',
link: '/guide/template.md', link: '/guide/template.md'
}, },{
{
text: 'Mock 数据', text: 'Mock 数据',
link: '/guide/mock.md', link: '/guide/mock.md'
}, },{
{ text: '从 2.0.x 迁移到 3.0.x',
text: '从 2.x 迁移到 3.x', link: '/guide/upgrade3.md'
link: '/guide/upgrade3.md', }
},
], ],
}, },
{ {
@ -63,102 +55,102 @@ export const zh = {
items: [ items: [
{ {
text: '使用图片', text: '使用图片',
link: '/guide/image.md', link: '/guide/image.md'
}, },
{ {
text: '使用 css', text: '使用 css',
link: '/guide/css.md', link: '/guide/css.md'
}, },
{ {
text: '静态资源', text: '静态资源',
link: '/guide/public.md', link: '/guide/public.md'
}, }
], ],
}, },
{ {
text: '贡献指南', text: '贡献指南',
link: '/guide/contributing.md', link: '/guide/contributing.md'
}, },
{ {
text: '常见问题', text: '常见问题',
link: '/guide/faq.md', link: '/guide/faq.md'
}, },
], ],
'/reference/plugin/': [ '/reference/plugin/': [
{ {
text: '介绍', text: '介绍',
link: '/reference/plugin/index.md', link: '/reference/plugin/index.md'
}, },
{ {
text: 'Plugins', text: 'Plugins',
items: [ items: [
{ {
text: '@fesjs/plugin-access', text: '@fesjs/plugin-access',
link: '/reference/plugin/plugins/access.md', link: '/reference/plugin/plugins/access.md'
}, },
{ {
text: '@fesjs/plugin-enums', text: '@fesjs/plugin-enums',
link: '/reference/plugin/plugins/enums.md', link: '/reference/plugin/plugins/enums.md'
}, },
{ {
text: '@fesjs/plugin-icon', text: '@fesjs/plugin-icon',
link: '/reference/plugin/plugins/icon.md', link: '/reference/plugin/plugins/icon.md'
}, },
{ {
text: '@fesjs/plugin-jest', text: '@fesjs/plugin-jest',
link: '/reference/plugin/plugins/jest.md', link: '/reference/plugin/plugins/jest.md'
}, },
{ {
text: '@fesjs/plugin-layout', text: '@fesjs/plugin-layout',
link: '/reference/plugin/plugins/layout.md', link: '/reference/plugin/plugins/layout.md'
}, },
{ {
text: '@fesjs/plugin-locale', text: '@fesjs/plugin-locale',
link: '/reference/plugin/plugins/locale.md', link: '/reference/plugin/plugins/locale.md'
}, },
{ {
text: '@fesjs/plugin-model', text: '@fesjs/plugin-model',
link: '/reference/plugin/plugins/model.md', link: '/reference/plugin/plugins/model.md'
}, },
{ {
text: '@fesjs/plugin-request', text: '@fesjs/plugin-request',
link: '/reference/plugin/plugins/request.md', link: '/reference/plugin/plugins/request.md'
}, },
{ {
text: '@fesjs/plugin-vuex', text: '@fesjs/plugin-vuex',
link: '/reference/plugin/plugins/vuex.md', link: '/reference/plugin/plugins/vuex.md'
}, },
{ {
text: '@fesjs/plugin-qiankun', text: '@fesjs/plugin-qiankun',
link: '/reference/plugin/plugins/qiankun.md', link: '/reference/plugin/plugins/qiankun.md'
}, },
{ {
text: '@fesjs/plugin-windicss', text: '@fesjs/plugin-windicss',
link: '/reference/plugin/plugins/windicss.md', link: '/reference/plugin/plugins/windicss.md'
}, },
{ {
text: '@fesjs/plugin-sass', text: '@fesjs/plugin-sass',
link: '/reference/plugin/plugins/sass.md', link: '/reference/plugin/plugins/sass.md'
}, },
{ {
text: '@fesjs/plugin-editor', text: '@fesjs/plugin-editor',
link: '/reference/plugin/plugins/editor.md', link: '/reference/plugin/plugins/editor.md'
}, },
{ {
text: '@fesjs/plugin-pinia', text: '@fesjs/plugin-pinia',
link: '/reference/plugin/plugins/pinia.md', link: '/reference/plugin/plugins/pinia.md'
}, },
{ {
text: '@fesjs/plugin-watermark', text: '@fesjs/plugin-watermark',
link: '/reference/plugin/plugins/watermark.md', link: '/reference/plugin/plugins/watermark.md'
}, },
{ {
text: '@fesjs/plugin-login', text: '@fesjs/plugin-login',
link: '/reference/plugin/plugins/login.md', link: '/reference/plugin/plugins/login.md'
}, },
{ {
text: '@fesjs/plugin-swc', text: '@fesjs/plugin-swc',
link: '/reference/plugin/plugins/swc.md', link: '/reference/plugin/plugins/swc.md'
}, },
], ],
}, },
@ -166,10 +158,10 @@ export const zh = {
text: '插件开发', text: '插件开发',
items: [{ items: [{
text: '插件介绍', text: '插件介绍',
link: '/reference/plugin/dev/index.md', link: '/reference/plugin/dev/index.md'
}, { }, {
text: '插件API', 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 ```bash
# 打印 node 版本 # 打印 node 版本
node -v node -v
v18.12.0 v12.13.0
``` ```
推荐使用 [pnpm](https://pnpm.io/installation) 管理 npm 依赖 推荐使用 [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` 1. 编译时的 [base](../reference/config/index.md/#base) 配置,移到了 [router.base](../reference/config/index.md/#router) 下。
2. 编译时的 [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. [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) 3. [layout 插件](../reference/plugin/plugins/layout.md#_4-x-升级到-5-x) 有一些属性变更
4. [layout 插件](../reference/plugin/plugins/layout.md#_4-x-升级到-5-x) 有一些属性变更 3. [request 插件](../reference/plugin/plugins/request.md#_2-x-升级到-3-x) 有一些参数变更
5. [request 插件](../reference/plugin/plugins/request.md#_2-x-升级到-3-x) 有一些参数变更,升级请使用最新版本
## 继续使用 Webpack ## 继续使用 Webpack
1. 添加 Webpack 构建依赖包: `npm i @fesjs/builder-webpack -D` 1. 添加 Webpack 构建依赖包: `npm i @fesjs/builder-webpack -D`
2. `dev``publicPath` 配置不能为 `./`,请更改为 `auto` 2. 如果设置了 `publicPath: './'`,请更改为 `publicPath: ''`
3. 将 html 模版文件从 `public/index.html` 挪到项目根目录,移除 [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) 相关配置,具体模版变量使用请查看[HTML 模版](../guide/template.html) 3. 如果有,`public/index.html` 文件挪到项目根目录,移除 [html-webpack-plugin](https://github.com/jantimon/html-webpack-plugin) 相关配置,具体模版变量使用请查看[HTML 模版](../guide/template.html)
## 换成 Vite ## 换成 Vite
1. 安装依赖包 `npm i @fesjs/builder-vite` 1. 安装依赖包 `npm i @fesjs/builder-vite`
2. 将 Webpack 相关的配置换成 Vite具体可查看[配置](../reference/config/index.md) 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) 的写法 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 支持的方式 4. 将 `require` 等 Vite 不支持的代码,改写成 Vite 支持的方式
## 插件 ## 插件
插件都需要升级到 `3.x` 版本,新版添加了兼容`builder`的逻辑,但是提供的接口和配置没有变化,只需要升级版本即可使用。 插件都需要升级到 `3.0.x` 版本,新版添加了兼容`builder`的逻辑,但是提供的接口和配置没有变化,只需要升级版本即可使用。
- [@fesjs/plugin-layout](../reference/plugin/plugins/layout.md) 需要升级到`5.0.x`版本。 - [@fesjs/plugin-layout](../reference/plugin/plugins/layout.md) 需要升级到`5.0.x`版本。
- [@fesjs/plugin-locale](../reference/plugin/plugins/locale.md) 需要升级到`4.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 开源运营小助手 | | 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> </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 ### define
- 类型: `object` - 类型: `object`

View File

@ -8,16 +8,16 @@ import { withBase } from 'vitepress'
为了进一步降低研发成本,我们将布局利用 `fes.js` 插件的方式内置,只需通过简单的配置即可拥有布局,包括导航以及侧边栏。从而做到用户无需关心布局。 为了进一步降低研发成本,我们将布局利用 `fes.js` 插件的方式内置,只需通过简单的配置即可拥有布局,包括导航以及侧边栏。从而做到用户无需关心布局。
- 侧边栏菜单数据根据路由中的配置自动生成。 - 侧边栏菜单数据根据路由中的配置自动生成。
- 布局,提供 `side``top``mixin``left-right``top-left-right`种布局。 - 布局,提供 `side``top``mixin``left-right`种布局。
- 主题,提供 `light``dark` 两种主题。 - 主题,提供 `light``dark` 两种主题。
- 默认实现对路由的 404、403 处理。 - 默认实现对路由的 404、403 处理。
- 搭配 [@fesjs/plugin-access](./access.html) 插件使用,可以完成对路由的权限控制。 - 搭配 [@fesjs/plugin-access](./access.html) 插件使用,可以完成对路由的权限控制。
- 搭配 [@fesjs/plugin-locale](./locale.html) 插件使用,提供切换语言的能力。 - 搭配 [@fesjs/plugin-locale](./locale.html) 插件使用,提供切换语言的能力。
- 支持自定义头部或者侧边栏区域。 - 支持自定义头部或者侧边栏区域。
- 菜单支持配置 icon。 - 菜单支持配置 icon。
- 菜单标题支持国际化。 - 菜单标题支持国际化。
- 可配置页面是否需要 layout。 - 可配置页面是否需要 layout。
## 启用方式 ## 启用方式
@ -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 ### side
@ -53,12 +53,9 @@ import { withBase } from 'vitepress'
### left-right ### left-right
<!-- ![mixin](/left-right.png) --> <!-- ![mixin](/mixin.png) -->
<img :src="withBase('left-right.png')" alt="left-right"> <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' name: 'simpleList'
}], }],
// 403 页面配置
403: {
title: '没有访问权限,请联系管理人员',
},
// 404 页面配置
404: {
title: '哎呀!这个页面找不到了',
}
}, },
}; };
``` ```
@ -189,58 +179,58 @@ export function layout(layoutConfig, { initialState }) {
### footer ### footer
- **类型**`String` - **类型**`String`
- **默认值**`null` - **默认值**`null`
- **详情**:页面底部的文字。 - **详情**:页面底部的文字。
### theme ### theme
- **类型**`String` - **类型**`String`
- **默认值**`dark` - **默认值**`dark`
- **详情**:主题,可选有 `dark``light` - **详情**:主题,可选有 `dark``light`
### navigation ### navigation
- **类型**`String` - **类型**`String`
- **默认值**`side` - **默认值**`side`
- **详情**:页面布局类型,可选有 `side``top``mixin` - **详情**:页面布局类型,可选有 `side``top``mixin`
### navigationOnError ### navigationOnError
- **类型**`String``Function` - **类型**`String``Function`
- **详情**:指定 `403``404` 时,页面的布局类型。值同 `navigation`。也支持函数返回。 - **详情**:指定 `403``404` 时,页面的布局类型。值同 `navigation`。也支持函数返回。
### isFixedHeader ### isFixedHeader
- **类型**`Boolean` - **类型**`Boolean`
- **默认值**`false` - **默认值**`false`
- **详情**:是否固定头部,不跟随页面滚动。 - **详情**:是否固定头部,不跟随页面滚动。
### isFixedSidebar ### isFixedSidebar
- **类型**`Boolean` - **类型**`Boolean`
- **默认值**`true` - **默认值**`true`
- **详情**:是否固定 sidebar不跟随页面滚动。 - **详情**:是否固定 sidebar不跟随页面滚动。
### title ### title
- **类型**`String` - **类型**`String`
- **默认值**:默认为 [编译时配置 title](../../../reference/config/#title) - **默认值**:默认为 [编译时配置 title](../../../reference/config/#title)
- **详情**:产品名,当配置为"$"开头时,开启国际化,使用`$`后面的内容去匹配语言设置 - **详情**:产品名。
### logo ### logo
- **类型**`String` - **类型**`String`
- **默认值**:默认提供 `fes.js` 的 Logo - **默认值**:默认提供 `fes.js` 的 Logo
- **详情**Logo 的链接,例如在 public/logo.png 放了一个 logo可以这么配置([BASE_URL 来自这里](../../../guide/env#process-env)) - **详情**Logo 的链接,例如在 public/logo.png 放了一个 logo可以这么配置([BASE_URL 来自这里](../../../guide/env#process-env))
```js ```js
export const layout = { export const layout = {
@ -250,29 +240,25 @@ export const layout = {
### multiTabs ### multiTabs
- **类型**`boolean` - **类型**`boolean`
- **默认值**`false` - **默认值**`false`
- **详情**:是否开启多页。可通过 tabReload: false 控制标签页是否重新加载。 - **详情**:是否开启多页。
### menus ### menus
- **类型**`[] | () => Ref<[]> | () => []` - **类型**`[] | () => Ref<[]> | () => []`
- **默认值**`[]` - **默认值**`[]`
- **详情**:菜单配置 - **详情**:菜单配置
子项具体配置如下: 子项具体配置如下:
- **name**:菜单的名称。通过匹配 `name` 和路由元信息 [meta](../../../guide/route.md#扩展路由元信息) 中的 `name`,把菜单和路由关联起来, 然后使用路由元信息补充菜单配置,比如 `title``path`  等。 - **name**:菜单的名称。通过匹配 `name` 和路由元信息 [meta](../../../guide/route.md#扩展路由元信息) 中的 `name`,把菜单和路由关联起来, 然后使用路由元信息补充菜单配置,比如 `title``path`  等。
- **path**:菜单的路径,可配置第三方地址。 - **path**:菜单的路径,可配置第三方地址。
- **query**:同 vue-router 的 query 参数。 - **match (v4.0.0+**:额外匹配的路径,当前路由命中匹配规则时,此菜单高亮。
- **params**:同 vue-router 的 params 参数。
- **match (v4.0.0+**:额外匹配的路径,当前路由命中匹配规则时,此菜单高亮。
``` ```
{ {
@ -281,17 +267,17 @@ export const layout = {
} }
``` ```
- **title**:菜单的标题。 - **title**:菜单的标题。
- 如果同时使用[国际化插件](./locale.md),而且`title`的值以`$`开头,则使用`$`后面的内容去匹配语言设置。 - 如果同时使用[国际化插件](./locale.md),而且`title`的值以`$`开头,则使用`$`后面的内容去匹配语言设置。
- title 支持配置函数,对应 Fes Design 中 Menu 组件的`label`插槽。仅在运行时配置中支持。 - title 支持配置函数,对应 Fes Design 中 Menu 组件的`label`插槽。仅在运行时配置中支持。
- **icon**: 菜单的图标,只一级标题展示图标。 - **icon**: 菜单的图标,只一级标题展示图标。
- 图标使用[fes-design icon](https://fes-design-4gvn317r3b6bfe17-1254145788.ap-shanghai.app.tcloudbase.com/zh/components/icon.html),编译时配置使用组件名称,我们会自动引入组件。 - 图标使用[fes-design icon](https://fes-design-4gvn317r3b6bfe17-1254145788.ap-shanghai.app.tcloudbase.com/zh/components/icon.html),编译时配置使用组件名称,我们会自动引入组件。
- 图标使用本地或者远程 svg 图片。 - 图标使用本地或者远程 svg 图片。
```js ```js
{ {
@ -299,8 +285,7 @@ export const layout = {
} }
``` ```
- **children**:子菜单配置。 - **children**:子菜单配置。
- **_blank**:是否在新的窗口打开页面,默认 http 开头的链接在新窗口打开
:::tip :::tip
函数类型仅在运行时可用,可以实现动态变更菜单。 函数类型仅在运行时可用,可以实现动态变更菜单。
@ -308,42 +293,42 @@ export const layout = {
### menuProps ### menuProps
- **类型**`Object` - **类型**`Object`
- **默认值**`{}` - **默认值**`{}`
- **详情**:菜单的配置: - **详情**:菜单的配置:
- **defaultExpandAll**:是否默认展开全部菜单。 - **defaultExpandAll**:是否默认展开全部菜单。
- **expandedKeys**:配置默认展开的菜单,需要传子项是菜单路径的数组。 - **expandedKeys**:配置默认展开的菜单,需要传子项是菜单路径的数组。
- **accordion**:是否只保持一个子菜单的展开。 - **accordion**:是否只保持一个子菜单的展开。
### sideWidth ### sideWidth
- **类型**`Number` - **类型**`Number`
- **默认值**`200` - **默认值**`200`
- **详情**sidebar 的宽度 - **详情**sidebar 的宽度
### renderCustom ### renderCustom
- **类型** `()=> VNodes` - **类型** `()=> VNodes`
- **默认值**`null` - **默认值**`null`
- **详情** 自定义区域内容,仅运行时。 - **详情** 自定义区域内容,仅运行时。
### unAccessHandler ### unAccessHandler
- **类型**`({ to, from, next})=> void` - **类型**`({ to, from, next})=> void`
- **默认值**`null` - **默认值**`null`
- **详情**:仅运行时,当进入某个路由时,如果路由对应的页面不属于可见资源列表,则会暂停进入,调用 `unAccessHandler` 函数。 - **详情**:仅运行时,当进入某个路由时,如果路由对应的页面不属于可见资源列表,则会暂停进入,调用 `unAccessHandler` 函数。
- **参数** - **参数**
- routercreateRouter 创建的路由实例 - routercreateRouter 创建的路由实例
- to 准备进入的路由 - to 准备进入的路由
- from离开的路由 - from离开的路由
- next [next 函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next) - next [next 函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)
比如: 比如:
@ -365,15 +350,15 @@ export const layout = {
### noFoundHandler ### noFoundHandler
- **类型**`({ to, from, next})=> void` - **类型**`({ to, from, next})=> void`
- **默认值**`null` - **默认值**`null`
- **详情**:仅运行时,当进入某个路由时,如果路由对应的页面不存在,则会调用 `noFoundHandler` 函数。 - **详情**:仅运行时,当进入某个路由时,如果路由对应的页面不存在,则会调用 `noFoundHandler` 函数。
- **参数** - **参数**
- routercreateRouter 创建的路由实例 - routercreateRouter 创建的路由实例
- to 准备进入的路由 - to 准备进入的路由
- from离开的路由 - from离开的路由
- next [next 函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next) - next [next 函数](https://next.router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%8F%AF%E9%80%89%E7%9A%84%E7%AC%AC%E4%B8%89%E4%B8%AA%E5%8F%82%E6%95%B0-next)
比如: 比如:
@ -391,7 +376,7 @@ export const layout = {
## API ## API
### useTabTitle建议使用useLayout ### useTabTitle
类型定义如下: 类型定义如下:
@ -412,18 +397,6 @@ titleRef.value = 'changed';
</script> </script>
``` ```
### useLayout
类型定义如下:
```ts
function useLayout(options: { title?: string }): { title: Ref<string>; reloadTab: () => void; closeTab: () => void };
```
- title: 更新当前页签的标题
- reloadTab重载当前页签
- closeTab关闭当前页签
## 4.x 升级到 5.x ## 4.x 升级到 5.x
1. 个性化 layout 配置改为使用传入 navigation 1. 个性化 layout 配置改为使用传入 navigation

View File

@ -69,9 +69,11 @@ export default {
想了解更多语言信息配置、匹配规则,请参考 [Vue I18n](https://vue-i18n.intlify.dev/guide/essentials/syntax.html) 文档。 想了解更多语言信息配置、匹配规则,请参考 [Vue I18n](https://vue-i18n.intlify.dev/guide/essentials/syntax.html) 文档。
### 多层配置
### 多层配置
如果国际化内容较多,希望模块化配置,则可以这样: 如果国际化内容较多,希望模块化配置,则可以这样:
```
src src
├── locales ├── locales
│ ├── zh-CN.js │ ├── zh-CN.js
@ -82,7 +84,6 @@ src
└── pages └── pages
│ └── index.vue │ └── index.vue
└── app.js └── app.js
``` ```
插件会把相同语言的配置合并在一起! 插件会把相同语言的配置合并在一起!
@ -114,49 +115,37 @@ export default {
#### locale #### locale
- **类型**`String` - **类型**`String`
- **默认值**`zh-CN` - **默认值**`zh-CN`
- **详情**:当前的语言。 - **详情**:当前的语言。
#### fallbackLocale #### fallbackLocale
- **类型**`String` - **类型**`String`
- **默认值**`zh-CN` - **默认值**`zh-CN`
- **详情**:兜底的语言,如果当前语言找不到配置,则使用默认语言,需要保证默认语言配置文件存在。 - **详情**:兜底的语言,如果当前语言找不到配置,则使用默认语言,需要保证默认语言配置文件存在。
#### baseNavigator #### baseNavigator
- **类型**`Boolean` - **类型**`Boolean`
- **默认值**`true` - **默认值**`true`
- **详情**:开启浏览器语言检测。 - **详情**:开启浏览器语言检测。
默认情况下,当前语言环境的识别按照:`localStorage``fes_locale` 值 > 浏览器检测 > `default` 设置的默认语言 > `zh-CN` 中文。 默认情况下,当前语言环境的识别按照:`localStorage``fes_locale` 值 > 浏览器检测 > `default` 设置的默认语言 > `zh-CN` 中文。
#### legacy #### legacy
- **类型**`Boolean` - **类型**`Boolean`
- **默认值**`false` - **默认值**`false`
- **详情**:用户是否需要 Legacy API 模式 - **详情**:用户是否需要 Legacy API 模式
### 运行时配置 ### 运行时配置
## onLocaleChange 暂无。
当语言环境发生变化时,会触发此函数。
```js
import { defineRuntimeConfig } from '@fesjs/fes';
export default defineRuntimeConfig({
onLocaleChange: ({ t, locale }) => {
}
});
```
## API ## API
@ -170,16 +159,16 @@ import { locale } from '@fesjs/fes';
#### locale.messages #### locale.messages
- **类型**`Object` - **类型**`Object`
- **详情**:当前的配置的语言信息。 - **详情**:当前的配置的语言信息。
#### locale.setLocale #### locale.setLocale
- **类型**`Function` - **类型**`Function`
- **详情**:设置当前的语言。 - **详情**:设置当前的语言。
- **参数** - **参数**
- locale语言的名称应该是符合 `<lang>-<COUNTRY>` 规范的名称。 - locale语言的名称应该是符合 `<lang>-<COUNTRY>` 规范的名称。
- **返回值**`null` - **返回值**`null`
```js ```js
import { locale } from '@fesjs/fes'; import { locale } from '@fesjs/fes';
@ -188,12 +177,12 @@ locale.setLocale({ locale: 'en-US' });
#### locale.addLocale #### locale.addLocale
- **类型**`Function` - **类型**`Function`
- **详情**:手动添加语言配置。 - **详情**:手动添加语言配置。
- **参数** - **参数**
- locale语言的名称符合 `<lang>-<COUNTRY>` 规范的名称。 - locale语言的名称符合 `<lang>-<COUNTRY>` 规范的名称。
- messages, 语言信息。 - messages, 语言信息。
- **返回值**`null` - **返回值**`null`
```js ```js
import { locale } from '@fesjs/fes'; import { locale } from '@fesjs/fes';
@ -202,10 +191,10 @@ locale.addLocale({ locale: 'ja-JP', messages: { test: 'テスト' } });
#### locale.getAllLocales #### locale.getAllLocales
- **类型**`Function` - **类型**`Function`
- **详情**:获取当前获得所有国际化文件的列表,默认会在 locales 文件夹下寻找类似 `en-US.js` 文件。 - **详情**:获取当前获得所有国际化文件的列表,默认会在 locales 文件夹下寻找类似 `en-US.js` 文件。
- **参数**null - **参数**null
- **返回值**`Array` - **返回值**`Array`
```js ```js
import { locale } from '@fesjs/fes'; import { locale } from '@fesjs/fes';

View File

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

View File

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

View File

@ -1,39 +1,39 @@
{ {
"name": "@fesjs/create-fes-app", "name": "@fesjs/create-fes-app",
"version": "3.0.6", "version": "3.0.2",
"description": "create a app base on fes.js", "description": "create a app base on fes.js",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [
"lib", "lib",
"bin", "bin",
"templates/**/*" "templates/**/*"
], ],
"bin": { "bin": {
"create-fes-app": "bin/create-fes-app.js" "create-fes-app": "bin/create-fes-app.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/create-fes-app" "directory": "packages/create-fes-app"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"sideEffects": false, "sideEffects": false,
"author": "qlin", "author": "qlin",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@fesjs/utils": "^3.0.3", "@fesjs/utils": "^3.0.1",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
"inquirer": "^7.3.3", "inquirer": "^7.3.3",
"readline": "^1.3.0", "readline": "^1.3.0",
"validate-npm-package-name": "^3.0.0" "validate-npm-package-name": "^3.0.0"
} }
} }

View File

@ -17,8 +17,8 @@
}, },
"dependencies": { "dependencies": {
"@fesjs/fes": "^3.0.0", "@fesjs/fes": "^3.0.0",
"@fesjs/plugin-access": "^3.1.9", "@fesjs/plugin-access": "^3.0.0",
"@fesjs/plugin-layout": "^5.4.3", "@fesjs/plugin-layout": "^5.0.0",
"@fesjs/plugin-model": "^3.0.0", "@fesjs/plugin-model": "^3.0.0",
"@fesjs/plugin-enums": "^3.0.0", "@fesjs/plugin-enums": "^3.0.0",
"@fesjs/fes-design": "^0.8.0", "@fesjs/fes-design": "^0.8.0",
@ -27,4 +27,4 @@
"core-js": "^3.29.1" "core-js": "^3.29.1"
}, },
"private": true "private": true
} }

View File

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

View File

@ -25,7 +25,7 @@ export default async (api, args) => {
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), { const bundleConfig = deepmerge(getInnerCommonConfig(api), {
mode: 'development', mode: 'development',

View File

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

View File

@ -1,28 +1,19 @@
import { extname } from 'node:path'; import { extname } from 'path';
import historyFallback from 'connect-history-api-fallback'; import historyFallback from 'connect-history-api-fallback';
const ASSET_EXT_NAMES = ['.ico', '.png', '.jpg', '.jpeg', '.gif', '.svg']; const ASSET_EXT_NAMES = ['.ico', '.png', '.jpg', '.jpeg', '.gif', '.svg'];
function proxyMiddleware(api) { const proxyMiddleware = (api) => (req, res, next) => {
return (req, res, next) => { const proxyConfig = api.config.proxy;
const proxyConfig = api.config.proxy; if (proxyConfig && Object.keys(proxyConfig).some((path) => req.url.startsWith(path))) {
if (proxyConfig) { return next();
if (Array.isArray(proxyConfig)) { }
if (proxyConfig.some(item => item.context.some(path => path && req.url.startsWith(path)))) { if (ASSET_EXT_NAMES.includes(extname(req.url))) {
return next(); 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();
}
const history = historyFallback(); const history = historyFallback();
history(req, res, next); history(req, res, next);
}; };
}
export default proxyMiddleware; export default proxyMiddleware;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
import { computed, reactive, unref } from "vue"; import { reactive, unref, computed, inject } from "vue";
import { isPlainObject } from "{{{ lodashPath }}}";
import createComponent from "./createComponent";
import createDirective from "./createDirective"; import createDirective from "./createDirective";
import createComponent from "./createComponent";
import {isPlainObject} from "{{{ lodashPath }}}";
function isPromise(obj) { function isPromise(obj) {
return ( return (
@ -20,23 +20,12 @@ const state = reactive({
const rolePromiseList = []; const rolePromiseList = [];
const accessPromiseList = []; 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 getAllowAccessIds = () => {
const result = [...presetAccessIds, ...state.currentAccessIds];
const roleAccessIds = state.roles[state.currentRoleId]; const roleAccessIds = state.roles[state.currentRoleId];
if (Array.isArray(roleAccessIds) && roleAccessIds.length > 0) { if (Array.isArray(roleAccessIds) && roleAccessIds.length > 0) {
result.push(...roleAccessIds); return state.currentAccessIds.concat(roleAccessIds);
} }
return state.currentAccessIds;
return result;
}; };
const _syncSetAccessIds = (promise) => { const _syncSetAccessIds = (promise) => {
@ -145,13 +134,8 @@ export const install = (app) => {
app.component("Access", createComponent(useAccess)); app.component("Access", createComponent(useAccess));
}; };
export const hasAccessSync = (path) => {
return match(unref(path), getAllowAccessIds());
}
export const access = { export const access = {
hasAccess, hasAccess,
hasAccessSync,
isDataReady, isDataReady,
setRole, setRole,
getRole: () => { getRole: () => {
@ -160,9 +144,12 @@ export const access = {
setAccess, setAccess,
match, match,
getAccess: getAllowAccessIds, getAccess: getAllowAccessIds,
setPresetAccess,
}; };
export const hasAccessSync = (path) => {
return match(unref(path), getAllowAccessIds());
}
export const useAccess = (path) => { export const useAccess = (path) => {
const allowPageIds = computed(getAllowAccessIds); const allowPageIds = computed(getAllowAccessIds);
const result = computed(() => { const result = computed(() => {

View File

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

View File

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

View File

@ -1,38 +1,38 @@
{ {
"name": "@fesjs/plugin-icon", "name": "@fesjs/plugin-icon",
"version": "4.0.0", "version": "3.0.0",
"description": "@fesjs/plugin-icon", "description": "@fesjs/plugin-icon",
"author": "qlin", "main": "lib/index.js",
"license": "MIT", "files": [
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "lib",
"repository": { "types.d.ts"
"type": "git", ],
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "scripts": {
"directory": "packages/fes-plugin-icon" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"bugs": { "repository": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "type": "git",
}, "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"keywords": [ "directory": "packages/fes-plugin-icon"
"fes" },
], "keywords": [
"main": "lib/index.js", "fes"
"files": [ ],
"lib", "author": "qlin",
"types.d.ts" "license": "MIT",
], "bugs": {
"scripts": { "url": "https://github.com/WeBankFinTech/fes.js/issues"
"test": "echo \"Error: no test specified\" && exit 1" },
}, "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"peerDependencies": { "peerDependencies": {
"@fesjs/fes": "^3.0.0", "@fesjs/fes": "^3.0.0",
"vue": "^3.2.47" "vue": "^3.2.47"
}, },
"dependencies": { "dependencies": {
"svgo": "^3.0.2" "svgo": "^3.0.2"
}, },
"typings": "./types.d.ts" "typings": "./types.d.ts"
} }

View File

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

View File

@ -1,8 +1,8 @@
import { computed } from 'vue'; import { computed } from 'vue';
// eslint-disable-next-line
import icons from '../icons'; import icons from '../icons';
function noop() {} const noop = () => {};
export default { export default {
name: 'FesIcon', name: 'FesIcon',
@ -19,9 +19,9 @@ export default {
const svgStyle = computed(() => const svgStyle = computed(() =>
props.rotate props.rotate
? { ? {
msTransform: `rotate(${props.rotate}deg)`, msTransform: `rotate(${props.rotate}deg)`,
transform: `rotate(${props.rotate}deg)`, transform: `rotate(${props.rotate}deg)`,
} }
: null, : null,
); );
const svgCls = computed(() => ({ const svgCls = computed(() => ({

View File

@ -29,7 +29,6 @@
&[tabindex] { &[tabindex] {
cursor: pointer; cursor: pointer;
} }
&--spin { &--spin {
display: inline-block; display: inline-block;
animation: loadingCircle 1s infinite linear; animation: loadingCircle 1s infinite linear;
@ -47,5 +46,5 @@
transform: rotate(360deg); transform: rotate(360deg);
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,2 +1,3 @@
export { default as Page } from './views/page.vue'; export { default as Page } from './views/page.vue';
export { useTabTitle } from './useTitle';
export * from './useLayout'; 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) => { export const access = (memo) => {
const runtimeConfig = getConfig(); 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 { return {
unAccessHandler({ router, to, from, next }) { unAccessHandler({ router, to, from, next }) {
if (runtimeConfig.unAccessHandler && typeof runtimeConfig.unAccessHandler === 'function') { 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'); return state;
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;
} }
export function useLayout(options) { export const useLayout = createSharedComposable(_useLayout);
const parent = inject(PLUGIN_LAYOUT_KEY, { reloadTab: () => void 0, closeTab: () => void 0 });
const titleRef = useTabTitle(options?.title);
return {
...parent,
title: titleRef,
};
}

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

View File

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

View File

@ -11,8 +11,8 @@
> >
<div class="layout-logo"> <div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img"> <img v-if="logo" :src="logo" class="logo-img">
<div v-if="transformedTitle" class="logo-name"> <div v-if="title" class="logo-name">
{{ transformedTitle }} {{ title }}
</div> </div>
</div> </div>
<LayoutMenu <LayoutMenu
@ -58,8 +58,8 @@
<div> <div>
<div class="layout-logo"> <div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img"> <img v-if="logo" :src="logo" class="logo-img">
<div v-if="transformedTitle" class="logo-name"> <div v-if="title" class="logo-name">
{{ transformedTitle }} {{ title }}
</div> </div>
</div> </div>
<LayoutMenu <LayoutMenu
@ -98,8 +98,8 @@
<FHeader ref="headerRef" class="layout-header" :inverted="theme === 'dark'" :fixed="currentFixedHeaderRef"> <FHeader ref="headerRef" class="layout-header" :inverted="theme === 'dark'" :fixed="currentFixedHeaderRef">
<div class="layout-logo"> <div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img"> <img v-if="logo" :src="logo" class="logo-img">
<div v-if="transformedTitle" class="logo-name"> <div v-if="title" class="logo-name">
{{ transformedTitle }} {{ title }}
</div> </div>
</div> </div>
<LayoutMenu <LayoutMenu
@ -127,65 +127,12 @@
</FFooter> </FFooter>
</FLayout> </FLayout>
</template> </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'"> <template v-else-if="currentNavigation === 'mixin'">
<FHeader ref="headerRef" class="layout-header" :fixed="currentFixedHeaderRef" :inverted="theme === 'dark'"> <FHeader ref="headerRef" class="layout-header" :fixed="currentFixedHeaderRef" :inverted="theme === 'dark'">
<div class="layout-logo"> <div class="layout-logo">
<img v-if="logo" :src="logo" class="logo-img"> <img v-if="logo" :src="logo" class="logo-img">
<div v-if="transformedTitle" class="logo-name"> <div v-if="title" class="logo-name">
{{ transformedTitle }} {{ title }}
</div> </div>
</div> </div>
<div class="layout-header-custom"> <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 { FAside, FFooter, FHeader, FLayout, FMain } from '@fesjs/fes-design';
import { computed, nextTick, ref, watch } from 'vue'; import { computed, nextTick, ref, watch } from 'vue';
import defaultLogo from '../assets/logo.png'; import defaultLogo from '../assets/logo.png';
import { flatNodes } from '../helpers/utils';
import { transTitle } from '../helpers/pluginLocale';
import LayoutMenu from './Menu.vue'; import LayoutMenu from './Menu.vue';
import MultiTabProvider from './MultiTabProvider.vue'; import MultiTabProvider from './MultiTabProvider.vue';
@ -270,7 +215,7 @@ export default {
}, },
navigation: { navigation: {
type: String, type: String,
default: 'side', // side / top / mixin //top-left-right // default: 'side', // side / top / mixin //
}, },
navigationOnError: { navigationOnError: {
type: [String, Function], // 403, 404 navigation type: [String, Function], // 403, 404 navigation
@ -303,10 +248,6 @@ export default {
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
const transformedTitle = computed(() => {
return transTitle(props.title);
});
const currentNavigation = computed(() => { const currentNavigation = computed(() => {
if (route.meta.layout && route.meta.layout.navigation !== undefined) { if (route.meta.layout && route.meta.layout.navigation !== undefined) {
return route.meta.layout.navigation; 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 { return {
headerRef, headerRef,
headerHeightRef, headerHeightRef,
@ -400,9 +291,6 @@ export default {
headerStyleRef, headerStyleRef,
sideStyleRef, sideStyleRef,
currentNavigation, currentNavigation,
rootMenus,
activeSubMenus,
transformedTitle,
}; };
}, },
}; };

View File

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

View File

@ -1,11 +1,11 @@
<script lang="jsx"> <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 Icons from '../icons';
import { validateContent } from '../helpers/svg'; import { validateContent } from '../helpers/svg';
const urlReg = /^((https?|ftp|file):\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/; 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 { export default {
props: { props: {
@ -25,8 +25,7 @@ export default {
}); });
} }
}); });
} } else {
else {
AIconComponent.value = Icons[props.icon]; AIconComponent.value = Icons[props.icon];
} }
} }
@ -40,14 +39,13 @@ export default {
return <AIconComponent.value />; return <AIconComponent.value />;
} }
if (AText.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; return null;
}; };
}, },
}; };
</script> </script>
<style> <style>
.fes-layout-icon { .fes-layout-icon {
display: inline-block; display: inline-block;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,11 +1,11 @@
<template> <template>
<FTooltip v-model="isOpened" popper-class="lang-popper" mode="popover"> <FTooltip v-model="isOpened" popperClass="lang-popper" mode="popover">
<div class="lang-icon"> <div class="lang-icon">
<LanguageOutlined /> <LanguageOutlined />
</div> </div>
<template #content> <template #content>
<FScrollbar height="274" class="lang-container"> <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.icon }}</span>
<span>{{ item.label }}</span> <span>{{ item.label }}</span>
</div> </div>
@ -15,12 +15,12 @@
</template> </template>
<script> <script>
import { FScrollbar, FTooltip } from '@fesjs/fes-design'; import { FTooltip, FScrollbar } from '@fesjs/fes-design';
import { LanguageOutlined } from '@fesjs/fes-design/icon'; import { LanguageOutlined } from '@fesjs/fes-design/icon';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import langUConfigMap from '../langUConfigMap'; import langUConfigMap from '../langUConfigMap';
// eslint-disable-next-line import/extensions
import { locale as _locale } from '../core'; import { locale as _locale } from '../core';
export default { export default {
@ -55,13 +55,11 @@ export default {
}, },
}; };
</script> </script>
<style> <style>
.fes-tooltip.fes-tooltip-popover.lang-popper { .fes-tooltip.fes-tooltip-popover.lang-popper {
padding: 0; padding: 0;
} }
</style> </style>
<style lang="less" scoped> <style lang="less" scoped>
.lang-icon { .lang-icon {
display: flex; 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'; import { glob, winPath } from '@fesjs/utils';
const ignore = /\.(d\.ts|\.test\.(js|ts))$/; const ignore = /\.(d\.ts|\.test\.(js|ts))$/;
@ -15,32 +15,30 @@ const getRouteName = function (path) {
.replace(/\[...([a-zA-Z]*)\]/, 'FUZZYMATCH-$1'); .replace(/\[...([a-zA-Z]*)\]/, 'FUZZYMATCH-$1');
}; };
export function getLocales(cwdArray) { export function getLocales(cwd) {
const map = {}; const map = {};
const files = []; const files = [];
cwdArray.forEach((cwd) => { glob.sync('**/*.js', {
glob.sync('**/*.js', { cwd,
cwd, })
}) .filter((file) => !ignore.test(file))
.filter(file => !ignore.test(file)) .forEach((fileName) => {
.forEach((fileName) => { const locale = basename(fileName, '.js');
const locale = basename(fileName, '.js'); const importName = getRouteName(fileName).replace('.js', '');
const importName = getRouteName(fileName).replace('.js', ''); const result = {
const result = { importName,
importName, // import语法的路径必须处理win
// import语法的路径必须处理win path: winPath(join(cwd, fileName)),
path: winPath(join(cwd, fileName)), };
}; files.push(result);
files.push(result); if (!map[locale]) {
if (!map[locale]) { map[locale] = [];
map[locale] = []; }
} map[locale].push(importName);
map[locale].push(importName); });
});
});
return { return {
locales: Object.keys(map).map(key => ({ locale: key, importNames: map[key] })), locales: Object.keys(map).map((key) => ({ locale: key, importNames: map[key] })),
files, files,
}; };
} }

View File

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

View File

@ -1,36 +1,36 @@
{ {
"name": "@fesjs/plugin-login", "name": "@fesjs/plugin-login",
"version": "3.0.2", "version": "3.0.0",
"description": "@fesjs/plugin-login", "description": "@fesjs/plugin-login",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [
"lib", "lib",
"types.d.ts" "types.d.ts"
], ],
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-login" "directory": "packages/fes-plugin-login"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"author": "qlin", "author": "qlin",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"peerDependencies": { "peerDependencies": {
"@fesjs/fes": "^3.0.0", "@fesjs/fes": "^3.0.0",
"@fesjs/plugin-request": "^4.0.0-rc.3", "@fesjs/plugin-request": "^3.0.0",
"vue": "^3.2.47" "vue": "^3.2.47"
}, },
"typings": "./types.d.ts" "typings": "./types.d.ts"
} }

View File

@ -1,12 +1,8 @@
import { request } from '@@/core/pluginExports';
import { ApplyPluginsType, getRouter, plugin } from '@fesjs/fes'; import { ApplyPluginsType, getRouter, plugin } from '@fesjs/fes';
let config; let config;
function getLoginConfig() { function getLoginConfig() {
if (config) { if (config) return config;
return config;
}
config = plugin.applyPlugins({ config = plugin.applyPlugins({
key: 'login', key: 'login',
type: ApplyPluginsType.modify, type: ApplyPluginsType.modify,
@ -18,67 +14,38 @@ function getLoginConfig() {
return config; return config;
} }
const defaultExport = {
onRouterCreated({ router }) {
const { hasLogin, loginPath } = getLoginConfig();
if (hasLogin && loginPath) {
let isAuthenticated;
router.beforeEach(async (to, from, next) => {
if (to.path !== loginPath && !isAuthenticated) {
isAuthenticated = await hasLogin();
if (!isAuthenticated) {
return next({ path: loginPath });
}
}
next();
});
}
},
};
// ACCESS // ACCESS
if (request.version) { export function request(memo) {
defaultExport.request = (memo) => { if (!memo.responseInterceptors) {
const config = getLoginConfig(); memo.responseInterceptors = [];
if (config.ignore401Redirect) { }
return memo; memo.responseInterceptors.push([
} (response) => response,
(error) => {
const errorHandler = memo.errorHandler;
memo.errorHandler = (error) => {
if (error?.response?.status === 401) { if (error?.response?.status === 401) {
const router = getRouter(); const router = getRouter();
const { loginPath } = getLoginConfig(); const { loginPath } = getLoginConfig();
router.push({ path: loginPath }); router.push({ path: loginPath });
} }
errorHandler && errorHandler(error); throw error;
}; },
return memo; ]);
}; 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; export function onRouterCreated({ router }) {
const { hasLogin, loginPath } = getLoginConfig();
if (hasLogin && loginPath) {
let isAuthenticated;
router.beforeEach(async (to, from, next) => {
if (to.path !== loginPath && !isAuthenticated) {
isAuthenticated = await hasLogin();
if (!isAuthenticated) {
return next({ path: loginPath });
}
}
next();
});
}
}

View File

@ -1,38 +1,38 @@
{ {
"name": "@fesjs/plugin-model", "name": "@fesjs/plugin-model",
"version": "3.0.3", "version": "3.0.1",
"description": "@fesjs/plugin-model", "description": "@fesjs/plugin-model",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [
"lib", "lib",
"types.d.ts" "types.d.ts"
], ],
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-model" "directory": "packages/fes-plugin-model"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"author": "harrywan", "author": "harrywan",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@fesjs/utils": "^3.0.3" "@fesjs/utils": "^3.0.1"
}, },
"peerDependencies": { "peerDependencies": {
"@fesjs/fes": "^3.1.12", "@fesjs/fes": "^3.1.4",
"vue": "^3.2.47" "vue": "^3.2.47"
}, },
"typings": "./types.d.ts" "typings": "./types.d.ts"
} }

View File

@ -1,40 +1,40 @@
{ {
"name": "@fesjs/plugin-monaco-editor", "name": "@fesjs/plugin-monaco-editor",
"version": "3.0.3", "version": "3.0.1",
"description": "@fesjs/plugin-monaco-editor", "description": "@fesjs/plugin-monaco-editor",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [
"lib", "lib",
"types.d.ts" "types.d.ts"
], ],
"scripts": {}, "scripts": {},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-monaco-editor" "directory": "packages/fes-plugin-monaco-editor"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"author": "harrywan", "author": "harrywan",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@fesjs/utils": "^3.0.3", "@fesjs/utils": "^3.0.1",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"monaco-editor": "^0.36.1", "monaco-editor": "^0.36.1",
"monaco-editor-webpack-plugin": "^7.0.1", "monaco-editor-webpack-plugin": "^7.0.1",
"vite-plugin-monaco-editor": "^1.1.0" "vite-plugin-monaco-editor": "^1.1.0"
}, },
"peerDependencies": { "peerDependencies": {
"@fesjs/fes": "^3.1.12", "@fesjs/fes": "^3.1.4",
"vue": "^3.2.47" "vue": "^3.2.47"
}, },
"typings": "./types.d.ts" "typings": "./types.d.ts"
} }

View File

@ -1,39 +1,39 @@
{ {
"name": "@fesjs/plugin-pinia", "name": "@fesjs/plugin-pinia",
"version": "3.0.3", "version": "3.0.1",
"description": "@fesjs/plugin-pinia", "description": "@fesjs/plugin-pinia",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [
"lib", "lib",
"types.d.ts" "types.d.ts"
], ],
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-pinia" "directory": "packages/fes-plugin-pinia"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"author": "harrywan", "author": "harrywan",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@fesjs/utils": "^3.0.3" "@fesjs/utils": "^3.0.1"
}, },
"peerDependencies": { "peerDependencies": {
"@fesjs/fes": "^3.1.12", "@fesjs/fes": "^3.1.4",
"pinia": "^2.0.11", "pinia": "^2.0.11",
"vue": "^3.2.47" "vue": "^3.2.47"
}, },
"typings": "./types.d.ts" "typings": "./types.d.ts"
} }

View File

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

View File

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

View File

@ -1,50 +1,50 @@
{ {
"name": "@fesjs/plugin-qiankun", "name": "@fesjs/plugin-qiankun",
"version": "3.1.6", "version": "3.1.1",
"description": "@fesjs/plugin-qiankun", "description": "@fesjs/plugin-qiankun",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [
"lib", "lib",
"types.d.ts" "types.d.ts"
], ],
"scripts": { "scripts": {
"start": "npm-run-all --parallel start:*", "start": "npm-run-all --parallel start:*",
"start:vite-main": "cd ./examples/vite-main && fes dev", "start:vite-main": "cd ./examples/vite-main && fes dev",
"start:vite-micro": "cd ./examples/vite-micro && fes dev", "start:vite-micro": "cd ./examples/vite-micro && fes dev",
"start:webpack-main": "cd ./examples/webpack-main && fes dev", "start:webpack-main": "cd ./examples/webpack-main && fes dev",
"start:webpack-micro": "cd ./examples/webpack-micro && fes dev" "start:webpack-micro": "cd ./examples/webpack-micro && fes dev"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-qiankun" "directory": "packages/fes-plugin-qiankun"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"author": "michaelxxie、harrywan", "author": "michaelxxie、harrywan",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@fesjs/utils": "^3.0.3", "@fesjs/utils": "^3.0.1",
"address": "^1.1.2", "address": "^1.1.2",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"qiankun": "^2.7.0", "qiankun": "^2.7.0",
"vite-plugin-qiankun": "^1.0.15" "vite-plugin-qiankun": "^1.0.15"
}, },
"devDependencies": { "devDependencies": {
"npm-run-all": "^4.1.5" "npm-run-all": "^4.1.5"
}, },
"peerDependencies": { "peerDependencies": {
"@fesjs/fes": "^3.1.13", "@fesjs/fes": "^3.1.4",
"@fesjs/fes-design": ">=0.7.20", "@fesjs/fes-design": ">=0.7.20",
"vue": "^3.2.47" "vue": "^3.2.47"
}, },
"typings": "./types.d.ts" "typings": "./types.d.ts"
} }

View File

@ -9,7 +9,7 @@ import {
shallowRef, shallowRef,
} from "vue"; } from "vue";
import { loadMicroApp } from "{{{QIANKUN}}}"; 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 // eslint-disable-next-line import/extensions
import { getMasterOptions } from "./masterOptions"; import { getMasterOptions } from "./masterOptions";
@ -66,7 +66,7 @@ export const MicroApp = defineComponent({
return {}; return {};
}); });
const propsConfigRef = shallowRef({}); const propsConfigRef = shallowRef({});
watch( watch(

View File

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

View File

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

View File

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

View File

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

View File

@ -1,40 +1,40 @@
{ {
"name": "@fesjs/plugin-swc", "name": "@fesjs/plugin-swc",
"version": "3.0.5", "version": "3.0.3",
"description": "@fesjs/plugin-swc", "description": "@fesjs/plugin-swc",
"main": "lib/index.js", "main": "lib/index.js",
"types": "types.d.ts", "types": "types.d.ts",
"files": [ "files": [
"lib", "lib",
"types.d.ts" "types.d.ts"
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-swc" "directory": "packages/fes-plugin-swc"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"author": "RiESAEX", "author": "RiESAEX",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@fesjs/utils": "^3.0.3", "@fesjs/utils": "^3.0.1",
"@swc/core": "^1.3.49", "@swc/core": "^1.3.49",
"@swc/css": "^0.0.20", "@swc/css": "^0.0.20",
"css-minimizer-webpack-plugin": "^5.0.0", "css-minimizer-webpack-plugin": "^5.0.0",
"swc-loader": "^0.2.3", "swc-loader": "^0.2.3",
"swc-plugin-vue-jsx": "^0.2.2", "swc-plugin-vue-jsx": "^0.2.2",
"terser-webpack-plugin": "^5.3.7" "terser-webpack-plugin": "^5.3.7"
}, },
"peerDependencies": { "peerDependencies": {
"@fesjs/fes": "^3.1.12" "@fesjs/fes": "^3.1.4"
} }
} }

View File

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

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

View File

@ -1,39 +1,39 @@
{ {
"name": "@fesjs/plugin-watermark", "name": "@fesjs/plugin-watermark",
"version": "3.0.3", "version": "3.0.1",
"description": "@fesjs/plugin-watermark", "description": "@fesjs/plugin-watermark",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [
"lib", "lib",
"types.d.ts" "types.d.ts"
], ],
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-plugin-watermark" "directory": "packages/fes-plugin-watermark"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"author": "harrywan", "author": "harrywan",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@fesjs/utils": "^3.0.3", "@fesjs/utils": "^3.0.1",
"lodash-es": "^4.17.21" "lodash-es": "^4.17.21"
}, },
"peerDependencies": { "peerDependencies": {
"@fesjs/fes": "^3.1.12", "@fesjs/fes": "^3.1.4",
"vue": "^3.2.47" "vue": "^3.2.47"
}, },
"typings": "./types.d.ts" "typings": "./types.d.ts"
} }

View File

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

View File

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

View File

@ -12,8 +12,6 @@ import DefaultContainer from './defaultContainer.vue';
{{{ entryCodeAhead }}} {{{ entryCodeAhead }}}
{{{ CONSOLE }}}
const renderClient = (opts = {}) => { const renderClient = (opts = {}) => {
const { plugin, routes, rootElement } = opts; const { plugin, routes, rootElement } = opts;
const rootContainer = plugin.applyPlugins({ 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) { export default function (api) {
const { const {
utils: { Mustache }, utils: { Mustache },
@ -33,7 +24,6 @@ export default function (api) {
path: 'fes.js', path: 'fes.js',
content: Mustache.render(fesTpl, { content: Mustache.render(fesTpl, {
enableTitle: api.config.title !== false, enableTitle: api.config.title !== false,
CONSOLE: getConsoleInfo(api.config, api.pkg),
defaultTitle: api.config.title || 'fes.js', defaultTitle: api.config.title || 'fes.js',
runtimePath, runtimePath,
rootElement: `#${api.config.mountElementId || 'app'}`, 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'); api.logger.info('mock.js should export Function');
return; return;
} }
const mockjs = require('@wll8/better-mock'); const mockjs = require('mockjs');
initFunction({ cgiMock, mockjs, utils }); initFunction({ cgiMock, mockjs, utils });
} catch (err) { } catch (err) {
api.logger.error('mock.js run fail!'); api.logger.error('mock.js run fail!');

View File

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

View File

@ -1,37 +1,37 @@
{ {
"name": "@fesjs/runtime", "name": "@fesjs/runtime",
"version": "3.0.1", "version": "3.0.0",
"description": "@fesjs/runtime", "description": "@fesjs/runtime",
"main": "es/index.js", "main": "es/index.js",
"module": "es/index.js", "module": "es/index.js",
"files": [ "files": [
"lib", "lib",
"es", "es",
"types.d.ts" "types.d.ts"
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-runtime" "directory": "packages/fes-runtime"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"sideEffects": false, "sideEffects": false,
"author": "qlin", "author": "qlin",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"peerDependencies": { "peerDependencies": {
"vue": "^3.2.47" "vue": "^3.2.47"
}, },
"dependencies": { "dependencies": {
"vue-router": "^4.0.1" "vue-router": "^4.0.1"
}, },
"typings": "./types.d.ts" "typings": "./types.d.ts"
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -3,11 +3,6 @@ import { ref, watch } from 'vue';
import PageLoading from '@/components/pageLoading.vue'; import PageLoading from '@/components/pageLoading.vue';
import UserCenter from '@/components/userCenter.vue'; import UserCenter from '@/components/userCenter.vue';
export function onLocaleChange({ locale, t }) {
//
console.log(locale, t);
}
export const beforeRender = { export const beforeRender = {
loading: <PageLoading />, loading: <PageLoading />,
action() { action() {
@ -25,29 +20,24 @@ export const beforeRender = {
}, },
}; };
export function layout(layoutConfig, { initialState }) { export const layout = (layoutConfig, { initialState }) => ({
return { ...layoutConfig,
...layoutConfig, renderCustom: (props) => {
403: { console.log(props);
title: 'hello word', return <UserCenter />;
}, },
renderCustom: (props) => { menus: () => {
console.log(props); const menusRef = ref(layoutConfig.menus);
return <UserCenter />; watch(
}, () => initialState.userName,
menus: () => { () => {
const menusRef = ref(layoutConfig.menus); menusRef.value = [
watch( {
() => initialState.userName, name: 'store',
() => { },
menusRef.value = [ ];
{ },
name: 'store', );
}, return menusRef;
]; },
}, });
);
return menusRef;
},
};
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,46 +1,46 @@
{ {
"name": "@fesjs/utils", "name": "@fesjs/utils",
"version": "3.0.3", "version": "3.0.1",
"description": "@fesjs/utils", "description": "@fesjs/utils",
"main": "lib/index.js", "main": "lib/index.js",
"files": [ "files": [
"lib" "lib"
], ],
"repository": { "repository": {
"type": "git", "type": "git",
"url": "git+https://github.com/WeBankFinTech/fes.js.git", "url": "git+https://github.com/WeBankFinTech/fes.js.git",
"directory": "packages/fes-utils" "directory": "packages/fes-utils"
}, },
"keywords": [ "keywords": [
"fes" "fes"
], ],
"author": "qlin", "author": "qlin",
"license": "MIT", "license": "MIT",
"bugs": { "bugs": {
"url": "https://github.com/WeBankFinTech/fes.js/issues" "url": "https://github.com/WeBankFinTech/fes.js/issues"
}, },
"homepage": "https://github.com/WeBankFinTech/fes.js#readme", "homepage": "https://github.com/WeBankFinTech/fes.js#readme",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@babel/generator": "^7.21.3", "@babel/generator": "^7.21.3",
"@babel/parser": "^7.21.3", "@babel/parser": "^7.21.3",
"@babel/traverse": "^7.21.3", "@babel/traverse": "^7.21.3",
"chalk": "^4.1.2", "chalk": "^4.1.2",
"chokidar": "^3.5.2", "chokidar": "^3.5.2",
"crequire": "^1.8.1", "crequire": "^1.8.1",
"debug": "^4.3.2", "debug": "^4.3.2",
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"glob": "^9.3.2", "glob": "^9.3.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mkdirp": "^2.1.6", "mkdirp": "^2.1.6",
"mustache": "^4.2.0", "mustache": "^4.2.0",
"pkg-up": "^3.1.0", "pkg-up": "^3.1.0",
"portfinder": "^1.0.32", "portfinder": "^1.0.32",
"resolve": "^1.20.0", "resolve": "^1.20.0",
"rimraf": "^4.4.1", "rimraf": "^4.4.1",
"semver": "^7.3.5", "semver": "^7.3.5",
"yargs-parser": "^21.1.1" "yargs-parser": "^21.1.1"
} }
} }

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