@umijs/plugins 4.0.0-rc.8 → 4.0.0-rc.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/access.js CHANGED
@@ -12,7 +12,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const path_1 = require("path");
13
13
  const withTmpPath_1 = require("./utils/withTmpPath");
14
14
  exports.default = (api) => {
15
- // TODO: route access
16
15
  api.describe({
17
16
  config: {
18
17
  schema(joi) {
@@ -52,10 +51,68 @@ export function accessProvider(container) {
52
51
  content: `
53
52
  import React from 'react';
54
53
  import { AccessContext } from './context';
54
+ import type { IRoute } from 'umi';
55
55
 
56
56
  export const useAccess = () => {
57
57
  return React.useContext(AccessContext);
58
58
  };
59
+
60
+ export interface AccessProps {
61
+ accessible: boolean;
62
+ fallback?: React.ReactNode;
63
+ }
64
+ export const Access: React.FC<AccessProps> = (props) => {
65
+ if (process.env.NODE_ENV === 'development' && typeof props.accessible !== 'boolean') {
66
+ throw new Error('[access] the \`accessible\` property on <Access /> should be a boolean');
67
+ }
68
+
69
+ return props.accessible ? props.children : props.fallback;
70
+ };
71
+
72
+ export const useAccessMarkedRoutes = (routes: IRoute[]) => {
73
+ const access = useAccess();
74
+ const markdedRoutes: IRoute[] = React.useMemo(() => {
75
+ const process = (route, parentAccessCode) => {
76
+ const accessCode = route.access || parentAccessCode;
77
+
78
+ // set default status
79
+ route.unaccessible = ${api.config.access.strictMode ? 'true' : 'false'};
80
+
81
+ // check access code
82
+ if (typeof accessCode === 'string') {
83
+ const detector = access[route.access];
84
+
85
+ if (typeof detector === 'function') {
86
+ route.unaccessible = !detector(route);
87
+ } else if (typeof detector === 'boolean') {
88
+ route.unaccessible = !detector;
89
+ } else if (typeof detector === 'undefined') {
90
+ route.unaccessible = true;
91
+ }
92
+ }
93
+
94
+ // check children access code
95
+ if (route.routes) {
96
+ const isNoAccessibleChild = !route.routes.reduce((hasAccessibleChild, child) => {
97
+ process(child, accessCode);
98
+
99
+ return hasAccessibleChild || !child.unaccessible;
100
+ }, false);
101
+
102
+ // make sure parent route is unaccessible if all children are unaccessible
103
+ if (isNoAccessibleChild) {
104
+ route.unaccessible = true;
105
+ }
106
+ }
107
+
108
+ return route;
109
+ }
110
+
111
+ return routes.map(route => process(route));
112
+ }, [routes.length]);
113
+
114
+ return markdedRoutes;
115
+ }
59
116
  `,
60
117
  });
61
118
  // context.ts
package/dist/antd.js CHANGED
@@ -61,6 +61,10 @@ exports.default = (api) => {
61
61
  }
62
62
  return memo;
63
63
  });
64
+ api.modifyConfig((memo) => {
65
+ memo.theme = Object.assign({ 'root-entry-name': 'default' }, memo.theme);
66
+ return memo;
67
+ });
64
68
  // babel-plugin-import
65
69
  api.addExtraBabelPlugins(() => {
66
70
  const style = api.config.antd.style || 'less';
package/dist/layout.js CHANGED
@@ -67,17 +67,23 @@ exports.default = (api) => {
67
67
  api.writeTmpFile({
68
68
  path: 'Layout.tsx',
69
69
  content: `
70
- import { Link, useLocation, useNavigate, Outlet, useAppData, useRouteContext } from 'umi';
70
+ import { Link, useLocation, useNavigate, Outlet, useAppData, useRouteData, matchRoutes } from 'umi';
71
+ import { useMemo } from 'react';
71
72
  import ProLayout, {
72
73
  PageLoading,
73
74
  } from '@ant-design/pro-layout';
74
75
  import './Layout.less';
75
76
  import Logo from './Logo';
77
+ import Exception from './Exception';
76
78
  import { getRightRenderContent } from './rightRender';
77
79
  ${hasInitialStatePlugin
78
80
  ? `import { useModel } from '@@/plugin-model';`
79
81
  : 'const useModel = null;'}
80
-
82
+ ${api.config.access
83
+ ? `
84
+ import { useAccessMarkedRoutes } from '@@/plugin-access';
85
+ `.trim()
86
+ : 'const useAccessMarkedRoutes = (r) => r;'}
81
87
  ${api.config.locale
82
88
  ? `
83
89
  import { useIntl } from '@@/plugin-locale';
@@ -85,7 +91,7 @@ import { useIntl } from '@@/plugin-locale';
85
91
  : ''}
86
92
 
87
93
 
88
- export default () => {
94
+ export default (props: any) => {
89
95
  const location = useLocation();
90
96
  const navigate = useNavigate();
91
97
  const { clientRoutes, pluginManager } = useAppData();
@@ -108,9 +114,8 @@ const { formatMessage } = useIntl();
108
114
  ...initialInfo
109
115
  },
110
116
  });
111
- const route = clientRoutes.filter(r => {
112
- return r.id === 'ant-design-pro-layout';
113
- })[0];
117
+ const matchedRoute = useMemo(() => matchRoutes(clientRoutes, location.pathname).pop()?.route, [location.pathname]);
118
+ const [route] = useAccessMarkedRoutes(clientRoutes.filter(({ id }) => id === 'ant-design-pro-layout'));
114
119
  return (
115
120
  <ProLayout
116
121
  route={route}
@@ -166,7 +171,16 @@ const { formatMessage } = useIntl();
166
171
  })
167
172
  }
168
173
  >
169
- <Outlet />
174
+ <Exception
175
+ route={matchedRoute}
176
+ notFound={runtimeConfig.notFound}
177
+ noAccessible={runtimeConfig.noAccessible}
178
+ >
179
+ {runtimeConfig.childrenRender
180
+ ? runtimeConfig.childrenRender(<Outlet />, props)
181
+ : <Outlet />
182
+ }
183
+ </Exception>
170
184
  </ProLayout>
171
185
  );
172
186
  }
@@ -468,6 +482,43 @@ const LogoIcon: React.FC = () => {
468
482
  export default LogoIcon;
469
483
  `,
470
484
  });
485
+ api.writeTmpFile({
486
+ path: 'Exception.tsx',
487
+ content: `
488
+ import React from 'react';
489
+ import { history, type IRoute } from 'umi';
490
+ import { Result, Button } from 'antd';
491
+
492
+ const Exception: React.FC<{
493
+ children: React.ReactNode;
494
+ route?: IRoute;
495
+ notFound?: React.ReactNode;
496
+ noAccessible?: React.ReactNode;
497
+ }> = (props) => (
498
+ // render custom 404
499
+ (!props.route && props.notFound) ||
500
+ // render custom 403
501
+ (props.route.unaccessible && props.noAccessible) ||
502
+ // render default exception
503
+ ((!props.route || props.route.unaccessible) && (
504
+ <Result
505
+ status={props.route ? '403' : '404'}
506
+ title={props.route ? '403' : '404'}
507
+ subTitle={props.route ? '抱歉,你无权访问该页面' : '抱歉,你访问的页面不存在'}
508
+ extra={
509
+ <Button type="primary" onClick={() => history.push('/')}>
510
+ 返回首页
511
+ </Button>
512
+ }
513
+ />
514
+ )) ||
515
+ // normal render
516
+ props.children
517
+ );
518
+
519
+ export default Exception;
520
+ `,
521
+ });
471
522
  });
472
523
  api.addLayouts(() => {
473
524
  return [
package/dist/locale.js CHANGED
@@ -19,7 +19,6 @@ const packageNormalize = (packageName) => packageName.replace(/[@\/\-.]/g, '_');
19
19
  exports.packageNormalize = packageNormalize;
20
20
  // TODO: runtime plugin
21
21
  exports.default = (api) => {
22
- var _a;
23
22
  // TODO: antd 的校验考虑 antd 插件
24
23
  let hasAntd = false;
25
24
  try {
@@ -52,30 +51,30 @@ exports.default = (api) => {
52
51
  });
53
52
  const reactIntlPkgPath = (0, plugin_utils_1.winPath)((0, path_1.dirname)(require.resolve('react-intl/package')));
54
53
  // polyfill
55
- if ((0, localeUtils_1.isNeedPolyfill)(((_a = api.userConfig) === null || _a === void 0 ? void 0 : _a.targets) || {})) {
56
- api.addEntryImportsAhead(() => [
54
+ api.addEntryImportsAhead(() => (0, localeUtils_1.isNeedPolyfill)(api.config.targets || {})
55
+ ? [
57
56
  {
58
57
  source: require.resolve('intl'),
59
58
  },
60
- ]);
61
- }
59
+ ]
60
+ : []);
62
61
  const addAntdLocales = (args) => __awaiter(void 0, void 0, void 0, function* () {
63
- var _b;
62
+ var _a;
64
63
  return yield api.applyPlugins({
65
64
  key: 'addAntdLocales',
66
65
  type: api.ApplyPluginsType.add,
67
66
  initialValue: [
68
- `antd/${((_b = api.config) === null || _b === void 0 ? void 0 : _b.ssr) ? 'lib' : 'es'}/locale/${(0, localeUtils_1.getAntdLocale)(args.lang, args.country)}`,
67
+ `antd/${((_a = api.config) === null || _a === void 0 ? void 0 : _a.ssr) ? 'lib' : 'es'}/locale/${(0, localeUtils_1.getAntdLocale)(args.lang, args.country)}`,
69
68
  ],
70
69
  args,
71
70
  });
72
71
  });
73
72
  const getList = (resolveKey) => __awaiter(void 0, void 0, void 0, function* () {
74
- var _c, _d;
73
+ var _b;
75
74
  const { paths } = api;
76
75
  return (0, localeUtils_1.getLocaleList)({
77
- localeFolder: ((_c = api.config) === null || _c === void 0 ? void 0 : _c.singular) ? 'locale' : 'locales',
78
- separator: (_d = api.config.locale) === null || _d === void 0 ? void 0 : _d.baseSeparator,
76
+ localeFolder: 'locales',
77
+ separator: (_b = api.config.locale) === null || _b === void 0 ? void 0 : _b.baseSeparator,
79
78
  absSrcPath: paths.absSrcPath,
80
79
  absPagesPath: paths.absPagesPath,
81
80
  addAntdLocales,
@@ -83,14 +82,14 @@ exports.default = (api) => {
83
82
  });
84
83
  });
85
84
  api.onGenerateFiles(() => __awaiter(void 0, void 0, void 0, function* () {
86
- var _e, _f, _g, _h;
85
+ var _c, _d, _e, _f;
87
86
  const localeTpl = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../libs/locale/locale.tpl'), 'utf-8');
88
87
  // moment2dayjs
89
88
  const resolveKey = api.config.moment2dayjs ? 'dayjs' : 'moment';
90
89
  const momentPkgPath = (0, plugin_utils_1.winPath)((0, path_1.dirname)(require.resolve(`${resolveKey}/package.json`)));
91
90
  const EventEmitterPkg = (0, plugin_utils_1.winPath)((0, path_1.dirname)(require.resolve('event-emitter/package')));
92
91
  const { baseSeparator, baseNavigator, antd, title, useLocalStorage } = Object.assign(Object.assign({}, defaultConfig), api.config.locale);
93
- const defaultLocale = ((_e = api.config.locale) === null || _e === void 0 ? void 0 : _e.default) || `zh${baseSeparator}CN`;
92
+ const defaultLocale = ((_c = api.config.locale) === null || _c === void 0 ? void 0 : _c.default) || `zh${baseSeparator}CN`;
94
93
  const localeList = yield getList(resolveKey);
95
94
  const momentLocales = localeList
96
95
  .map(({ momentLocale }) => momentLocale)
@@ -101,7 +100,7 @@ exports.default = (api) => {
101
100
  let MomentLocales = momentLocales;
102
101
  let DefaultMomentLocale = '';
103
102
  // set moment default accounding to locale.default
104
- if (!MomentLocales.length && ((_f = api.config.locale) === null || _f === void 0 ? void 0 : _f.default)) {
103
+ if (!MomentLocales.length && ((_d = api.config.locale) === null || _d === void 0 ? void 0 : _d.default)) {
105
104
  const [lang, country = ''] = defaultLocale.split(baseSeparator);
106
105
  const { momentLocale } = (0, localeUtils_1.getMomentLocale)(lang, country, resolveKey);
107
106
  if (momentLocale) {
@@ -111,7 +110,7 @@ exports.default = (api) => {
111
110
  }
112
111
  let DefaultAntdLocales = [];
113
112
  // set antd default locale
114
- if (!antdLocales.length && ((_g = api.config.locale) === null || _g === void 0 ? void 0 : _g.antd)) {
113
+ if (!antdLocales.length && ((_e = api.config.locale) === null || _e === void 0 ? void 0 : _e.antd)) {
115
114
  const [lang, country = ''] = defaultLocale.split(baseSeparator);
116
115
  DefaultAntdLocales = plugin_utils_1.lodash.uniq(yield addAntdLocales({
117
116
  lang,
@@ -138,7 +137,7 @@ exports.default = (api) => {
138
137
  path: 'locale.tsx',
139
138
  });
140
139
  const localeExportsTpl = (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../libs/locale/localeExports.tpl'), 'utf-8');
141
- const localeDirName = api.config.singular ? 'locale' : 'locales';
140
+ const localeDirName = 'locales';
142
141
  const localeDirPath = (0, path_1.join)(api.paths.absSrcPath, localeDirName);
143
142
  api.writeTmpFile({
144
143
  path: 'localeExports.ts',
@@ -178,14 +177,14 @@ exports.default = (api) => {
178
177
  Antd: !!antd,
179
178
  LocaleList: localeList,
180
179
  ShowSelectLang: localeList.length > 1 && !!antd,
181
- antdFiles: ((_h = api.config) === null || _h === void 0 ? void 0 : _h.ssr) ? 'lib' : 'es',
180
+ antdFiles: ((_f = api.config) === null || _f === void 0 ? void 0 : _f.ssr) ? 'lib' : 'es',
182
181
  }),
183
182
  });
184
183
  // index.ts
185
184
  api.writeTmpFile({
186
185
  path: 'index.ts',
187
186
  content: `
188
- export { useIntl, formatMessage, FormattedMessage } from './localeExports.ts';
187
+ export { setLocale, getLocale, useIntl, formatMessage, FormattedMessage } from './localeExports.ts';
189
188
  export { SelectLang } from './SelectLang.tsx';
190
189
  `,
191
190
  });
package/dist/request.js CHANGED
@@ -265,6 +265,7 @@ export {
265
265
  useRequest,
266
266
  UseRequestProvider,
267
267
  request,
268
+ getRequestInstance,
268
269
  };
269
270
 
270
271
  export type {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umijs/plugins",
3
- "version": "4.0.0-rc.8",
3
+ "version": "4.0.0-rc.9",
4
4
  "description": "@umijs/plugins",
5
5
  "homepage": "https://github.com/umijs/umi-next/tree/master/packages/plugins#readme",
6
6
  "bugs": "https://github.com/umijs/umi-next/issues",
@@ -24,8 +24,8 @@
24
24
  "dependencies": {
25
25
  "@ahooksjs/use-request": "^2.0.0",
26
26
  "@ant-design/icons": "^4.7.0",
27
- "@ant-design/pro-layout": "^7.0.1-beta.3",
28
- "@umijs/bundler-utils": "4.0.0-rc.8",
27
+ "@ant-design/pro-layout": "^6.34.6",
28
+ "@umijs/bundler-utils": "4.0.0-rc.9",
29
29
  "antd-dayjs-webpack-plugin": "^1.0.6",
30
30
  "axios": "^0.26.1",
31
31
  "babel-plugin-import": "^1.13.3",
@@ -44,7 +44,7 @@
44
44
  "warning": "^4.0.3"
45
45
  },
46
46
  "devDependencies": {
47
- "umi": "4.0.0-rc.8"
47
+ "umi": "4.0.0-rc.9"
48
48
  },
49
49
  "publishConfig": {
50
50
  "access": "public"