refactor: 优化乾坤插件,增加构建配置提示

This commit is contained in:
wanchun 2022-03-29 13:11:09 +08:00
commit abffcdb9a1
28 changed files with 213 additions and 267 deletions

View File

@ -3,18 +3,13 @@ import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import SFCConfigBlockPlugin from './SFCConfigBlockPlugin';
const assert = require('assert');
export default (api) => {
const {
env,
paths,
utils: { chalk },
} = api;
const unwatchs = [];
let port;
let hostname;
let server;
function destroy() {
@ -63,30 +58,6 @@ export default (api) => {
},
});
api.registerMethod({
name: 'getPort',
fn() {
assert(env === 'development', 'api.getPort() is only valid in development.');
return port;
},
});
api.registerMethod({
name: 'getHostname',
fn() {
assert(env === 'development', 'api.getHostname() is only valid in development.');
return hostname;
},
});
api.registerMethod({
name: 'getServer',
fn() {
assert(env === 'development', 'api.getServer() is only valid in development.');
return server;
},
});
api.registerMethod({
name: 'restartServer',
fn() {

View File

@ -3,11 +3,8 @@
* https://github.com/umijs/umi/blob/master/packages/preset-built-in/src/plugins/commands/dev/dev.ts
*/
const assert = require('assert');
export default (api) => {
const {
env,
paths,
utils: { chalk, portfinder, generateFiles },
} = api;
@ -165,30 +162,6 @@ export default (api) => {
},
});
api.registerMethod({
name: 'getPort',
fn() {
assert(env === 'development', 'api.getPort() is only valid in development.');
return port;
},
});
api.registerMethod({
name: 'getHostname',
fn() {
assert(env === 'development', 'api.getHostname() is only valid in development.');
return hostname;
},
});
api.registerMethod({
name: 'getServer',
fn() {
assert(env === 'development', 'api.getServer() is only valid in development.');
return server;
},
});
api.registerMethod({
name: 'restartServer',
fn() {

View File

@ -9,18 +9,12 @@ import { AsyncSeriesWaterfallHook } from 'tapable';
import { existsSync } from 'fs';
import { lodash, chalk } from '@fesjs/utils';
import { Command, Option } from 'commander';
import { resolvePresets, pathToObj, resolvePlugins } from './utils/pluginUtils';
import { resolvePresets, filterBuilder, pathToObj, resolvePlugins } from './utils/pluginUtils';
import loadDotEnv from './utils/loadDotEnv';
import isPromise from './utils/isPromise';
import BabelRegister from './babelRegister';
import PluginAPI from './pluginAPI';
import {
ApplyPluginsType,
ConfigChangeType,
EnableBy,
PluginType,
ServiceStage
} from './enums';
import { ApplyPluginsType, ConfigChangeType, EnableBy, PluginType, ServiceStage } from './enums';
import Config from '../config';
import { getUserConfigWithKey } from '../config/utils/configUtils';
import getPaths from './getPaths';
@ -95,6 +89,11 @@ export default class Service extends EventEmitter {
this.env = opts.env || process.env.NODE_ENV;
this.fesPkg = opts.fesPkg || {};
const builderPkgPath = filterBuilder(this.pkg);
this.builder = {
isVite: (builderPkgPath[0] || '').includes('build-vite'),
innerDepPrefix: '@fesInner',
};
assert(existsSync(this.cwd), `cwd ${this.cwd} does not exist.`);
@ -108,7 +107,7 @@ export default class Service extends EventEmitter {
this.configInstance = new Config({
cwd: this.cwd,
service: this,
localConfig: this.env === 'development'
localConfig: this.env === 'development',
});
this.userConfig = this.configInstance.getUserConfig();
@ -116,26 +115,25 @@ export default class Service extends EventEmitter {
this.paths = getPaths({
cwd: this.cwd,
config: this.userConfig,
env: this.env
env: this.env,
});
this.program = this.initCommand();
// setup initial plugins
const baseOpts = {
pkg: this.pkg,
cwd: this.cwd
cwd: this.cwd,
};
this.initialPresets = resolvePresets({
...baseOpts,
presets: opts.presets || [],
userConfigPresets: this.userConfig.presets || []
userConfigPresets: this.userConfig.presets || [],
});
this.initialPlugins = resolvePlugins({
...baseOpts,
plugins: opts.plugins || [],
userConfigPlugins: this.userConfig.plugins || []
userConfigPlugins: this.userConfig.plugins || [],
});
}
@ -182,7 +180,7 @@ export default class Service extends EventEmitter {
this.setStage(ServiceStage.pluginReady);
await this.applyPlugins({
key: 'onPluginReady',
type: ApplyPluginsType.event
type: ApplyPluginsType.event,
});
// get config, including:
@ -200,7 +198,7 @@ export default class Service extends EventEmitter {
const paths = await this.applyPlugins({
key: 'modifyPaths',
type: ApplyPluginsType.modify,
initialValue: this.paths
initialValue: this.paths,
});
Object.keys(paths).forEach((key) => {
this.paths[key] = paths[key];
@ -211,14 +209,14 @@ export default class Service extends EventEmitter {
const defaultConfig = await this.applyPlugins({
key: 'modifyDefaultConfig',
type: this.ApplyPluginsType.modify,
initialValue: await this.configInstance.getDefaultConfig()
initialValue: await this.configInstance.getDefaultConfig(),
});
this.config = await this.applyPlugins({
key: 'modifyConfig',
type: this.ApplyPluginsType.modify,
initialValue: this.configInstance.getConfig({
defaultConfig
})
defaultConfig,
}),
});
}
@ -242,16 +240,10 @@ export default class Service extends EventEmitter {
const pluginAPI = new PluginAPI(opts);
// register built-in methods
[
'onPluginReady',
'modifyPaths',
'onStart',
'modifyDefaultConfig',
'modifyConfig'
].forEach((name) => {
['onPluginReady', 'modifyPaths', 'onStart', 'modifyDefaultConfig', 'modifyConfig'].forEach((name) => {
pluginAPI.registerMethod({
name,
exitsError: false
exitsError: false,
});
});
@ -279,15 +271,14 @@ export default class Service extends EventEmitter {
'args',
'hasPlugins',
'hasPresets',
'setConfig'
'setConfig',
'builder',
].includes(prop)
) {
return typeof this[prop] === 'function'
? this[prop].bind(this)
: this[prop];
return typeof this[prop] === 'function' ? this[prop].bind(this) : this[prop];
}
return target[prop];
}
},
});
}
@ -309,24 +300,23 @@ export default class Service extends EventEmitter {
this.registerPlugin(preset);
const { presets, plugins } = await this.applyAPI({
api,
apply
apply,
});
// register extra presets and plugins
if (presets) {
assert(
Array.isArray(presets),
`presets returned from preset ${id} must be Array.`
);
assert(Array.isArray(presets), `presets returned from preset ${id} must be Array.`);
// 插到最前面,下个 while 循环优先执行
this._extraPresets.splice(
0,
0,
...presets.map(path => pathToObj({
type: PluginType.preset,
path,
cwd: this.cwd
}))
...presets.map((path) =>
pathToObj({
type: PluginType.preset,
path,
cwd: this.cwd,
}),
),
);
}
@ -339,42 +329,40 @@ export default class Service extends EventEmitter {
}
if (plugins) {
assert(
Array.isArray(plugins),
`plugins returned from preset ${id} must be Array.`
);
assert(Array.isArray(plugins), `plugins returned from preset ${id} must be Array.`);
this._extraPlugins.push(
...plugins.map(path => pathToObj({
type: PluginType.plugin,
path,
cwd: this.cwd
}))
...plugins.map((path) =>
pathToObj({
type: PluginType.plugin,
path,
cwd: this.cwd,
}),
),
);
}
}
async initPlugin(plugin) {
const { id, key, apply } = plugin;
const api = this.getPluginAPI({
id,
key,
service: this
service: this,
});
// register before apply
this.registerPlugin(plugin);
await this.applyAPI({
api,
apply
apply,
});
}
getPluginOptsWithKey(key) {
return getUserConfigWithKey({
key,
userConfig: this.userConfig
userConfig: this.userConfig,
});
}
@ -424,10 +412,7 @@ export default class Service extends EventEmitter {
switch (opts.type) {
case ApplyPluginsType.add:
if ('initialValue' in opts) {
assert(
Array.isArray(opts.initialValue),
'applyPlugins failed, opts.initialValue must be Array if opts.type is add.'
);
assert(Array.isArray(opts.initialValue), 'applyPlugins failed, opts.initialValue must be Array if opts.type is add.');
}
// eslint-disable-next-line
const tAdd = new AsyncSeriesWaterfallHook(["memo"]);
@ -440,12 +425,12 @@ export default class Service extends EventEmitter {
name: hook.pluginId,
stage: hook.stage || 0,
// @ts-ignore
before: hook.before
before: hook.before,
},
async (memo) => {
const items = await hook.fn(opts.args);
return memo.concat(items);
}
},
);
}
return tAdd.promise(opts.initialValue || []);
@ -461,9 +446,9 @@ export default class Service extends EventEmitter {
name: hook.pluginId,
stage: hook.stage || 0,
// @ts-ignore
before: hook.before
before: hook.before,
},
async memo => hook.fn(memo, opts.args)
async (memo) => hook.fn(memo, opts.args),
);
}
return tModify.promise(opts.initialValue);
@ -479,18 +464,16 @@ export default class Service extends EventEmitter {
name: hook.pluginId,
stage: hook.stage || 0,
// @ts-ignore
before: hook.before
before: hook.before,
},
async () => {
await hook.fn(opts.args);
}
},
);
}
return tEvent.promise();
default:
throw new Error(
`applyPlugin failed, type is not defined or is not matched, got ${opts.type}.`
);
throw new Error(`applyPlugin failed, type is not defined or is not matched, got ${opts.type}.`);
}
}
@ -511,8 +494,8 @@ export default class Service extends EventEmitter {
key: 'onStart',
type: ApplyPluginsType.event,
args: {
args
}
args,
},
});
return this.runCommand({ rawArgv, args });
@ -539,7 +522,10 @@ export default class Service extends EventEmitter {
if (commandOptionConfig.fn) {
c.action(async () => {
await commandOptionConfig.fn({
rawArgv, args, options: c.opts(), program
rawArgv,
args,
options: c.opts(),
program,
});
});
}
@ -551,14 +537,10 @@ export default class Service extends EventEmitter {
async parseCommand() {
this.program.on('--help', () => {
console.log();
console.log(
` Run ${chalk.cyan(
'fes <command> --help'
)} for detailed usage of given command.`
);
console.log(` Run ${chalk.cyan('fes <command> --help')} for detailed usage of given command.`);
console.log();
});
this.program.commands.forEach(c => c.on('--help', () => console.log()));
this.program.commands.forEach((c) => c.on('--help', () => console.log()));
return this.program.parseAsync(process.argv);
}
}

View File

@ -26,7 +26,7 @@ function filterPluginAndPreset(type, pkg) {
.filter(isPluginOrPreset.bind(null, type));
}
function filterBuilder(pkg) {
export function filterBuilder(pkg) {
const builders = Object.keys(pkg.devDependencies || {})
.concat(Object.keys(pkg.dependencies || {}))
.filter((name) => /^@fesjs\/build-/.test(name));

View File

@ -1,6 +1,7 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { resolvePkg } from '@fesjs/utils';
import { resolveInnerDep } from '@fesjs/utils';
import { name } from '../package.json';
const namespace = 'plugin-access';
@ -32,7 +33,7 @@ export default (api) => {
path: absoluteFilePath,
content: Mustache.render(readFileSync(join(__dirname, 'runtime/core.tpl'), 'utf-8'), {
REPLACE_ROLES: JSON.stringify(roles),
lodashPath: resolvePkg('lodash-es'),
lodashPath: resolveInnerDep('lodash-es', api.builder),
}),
});
@ -53,4 +54,10 @@ export default (api) => {
api.addRuntimePluginKey(() => 'access');
api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`);
api.addConfigType(() => ({
source: name,
runtime: ['AccessRuntimeConfig'],
build: ['AccessBuildConfig'],
}));
};

View File

@ -1,6 +1,7 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { winPath } from '@fesjs/utils';
import { name } from '../package.json';
const namespace = 'plugin-layout';
@ -28,13 +29,11 @@ export default (api) => {
const absRuntimeFilePath = join(namespace, 'runtime.js');
api.onGenerateFiles(async () => {
const { name } = api.pkg;
const HAS_LOCALE = api.hasPlugins(['@fesjs/plugin-locale']);
// .fes配置
const userConfig = {
title: name,
title: api.pkg.name,
footer: 'Created by Fes.js',
...(api.config.layout || {}),
};
@ -81,4 +80,10 @@ export default (api) => {
children: routes,
},
]);
api.addConfigType(() => ({
source: name,
runtime: ['LayoutRuntimeConfig'],
build: ['LayoutBuildConfig'],
}));
};

View File

@ -1,7 +1,8 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { resolvePkg } from '@fesjs/utils';
import { resolveInnerDep } from '@fesjs/utils';
import { getLocalesJSON } from './utils';
import { name } from '../package.json';
const namespace = 'plugin-locale';
@ -62,7 +63,7 @@ export default (api) => {
2,
),
BASE_NAVIGATOR: userConfig.baseNavigator,
VUE_I18N_PATH: resolvePkg('vue-i18n'),
VUE_I18N_PATH: resolveInnerDep('vue-i18n', api.builder),
}),
});
@ -81,4 +82,9 @@ export default (api) => {
]);
api.addRuntimePlugin(() => `@@/${absRuntimeFilePath}`);
api.addConfigType(() => ({
source: name,
build: ['LocalBuildConfig'],
}));
};

View File

@ -1,6 +1,7 @@
import { readFileSync } from 'fs';
import { join } from 'path';
import { resolvePkg } from '@fesjs/utils';
import { resolveInnerDep } from '@fesjs/utils';
import { name } from '../package.json';
const namespace = 'plugin-monaco-editor';
@ -47,14 +48,14 @@ export default (api) => {
api.writeTmpFile({
path: absLoaderFilePath,
content: Mustache.render(readFileSync(join(__dirname, 'runtime/loader.tpl'), 'utf-8'), {
MONACO_EDITOR: resolvePkg('monaco-editor'),
MONACO_EDITOR: resolveInnerDep('monaco-editor', api.builder),
}),
});
api.writeTmpFile({
path: absEditorFilePath,
content: Mustache.render(readFileSync(join(__dirname, 'runtime/editor.tpl'), 'utf-8'), {
LODASH_ES: resolvePkg('lodash-es'),
LODASH_ES: resolveInnerDep('lodash-es', api.builder),
}),
});
@ -80,4 +81,9 @@ export default (api) => {
webpackConfig.plugin('monaco-editor').use(require('monaco-editor-webpack-plugin'), [api.config?.monacoEditor || {}]);
return webpackConfig;
});
api.addConfigType(() => ({
source: name,
build: ['MonacoEditorBuildConfig'],
}));
};

View File

@ -44,6 +44,7 @@
},
"dependencies": {
"@fesjs/fes": "^2.0.0",
"@fesjs/build-webpack": "^1.0.0",
"vue": "^3.0.5",
"@fesjs/fes-design": "^0.1.10"
},

View File

@ -44,6 +44,7 @@
},
"dependencies": {
"@fesjs/fes": "^2.0.0",
"@fesjs/build-webpack": "^1.0.0",
"vue": "^3.0.5",
"@fesjs/fes-design": "^0.1.10"
},

View File

@ -1,3 +1,5 @@
import { name } from '../package.json';
export default (api) => {
api.describe({
key: 'qiankun',
@ -14,4 +16,9 @@ export default (api) => {
api.addRuntimePluginKey(() => 'qiankun');
api.registerPlugins([require.resolve('./main'), require.resolve('./micro')]);
api.addConfigType(() => ({
source: name,
build: ['QiankunBuildConfig'],
}));
};

View File

@ -1,6 +1,6 @@
import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
import { resolvePkg } from '@fesjs/utils';
import { resolveInnerDep } from '@fesjs/utils';
import { defaultMainRootId, defaultHistoryType, qiankunStateForMicroModelNamespace } from '../constants';
import modifyRoutes from './modifyRoutes';
@ -39,24 +39,20 @@ export default function (api) {
content: Mustache.render(readFileSync(join(__dirname, 'runtime/MicroApp.tpl'), 'utf-8'), {
qiankunStateForMicroModelNamespace,
HAS_PLUGIN_MODEL: HAS_PLUGIN_MODEL && existsSync(winPath(join(api.paths.absSrcPath, 'models/qiankunStateForMicro.js'))),
QIANKUN: resolvePkg('qiankun'),
LODASH_ES: resolvePkg('lodash-es'),
QIANKUN: resolveInnerDep('qiankun', api.builder),
LODASH_ES: resolveInnerDep('lodash-es', api.builder),
}),
});
api.writeTmpFile({
path: absMicroAppWithMemoHistoryPath,
content: Mustache.render(readFileSync(join(__dirname, 'runtime/MicroAppWithMemoHistory.tpl'), 'utf-8'), {}),
});
api.writeTmpFile({
path: absRuntimePath,
content: readFileSync(join(__dirname, 'runtime/runtime.tpl'), 'utf-8'),
});
api.writeTmpFile({
path: absGetMicroAppRouteCompPath,
content: readFileSync(join(__dirname, 'runtime/getMicroAppRouteComponent.tpl'), 'utf-8'),
api.copyTmpFiles({
namespace,
path: join(__dirname, 'runtime'),
ignore: ['.tpl'],
});
const { main: options } = api.config?.qiankun || {};

View File

@ -2,12 +2,15 @@ import { defaultHistoryType } from '../constants';
function getMicroApp(options) {
const { key, microAppName, masterHistoryType, base, namespace, ...normalizedRouteProps } = options;
return `(() => {
const { getMicroAppRouteComponent } = require('@@/${namespace}/getMicroAppRouteComponent');
return getMicroAppRouteComponent({key: '${key}', appName: '${microAppName}', base: '${base}', masterHistoryType: '${masterHistoryType}', routeProps: ${JSON.stringify(
return `() => {
return new Promise((resolve)=>{
import('@@/${namespace}/getMicroAppRouteComponent').then(({ getMicroAppRouteComponent })=>{
resolve(getMicroAppRouteComponent({ key: '${key}', appName: '${microAppName}', base: '${base}', masterHistoryType: '${masterHistoryType}', routeProps: ${JSON.stringify(
normalizedRouteProps,
)} })
})()`;
)} }))
})
})
}`;
}
function modifyRoutesWithAttachMode({ routes, masterHistoryType, base, namespace }) {

View File

@ -8,7 +8,7 @@ import {
onMounted,
} from "vue";
import { loadMicroApp } from "{{{QIANKUN}}}";
import {mergeWith} from "{{{LODASH_ES}}}";
import { mergeWith } from "{{{LODASH_ES}}}";
// eslint-disable-next-line import/extensions
import { getMasterOptions } from "./masterOptions";
import { onBeforeRouteLeave } from "@@/core/coreExports";

View File

@ -1,22 +1,19 @@
import {
defineComponent, isRef, watch
} from 'vue';
import { defineComponent, watch } from 'vue';
// eslint-disable-next-line import/extensions
import { MicroApp } from './MicroApp';
export const MicroAppWithMemoHistory = defineComponent({
components: {
MicroApp
MicroApp,
},
props: {
name: {
type: String,
required: true
required: true,
},
settings: Object,
lifeCycles: Object,
url: String
url: String,
},
setup(props, { attrs }) {
let microRouter;
@ -24,9 +21,12 @@ export const MicroAppWithMemoHistory = defineComponent({
microRouter = router;
microRouter.push(props.url);
};
watch(()=>props.url, () => {
microRouter.push(props.url);
});
watch(
() => props.url,
() => {
microRouter.push(props.url);
},
);
return () => <MicroApp onRouterInit={onRouterInit} {...props} {...attrs}></MicroApp>;
}
},
});

View File

@ -0,0 +1,6 @@
// eslint-disable-next-line import/extensions
import { MicroApp } from './MicroApp';
export function getMicroAppRouteComponent({ key, appName, base, masterHistoryType, routeProps }) {
return <MicroApp key={key} base={base} masterHistoryType={masterHistoryType} name={appName} {...routeProps} />;
}

View File

@ -1,12 +0,0 @@
import { MicroApp } from './MicroApp';
export function getMicroAppRouteComponent({
key,
appName,
base,
masterHistoryType,
routeProps
}) {
return <MicroApp key={key} base={base} masterHistoryType={masterHistoryType} name={appName} {...routeProps} />;
}

View File

@ -1,7 +1,7 @@
import { Logger } from '@fesjs/compiler';
import { readFileSync } from 'fs';
import { join } from 'path';
import { resolvePkg } from '@fesjs/utils';
import { resolveInnerDep } from '@fesjs/utils';
import { name } from '../package.json';
const logger = new Logger('fes:plugin-request');
@ -45,7 +45,7 @@ export default (api) => {
content: requestTemplate
.replace('REPLACE_DATA_FIELD', JSON.stringify(dataField))
.replace('REPLACE_BASE', base || '')
.replace('AXIOS_PATH', resolvePkg('axios')),
.replace('AXIOS_PATH', resolveInnerDep('axios', api.builder)),
});
});
@ -67,13 +67,9 @@ export default (api) => {
},
]);
api.addRuntimeType(() => ({
api.addConfigType(() => ({
source: name,
specifier: ['RequestRuntimeConfig'],
}));
api.addBuildType(() => ({
source: name,
specifier: ['RequestBuildConfig'],
runtime: ['RequestRuntimeConfig'],
build: ['RequestBuildConfig'],
}));
};

View File

@ -49,8 +49,8 @@ export default (api) => {
return memo;
});
api.addBuildType(() => ({
api.addConfigType(() => ({
source: name,
specifier: ['WindicssBuildConfig'],
build: ['WindicssBuildConfig'],
}));
};

View File

@ -1,17 +1,14 @@
function importsToStr(imports) {
return imports.map((imp) => {
const { source, specifier } = imp;
if (specifier) {
return `import {${specifier.join(', ')}} from '${source}';`;
}
return '';
const { source, build = [], runtime = [] } = imp;
return `import {${build.concat(runtime).join(', ')}} from '${source}';`;
});
}
function genTypeContent(name, imports) {
function genTypeContent(imports) {
return {
TYP_NAME: name,
TYPES: imports.reduce((previousValue, currentValue) => previousValue.concat(currentValue.specifier || []), []).join(' & '),
RUNTIME_TYPES: imports.reduce((previousValue, currentValue) => previousValue.concat(currentValue.runtime || []), []).join(' & '),
BUILD_TYPES: imports.reduce((previousValue, currentValue) => previousValue.concat(currentValue.build || []), []).join(' & '),
imports: importsToStr(imports).join('\n'),
};
}
@ -22,31 +19,20 @@ export default function (api) {
} = api;
api.onGenerateFiles(async () => {
const runtimeTypeName = 'PluginRuntimeConfig';
const buildTypeName = 'PluginBuildConfig';
const typeTpl = `
{{{ imports }}}
export type {{{TYP_NAME}}} = {{{TYPES}}}
export type PluginRuntimeConfig = {{{RUNTIME_TYPES}}};
export type PluginBuildConfig = {{{BUILD_TYPES}}};
`;
const runtimeImportSources = await api.applyPlugins({
key: 'addRuntimeType',
const importSources = await api.applyPlugins({
key: 'addConfigType',
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)),
path: 'configType.d.ts',
content: Mustache.render(typeTpl, genTypeContent(importSources)),
});
});
}

View File

@ -16,8 +16,7 @@ export default function (api) {
'addEntryCode',
'modifyRoutes',
'addRuntimeType',
'addBuildType',
'addConfigType',
'addTmpGenerateWatcherPaths',

View File

@ -86,7 +86,6 @@ function getRouteMeta(content) {
let cacheGenRoutes = {};
// TODO 约定 layout 目录作为布局文件夹,
const genRoutes = function (parentRoutes, path, parentRoutePath, config) {
const dirList = readdirSync(path);
const hasLayout = checkHasLayout(path);
@ -231,45 +230,33 @@ const getRoutesJSON = function ({ routes, config }) {
// 因为要往 routes 里加无用的信息,所以必须 deep clone 一下,避免污染
const clonedRoutes = lodash.cloneDeep(routes);
const importList = [];
function replacer(key, value) {
switch (key) {
case 'component':
if (isFunctionComponent(value)) return value;
if (config.dynamicImport) {
// TODO 针对目录进行 chunk 划分import(/* webpackChunkName: "group-user" */ './UserDetails.vue')
return `() => import('${value}')`;
}
return genComponentName(value, config);
default:
return value;
if (key !== 'component') {
return value;
}
if (isFunctionComponent(value)) return value;
if (config.dynamicImport) {
// TODO 针对目录进行 chunk 划分import(/* webpackChunkName: "group-user" */ './UserDetails.vue')
return `() => import('${value}')`;
}
const componentName = genComponentName(value, config);
importList.push(`import ${componentName} from '${value}'`);
return componentName;
}
return JSON.stringify(clonedRoutes, replacer, 2)
const routesJSON = JSON.stringify(clonedRoutes, replacer, 2)
.replace(/"component": ("(.+?)")/g, (global, m1, m2) => `"component": ${m2.replace(/\^/g, '"')}`)
.replace(/\\r\\n/g, '\r\n')
.replace(/\\n/g, '\r\n');
return {
importList,
routesJSON,
};
};
function genComponentImportExpression(routes, config) {
if (config.dynamicImport) {
return [];
}
const result = [];
for (const routeConfig of routes) {
if (routeConfig.children) {
result.push(...genComponentImportExpression(routeConfig.children, config));
}
if (routeConfig.component && !isFunctionComponent(routeConfig.component)) {
result.push(`import ${genComponentName(routeConfig.component, config)} from '${routeConfig.component}';`);
}
}
return result;
}
export default function (api) {
api.describe({
key: 'router',
@ -326,12 +313,12 @@ export default function (api) {
api.onGenerateFiles(async () => {
const routesTpl = readFileSync(join(__dirname, 'template/routes.tpl'), 'utf-8');
const routes = await api.getRoutes();
const routes = await api.getRoutesJSON();
api.writeTmpFile({
path: absCoreFilePath,
content: Mustache.render(routesTpl, {
COMPONENTS_IMPORT: genComponentImportExpression(routes, api.config).join('\n'),
routes: await api.getRoutesJSON(),
COMPONENTS_IMPORT: routes.importList.join('\n'),
routes: routes.routesJSON,
}),
});

View File

@ -44,6 +44,6 @@ export default defineBuildConfig({
}
}
}
}
},
});

View File

@ -29,19 +29,19 @@
}
},
"include": [
"*.js",
".fes.js",
"src/**/*",
"tests/**/*",
"test/**/*",
"__test__/**/*",
"typings/**/*",
"config/**/*",
"src/.fes/runtime.d.ts"
"src/.fes/configType.d.ts"
],
"exclude": [
"build",
"dist",
"scripts",
"webpack",
"jest"
"jest",
"node_modules"
]
}

View File

@ -31,7 +31,8 @@
"config/**/*",
".eslintrc.js",
".stylelintrc.js",
".prettierrc.js"
".prettierrc.js",
"src/.fes/configType.d.ts"
],
"exclude": ["node_modules", "build", "dist", "scripts", "src/.fes/*", "webpack", "jest"]
}

View File

@ -20,6 +20,7 @@ import Generator from './Generator';
import winPath from './winPath';
import delay from './delay';
import resolvePkg from './resolvePkg';
import resolveInnerDep from './resolveInnerDep';
import compatESModuleRequire from './compatESModuleRequire';
import cleanRequireCache from './cleanRequireCache';
import parseRequireDeps from './parseRequireDeps';
@ -47,4 +48,16 @@ export {
generator,
};
export { Generator, winPath, delay, compatESModuleRequire, cleanRequireCache, parseRequireDeps, mergeConfig, resolvePkg, generateFiles, getAppEntryPath };
export {
Generator,
winPath,
delay,
compatESModuleRequire,
cleanRequireCache,
parseRequireDeps,
mergeConfig,
resolvePkg,
resolveInnerDep,
generateFiles,
getAppEntryPath,
};

View File

@ -0,0 +1,12 @@
import { dirname } from 'path';
import winPath from './winPath';
const resolvePkg = (pkgName, builder) => {
const pkgPath = dirname(require.resolve(`${pkgName}/package.json`));
if (builder.isVite) {
return winPath(pkgPath.replace('/', `${builder.innerDepPrefix}/`));
}
return winPath(pkgPath);
};
export default resolvePkg;

View File

@ -1,8 +1,8 @@
import { Component, DefineComponent, App } from 'vue';
import { RouteRecordRaw, Router } from 'vue-router';
import { Plugin } from '@fesjs/runtime';
import { PluginRuntimeConfig } from '@@/runtime';
import { PluginBuildConfig } from '@@/build';
// @ts-ignore
import type { PluginRuntimeConfig, PluginBuildConfig } from '@@/configType';
// @ts-ignore
export * from '@@/core/coreExports';