Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

app组件的pages或者api很大会不会出现性能问题 #10606

Open
lawbc opened this issue Jul 8, 2024 · 8 comments
Open

app组件的pages或者api很大会不会出现性能问题 #10606

lawbc opened this issue Jul 8, 2024 · 8 comments

Comments

@lawbc
Copy link

lawbc commented Jul 8, 2024

实现场景:

在app组件中,把一个系统的所有页面都使用js编写(schema是js文件)然后设置到app的pages数组中,这样一个系统几百个页面会导致这个数组非常大,可能有5M,会不会出现性能问题,比如第一次进入页面卡顿

存在的问题:

因为无法使用js动态加载页面的schema,可能会导致第一次加载页面卡顿,pages使用schemaApi加载的话,js文件限制很多,我看只能是立即执行函数或者直接返回一个json对象才行,页面如果存在import就会报错

当前方案:

请粘贴你当前方案的完整 amis schema 代码...

index.js:

import 'amis/sdk/sdk.css'
import 'amis/sdk/antd.css'
import 'amis/sdk/helper.css'
import 'amis/sdk/iconfont.css'

import 'amis/sdk/sdk.js'
import { createBrowserHistory } from 'history';

import * as u from './utils'
import {configAxios} from './axiosConfig'
import pages from './site'
import loadMenus from './menu'

