feat: 修改export接口

This commit is contained in:
bac-joker 2020-12-10 17:09:34 +08:00
parent 8fc1141056
commit 78fccc3dad
23 changed files with 163 additions and 714 deletions

View File

@ -109,7 +109,7 @@ export default (api) => {
});
});
// api.addExports(() => [
// api.addPluginExports(() => [
// {
// exportAll: true,
// source: absoluteFilePath

View File

@ -10,7 +10,8 @@ export default [
// generate files
require.resolve('./plugins/generateFiles/core/plugin'),
require.resolve('./plugins/generateFiles/core/routes'),
require.resolve('./plugins/generateFiles/core/exports'),
require.resolve('./plugins/generateFiles/core/exports/coreExports'),
require.resolve('./plugins/generateFiles/core/exports/pluginExports'),
require.resolve('./plugins/generateFiles/fes'),
// bundle configs

View File

@ -1,5 +1,3 @@
import { join } from 'path';
import { existsSync } from 'fs';
import { winPath } from '@umijs/utils';
export default (api) => {
@ -14,14 +12,13 @@ export default (api) => {
api.chainWebpack((webpackConfig) => {
const cwd = api.cwd;
const prefix = existsSync(join(cwd, 'src')) ? join(cwd, 'src') : cwd;
// 添加 .vue 后缀
webpackConfig.resolve.extensions.merge([
'.vue'
]);
webpackConfig.module
.rule('js-in-node_modules').use('babel-loader').tap((options) => {
options.cacheDirectory = winPath(`${prefix}/.fes/.cache/babel-loader`);
options.cacheDirectory = winPath(`${cwd}/.cache/babel-loader`);
return options;
});

View File

@ -1,5 +1,3 @@
import { join } from 'path';
import { existsSync } from 'fs';
import { winPath } from '@umijs/utils';
export default (api) => {
@ -13,10 +11,8 @@ export default (api) => {
});
api.modifyBabelOpts((babelOpts) => {
const cwd = api.cwd;
const prefix = existsSync(join(cwd, 'src')) ? join(cwd, 'src') : cwd;
babelOpts.cacheDirectory = process.env.BABEL_CACHE !== 'none'
? winPath(`${prefix}/.fes/.cache/babel-loader`)
? winPath(`${api.cwd}/.cache/babel-loader`)
: false;
babelOpts.plugins.push(require.resolve('@vue/babel-plugin-jsx'));

View File

@ -0,0 +1,27 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import generateExports from '../../../../utils/generateExports';
export default function (api) {
api.onGenerateFiles(async () => {
const coreExports = await api.applyPlugins({
key: 'addCoreExports',
type: api.ApplyPluginsType.add,
initialValue: []
});
const fesExportsHook = {}; // repeated definition
const absoluteFilePath = 'core/coreExports.js';
const content = `${coreExports
.map(item => generateExports(absoluteFilePath, {
item,
fesExportsHook
}))
.join('\n')}\n`;
const tpl = readFileSync(join(__dirname, './coreExports.tpl'), 'utf-8');
api.writeTmpFile({
path: absoluteFilePath,
content: tpl.replace('CORE_EXPORTS', content)
});
});
}

View File

@ -0,0 +1,14 @@
export {
useRoute,
useRouter,
onBeforeRouteUpdate,
onBeforeRouteLeave,
RouterLink,
useLink,
createWebHashHistory,
createRouter,
Plugin,
ApplyPluginsType
} from '@webank/fes-runtime';
CORE_EXPORTS

View File

@ -0,0 +1,3 @@
# 为了避免在运行时循环依赖
将 exports 拆分成 coreExports 和 pluginExports第三方插件只能依赖 coreExports插件之间的运行时依赖通过 runtime plugin 解耦。

View File

@ -0,0 +1,23 @@
import generateExports from '../../../../utils/generateExports';
export default function (api) {
api.onGenerateFiles(async () => {
const fesExports = await api.applyPlugins({
key: 'addPluginExports',
type: api.ApplyPluginsType.add,
initialValue: []
});
const fesExportsHook = {}; // repeated definition
const absoluteFilePath = 'core/pluginExports.js';
api.writeTmpFile({
path: absoluteFilePath,
content: `${fesExports
.map(item => generateExports(absoluteFilePath, {
item,
fesExportsHook
}))
.join('\n')}\n`
});
});
}

View File

@ -61,7 +61,7 @@ export default function (api) {
});
});
api.addExports(() => ({
api.addCoreExports(() => ({
specifiers: ['plugin'],
source: absoluteFilePath
}));

View File

@ -15,7 +15,7 @@ import { createRouter, getRoutes } from './core/routes';
const renderClient = (opts = {}) => {
const { plugin, routes, rootElement } = opts;
const rootContainer = plugin.applyPlugins({
type: 'modify',
type: ApplyPluginsType.modify,
key: 'rootContainer',
initialValue: defineComponent(() => () => (<RouterView></RouterView>)),
args: {

View File

@ -6,7 +6,8 @@ export default function (api) {
[
'onExit',
'onGenerateFiles',
'addExports',
'addPluginExports',
'addCoreExports',
'addRuntimePluginKey',
'addRuntimePlugin',
'addEntryImportsAhead',

View File

@ -42,7 +42,7 @@ export async function getBundleAndConfigs({
port,
hot: process.env.HMR !== 'none',
entry: {
umi: join(api.paths.absTmpPath, 'fes.js')
fes: join(api.paths.absTmpPath, 'fes.js')
},
// @ts-ignore
bundleImplementor,

View File

@ -13,7 +13,7 @@ const reserveExportsNames = [
'Route'
];
export function generateExports(basePath, { item, fesExportsHook }) {
export default function generateExports(basePath, { item, fesExportsHook }) {
assert(item.source, 'source should be supplied.');
const source = path.relative(path.basename(basePath), item.source);
assert(
@ -58,25 +58,3 @@ export function generateExports(basePath, { item, fesExportsHook }) {
source
)}';`;
}
export default function (api) {
api.onGenerateFiles(async () => {
const fesExports = await api.applyPlugins({
key: 'addExports',
type: api.ApplyPluginsType.add,
initialValue: []
});
const fesExportsHook = {}; // repeated definition
const absoluteFilePath = 'core/exports.js';
api.writeTmpFile({
path: absoluteFilePath,
content: `${fesExports
.map(item => generateExports(absoluteFilePath, {
item,
fesExportsHook
}))
.join('\n')}\n`
});
});
}

View File

@ -0,0 +1,82 @@
<template>
<a-layout id="components-layout-demo-custom-trigger">
<a-layout-sider v-model:collapsed="collapsed" :trigger="null" collapsible>
<div class="logo" />
<a-menu v-model:selectedKeys="selectedKeys" theme="dark" mode="inline">
<a-menu-item key="1">
<user-outlined />
<span>nav 1</span>
</a-menu-item>
<a-menu-item key="2">
<video-camera-outlined />
<span>nav 2</span>
</a-menu-item>
<a-menu-item key="3">
<upload-outlined />
<span>nav 3</span>
</a-menu-item>
</a-menu>
</a-layout-sider>
<a-layout>
<a-layout-header style="background: #fff; padding: 0">
<menu-unfold-outlined
v-if="collapsed"
@click="() => (collapsed = !collapsed)"
class="trigger"
/>
<menu-fold-outlined v-else @click="() => (collapsed = !collapsed)" class="trigger" />
</a-layout-header>
<a-layout-content
:style="{ margin: '24px 16px', padding: '24px', background: '#fff', minHeight: '280px' }"
>
Content
</a-layout-content>
</a-layout>
</a-layout>
</template>
<script>
import {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
MenuUnfoldOutlined,
MenuFoldOutlined
} from '@ant-design/icons-vue';
export default {
components: {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
MenuUnfoldOutlined,
MenuFoldOutlined
},
data() {
return {
selectedKeys: ['1'],
collapsed: false
};
}
};
</script>
<style>
#components-layout-demo-custom-trigger .trigger {
font-size: 18px;
line-height: 64px;
padding: 0 24px;
cursor: pointer;
transition: color 0.3s;
}
#components-layout-demo-custom-trigger .trigger:hover {
color: #1890ff;
}
#components-layout-demo-custom-trigger .logo {
height: 32px;
background: rgba(255, 255, 255, 0.2);
margin: 16px;
}
</style>

View File

@ -1,89 +0,0 @@
import { defineComponent, computed } from 'vue';
import { useFesContext } from '@webank/fes-core';
import RightRender from './RightRender';
import RouteMenu from './RouteMenu.vue';
const DEFAULT_THEME = {
light: 'light',
blue: 'dark',
dark: 'dark'
};
function useMenu(menu) {
// 根据当前权限控制,显示 隐藏菜单
const { useI18n, accessibleElementTags, accessibleValidator } = useFesContext();
const accessibleMenu = computed(() => {
if (accessibleElementTags) {
const menuData = [];
// 循环menu可以访问页面才放入新对象中
for (let i = 0; i < menu.length; i++) {
const item = menu[i];
if (item.path && (!item.subMenu || item.subMenu.length === 0)) {
if (accessibleValidator(item.path)) {
menuData.push(item);
}
} else if (item.subMenu && item.subMenu.length > 0) {
const subMenu = [];
for (let j = 0; j < item.subMenu.length; j++) {
const subItem = item.subMenu[j];
if ((subItem.path && accessibleValidator(subItem.path)) || !subItem.path) {
subMenu.push(subItem);
}
}
if (subMenu.length > 0) {
menuData.push({
...item,
subMenu
});
}
} else {
menuData.push(item);
}
}
return menuData;
}
return menu;
});
const localeMenu = computed(() => {
if (useI18n) {
const { t } = useI18n();
// 给菜单title搞国际化
return accessibleMenu.map((element) => {
const copyElement = { ...element };
copyElement.title = t(element.title);
// 子菜单
if (copyElement.subMenu) {
copyElement.subMenu = element.subMenu.map((son) => {
const copySon = { ...son };
copySon.title = t(son.title);
return copySon;
});
}
return copyElement;
});
}
return accessibleMenu;
});
return localeMenu;
}
export default defineComponent((props) => {
const clickLogo = () => props.clickLogo && props.clickLogo;
const menuTheme = computed(() => DEFAULT_THEME[props.theme] || DEFAULT_THEME.light);
const menu = useMenu(props.menu);
return () => (
<div class="layout-left-body">
<div class={['layout-left-logo', 'has-logo-event' && props.clickLogo]} onClick={clickLogo}>
<img src="~assets/images/logo.png" />
<p>{props.projectName}</p>
</div>
<div class="layout-left-menu">
<RouteMenu menu={menu} type={menuTheme} mode={props.menuMode} auto-close={true} />
</div>
<RightRender rightRender={props.rightRender} layout={props.layout} />
</div>
);
});

View File

@ -1,12 +0,0 @@
import { defineComponent } from 'vue';
import { noop } from '../../helpers';
export default defineComponent(props => () => {
if (props.rightRender) return props.rightRender;
return (<div class="layout-left-user">
<div class="layout-left-user-logout">
<Icon onClick={props.logout || noop} type="md-log-out" size="28" />
</div>
</div>);
});

View File

@ -1,43 +0,0 @@
<template>
<route-menu
:menu="props.menu"
:width="props.width"
:type="props.type"
:mode="props.mode"
:auto-close="props.autoClose"
/>
</template>
<script>
export default {
props: {
mode: {
type: String,
default: 'vertical' //
},
width: {
type: [String, Number],
default: undefined
},
menu: {
type: Array,
default() {
return [];
}
},
type: {
type: String,
default: 'light'
},
autoClose: {
type: Boolean,
default: false
}
},
setup(props) {
return {
props
};
}
};
</script>

View File

@ -1,73 +0,0 @@
import {
defineComponent,
computed,
readonly,
ref
} from 'vue';
import LayoutNav from './LayoutNav';
export default function generateLayout(config) {
return defineComponent(() => {
const menu = readonly(config.menu);
const themeRef = ref(config.theme);
const modeRef = ref(config.mode || 'vertical');
const animateRef = ref(false);
const leftHiddenRef = ref(false);
const headerRef = ref(false);
const rootCls = computed(() => {
const arr = [
'layout',
`layout-mode-${modeRef.value}`,
`layout-theme-${themeRef.value}`
];
if (leftHiddenRef.value) {
arr.push('layout-left-hidden');
}
if (!headerRef.value) {
arr.push('layout-header-hide');
}
if (animateRef.value) {
arr.push('layout-animate');
}
return arr;
});
function toggleMenu() {
animateRef.value = true;
setTimeout(() => {
animateRef.value = false;
}, 300);
leftHiddenRef.value = !leftHiddenRef.value;
}
return () => (
<div class={rootCls}>
<div class="layout-left">
<LayoutNav
menuMode={modeRef.value}
menu={menu}
theme={themeRef.value}
/>
{
modeRef.value === 'vertical' && (<span onClick={toggleMenu} class="layout-left-fold-menu">
<span>
<Icon type={`ios-arrow-${leftHiddenRef.value ? 'forward' : 'back'}`} />
<Icon type={`ios-arrow-${leftHiddenRef.value ? 'forward' : 'back'}`} />
</span>
</span>)
}
</div>
<div class="layout-right">
{
headerRef.value && (<div class="layout-right-header">
<fes-header />
</div>)
}
<div class="layout-right-body">
<router-view />
</div>
</div>
</div >
);
});
}

View File

@ -1,2 +0,0 @@
@import "layout.scss";
@import "polyfill.scss";

View File

@ -1,424 +0,0 @@
$white-bg: #ffffff;
$white-border: #d7dde4;
$white-selected: #f3f3f3;
$blue-bg: #128bd6;
$blue-selected: #077cc5;
$blue-color: #ffffff;
$dark-bg: rgb(0, 21, 41);
$dark-bg-light: rgb(0, 33, 64);
$dark-bg-dark: rgb(0, 12, 23);
$dark-color: rgba(255, 255, 255, 0.65);
$dark-selected-bg: rgb(24, 144, 255);
$dark-selected-color: #ffffff;
.layout {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
background-color: $white-bg;
&.layout-left-hide {
left: -200px;
}
&.layout-animate{
transition: left 0.3s;
}
&.layout-left-hidden{
left: -200px;
.layout-left-fold-menu {
border-left: none;
border-radius: 0px 4px 4px 0px;
right: -16px;
display: block;
}
}
&.layout-header-hide {
.layout-right-body {
top: 0;
}
}
&.layout-theme-blue {
.layout-left {
color: $blue-color;
}
.layout-left-body {
background: $blue-bg;
}
.layout-left-fold-menu {
border-color: $blue-selected;
background-color: $blue-selected;
}
.layout-left-logo {
background: $blue-bg;
&.hasLogoEvent:hover {
background-color: $blue-selected;
cursor: pointer;
}
}
.layout-left-user-logout {
background-color: $blue-selected;
}
}
&.layout-theme-dark {
.layout-left {
color: $dark-color;
}
.layout-left-body {
background: $dark-bg;
}
.layout-left-fold-menu {
color: $dark-selected-color;
border-color: $blue-selected;
background-color: $blue-selected;
}
.layout-left-logo {
background: $dark-bg;
color: $dark-selected-color;
&.hasLogoEvent:hover {
background: $dark-bg;
cursor: pointer;
}
}
.layout-left-user-logout {
background: $dark-bg-dark;
}
.ui-menu.ui-menu-type-dark {
background: $dark-bg;
.ui-menu-arrow {
color: $dark-color;
}
.ui-menu-submenu-title,
.ui-menu-item {
color: $dark-color;
&:hover {
color: $dark-selected-color;
background: $dark-bg;
.ui-menu-arrow {
color: $dark-selected-color;
}
}
&.ui-menu-item-actived {
color: $dark-selected-color;
background: $dark-selected-bg;
&:hover {
background: $dark-selected-bg;
}
}
}
.ui-menu-submenu-ul {
background: $dark-bg-dark;
.ui-menu-item {
color: $dark-color;
&:hover {
color: $dark-selected-color;
background: $dark-bg-dark;
}
&.ui-menu-item-actived {
color: $dark-selected-color;
background: $dark-selected-bg;
&:hover {
background: $dark-selected-bg;
}
}
}
}
.ui-menu-submenu {
&.ui-menu-submenu-actived,
&.ui-menu-submenu-choosed {
.ui-menu-submenu-title {
color: $dark-selected-color;
}
.ui-menu-arrow {
color: $dark-selected-color;
}
}
}
}
}
&.layout-mode-vertical {
&.layout-theme-blue {
.layout-left {
box-shadow: rgba(0, 21, 41, 0.35) 2px 0px 6px;
}
// 修改蓝色的
.ui-menu-mode-vertical.ui-menu-type-dark {
.ui-menu-submenu {
&:hover {
background: $blue-selected;
}
.ui-menu-item {
color: #8dcff8;
&:hover {
color: $blue-color;
}
&.ui-menu-item-actived {
color: $blue-color;
background: transparent;
}
}
&.ui-menu-submenu-choosed{
background: $blue-selected;
}
&.ui-menu-submenu-actived{
background: $blue-selected;
}
}
}
}
&.layout-theme-dark {
.layout-left {
box-shadow: rgba(0, 21, 41, 0.35) 2px 0px 6px;
}
}
}
&.layout-mode-horizontal {
.layout-left {
left: 0;
top: 0;
width: 100%;
min-width: 1240px;
height: 60px;
}
.layout-right {
top: 60px;
bottom: 0;
left: 0;
right: 0;
}
.layout-left-body {
flex-direction: row;
}
.layout-left-menu {
margin-bottom: 0;
margin-left: 40px;
margin-right: 40px;
}
.layout-left-logo {
width: 200px;
height: 100%;
padding: 6px 0;
img {
height: 24px;
width: auto;
}
}
.layout-left-menu {
overflow: inherit;
}
.layout-left-user {
display: flex;
flex-direction: row;
width: 240px;
.layout-left-user-name {
flex: 2;
}
.layout-left-user-logout {
flex: 1;
height: 60px;
line-height: 60px;
background: $blue-bg;
border-left: 1px solid $blue-selected;
}
}
&.layout-theme-blue {
.layout-left {
box-shadow: rgba(0, 21, 41, 0.35) 0 2px 6px;
}
.ui-menu.ui-menu-type-dark {
.ui-menu-submenu {
&.ui-menu-submenu-actived {
.ui-menu-submenu-title {
background: $blue-selected;
}
}
}
}
}
&.layout-theme-dark {
.layout-left {
box-shadow: rgba(0, 21, 41, 0.35) 0 2px 6px;
}
.layout-left-user {
.layout-left-user-logout {
background: $dark-bg;
border-left-color: rgba(255, 255, 255, 0.3);
}
}
.ui-menu.ui-menu-type-dark {
.ui-menu-submenu {
&.ui-menu-submenu-actived {
.ui-menu-submenu-title {
color: $dark-selected-color;
background: $dark-bg;
}
}
&.ui-menu-submenu-choosed {
.ui-menu-submenu-title {
background: $dark-selected-bg;
}
}
}
.ui-menu-submenu-ul {
background: $dark-selected-color;
.ui-menu-item {
color: #657180;
&:hover {
color: $dark-selected-color;
background: $dark-selected-bg;
}
&.ui-menu-item-actived {
color: $dark-selected-color;
&:hover {
color: $dark-selected-color;
background: $dark-selected-bg;
}
}
}
.ui-menu-group-title {
color: #999;
}
}
}
}
}
}
.layout-left {
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 100%;
font-size: 14px;
&:hover {
.layout-left-fold-menu {
display: block;
}
}
/* 设置滚动条的样式 */
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
/* 滚动槽 */
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
border-radius: 10px;
}
/* 滚动条滑块 */
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: rgba(0, 0, 0, 0.1);
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.5);
}
::-webkit-scrollbar-thumb:window-inactive {
background: rgba(0, 0, 0, 0.1);
}
}
.layout-left-fold-menu {
display: none;
position: absolute;
top: 80px;
right: 0;
overflow: hidden;
width: 16px;
height: 36px;
line-height: 36px;
border: 1px solid;
border-radius: 4px 0 0 4px;
z-index: 2;
font-size: 14px;
text-align: center;
cursor: pointer;
}
.layout-left-body {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.layout-left-menu {
display: flex;
flex: 1;
overflow: auto;
margin-bottom: 24px;
}
.layout-left-logo {
padding: 50px 20px 40px;
text-align: center;
img {
width: auto;
max-height: 30px;
}
p {
font-size: 16px;
}
&.hasLogoEvent:hover {
cursor: pointer;
}
}
.layout-left-user-name {
padding: 0 20px;
p {
margin: 10px 0;
line-height: 15px;
}
}
.layout-left-user-logout {
height: 70px;
line-height: 70px;
text-align: center;
.ui-icon {
cursor: pointer;
vertical-align: middle;
}
}
.layout-right {
position: absolute;
left: 200px;
right: 0;
top: 0;
bottom: 0;
min-width: 1240px;
}
.layout-right-header {
width: 100%;
min-width: 1240px;
height: 60px;
line-height: 60px;
position: relative;
}
.layout-right-body {
position: absolute;
left: 0;
right: 0;
top: 60px;
bottom: 0;
overflow-y: auto;
}

View File

@ -1,19 +0,0 @@
@media all and (min-width: 0\0) and (min-resolution: 0.001dpcm) {
.layout-left-menu {
padding-bottom: 24px;
margin-bottom: 0px;
position: absolute;
width: 200px;
top: 143px;
bottom: 130px;
}
.layout-left-user {
position: fixed;
width: 200px;
bottom: 0px;
left: 0px;
}
}
input[type=text]::-ms-clear {
display: none;
}

View File

@ -56,7 +56,7 @@ export default (api) => {
});
});
api.addExports(() => [
api.addPluginExports(() => [
{
exportAll: true,
source: absoluteFilePath

View File

@ -1,15 +1,4 @@
export {
useRoute,
useRouter,
onBeforeRouteUpdate,
onBeforeRouteLeave,
RouterLink,
useLink,
createWebHashHistory,
createRouter,
Plugin,
ApplyPluginsType
} from '@webank/fes-runtime';
export * from '@@/core/coreExports';
// @ts-ignore
export * from '@@/core/exports';
export * from '@@/core/pluginExports';