项目配置

TvT.js 目前选用的是 Vite 构建,原则上是支持 Webpack 构建的,具体将在后期放开。

编译时配置

我们约定 .fes.js 文件为项目编译需要编译时配置文件,可以引入 node 端依赖项,不要引入 浏览器端 依赖项。

WARNING

此文件.fes.js 中引入的第三方包,请确认第三方包包含 commonjs 的构建方法。若其不包含则会在编译中报错:equire() of ES Module *** from */.fes.js not supported。 若需要给其增加 commonjs 的构建方法,详情请查看稍后章节:常见问题

import { join } from 'path';
import { defineBuildConfig } from '@fesjs/fes';
import { templateCompilerOptions } from '@tresjs/core';
import UnoCSS from 'unocss/vite';

export default defineBuildConfig({
    publicPath: './',
	mock: {										// mock 配置
        prefix: '/v2',
    },
    proxy: {									// 代理 配置
        '/v2': {
            target: 'https://api.douban.com/',
            changeOrigin: true,
        },
    },
    access: {									// 默认的 fes.js access 插件配置
        roles: {
            admin: ['*'],
            manager: ['/'],
        },
    },
    layout: {									// 默认的 fes.js layout 插件配置
        navigation: null,
    },
    enums: {
        status: [['0', '无效的'], ['1', '有效的']]// 默认的 fes.js enums 插件配置
    },
	// ---Vite 专属配置 start----
    viteVuePlugin: {
        ...templateCompilerOptions,
    },
    viteOption: {
        base: "./",
        plugins: [
            UnoCSS({}),
        ],
    },
	// ......
	// ---Vite 专属配置 end---
    alias: { PLS: join(__dirname, './src/plugins') },
});

Vite 专属配置

viteOption

viteVuePlugin

viteVueJsx

viteLegacy

viteHtml

TIP

  • 项目中除了 .fes.js 还有 .fes.predev.js,在预览模式下,会增加.fes.predev.js配置后再与.fes.jsdeep merge 后形成最终配置。
  • 在项目中可以自行添加环境配置,类似:FES_ENV=aaa fes dev,这时候会命中 .fes.aaa.js 这份环境配置文件。
  • 详细配置可参考open in new window

运行时配置

我们 约定 src/app.jsx 为运行时配置文件。运行时配置和配置的区别是他跑在浏览器端,因此我们可以在这里写函数、引入浏览器端依赖项等等,注意不要引入 node 端依赖项。

运行时为啥需要配置?

Fes.js 框架跟传统开发模式不一样。传统开发模式中用户编写 entry 文件,而 Fes.js 中 entry 文件由框架生成,用户就不必要编写胶水代码。内置插件和其他插件提供的一些运行时功能提供用户或者其他插件自定义。

例如:

plugin-access 插件定义运行时配置项:

api.addRuntimePluginKey(() => 'access');

plugin-access 插件读取配置项:

const runtimeConfig = plugin.applyPlugins({
    key: 'access',
    type: ApplyPluginsType.modify,
    initialValue: {},
});

而用户则只需要配置:

// app.js
import { defineRuntimeConfig } from '@fesjs/fes';

export default defineRuntimeConfig({
    access: memo => ({
        ...memo
        unAccessHandler({
            router, to, from, next
        }) {
            // 处理逻辑
        },
        noFoundHandler({
            router, to, from, next
        }) {
            // 处理逻辑
        },
    }),
});

配置智能提示

配置可以单独导出,也可以通过 defineRuntimeConfig 工具函数获取类型提示。

方式一(推荐,有类型提示):

// app.jsx
import { defineRuntimeConfig } from '@fesjs/fes';
export default defineRuntimeConfig({
    access: memo => ({
        ...memo
        unAccessHandler({
            router, to, from, next
        }) {
            // 处理逻辑
        },
        noFoundHandler({
            router, to, from, next
        }) {
            // 处理逻辑
        },
    }),
    // ...其他配置项
});

方式二:

// app.jsx
export const access = memo => ({
    ...memo
    unAccessHandler({
        router, to, from, next
    }) {
        // 处理逻辑
    },
    noFoundHandler({
        router, to, from, next
    }) {
        // 处理逻辑
    },
});

Fes.js配置项

beforeRender

beforeRender(lastOpts)

在渲染之前执行,执行action过程中显示 loading 配置的组件,执行结果作为参数 initialState 传给 modifyClientRenderOpts

示例:

// app.jsx
import { access } from '@fesjs/fes';
import PageLoading from '@/components/PageLoading';
import UserCenter from '@/components/UserCenter';

export function beforeRender(lastOpts) {
    return {
        ...lastOpts,
        loading: <PageLoading />,
        action() {
            const { setRole } = access;
            return new Promise((resolve) => {
                setTimeout(() => {
                    setRole('admin');
                    resolve({
                        userName: 'harrywan',
                    });
                }, 1000);
            });
        },
    };
}

patchRoutes

patchRoutes({routes })

WARNING

准备删除此API,推荐使用modifyRoute

修改路由。

比如在最前面添加一个 /foo 路由:

export function patchRoutes({ routes }) {
    routes.unshift({
        path: '/foo',
        component: require('@/extraRoutes/foo').default,
    });
}

TIP

直接修改 routes, 不需要返回

modifyRoute

modifyRoute({base, createHistory, routes})

修改路由配置信息。

比如在最前面添加一个 /foo 路由:

export function modifyRoute(memo) {
    return {
        ...memo,
        routes: [
            {
                path: '/foo',
                component: require('@/extraRoutes/foo').default,
            }, 
            ...memo.routes
        ]
    }
}

比如修改 base:

export function modifyRoute(memo) {
    return {
        ...memo,
        base: window.location.href
    }
}

比如改为使用createMemoryHistory:

export function modifyRoute(memo) {
    return {
        ...memo,
        createHistory: createMemoryHistory
    }
}

modifyClientRenderOpts

modifyClientRenderOpts(lastOpts)

修改 clientRender 参数。参数是一个对象:

  • routes,路由配置信息
  • rootElement, 渲染的根节点,默认是 #app,可通过配置 mountElementId 修改。
  • initialState, 初始化数据,beforeRender 运行得到的数据。

比如在微前端里动态修改渲染根节点:

let isSubApp = false;
export function modifyClientRenderOpts(lastOpts) {
    return {
        ...lastOpts,
        rootElement: isSubApp ? 'sub-root' : lastOpts.rootElement,
    };
}

rootContainer

rootContainer(LastRootContainer, args)

修改交给 Vue 渲染时的根组件,默认是 <RouterView></RouterView>

  • LastRootContainer,上一个插件修改后的结果。
  • args,包含:
    • routes,全量路由配置
    • plugin,运行时插件机制

比如在可以包一层 DIV:

export function rootContainer(container) {
    return () => {
        return (
            <div>
                <RouterView></RouterView>
            </div>
        );
    };
}

onAppCreated

onAppCreated({app})

创建 app 实例后触发。

比如用于安装 Vue 插件:

import { createRouter } from 'vue-router';

export function onAppCreated({ app }) {
    const router = createRouter();
    app.use(router);
}

render

render(oldRender: Function)

覆写 render。

比如用于渲染之前做权限校验。

onRouterCreated

onRouterCreated({router})

生成 router 时触发。

比如用于收集切换路由的记录:

export function onRouterCreated({ router }) {
    router.afterEach((to, from) => {
        console.log(to);
    });
}