;(async () => {
  //这里加入登录token判断,没有登录就跳转到login页面
  if(!u.getToken()){
    window.location = '/login.html'
    return;
  }

  //configAxios();
  //const menuResult = await loadMenus();

  let amis = amisRequire('amis/embed');
  const match = amisRequire('path-to-regexp').match;

  // 如果想用 browserHistory 请切换下这处代码, 其他不用变
  const history = createBrowserHistory();
  //const history = createHashHistory();

  const app = {
    type: 'app',
    brandName: 'XXX管理后台',
    logo: '/public/logo.png',
    header: {
      type: 'tpl',
      inline: false,
      className: 'w-full',
      tpl: '<div class="flex justify-between"><div>顶部区域左侧</div><div>顶部区域右侧</div></div>'
    },
    // footer: '<div class="p-2 text-center bg-light">底部区域</div>',
    // asideBefore: '<div class="p-2 text-center">菜单前面区域</div>',
    // asideAfter: '<div class="p-2 text-center">菜单后面区域</div>',
    pages: pages
  };

  function normalizeLink(to, location = history.location) {
    to = to || '';

    if (to && to[0] === '#') {
      to = location.pathname + location.search + to;
    } else if (to && to[0] === '?') {
      to = location.pathname + to;
    }

    const idx = to.indexOf('?');
    const idx2 = to.indexOf('#');
    let pathname = ~idx
      ? to.substring(0, idx)
      : ~idx2
        ? to.substring(0, idx2)
        : to;
    let search = ~idx ? to.substring(idx, ~idx2 ? idx2 : undefined) : '';
    let hash = ~idx2 ? to.substring(idx2) : location.hash;

    if (!pathname) {
      pathname = location.pathname;
    } else if (pathname[0] != '/' && !/^https?\:\/\//.test(pathname)) {
      let relativeBase = location.pathname;
      const paths = relativeBase.split('/');
      paths.pop();
      let m;
      while ((m = /^\.\.?\//.exec(pathname))) {
        if (m[0] === '../') {
          paths.pop();
        }
        pathname = pathname.substring(m[0].length);
      }
      pathname = paths.concat(pathname).join('/');
    }

    return pathname + search + hash;
  }

  function isCurrentUrl(to, ctx) {
    if (!to) {
      return false;
    }
    const pathname = history.location.pathname;
    const link = normalizeLink(to, {
      ...location,
      pathname,
      hash: ''
    });

    if (!~link.indexOf('http') && ~link.indexOf(':')) {
      let strict = ctx && ctx.strict;
      return match(link, {
        decode: decodeURIComponent,
        strict: typeof strict !== 'undefined' ? strict : true
      })(pathname);
    }

    return decodeURI(pathname) === link;
  }

  let amisInstance = amis.embed(
    '#app',
    app,
    {
      location: history.location,
      data: {
        // 全局数据,是受控的数据
      },
      context: {
        // 全局上下文数据, 非受控的数据,无论哪一层都能获取到,包括弹窗自定义数据映射后都能获取到。
        // 可以用来放一下全局配置等。比如 API_HOST, 这样页面配置里面可以通过 ${API_HOST} 来获取到。
        API_HOST: import.meta.env.VITE_API_URL
      }
    },
    {
      // watchRouteChange: fn => {
      //   return history.listen(fn);
      // },
      updateLocation: (location, replace) => {
        location = normalizeLink(location);
        if (location === 'goBack') {
          return history.goBack();
        } else if (
          (!/^https?\:\/\//.test(location) &&
            location ===
            history.location.pathname + history.location.search) ||
          location === history.location.href
        ) {
          // 目标地址和当前地址一样,不处理,免得重复刷新
          return;
        } else if (/^https?\:\/\//.test(location) || !history) {
          return (window.location.href = location);
        }

        history[replace ? 'replace' : 'push'](location);
      },
      jumpTo: (to, action) => {
        if (to === 'goBack') {
          return history.goBack();
        }

        to = normalizeLink(to);

        if (isCurrentUrl(to)) {
          return;
        }

        if (action && action.actionType === 'url') {
          action.blank === false
            ? (window.location.href = to)
            : window.open(to, '_blank');
          return;
        } else if (action && action.blank) {
          window.open(to, '_blank');
          return;
        }

        if (/^https?:\/\//.test(to)) {
          window.location.href = to;
        } else if (
          (!/^https?\:\/\//.test(to) &&
            to === history.pathname + history.location.search) ||
          to === history.location.href
        ) {
          // do nothing
        } else {
          history.push(to);
        }
      },
      requestAdaptor: async (api, context) => {
        const headers = api.headers || {};
        headers['X-APP'] = 'bqex';
        //这里加入token的逻辑,如果获取到了就放到header中
        if(!u.isIgnoreUrl(api.url)){
          headers['Authorization'] = u.getToken() || '';
        }
        api.headers = headers;
        console.log(api.url)
        //当请求url不包含http且不是js和json后缀的时候(amis本身的请求,非后端接口),自动加上域名
        if(!api.url.startsWith('http') && !api.url.includes('.js') && !api.url.includes('.json')){
          api.url = import.meta.env.VITE_API_URL + api.url;
        }
        return api;
      },
      responseAdaptor: (api, payload, query, request, response) => {
        if(payload.code == 401){
          window.location = '/login.html';
          return;
        }
      
        if(api.url.includes('.js')){
          let module = {};
          let oldModule = window.module;
          window.module = module;
          try {
              eval('(' + payload + ')');
          } catch (e) {
              console.error('Error loading script: ', e);
          }
          window.module = oldModule;
          payload = module.exports;
        }

       
        return payload;
      },
      isCurrentUrl: isCurrentUrl,
      theme: 'antd'
    }
  );

  //这里可以拦截路由变化
  history.listen(state => {
    amisInstance.updateProps({
      location: state.location || state
    });
  });
})();

site.js(app的pages返回值)

import rolePage from './pages/role/index'
import roleOrgPage from './pages/role/org-index'
import menuPage from './pages/menu/index'
import userPage from './pages/user/index'
import adminPage from './pages/admin/index'
import onlineUserPage from './pages/user/online'
import systemPage from './pages/system/index'
import regionPage from './pages/region/index'
import areaPage from './pages/area/index'
import dictPage from './pages/dict/index'
import loginLogPage from './pages/log/login-log'
import operationLogPage from './pages/log/operation-log'

export default [
    {
      label: 'Home',
      url: '/',
      redirect: '/user'
    },
    {
      children: [
        {
          label: '系统管理',
          children: [
            {
              label: '用户管理',
              url: 'user',
              schema: userPage
            },
            {
              label: '管理员管理',
              url: 'admin',
              schema: adminPage
            },
            {
              label: '在线用户',
              url: 'user/online',
              schema: onlineUserPage
            },
            {
              label: '菜单管理',
              url: 'menu',
              schema: menuPage
            },
            {
              label: '角色管理',
              url: 'role',
              schema: rolePage
            },
            {
              label: '机构角色管理',
              url: 'role/org',
              schema: roleOrgPage
            },
            {
              label: '子系统管理',
              url: 'system',
              schema: systemPage
            },
            {
              label: '片区管理',
              url: 'region',
              schema: regionPage
            },
            {
              label: '行政区管理',
              url: 'area',
              schema: areaPage
            },
            {
              label: '字典表管理',
              url: 'dict',
              schema: dictPage
            },
            {
              label: '登录日志管理',
              url: 'log/login',
              schema: loginLogPage
            },
            {
              label: '操作日志管理',
              url: 'log/operation',
              schema: operationLogPage
            }
          ]
        }
      ]
    }
  ]

上面这种需要一次性import所有的页面,导致pages对象非常大,有没有办法动态import呢

@lawbc
Copy link
Author

lawbc commented Jul 8, 2024

schema能否支持动态import,比如schema: await import('./xxx.js')

@xiahao90
Copy link

xiahao90 commented Jul 9, 2024

schema用api动态加载就行了,再api配置上缓存,也不会重复加载

@lawbc
Copy link
Author

lawbc commented Jul 9, 2024

schema用api动态加载就行了,再api配置上缓存,也不会重复加载

api方式不支持加载模块化的js代码呢,有demo吗,因为一个页面的js文件需要导入其他js函数不是简单的返回json对象的

@xiahao90
Copy link

如你的:{ label: '用户管理', url: 'user', schema: userPage },
改成
{ label: '用户管理', url: 'user', schemaApi: { "method": "get", "url": "/pages/user/index", "cache": 2000 } },
后端返回这个json格式

@lawbc
Copy link
Author

lawbc commented Jul 10, 2024

如你的:{ label: '用户管理', url: 'user', schema: userPage }, 改成 { label: '用户管理', url: 'user', schemaApi: { "method": "get", "url": "/pages/user/index", "cache": 2000 } }, 后端返回这个json格式

如果userPage中有一些自定义的逻辑需要import其他库函数就不行了,如果全都是单纯的js那很好办,都可以直接使用js:xxxx.js来加载,问题就是每个js都有可能有自定义逻辑的

@xiahao90
Copy link

杠精不看文档?/pages/user/index接口返回这个不就可以模块化加载了?
{"type":"page","onEvent":{"init":{"actions":[{"actionType":"custom","script":"console.log('加载你的动态js')"}]}}}

@lawbc
Copy link
Author

lawbc commented Jul 11, 2024

杠精不看文档?/pages/user/index接口返回这个不就可以模块化加载了? {"type":"page","onEvent":{"init":{"actions":[{"actionType":"custom","script":"console.log('加载你的动态js')"}]}}}

没有杠精的意思,虚心请教,文档也看了很多遍了,确实不知道schemaApi如何加载模块化的js文件,直接return {}这种是官方有介绍,actionType为custom的文档里面没有看到过

@lawbc
Copy link
Author

lawbc commented Jul 11, 2024

杠精不看文档?/pages/user/index接口返回这个不就可以模块化加载了? {"type":"page","onEvent":{"init":{"actions":[{"actionType":"custom","script":"console.log('加载你的动态js')"}]}}}

/pages/user/index这个是一个js文件,js里面又import了其他模块的js

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants