refactor: beforeRender迁移到router创建后

This commit is contained in:
wanchun 2023-01-10 17:35:50 +08:00
parent 773082f8e1
commit cc20923e07
20 changed files with 87 additions and 272 deletions

View File

@ -1,12 +1,15 @@
import { winPath } from '@fesjs/utils';
import { readdirSync, statSync } from 'fs';
import { readdirSync, statSync, existsSync } from 'fs';
import { join } from 'path';
import { winPath } from '@fesjs/utils';
/**
* 获取文件夹所有JS文件路径
* @param {string} dir
*/
function getDirFilePaths(dir) {
if (!existsSync(dir)) {
return [];
}
const dirs = readdirSync(dir);
let pathList = [];
for (const name of dirs) {
@ -26,13 +29,13 @@ function getDirFilePaths(dir) {
* @param {*} path
*/
function pathToHump(path, root) {
return path.replace(root, '')
return path
.replace(root, '')
.replace('.js', '')
.replace(RegExp('(/|\\.|-|_)\\S', 'g'), text => text[1].toUpperCase())
.replace(/\S/, text => text.toLowerCase());
.replace(RegExp('(/|\\.|-|_)\\S', 'g'), (text) => text[1].toUpperCase())
.replace(/\S/, (text) => text.toLowerCase());
}
function parsePlugin(paths = [], root) {
const plugins = [];
const importPlugins = [];
@ -53,6 +56,6 @@ export function parseStore(root) {
}
});
return {
...parsePlugin(pluginPaths, root)
...parsePlugin(pluginPaths, root),
};
}

View File

@ -1,8 +1,8 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { winPath } from '@fesjs/utils';
import { parseStore } from './helper';
import { name } from '../package.json';
import { parseStore } from './helper';
const namespace = 'plugin-pinia';

View File

@ -16,8 +16,6 @@ export default function (api) {
key: 'addRuntimePluginKey',
type: api.ApplyPluginsType.add,
initialValue: [
// 初始化数据
'beforeRender',
// modify渲染工具
'modifyClientRenderOpts',
'rootContainer',
@ -31,6 +29,8 @@ export default function (api) {
'modifyCreateHistory',
// 修改路由配置
'modifyRoute',
// 初始化数据
'beforeRender',
// 生成router时触发
'onRouterCreated',
],

View File

@ -1,13 +1,11 @@
{{{ importsAhead }}}
import {
createApp,
reactive,
} from 'vue';
import { plugin } from './core/plugin';
import './core/pluginRegister';
import { ApplyPluginsType } from '{{{ runtimePath }}}';
import { getRoutes } from './core/routes/routes';
import { updateInitialState } from './initialState';
import DefaultContainer from './defaultContainer.jsx';
{{{ imports }}}
@ -40,34 +38,10 @@ const renderClient = (opts = {}) => {
return app;
}
const beforeRender = async ({rootElement}) => {
const beforeRenderConfig = plugin.applyPlugins({
key: "beforeRender",
type: ApplyPluginsType.modify,
initialValue: {
loading: null,
action: null
},
});
if (typeof beforeRenderConfig.action === "function") {
const app = createApp(beforeRenderConfig.loading);
app.mount(rootElement);
try {
const initialState = await beforeRenderConfig.action();
updateInitialState(initialState || {})
} catch(e){
console.error(`[fes] beforeRender执行出现异常`);
console.error(e);
}
app.unmount();
app._container.innerHTML = '';
}
};
const getClientRender = (args = {}) => plugin.applyPlugins({
key: 'render',
type: ApplyPluginsType.compose,
initialValue: async () => {
initialValue: () => {
const opts = plugin.applyPlugins({
key: 'modifyClientRenderOpts',
type: ApplyPluginsType.modify,
@ -80,7 +54,6 @@ const getClientRender = (args = {}) => plugin.applyPlugins({
{{/enableTitle}}
},
});
await beforeRender(opts);
return renderClient(opts);
},
args,

View File

@ -1,5 +1,7 @@
import { createApp } from 'vue';
import { createRouter as createVueRouter, {{{ CREATE_HISTORY }}}, ApplyPluginsType } from '{{{ runtimePath }}}';
import { plugin } from '../plugin';
import { updateInitialState } from '../../initialState';
const ROUTER_BASE = '{{{ routerBase }}}';
let router = null;
@ -28,12 +30,45 @@ export const createRouter = (routes) => {
createHistory: createHistory
},
});
history = route['createHistory']?.(route.base);
router = createVueRouter({
history,
routes: route.routes
});
let isInit = false
router.beforeEach(async (to, from, next) => {
if(!isInit) {
isInit = true
const beforeRenderConfig = plugin.applyPlugins({
key: "beforeRender",
type: ApplyPluginsType.modify,
initialValue: {
loading: null,
action: null
},
});
if (typeof beforeRenderConfig.action === "function") {
const rootElement = document.createElement('div');
document.body.appendChild(rootElement)
const app = createApp(beforeRenderConfig.loading);
app.mount(rootElement);
try {
const initialState = await beforeRenderConfig.action({router, history});
updateInitialState(initialState || {})
} catch(e){
console.error(`[fes] beforeRender执行出现异常`);
console.error(e);
}
app.unmount();
app._container.innerHTML = '';
document.body.removeChild(rootElement);
}
}
next();
})
plugin.applyPlugins({
key: 'onRouterCreated',
type: ApplyPluginsType.event,

View File

@ -20,7 +20,7 @@ function isPromiseLike(obj) {
export const ApplyPluginsType = {
compose: 'compose',
event: 'event',
modify: 'modify'
modify: 'modify',
};
export default class Plugin {
@ -44,10 +44,7 @@ export default class Plugin {
assert(!!plugin.apply, 'register failed, plugin.apply must supplied');
assert(!!plugin.path, 'register failed, plugin.path must supplied');
Object.keys(plugin.apply).forEach((key) => {
assert(
this.validKeys.indexOf(key) > -1,
`register failed, invalid key ${key} from plugin ${plugin.path}.`
);
assert(this.validKeys.indexOf(key) > -1, `register failed, invalid key ${key} from plugin ${plugin.path}.`);
if (!this.hooks[key]) this.hooks[key] = [];
this.hooks[key] = this.hooks[key].concat(plugin.apply[key]);
});
@ -74,20 +71,11 @@ export default class Plugin {
return hooks;
}
applyPlugins({
key,
type,
initialValue,
args,
async
}) {
applyPlugins({ key, type, initialValue, args, async }) {
const hooks = this.getHooks(key) || [];
if (args) {
assert(
typeof args === 'object',
'applyPlugins failed, args must be plain object.'
);
assert(typeof args === 'object', 'applyPlugins failed, args must be plain object.');
}
switch (type) {
@ -95,8 +83,10 @@ export default class Plugin {
if (async) {
return hooks.reduce(
async (memo, hook) => {
assert(typeof hook === 'function' || typeof hook === 'object' || isPromiseLike(hook),
`applyPlugins failed, all hooks for key ${key} must be function, plain object or Promise.`);
assert(
typeof hook === 'function' || typeof hook === 'object' || isPromiseLike(hook),
`applyPlugins failed, all hooks for key ${key} must be function, plain object or Promise.`,
);
if (isPromiseLike(memo)) {
memo = await memo;
}
@ -112,15 +102,13 @@ export default class Plugin {
}
return { ...memo, ...hook };
},
isPromiseLike(initialValue)
? initialValue
: Promise.resolve(initialValue)
isPromiseLike(initialValue) ? initialValue : Promise.resolve(initialValue),
);
}
return hooks.reduce((memo, hook) => {
assert(
typeof hook === 'function' || typeof hook === 'object',
`applyPlugins failed, all hooks for key ${key} must be function or plain object.`
`applyPlugins failed, all hooks for key ${key} must be function or plain object.`,
);
if (typeof hook === 'function') {
return hook(memo, args);
@ -128,21 +116,18 @@ export default class Plugin {
return { ...memo, ...hook };
}, initialValue);
case ApplyPluginsType.event:
return hooks.forEach((hook) => {
assert(
typeof hook === 'function',
`applyPlugins failed, all hooks for key ${key} must be function.`
);
assert(typeof hook === 'function', `applyPlugins failed, all hooks for key ${key} must be function.`);
hook(args);
});
case ApplyPluginsType.compose:
return () => _compose({
fns: hooks.concat(initialValue),
args
})();
return () =>
_compose({
fns: hooks.concat(initialValue),
args,
})();
default:
return null;
}

View File

@ -36,9 +36,6 @@ export default defineBuildConfig({
icon: '/wine-outline.svg',
match: ['/route/*'],
},
{
name: 'store',
},
{
name: 'editor',
icon: '/wine-outline.svg',
@ -74,9 +71,6 @@ export default defineBuildConfig({
['1', '有效的'],
],
},
vuex: {
strict: true,
},
dynamicImport: true,
monacoEditor: {
languages: ['javascript', 'typescript', 'html', 'json'],

View File

@ -58,7 +58,6 @@
"@fesjs/plugin-pinia": "^3.0.0-rc.0",
"@fesjs/plugin-request": "^3.0.0-rc.0",
"@fesjs/plugin-sass": "^3.0.0-rc.0",
"@fesjs/plugin-vuex": "^3.0.0-rc.0",
"@fesjs/plugin-windicss": "^3.0.0-rc.0",
"core-js": "^3.27.0",
"cssnano": "^5.1.12",

View File

@ -1,4 +1,4 @@
import { access as accessApi, pinia } from '@fesjs/fes';
import { access as accessApi } from '@fesjs/fes';
import PageLoading from '@/components/pageLoading.vue';
import UserCenter from '@/components/userCenter.vue';
import { useStore } from '@/store/main';
@ -9,7 +9,7 @@ export const beforeRender = {
const { setRole } = accessApi;
return new Promise((resolve) => {
setTimeout(() => {
const store = useStore(pinia);
const store = useStore();
store.$patch({
userName: '李雷',
});

View File

@ -1,5 +1,5 @@
<template>
<div>{{store.counter}}</div>
<div>{{ store.counter }} {{ store.userName }}</div>
<FButton class="m-2" @click="store.increment">Button</FButton>
</template>
<config>
@ -9,23 +9,21 @@
}
</config>
<script>
import { useStore } from '@/store/main';
import { FButton } from '@fesjs/fes-design';
import { useStore } from '@/store/main';
export default {
components: {
FButton
FButton,
},
setup() {
const store = useStore();
console.log(store);
return {
store
store,
};
}
},
};
</script>
<style>
</style>
<style></style>

View File

@ -1,60 +0,0 @@
<template>
<div class="page">
<h4>Vuex</h4>
<div>
<button @click="increment">click me{{doubleCount}}</button>
</div>
<div>
<button :disabled="disabled" @click="login">async login</button>
</div>
<div>
<button @click="fooBarIncrement">
foo/bar{{fooBarDoubleCount}}
</button>
</div>
<div>{{address}}</div>
</div>
</template>
<config>
{
"name": "store",
"title": "$store"
}
</config>
<script>
import { computed, ref } from 'vue';
import { useStore } from 'vuex';
import { MUTATION_TYPES, GETTER_TYPES, ACTION_TYPES } from '@fesjs/fes';
export default {
setup() {
const store = useStore();
console.log('store==>', store);
const disabled = ref(false);
return {
address: computed(() => store.getters[GETTER_TYPES.user.address]),
doubleCount: computed(
() => store.getters[GETTER_TYPES.counter.doubleCount]
),
disabled,
increment: () => store.commit(MUTATION_TYPES.counter.increment),
login: () => {
disabled.value = true;
store.dispatch(ACTION_TYPES.user.login).then((res) => {
// eslint-disable-next-line no-alert
window.alert(res);
disabled.value = false;
});
},
fooBarIncrement: () => store.commit(MUTATION_TYPES.fooBar.increment),
fooBarDoubleCount: computed(
() => store.getters[GETTER_TYPES.fooBar.doubleCount]
)
};
}
};
</script>
<style scoped>
.page {
}
</style>

View File

@ -7,8 +7,8 @@ export const useStore = defineStore('main', {
state: () => ({
// all these properties will have their type inferred automatically
counter: 0,
name: 'Eduardo',
isAdmin: true
userName: 'Eduardo',
isAdmin: true,
}),
actions: {
increment() {
@ -16,6 +16,6 @@ export const useStore = defineStore('main', {
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random());
}
}
},
},
});

View File

@ -1,23 +0,0 @@
export default {
namespaced: true,
state: () => ({
count: 0
}),
mutations: {
increment(state) {
state.count++;
}
},
getters: {
doubleCount(state) {
return state.count * 2;
}
},
actions: {
asyncIncrement({ commit }) {
setTimeout(() => {
commit('increment');
}, 2000);
}
}
};

View File

@ -1,23 +0,0 @@
export default {
namespaced: true,
state: () => ({
count: 0
}),
mutations: {
increment(state) {
state.count++;
}
},
getters: {
doubleCount(state) {
return state.count * 2;
}
},
actions: {
asyncIncrement({ commit }) {
setTimeout(() => {
commit('increment');
}, 2000);
}
}
};

View File

@ -1,3 +0,0 @@
import { createLogger } from 'vuex';
export default createLogger();

View File

@ -1,54 +0,0 @@
export default {
namespaced: true,
state: () => ({
name: 'aring',
age: 20,
count: 0
}),
mutations: {
increment(state) {
state.count++;
}
},
getters: {
doubleCount(state) {
return state.count * 2;
}
},
actions: {
asyncIncrement({ commit }) {
setTimeout(() => {
commit('increment');
}, 2000);
},
login() {
return new Promise((reslove) => {
setTimeout(() => {
console.log('login');
reslove('OK');
}, 1000);
});
}
},
modules: {
address: {
state: () => ({
province: '广东省',
city: '深圳市',
zone: '南山区'
}),
getters: {
address(state) {
return state.province + state.city + state.zone;
}
}
},
posts: {
namespaced: true,
state: () => ({}),
mutations: {
doSomething() {}
}
}
}
};

View File

@ -84,9 +84,6 @@ export default defineBuildConfig({
['1', '有效的'],
],
},
vuex: {
strict: true,
},
dynamicImport: true,
monacoEditor: {
languages: ['javascript', 'typescript', 'html', 'json'],

View File

@ -57,7 +57,6 @@
"@fesjs/plugin-sass": "^3.0.0-rc.0",
"@fesjs/plugin-monaco-editor": "^3.0.0-rc.0",
"@fesjs/plugin-windicss": "^3.0.0-rc.0",
"@fesjs/plugin-pinia": "^3.0.0-rc.0",
"@fesjs/plugin-watermark": "^3.0.0-rc.0",
"@fesjs/fes-design": "^0.7.0",
"core-js": "^3.27.0",

View File

@ -1,8 +1,7 @@
import { access as accessApi, pinia, createWatermark } from '@fesjs/fes';
import { access as accessApi, createWatermark } from '@fesjs/fes';
import { ref, watch } from 'vue';
import PageLoading from '@/components/pageLoading.vue';
import UserCenter from '@/components/userCenter.vue';
import { useStore } from '@/store/main';
export const beforeRender = {
loading: <PageLoading />,
@ -10,11 +9,7 @@ export const beforeRender = {
const { setRole } = accessApi;
return new Promise((resolve) => {
setTimeout(() => {
const store = useStore(pinia);
store.$patch({
userName: '李雷',
});
setRole('menuTest');
setRole('admin');
resolve({
userName: '李雷',
});
@ -24,11 +19,11 @@ export const beforeRender = {
},
};
export const login = {
hasLogin() {
return !!sessionStorage.getItem('login');
},
};
// export const login = {
// hasLogin() {
// return !!sessionStorage.getItem('login');
// },
// };
export const layout = (layoutConfig, { initialState }) => ({
...layoutConfig,

View File

@ -8,7 +8,7 @@ export const useStore = defineStore('main', {
// all these properties will have their type inferred automatically
counter: 0,
name: 'Eduardo',
isAdmin: true
isAdmin: true,
}),
actions: {
increment() {
@ -16,6 +16,6 @@ export const useStore = defineStore('main', {
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random());
}
}
},
},
});