fix: 优化plugin-layout,在编译时探测需要的icon组件,然后按需加载

This commit is contained in:
万纯 2021-03-08 15:30:34 +08:00
parent 007647044c
commit 7d1c97aadf
5 changed files with 62 additions and 26 deletions

View File

@ -9,6 +9,8 @@ export default (api) => {
utils: { Mustache }
} = api;
const helper = require('./node/helper');
api.describe({
key: 'layout',
config: {
@ -25,7 +27,7 @@ export default (api) => {
const absRuntimeFilePath = join(namespace, 'runtime.js');
api.onGenerateFiles(() => {
api.onGenerateFiles(async () => {
const { name } = api.pkg;
const HAS_LOCALE = api.hasPlugins(['@fesjs/plugin-locale']);
@ -37,6 +39,25 @@ export default (api) => {
...(api.config.layout || {})
};
// 路由信息
const routes = await api.getRoutes();
// 把路由的meta合并到menu配置中
userConfig.menus = helper.fillMenuByRoute(userConfig.menus, routes);
const icons = helper.getIconsFromMenu(userConfig.menus);
const iconsString = icons.map(
iconName => `import ${iconName} from '@ant-design/icons-vue/es/icons/${iconName}'`
);
api.writeTmpFile({
path: join(namespace, 'icons.js'),
content: `
${iconsString.join(';\n')}
export default {
${icons.join(',\n')}
}`
});
api.writeTmpFile({
path: absFilePath,
content: Mustache.render(

View File

@ -1,4 +1,4 @@
export const noop = () => {};
import * as allIcons from '@ant-design/icons-vue';
const matchName = (config, name) => {
let res = {};
@ -21,7 +21,7 @@ const matchName = (config, name) => {
return res;
};
export const fillMenuData = (menuConfig, routeConfig, dep = 0) => {
export const fillMenuByRoute = (menuConfig, routeConfig, dep = 0) => {
dep += 1;
if (dep > 3) {
throw new Error('[plugin-layout]: menu层级不能超出三层');
@ -39,11 +39,37 @@ export const fillMenuData = (menuConfig, routeConfig, dep = 0) => {
menu[prop] = pageConfig[prop];
}
});
// 处理icon
if (menu.icon) {
const icon = menu.icon;
const iconName = `${icon.replace(icon[0], icon[0].toUpperCase())}Outlined`;
if (!allIcons[icon]) {
menu.icon = iconName;
}
}
if (menu.children && menu.children.length > 0) {
menu.children = fillMenuData(menu.children, routeConfig, dep);
menu.children = fillMenuByRoute(menu.children, routeConfig, dep);
}
arr.push(menu);
});
}
return arr;
};
export function getIconsFromMenu(data) {
if (!Array.isArray(data)) {
return [];
}
let icons = [];
(data || []).forEach((item = { path: '/' }) => {
if (item.icon) {
const { icon } = item;
icons.push(icon);
}
if (item.children) {
icons = icons.concat(getIconsFromMenu(item.children));
}
});
return Array.from(new Set(icons));
}

View File

@ -1,7 +1,6 @@
import { reactive, defineComponent } from "vue";
import { getRoutes, plugin, ApplyPluginsType } from "@@/core/coreExports";
import { plugin, ApplyPluginsType } from "@@/core/coreExports";
import BaseLayout from "./views/BaseLayout.vue";
import { fillMenuData } from "./helpers";
const userConfig = reactive({{{REPLACE_USER_CONFIG}}});
@ -14,8 +13,6 @@ const Layout = defineComponent({
initialValue: {},
});
const localeShared = plugin.getShared("locale");
const routeConfig = getRoutes();
userConfig.menus = fillMenuData(userConfig.menus, routeConfig);
return () => {
const slots = {
customHeader: () => {

View File

@ -50,7 +50,7 @@ import { toRefs, computed } from 'vue';
import { useRoute, useRouter } from '@@/core/coreExports';
import Menu from 'ant-design-vue/lib/menu';
import 'ant-design-vue/lib/menu/style/css';
import MenuIcon from './MenuIcon'
import MenuIcon from './MenuIcon';
import { addAccessTag } from '../helpers/pluginAccess';
export default {

View File

@ -2,29 +2,21 @@
// 使 ant-design/icons-vue
// 使 svg
// 使 svg
import { ref, onMounted } from 'vue';
// eslint-disable-next-line import/extensions
import Icons from '../icons';
// import AntdIcon from '@ant-design/icons-vue/es/components/AntdIcon';
export default {
props: {
icon: String
},
setup(props) {
const AIcon = ref(null);
onMounted(()=>{
const iconName = props.icon.slice(0, 1).toUpperCase() + props.icon.slice(1) + 'Outlined';
import(`@ant-design/icons-vue/es/icons/${iconName}`).then(res=>{
AIcon.value = res.default;
}).catch(e=>{
console.warn(`[fes-layout] icon ${props.icon} 不存在!`)
})
})
return ()=>{
if(AIcon.value){
return <AIcon.value />
const AIcon = Icons[props.icon];
return () => {
if (AIcon) {
return < AIcon />;
}
return null
}
return null;
};
}
}
};
</script>