diff --git a/.fatherrc.js b/.fatherrc.js index f16ce608..365d43bd 100644 --- a/.fatherrc.js +++ b/.fatherrc.js @@ -3,7 +3,8 @@ import { join } from 'path'; // utils must build before core // runtime must build before renderer-react -const headPkgs = ['fes-runtime', 'fes-core', 'fes', 'fes-plugin-built-in', 'fes-plugin-request']; + +const headPkgs = ['fes-runtime', 'fes-core', 'fes', 'fes-plugin-built-in', 'fes-plugin-request', 'fes-plugin-access']; const tailPkgs = []; // const otherPkgs = readdirSync(join(__dirname, 'packages')).filter( // (pkg) => @@ -14,7 +15,7 @@ const otherPkgs = []; export default { target: 'node', - cjs: { type: 'babel', lazy: true }, + cjs: { type: 'babel', lazy: false }, disableTypeCheck: true, pkgs: [...headPkgs, ...otherPkgs, ...tailPkgs], }; diff --git a/packages/fes-plugin-access/.fatherrc.js b/packages/fes-plugin-access/.fatherrc.js new file mode 100644 index 00000000..332f1bff --- /dev/null +++ b/packages/fes-plugin-access/.fatherrc.js @@ -0,0 +1,3 @@ +export default { + disableTypeCheck: false, +}; diff --git a/packages/fes-plugin-access/package.json b/packages/fes-plugin-access/package.json index 7b4f184b..d32f0c9c 100644 --- a/packages/fes-plugin-access/package.json +++ b/packages/fes-plugin-access/package.json @@ -2,11 +2,18 @@ "name": "@webank/fes-plugin-access", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "lib/index.js", + "files": [ + "lib" + ], + "module": "dist/index.esm.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", - "license": "MIT" + "license": "MIT", + "peerDependencies": { + "@webank/fes": "^2.0.0" + } } diff --git a/packages/fes-plugin-access/index.js b/packages/fes-plugin-access/src/index.js similarity index 72% rename from packages/fes-plugin-access/index.js rename to packages/fes-plugin-access/src/index.js index ff25eeed..c6eb5d29 100644 --- a/packages/fes-plugin-access/index.js +++ b/packages/fes-plugin-access/src/index.js @@ -76,3 +76,45 @@ // } // } // }); +import { readFileSync } from 'fs'; +import { join } from 'path'; + +const namespace = 'plugin-access'; + +export default (api) => { + const { + utils: { Mustache } + } = api; + + api.addRuntimePluginKey(() => 'access'); + + const absoluteFilePath = join(namespace, 'core.js'); + + const absRuntimeFilePath = join(namespace, 'runtime.js'); + + api.onGenerateFiles(() => { + // 文件写出 + const { roles = {} } = api.config.access || {}; + + api.writeTmpFile({ + path: absoluteFilePath, + content: Mustache.render(readFileSync(join(__dirname, 'template/core.tpl'), 'utf-8'), { + REPLACE_ROLES: JSON.stringify(roles) + }) + }); + + api.writeTmpFile({ + path: absRuntimeFilePath, + content: readFileSync(join(__dirname, 'template/runtime.tpl'), 'utf-8') + }); + }); + + // api.addExports(() => [ + // { + // exportAll: true, + // source: absoluteFilePath + // } + // ]); + + api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`); +}; diff --git a/packages/fes-plugin-access/src/runtime.js b/packages/fes-plugin-access/src/runtime.js new file mode 100644 index 00000000..dba2aa7e --- /dev/null +++ b/packages/fes-plugin-access/src/runtime.js @@ -0,0 +1,18 @@ +import { hasAccess } from './core'; + +export function onRouterCreated({ router }) { + router.beforeEach(async (to, from, next) => { + let path; + if (to.matched.length === 1) { + path = to.matched[0].path; + } else { + path = to.path; + } + const canRoute = await hasAccess(path); + if (canRoute) { + next(); + } else { + next(false); + } + }); +} diff --git a/packages/fes-plugin-access/src/template/core.tpl b/packages/fes-plugin-access/src/template/core.tpl new file mode 100644 index 00000000..723a63aa --- /dev/null +++ b/packages/fes-plugin-access/src/template/core.tpl @@ -0,0 +1,48 @@ +const roles = {{{REPLACE_ROLES}}}; + +let allowPageIds = []; + +const get = () => Promise.all(allowPageIds).then(data => data.reduce((merge, cur) => merge.concat(cur), [])); + +export const setPageIds = (pageIds) => { + if (Array.isArray(pageIds)) { + allowPageIds = pageIds.map(id => Promise.resolve(id)); + } else { + allowPageIds = [Promise.resolve(pageIds)]; + } +}; + +export const setRoleId = async (roleId) => { + console.log('setRole'); + const _roleId = await Promise.resolve(roleId); + if (typeof _roleId !== 'string') { + throw new Error( + '[plugin-access]: roleId必须是string或者Promise的结果必须是string', + ); + } + setPageIds(roles[_roleId]); +}; + +export const hasAccess = async (path) => { + const allowPage = await get(); + if (!Array.isArray(allowPage) || allowPage.length === 0) { + return false; + } + path = path.split('?')[0]; + // 进入"/"路由时,此时path为“” + if (path === '') { + path = '/'; + } + const len = allowPage.length; + for (let i = 0; i < len; i++) { + if (path === allowPage[i]) { + return true; + } + // 支持*匹配 + const reg = new RegExp(`^${allowPage[i].replace('*', '.+')}$`); + if (reg.test(path)) { + return true; + } + } + return false; +}; \ No newline at end of file diff --git a/packages/fes-plugin-access/src/template/runtime.tpl b/packages/fes-plugin-access/src/template/runtime.tpl new file mode 100644 index 00000000..dba2aa7e --- /dev/null +++ b/packages/fes-plugin-access/src/template/runtime.tpl @@ -0,0 +1,18 @@ +import { hasAccess } from './core'; + +export function onRouterCreated({ router }) { + router.beforeEach(async (to, from, next) => { + let path; + if (to.matched.length === 1) { + path = to.matched[0].path; + } else { + path = to.path; + } + const canRoute = await hasAccess(path); + if (canRoute) { + next(); + } else { + next(false); + } + }); +} diff --git a/packages/fes-plugin-built-in/src/plugins/generateFiles/core/plugin/index.js b/packages/fes-plugin-built-in/src/plugins/generateFiles/core/plugin/index.js index c00179d5..85a0148b 100644 --- a/packages/fes-plugin-built-in/src/plugins/generateFiles/core/plugin/index.js +++ b/packages/fes-plugin-built-in/src/plugins/generateFiles/core/plugin/index.js @@ -18,7 +18,12 @@ export default function (api) { initialValue: [ 'modifyClientRenderOpts', 'rootContainer', - 'render' + // 渲染 + 'render', + // 修改路由 + 'patchRoutes', + // 生成router时触发 + 'onRouterCreated' ] }); const plugins = await api.applyPlugins({ diff --git a/packages/fes-plugin-built-in/src/plugins/generateFiles/core/routes/index.js b/packages/fes-plugin-built-in/src/plugins/generateFiles/core/routes/index.js index 3aff2e95..64515db1 100644 --- a/packages/fes-plugin-built-in/src/plugins/generateFiles/core/routes/index.js +++ b/packages/fes-plugin-built-in/src/plugins/generateFiles/core/routes/index.js @@ -21,9 +21,4 @@ export default function (api) { }) }); }); - - api.addExports(() => ({ - specifiers: ['router'], - source: absoluteFilePath - })); } diff --git a/packages/fes-plugin-built-in/src/plugins/generateFiles/core/routes/routes.tpl b/packages/fes-plugin-built-in/src/plugins/generateFiles/core/routes/routes.tpl index 6bb6df1c..cbf32ff7 100644 --- a/packages/fes-plugin-built-in/src/plugins/generateFiles/core/routes/routes.tpl +++ b/packages/fes-plugin-built-in/src/plugins/generateFiles/core/routes/routes.tpl @@ -1,8 +1,15 @@ -import { createRouter as createVueRouter, createWebHashHistory } from '{{{ runtimePath }}}'; +import { createRouter as createVueRouter, createWebHashHistory, ApplyPluginsType } from '{{{ runtimePath }}}'; +import { plugin } from './plugin'; export function getRoutes() { const routes = {{{ routes }}}; - // TODO 支持动态变更路由 + + plugin.applyPlugins({ + key: 'patchRoutes', + type: ApplyPluginsType.event, + args: { routes }, + }); + return routes; } @@ -16,7 +23,11 @@ export const createRouter = () => { routes: getRoutes() }); + plugin.applyPlugins({ + key: 'onRouterCreated', + type: ApplyPluginsType.event, + args: { router }, + }); + return router; }; - -export { router }; diff --git a/packages/fes-plugin-built-in/src/plugins/generateFiles/fes/fes.tpl b/packages/fes-plugin-built-in/src/plugins/generateFiles/fes/fes.tpl index 30282eff..9861d38f 100644 --- a/packages/fes-plugin-built-in/src/plugins/generateFiles/fes/fes.tpl +++ b/packages/fes-plugin-built-in/src/plugins/generateFiles/fes/fes.tpl @@ -13,13 +13,14 @@ import { createRouter, getRoutes } from './core/routes'; {{{ entryCodeAhead }}} const renderClient = (opts = {}) => { - const rootContainer = opts.plugin.applyPlugins({ + const { plugin, routes, rootElement } = opts; + const rootContainer = plugin.applyPlugins({ type: 'modify', key: 'rootContainer', initialValue: defineComponent(() => () => ()), args: { - routes: opts.routes, - plugin: opts.plugin + routes: routes, + plugin: plugin } }); @@ -28,8 +29,8 @@ const renderClient = (opts = {}) => { app.use(router); // TODO other plugins install - if (opts.rootElement) { - app.mount(opts.rootElement); + if (rootElement) { + app.mount(rootElement); } return app; } diff --git a/packages/fes-template/package.json b/packages/fes-template/package.json index 4da109cf..e6ccfee6 100644 --- a/packages/fes-template/package.json +++ b/packages/fes-template/package.json @@ -1,8 +1,7 @@ { "name": "@webank/fes-template", - "version": "0.2.1", + "version": "2.0.0", "description": "fes项目模版", - "main": "index.js", "scripts": { "build": "fes build", "dev": "fes dev" @@ -35,6 +34,7 @@ "dependencies": { "vue": "^3.0.2", "@webank/fes": "^2.0.0", - "@webank/fes-plugin-request": "^1.0.0" + "@webank/fes-plugin-request": "^1.0.0", + "@webank/fes-plugin-access": "^1.0.0" } } diff --git a/packages/fes/.fatherrc.js b/packages/fes/.fatherrc.js index e4b81547..e23e4242 100644 --- a/packages/fes/.fatherrc.js +++ b/packages/fes/.fatherrc.js @@ -2,5 +2,5 @@ export default { cjs: { type: 'babel', lazy: true }, esm: { type: 'rollup' }, disableTypeCheck: false, - extraExternals: ['@@/core/fesExports'], + extraExternals: ['@@/core/exports'], };