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 } utils: { Mustache }
} = api; } = api;
const helper = require('./node/helper');
api.describe({ api.describe({
key: 'layout', key: 'layout',
config: { config: {
@ -25,7 +27,7 @@ export default (api) => {
const absRuntimeFilePath = join(namespace, 'runtime.js'); const absRuntimeFilePath = join(namespace, 'runtime.js');
api.onGenerateFiles(() => { api.onGenerateFiles(async () => {
const { name } = api.pkg; const { name } = api.pkg;
const HAS_LOCALE = api.hasPlugins(['@fesjs/plugin-locale']); const HAS_LOCALE = api.hasPlugins(['@fesjs/plugin-locale']);
@ -37,6 +39,25 @@ export default (api) => {
...(api.config.layout || {}) ...(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({ api.writeTmpFile({
path: absFilePath, path: absFilePath,
content: Mustache.render( content: Mustache.render(

View File

@ -1,4 +1,4 @@
export const noop = () => {}; import * as allIcons from '@ant-design/icons-vue';
const matchName = (config, name) => { const matchName = (config, name) => {
let res = {}; let res = {};
@ -21,7 +21,7 @@ const matchName = (config, name) => {
return res; return res;
}; };
export const fillMenuData = (menuConfig, routeConfig, dep = 0) => { export const fillMenuByRoute = (menuConfig, routeConfig, dep = 0) => {
dep += 1; dep += 1;
if (dep > 3) { if (dep > 3) {
throw new Error('[plugin-layout]: menu层级不能超出三层'); throw new Error('[plugin-layout]: menu层级不能超出三层');
@ -39,11 +39,37 @@ export const fillMenuData = (menuConfig, routeConfig, dep = 0) => {
menu[prop] = pageConfig[prop]; 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) { if (menu.children && menu.children.length > 0) {
menu.children = fillMenuData(menu.children, routeConfig, dep); menu.children = fillMenuByRoute(menu.children, routeConfig, dep);
} }
arr.push(menu); arr.push(menu);
}); });
} }
return arr; 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 { reactive, defineComponent } from "vue";
import { getRoutes, plugin, ApplyPluginsType } from "@@/core/coreExports"; import { plugin, ApplyPluginsType } from "@@/core/coreExports";
import BaseLayout from "./views/BaseLayout.vue"; import BaseLayout from "./views/BaseLayout.vue";
import { fillMenuData } from "./helpers";
const userConfig = reactive({{{REPLACE_USER_CONFIG}}}); const userConfig = reactive({{{REPLACE_USER_CONFIG}}});
@ -14,8 +13,6 @@ const Layout = defineComponent({
initialValue: {}, initialValue: {},
}); });
const localeShared = plugin.getShared("locale"); const localeShared = plugin.getShared("locale");
const routeConfig = getRoutes();
userConfig.menus = fillMenuData(userConfig.menus, routeConfig);
return () => { return () => {
const slots = { const slots = {
customHeader: () => { customHeader: () => {

View File

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

View File

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