diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 000000000..e65bec96b --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +**/*.ts + +lib \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js index 4b7aabb3d..d09347a26 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,14 +1,11 @@ - module.exports = { - extends: [ - '@webank/eslint-config-webank/vue.js' - ], + extends: ['@webank/eslint-config-webank/vue.js'], globals: { // 这里填入你的项目需要的全局变量 // 这里值为 false 表示这个全局变量不允许被重新赋值,比如: // // Vue: false - __DEV__: false + __DEV__: false, }, rules: { 'vue/comment-directive': 'off', @@ -16,9 +13,9 @@ module.exports = { 'import/no-unresolved': 'off', 'no-restricted-syntax': 'off', 'no-undefined': 'off', - 'vue/valid-template-root': 'off' + 'vue/valid-template-root': 'off', }, env: { - jest: true - } + jest: true, + }, }; diff --git a/packages/fes-compiler/src/service/utils/pluginUtils.js b/packages/fes-compiler/src/service/utils/pluginUtils.js index 9b7631b7c..e834e59c8 100644 --- a/packages/fes-compiler/src/service/utils/pluginUtils.js +++ b/packages/fes-compiler/src/service/utils/pluginUtils.js @@ -1,8 +1,11 @@ import { dirname, join, basename, relative, extname } from 'path'; import { compatESModuleRequire, resolve, winPath, pkgUp, lodash } from '@fesjs/utils'; +import Logger from '../../logger'; import { PluginType } from '../enums'; +const logger = new Logger('fes:compiler'); + const RE = { [PluginType.plugin]: /^(@fesjs\/|@webank\/fes-|fes-)plugin-/, [PluginType.preset]: /^(@fesjs\/|@webank\/fes-|fes-)preset-/, @@ -24,9 +27,15 @@ function filterPluginAndPreset(type, pkg) { } function filterBuilder(pkg) { - return Object.keys(pkg.devDependencies || {}) + const builders = Object.keys(pkg.devDependencies || {}) .concat(Object.keys(pkg.dependencies || {})) .filter((name) => /^@fesjs\/build-/.test(name)); + + if (builders.length > 1) { + logger.warn(`检测到您使用了多个个 builder: ${builders},当前生效的是 ${builders[0]}, 请保留一个`); + } + + return builders.slice(0, 1); } export function getPluginsOrPresets(type, opts) { diff --git a/packages/fes-plugin-request/package.json b/packages/fes-plugin-request/package.json index b2bf6fb17..6563308b4 100644 --- a/packages/fes-plugin-request/package.json +++ b/packages/fes-plugin-request/package.json @@ -34,5 +34,6 @@ "@fesjs/compiler": "^2.0.5", "@fesjs/utils": "^2.0.4", "axios": "0.21.1" - } -} + }, + "typings": "./types.d.ts" +} \ No newline at end of file diff --git a/packages/fes-plugin-request/src/index.js b/packages/fes-plugin-request/src/index.js index a0e0d680c..d1b28326f 100644 --- a/packages/fes-plugin-request/src/index.js +++ b/packages/fes-plugin-request/src/index.js @@ -2,6 +2,7 @@ import { Logger } from '@fesjs/compiler'; import { readFileSync } from 'fs'; import { join } from 'path'; import { resolvePkg } from '@fesjs/utils'; +import { name } from '../package.json'; const logger = new Logger('fes:plugin-request'); @@ -65,4 +66,14 @@ export default (api) => { source: absoluteFilePath, }, ]); + + api.addRuntimeType(() => ({ + source: name, + specifier: ['RequestRuntimeConfig'], + })); + + api.addBuildType(() => ({ + source: name, + specifier: ['RequestBuildConfig'], + })); }; diff --git a/packages/fes-plugin-request/types.d.ts b/packages/fes-plugin-request/types.d.ts new file mode 100644 index 000000000..2efbebecb --- /dev/null +++ b/packages/fes-plugin-request/types.d.ts @@ -0,0 +1,24 @@ +import { AxiosRequestConfig, AxiosResponse } from 'axios'; + +export interface RequestBuildConfig { + request: { + dataField: string + } +} + + +type RequestInterceptor = (value: AxiosRequestConfig) => AxiosRequestConfig | [(value: AxiosRequestConfig) => AxiosRequestConfig, (error: any) => any]; +type ResponseInterceptor = (value: AxiosResponse) => AxiosResponse | [(value: AxiosResponse) => AxiosResponse, (error: any) => any]; + + +export interface RequestRuntimeConfig { + request: { + responseDataAdaptor?(data: T): T; + closeResDataCheck?: boolean; + requestInterceptors?: RequestInterceptor[]; + responseInterceptors?: ResponseInterceptor[]; + errorHandler: { + [key: string]: (error: { response: AxiosResponse } | AxiosResponse) => void; + }; + } & AxiosRequestConfig; +} \ No newline at end of file diff --git a/packages/fes-preset-built-in/src/index.js b/packages/fes-preset-built-in/src/index.js index 9da5e5aa7..21aa71cd3 100644 --- a/packages/fes-preset-built-in/src/index.js +++ b/packages/fes-preset-built-in/src/index.js @@ -9,6 +9,7 @@ export default function () { require.resolve('./plugins/generateFiles/core/exports/coreExports'), require.resolve('./plugins/generateFiles/core/exports/pluginExports'), require.resolve('./plugins/generateFiles/fes'), + require.resolve('./plugins/generateFiles/genType'), // bundle configs require.resolve('./plugins/features/base'), diff --git a/packages/fes-preset-built-in/src/plugins/generateFiles/core/plugin/pluginRegister.tpl b/packages/fes-preset-built-in/src/plugins/generateFiles/core/plugin/pluginRegister.tpl index 8bdc28805..0763c160a 100644 --- a/packages/fes-preset-built-in/src/plugins/generateFiles/core/plugin/pluginRegister.tpl +++ b/packages/fes-preset-built-in/src/plugins/generateFiles/core/plugin/pluginRegister.tpl @@ -3,9 +3,12 @@ import { plugin } from './plugin'; import * as Plugin_{{{ index }}} from '{{{ path }}}'; {{/plugins}} +// 避免编译警告 +const defaultKey = 'default'; + {{#plugins}} plugin.register({ - apply: Plugin_{{{ index }}}, + apply: Plugin_{{{ index }}}[defaultKey] ? Plugin_{{{ index }}}[defaultKey] : Plugin_{{{ index }}}, path: '{{{ path }}}', }); {{/plugins}} diff --git a/packages/fes-preset-built-in/src/plugins/generateFiles/genType.js b/packages/fes-preset-built-in/src/plugins/generateFiles/genType.js new file mode 100644 index 000000000..7ea90f7ab --- /dev/null +++ b/packages/fes-preset-built-in/src/plugins/generateFiles/genType.js @@ -0,0 +1,52 @@ +function importsToStr(imports) { + return imports.map((imp) => { + const { source, specifier } = imp; + if (specifier) { + return `import {${specifier.join(', ')}} from '${source}';`; + } + return ''; + }); +} + +function genTypeContent(name, imports) { + return { + TYP_NAME: name, + TYPES: imports.reduce((previousValue, currentValue) => previousValue.concat(currentValue.specifier || []), []).join(' & '), + imports: importsToStr(imports).join('\n'), + }; +} + +export default function (api) { + const { + utils: { Mustache }, + } = api; + + api.onGenerateFiles(async () => { + const runtimeTypeName = 'PluginRuntimeConfig'; + const buildTypeName = 'PluginBuildConfig'; + const typeTpl = ` +{{{ imports }}} + +export type {{{TYP_NAME}}} = {{{TYPES}}} +`; + const runtimeImportSources = await api.applyPlugins({ + key: 'addRuntimeType', + type: api.ApplyPluginsType.add, + initialValue: [], + }); + api.writeTmpFile({ + path: 'runtime.d.ts', + content: Mustache.render(typeTpl, genTypeContent(runtimeTypeName, runtimeImportSources)), + }); + + const buildImportSources = await api.applyPlugins({ + key: 'addBuildType', + type: api.ApplyPluginsType.add, + initialValue: [], + }); + api.writeTmpFile({ + path: 'build.d.ts', + content: Mustache.render(typeTpl, genTypeContent(buildTypeName, buildImportSources)), + }); + }); +} diff --git a/packages/fes-preset-built-in/src/plugins/registerMethods.js b/packages/fes-preset-built-in/src/plugins/registerMethods.js index a5477baf5..c7dc0b6d9 100644 --- a/packages/fes-preset-built-in/src/plugins/registerMethods.js +++ b/packages/fes-preset-built-in/src/plugins/registerMethods.js @@ -14,16 +14,21 @@ export default function (api) { 'addEntryImports', 'addEntryCodeAhead', 'addEntryCode', + 'modifyRoutes', + + 'addRuntimeType', + 'addBuildType', + + 'addTmpGenerateWatcherPaths', + 'addBeforeMiddlewares', 'addHTMLHeadScripts', 'addMiddlewares', - 'modifyRoutes', 'modifyBundleConfigOpts', 'modifyBundleConfig', 'modifyBabelOpts', 'modifyBabelPresetOpts', 'chainWebpack', - 'addTmpGenerateWatcherPaths', 'modifyPublicPathStr', ].forEach((name) => { api.registerMethod({ name }); diff --git a/packages/fes-template-h5/src/app.js b/packages/fes-template-h5/src/app.js index 0797ca30c..c0a707f43 100644 --- a/packages/fes-template-h5/src/app.js +++ b/packages/fes-template-h5/src/app.js @@ -1,19 +1,22 @@ -export const request = { - errorHandler: { - 111() { - console.log('root:111'); - }, - 500() { - console.log('500 error'); - }, - default(error) { - console.log(error); - const msg = error?.data?.msg || error?.msg; - console.log(msg); - } - } -}; +import { defineRuntimeConfig } from '@fesjs/fes'; -export function patchRoutes() { - console.log('patchRoutes'); -} +export default defineRuntimeConfig({ + request: { + errorHandler: { + 111() { + console.log('root:111'); + }, + 500() { + console.log('500 error'); + }, + default(error) { + console.log(error); + const msg = error?.data?.msg || error?.msg; + console.log(msg); + }, + }, + }, + patchRoutes: () => { + console.log('patchRoutes'); + }, +}); diff --git a/packages/fes-template-h5/tsconfig.json b/packages/fes-template-h5/tsconfig.json index ea930c0b5..e506d82ce 100644 --- a/packages/fes-template-h5/tsconfig.json +++ b/packages/fes-template-h5/tsconfig.json @@ -3,7 +3,10 @@ "outDir": "build/dist", "module": "esnext", "target": "esnext", - "lib": ["esnext", "dom"], + "lib": [ + "esnext", + "dom" + ], "sourceMap": true, "baseUrl": ".", "jsx": "preserve", @@ -14,12 +17,15 @@ "suppressImplicitAnyIndexErrors": true, "noUnusedLocals": true, "allowJs": true, - "skipLibCheck": true, "experimentalDecorators": true, "strict": true, "paths": { - "@/*": ["./src/*"], - "@@/*": ["./src/.fes/*"] + "@/*": [ + "./src/*" + ], + "@@/*": [ + "./src/.fes/*" + ] } }, "include": [ @@ -29,9 +35,13 @@ "__test__/**/*", "typings/**/*", "config/**/*", - ".eslintrc.js", - ".stylelintrc.js", - ".prettierrc.js" + "src/.fes/runtime.d.ts" ], - "exclude": ["node_modules", "build", "dist", "scripts", "src/.fes/*", "webpack", "jest"] -} + "exclude": [ + "build", + "dist", + "scripts", + "webpack", + "jest" + ] +} \ No newline at end of file diff --git a/packages/fes/package.json b/packages/fes/package.json index 3b49b3ac1..32b6a904d 100644 --- a/packages/fes/package.json +++ b/packages/fes/package.json @@ -42,10 +42,11 @@ "@fesjs/preset-built-in": "^2.0.22", "@fesjs/runtime": "^2.0.2", "@fesjs/utils": "^2.0.4", - "resolve-cwd": "^3.0.0" + "resolve-cwd": "^3.0.0", + "vue-router": "^4.0.1" }, "engines": { "node": "^10.12.0 || ^12.0.0 || >= 14.0.0" }, "types": "types.d.ts" -} +} \ No newline at end of file diff --git a/packages/fes/src/index.js b/packages/fes/src/index.js index 7d1e2eead..1a4f7f669 100644 --- a/packages/fes/src/index.js +++ b/packages/fes/src/index.js @@ -1,4 +1,11 @@ - export * from '@@/core/coreExports'; // @ts-ignore export * from '@@/core/pluginExports'; + +export function defineBuildConfig(params) { + return params; +} + +export function defineRuntimeConfig(params) { + return params; +} diff --git a/packages/fes/types.d.ts b/packages/fes/types.d.ts index 1a880b6ba..be3518610 100644 --- a/packages/fes/types.d.ts +++ b/packages/fes/types.d.ts @@ -1,10 +1,45 @@ +import { Component, DefineComponent, App } from 'vue'; +import { RouteRecordRaw, Router } from 'vue-router'; +import { Plugin } from '@fesjs/runtime'; +import { PluginRuntimeConfig } from '@@/runtime'; + // @ts-ignore export * from '@@/core/coreExports'; // @ts-ignore export * from '@@/core/pluginExports'; -export declare function defineRouteMeta(routeMeta: { +interface RouteMeta { name?: string; title?: string; layout?: boolean | { sidebar?: boolean; header?: boolean; logo?: boolean }; -}); +} + +export declare function defineRouteMeta(routeMeta: RouteMeta): RouteMeta; + + +interface BeforeRenderConfig { + loading: Component; + action: () => Promise; +} + +interface ClientRenderOption { + routes: RouteRecordRaw[]; + rootElement: string; + defaultTitle: string; + plugin: Plugin; +} + +type RenderFunc = () => Promise + +interface InnerRuntimeConfig { + beforeRender?: (option: BeforeRenderConfig) => BeforeRenderConfig; + patchRoutes?: ({ routes }: { routes: RouteRecordRaw[] }) => void; + modifyClientRenderOpts?: (option: ClientRenderOption) => ClientRenderOption; + rootContainer?: (component: DefineComponent, option: { routes: RouteRecordRaw[], plugin: Plugin }) => DefineComponent; + onAppCreated?: ({ app, routes }: { app: App, routes: RouteRecordRaw[] }) => void; + render?: (defaultRender: RenderFunc) => RenderFunc; + onRouterCreated?: ({ router }: { router: Router }) => void; +} + +export function defineRuntimeConfig(config: InnerRuntimeConfig & PluginRuntimeConfig): InnerRuntimeConfig & PluginRuntimeConfig; +