mirror of
https://github.com/WeBankFinTech/fes.js.git
synced 2025-04-06 03:59:53 +08:00
feat: 去掉文件名大写
This commit is contained in:
parent
67903dab8b
commit
05d994e50d
@ -60,7 +60,8 @@ export function pathToObj({ path, cwd }) {
|
||||
if (pkgJSONPath) {
|
||||
// eslint-disable-next-line
|
||||
pkg = require(pkgJSONPath);
|
||||
isPkgPlugin = winPath(join(dirname(pkgJSONPath), pkg.main || 'index.js')) === winPath(path);
|
||||
isPkgPlugin = winPath(join(dirname(pkgJSONPath), pkg.main || 'index.js'))
|
||||
=== winPath(path);
|
||||
}
|
||||
|
||||
let id;
|
||||
@ -107,7 +108,6 @@ export function resolvePlugins(opts) {
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
export function isValidPlugin(plugin) {
|
||||
return plugin.id && plugin.key && plugin.apply;
|
||||
}
|
||||
|
@ -1,10 +1,5 @@
|
||||
import {
|
||||
existsSync
|
||||
} from 'fs';
|
||||
import {
|
||||
extname,
|
||||
join
|
||||
} from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
import { extname, join } from 'path';
|
||||
import {
|
||||
chalk,
|
||||
chokidar,
|
||||
@ -18,9 +13,7 @@ import {
|
||||
} from '@umijs/utils';
|
||||
import assert from 'assert';
|
||||
import joi from 'joi';
|
||||
import {
|
||||
ServiceStage
|
||||
} from '../Service/enums';
|
||||
import { ServiceStage } from '../service/enums';
|
||||
import {
|
||||
getUserConfigWithKey,
|
||||
updateUserConfigWithKey
|
||||
@ -28,10 +21,7 @@ import {
|
||||
import isEqual from './utils/isEqual';
|
||||
import mergeDefault from './utils/mergeDefault';
|
||||
|
||||
const CONFIG_FILES = [
|
||||
'.fes.js',
|
||||
'config/config.js'
|
||||
];
|
||||
const CONFIG_FILES = ['.fes.js', 'config/config.js'];
|
||||
|
||||
// TODO:
|
||||
// 1. custom config file
|
||||
@ -57,10 +47,7 @@ export default class Config {
|
||||
|
||||
// collect default config
|
||||
const defaultConfig = pluginIds.reduce((memo, pluginId) => {
|
||||
const {
|
||||
key,
|
||||
config = {}
|
||||
} = this.service.plugins[pluginId];
|
||||
const { key, config = {} } = this.service.plugins[pluginId];
|
||||
if ('default' in config) memo[key] = config.default;
|
||||
return memo;
|
||||
}, {});
|
||||
@ -68,26 +55,23 @@ export default class Config {
|
||||
return defaultConfig;
|
||||
}
|
||||
|
||||
getConfig({
|
||||
defaultConfig
|
||||
}) {
|
||||
getConfig({ defaultConfig }) {
|
||||
assert(
|
||||
this.service.stage >= ServiceStage.pluginReady,
|
||||
'Config.getConfig() failed, it should not be executed before plugin is ready.',
|
||||
'Config.getConfig() failed, it should not be executed before plugin is ready.'
|
||||
);
|
||||
|
||||
const userConfig = this.getUserConfig();
|
||||
// 用于提示用户哪些 key 是未定义的
|
||||
// TODO: 考虑不排除 false 的 key
|
||||
const userConfigKeys = Object.keys(userConfig).filter(key => userConfig[key] !== false);
|
||||
const userConfigKeys = Object.keys(userConfig).filter(
|
||||
key => userConfig[key] !== false
|
||||
);
|
||||
|
||||
// get config
|
||||
const pluginIds = Object.keys(this.service.plugins);
|
||||
pluginIds.forEach((pluginId) => {
|
||||
const {
|
||||
key,
|
||||
config = {}
|
||||
} = this.service.plugins[pluginId];
|
||||
const { key, config = {} } = this.service.plugins[pluginId];
|
||||
// recognize as key if have schema config
|
||||
if (!config.schema) return;
|
||||
|
||||
@ -102,14 +86,12 @@ export default class Config {
|
||||
const schema = config.schema(joi);
|
||||
assert(
|
||||
joi.isSchema(schema),
|
||||
`schema return from plugin ${pluginId} is not valid schema.`,
|
||||
`schema return from plugin ${pluginId} is not valid schema.`
|
||||
);
|
||||
const {
|
||||
error
|
||||
} = schema.validate(value);
|
||||
const { error } = schema.validate(value);
|
||||
if (error) {
|
||||
const e = new Error(
|
||||
`Validate config "${key}" failed, ${error.message}`,
|
||||
`Validate config "${key}" failed, ${error.message}`
|
||||
);
|
||||
e.stack = error.stack;
|
||||
throw e;
|
||||
@ -137,7 +119,9 @@ export default class Config {
|
||||
|
||||
if (userConfigKeys.length) {
|
||||
const keys = userConfigKeys.length > 1 ? 'keys' : 'key';
|
||||
throw new Error(`Invalid config ${keys}: ${userConfigKeys.join(', ')}`);
|
||||
throw new Error(
|
||||
`Invalid config ${keys}: ${userConfigKeys.join(', ')}`
|
||||
);
|
||||
}
|
||||
|
||||
return userConfig;
|
||||
@ -153,11 +137,11 @@ export default class Config {
|
||||
if (process.env.FES_ENV) {
|
||||
const envConfigFileName = this.addAffix(
|
||||
configFile,
|
||||
process.env.FES_ENV,
|
||||
process.env.FES_ENV
|
||||
);
|
||||
const fileNameWithoutExt = envConfigFileName.replace(
|
||||
extname(envConfigFileName),
|
||||
'',
|
||||
''
|
||||
);
|
||||
envConfigFile = getFile({
|
||||
base: this.cwd,
|
||||
@ -166,7 +150,7 @@ export default class Config {
|
||||
}).filename;
|
||||
if (!envConfigFile) {
|
||||
throw new Error(
|
||||
`get user config failed, ${envConfigFile} does not exist, but process.env.FES_ENV is set to ${process.env.FES_ENV}.`,
|
||||
`get user config failed, ${envConfigFile} does not exist, but process.env.FES_ENV is set to ${process.env.FES_ENV}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -203,7 +187,7 @@ export default class Config {
|
||||
|
||||
requireConfigs(configFiles) {
|
||||
// eslint-disable-next-line
|
||||
return configFiles.map(f => compatESModuleRequire(require(f)));
|
||||
return configFiles.map((f) => compatESModuleRequire(require(f)));
|
||||
}
|
||||
|
||||
mergeConfig(...configs) {
|
||||
@ -266,10 +250,7 @@ export default class Config {
|
||||
const pluginChanged = [];
|
||||
const valueChanged = [];
|
||||
Object.keys(this.service.plugins).forEach((pluginId) => {
|
||||
const {
|
||||
key,
|
||||
config = {}
|
||||
} = this.service.plugins[pluginId];
|
||||
const { key, config = {} } = this.service.plugins[pluginId];
|
||||
// recognize as key if have schema config
|
||||
if (!config.schema) return;
|
||||
if (!isEqual(newUserConfig[key], userConfig[key])) {
|
||||
@ -277,7 +258,10 @@ export default class Config {
|
||||
key,
|
||||
pluginId
|
||||
};
|
||||
if (newUserConfig[key] === false || userConfig[key] === false) {
|
||||
if (
|
||||
newUserConfig[key] === false
|
||||
|| userConfig[key] === false
|
||||
) {
|
||||
pluginChanged.push(changed);
|
||||
} else {
|
||||
valueChanged.push(changed);
|
17
packages/fes-core/src/config/utils/configUtils.js
Normal file
17
packages/fes-core/src/config/utils/configUtils.js
Normal file
@ -0,0 +1,17 @@
|
||||
import { lodash } from '@umijs/utils';
|
||||
import set from 'set-value';
|
||||
|
||||
export function updateUserConfigWithKey({
|
||||
key,
|
||||
value,
|
||||
userConfig
|
||||
}) {
|
||||
set(userConfig, key, value);
|
||||
}
|
||||
|
||||
export function getUserConfigWithKey({
|
||||
key,
|
||||
userConfig
|
||||
}) {
|
||||
return lodash.get(userConfig, key);
|
||||
}
|
16
packages/fes-core/src/config/utils/isEqual.js
Normal file
16
packages/fes-core/src/config/utils/isEqual.js
Normal file
@ -0,0 +1,16 @@
|
||||
import { lodash } from '@umijs/utils';
|
||||
|
||||
function funcToStr(obj) {
|
||||
if (typeof obj === 'function') return obj.toString();
|
||||
if (lodash.isPlainObject(obj)) {
|
||||
return Object.keys(obj).reduce((memo, key) => {
|
||||
memo[key] = funcToStr(obj[key]);
|
||||
return memo;
|
||||
}, {});
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
export default function (a, b) {
|
||||
return lodash.isEqual(funcToStr(a), funcToStr(b));
|
||||
}
|
9
packages/fes-core/src/config/utils/mergeDefault.js
Normal file
9
packages/fes-core/src/config/utils/mergeDefault.js
Normal file
@ -0,0 +1,9 @@
|
||||
import { deepmerge, lodash } from '@umijs/utils';
|
||||
|
||||
|
||||
export default ({ defaultConfig, config }) => {
|
||||
if (lodash.isPlainObject(defaultConfig) && lodash.isPlainObject(config)) {
|
||||
return deepmerge(defaultConfig, config);
|
||||
}
|
||||
return typeof config !== 'undefined' ? config : defaultConfig;
|
||||
};
|
@ -1,11 +1,11 @@
|
||||
|
||||
|
||||
import Config from './Config/Config';
|
||||
import Service from './Service/Service';
|
||||
import PluginAPI from './Service/PluginAPI';
|
||||
import Config from './config';
|
||||
import Service from './service';
|
||||
import PluginAPI from './service/pluginAPI';
|
||||
import Logger from './logger/logger';
|
||||
import { PluginType } from './Service/enums';
|
||||
import { isPlugin } from './Service/utils/pluginUtils';
|
||||
import { PluginType } from './service/enums';
|
||||
import { isPlugin } from './service/utils/pluginUtils';
|
||||
|
||||
export * from './route';
|
||||
|
||||
|
32
packages/fes-core/src/service/enums.js
Normal file
32
packages/fes-core/src/service/enums.js
Normal file
@ -0,0 +1,32 @@
|
||||
export const PluginType = {
|
||||
preset: 'preset',
|
||||
plugin: 'plugin'
|
||||
};
|
||||
|
||||
export const ServiceStage = {
|
||||
uninitialized: 0,
|
||||
constructor: 1,
|
||||
init: 2,
|
||||
initPlugins: 3,
|
||||
initHooks: 4,
|
||||
pluginReady: 5,
|
||||
getConfig: 6,
|
||||
getPaths: 7,
|
||||
run: 8
|
||||
};
|
||||
|
||||
export const ConfigChangeType = {
|
||||
reload: 'reload',
|
||||
regenerateTmpFiles: 'regenerateTmpFiles'
|
||||
};
|
||||
|
||||
export const ApplyPluginsType = {
|
||||
add: 'add',
|
||||
modify: 'modify',
|
||||
event: 'event'
|
||||
};
|
||||
|
||||
export const EnableBy = {
|
||||
register: 'register',
|
||||
config: 'config'
|
||||
};
|
37
packages/fes-core/src/service/getPaths.js
Normal file
37
packages/fes-core/src/service/getPaths.js
Normal file
@ -0,0 +1,37 @@
|
||||
import { join } from 'path';
|
||||
import { existsSync, statSync } from 'fs';
|
||||
import { lodash, winPath } from '@umijs/utils';
|
||||
|
||||
function isDirectoryAndExist(path) {
|
||||
return existsSync(path) && statSync(path).isDirectory();
|
||||
}
|
||||
|
||||
function normalizeWithWinPath(obj) {
|
||||
return lodash.mapValues(obj, value => winPath(value));
|
||||
}
|
||||
|
||||
export default function getServicePaths({
|
||||
cwd,
|
||||
config,
|
||||
env
|
||||
}) {
|
||||
let absSrcPath = cwd;
|
||||
if (isDirectoryAndExist(join(cwd, 'src'))) {
|
||||
absSrcPath = join(cwd, 'src');
|
||||
}
|
||||
const absPagesPath = config.singular
|
||||
? join(absSrcPath, 'page')
|
||||
: join(absSrcPath, 'pages');
|
||||
|
||||
const tmpDir = ['.fes', env !== 'development' && env]
|
||||
.filter(Boolean)
|
||||
.join('-');
|
||||
return normalizeWithWinPath({
|
||||
cwd,
|
||||
absNodeModulesPath: join(cwd, 'node_modules'),
|
||||
absOutputPath: join(cwd, config.outputPath || './dist'),
|
||||
absSrcPath,
|
||||
absPagesPath,
|
||||
absTmpPath: join(absSrcPath, tmpDir)
|
||||
});
|
||||
}
|
@ -1,33 +1,21 @@
|
||||
import {
|
||||
join
|
||||
} from 'path';
|
||||
import {
|
||||
EventEmitter
|
||||
} from 'events';
|
||||
import { join } from 'path';
|
||||
import { EventEmitter } from 'events';
|
||||
import assert from 'assert';
|
||||
import {
|
||||
AsyncSeriesWaterfallHook
|
||||
} from 'tapable';
|
||||
import {
|
||||
existsSync
|
||||
} from 'fs';
|
||||
import { AsyncSeriesWaterfallHook } from 'tapable';
|
||||
import { existsSync } from 'fs';
|
||||
import { BabelRegister } from '@umijs/utils';
|
||||
import {
|
||||
resolvePlugins
|
||||
} from './utils/pluginUtils';
|
||||
import { resolvePlugins } from './utils/pluginUtils';
|
||||
import loadDotEnv from './utils/loadDotEnv';
|
||||
import isPromise from './utils/isPromise';
|
||||
import PluginAPI from './PluginAPI';
|
||||
import PluginAPI from './pluginAPI';
|
||||
import {
|
||||
ApplyPluginsType,
|
||||
ConfigChangeType,
|
||||
EnableBy,
|
||||
ServiceStage
|
||||
} from './enums';
|
||||
import Config from '../Config/Config';
|
||||
import {
|
||||
getUserConfigWithKey
|
||||
} from '../Config/utils/configUtils';
|
||||
import Config from '../config';
|
||||
import { getUserConfigWithKey } from '../config/utils/configUtils';
|
||||
import getPaths from './getPaths';
|
||||
|
||||
// TODO
|
||||
@ -137,7 +125,7 @@ export default class Service extends EventEmitter {
|
||||
resolvePackage() {
|
||||
try {
|
||||
// eslint-disable-next-line
|
||||
return require(join(this.cwd, 'package.json'));
|
||||
return require(join(this.cwd, "package.json"));
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
@ -161,9 +149,7 @@ export default class Service extends EventEmitter {
|
||||
Object.keys(this.hooksByPluginId).forEach((id) => {
|
||||
const hooks = this.hooksByPluginId[id];
|
||||
hooks.forEach((hook) => {
|
||||
const {
|
||||
key
|
||||
} = hook;
|
||||
const { key } = hook;
|
||||
hook.pluginId = id;
|
||||
this.hooks[key] = (this.hooks[key] || []).concat(hook);
|
||||
});
|
||||
@ -188,11 +174,11 @@ export default class Service extends EventEmitter {
|
||||
if (this.config.outputPath) {
|
||||
this.paths.absOutputPath = join(this.cwd, this.config.outputPath);
|
||||
}
|
||||
const paths = (await this.applyPlugins({
|
||||
const paths = await this.applyPlugins({
|
||||
key: 'modifyPaths',
|
||||
type: ApplyPluginsType.modify,
|
||||
initialValue: this.paths
|
||||
}));
|
||||
});
|
||||
Object.keys(paths).forEach((key) => {
|
||||
this.paths[key] = paths[key];
|
||||
});
|
||||
@ -283,11 +269,7 @@ export default class Service extends EventEmitter {
|
||||
}
|
||||
|
||||
async initPlugin(plugin) {
|
||||
const {
|
||||
id,
|
||||
key,
|
||||
apply
|
||||
} = plugin;
|
||||
const { id, key, apply } = plugin;
|
||||
|
||||
const api = this.getPluginAPI({
|
||||
id,
|
||||
@ -318,10 +300,7 @@ export default class Service extends EventEmitter {
|
||||
// api.skipPlugins() 的插件
|
||||
if (this.skipPluginIds.has(pluginId)) return false;
|
||||
|
||||
const {
|
||||
key,
|
||||
enableBy
|
||||
} = this.plugins[pluginId];
|
||||
const { key, enableBy } = this.plugins[pluginId];
|
||||
|
||||
// 手动设置为 false
|
||||
if (this.userConfig[key] === false) return false;
|
||||
@ -354,16 +333,17 @@ export default class Service extends EventEmitter {
|
||||
if ('initialValue' in opts) {
|
||||
assert(
|
||||
Array.isArray(opts.initialValue),
|
||||
'applyPlugins failed, opts.initialValue must be Array if opts.type is add.',
|
||||
'applyPlugins failed, opts.initialValue must be Array if opts.type is add.'
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line
|
||||
const tAdd = new AsyncSeriesWaterfallHook(['memo']);
|
||||
const tAdd = new AsyncSeriesWaterfallHook(["memo"]);
|
||||
for (const hook of hooks) {
|
||||
if (!this.isPluginEnable(hook.pluginId)) {
|
||||
continue;
|
||||
}
|
||||
tAdd.tapPromise({
|
||||
tAdd.tapPromise(
|
||||
{
|
||||
name: hook.pluginId,
|
||||
stage: hook.stage || 0,
|
||||
// @ts-ignore
|
||||
@ -372,33 +352,37 @@ export default class Service extends EventEmitter {
|
||||
async (memo) => {
|
||||
const items = await hook.fn(opts.args);
|
||||
return memo.concat(items);
|
||||
},);
|
||||
}
|
||||
);
|
||||
}
|
||||
return tAdd.promise(opts.initialValue || []);
|
||||
case ApplyPluginsType.modify:
|
||||
// eslint-disable-next-line
|
||||
const tModify = new AsyncSeriesWaterfallHook(['memo']);
|
||||
const tModify = new AsyncSeriesWaterfallHook(["memo"]);
|
||||
for (const hook of hooks) {
|
||||
if (!this.isPluginEnable(hook.pluginId)) {
|
||||
continue;
|
||||
}
|
||||
tModify.tapPromise({
|
||||
tModify.tapPromise(
|
||||
{
|
||||
name: hook.pluginId,
|
||||
stage: hook.stage || 0,
|
||||
// @ts-ignore
|
||||
before: hook.before
|
||||
},
|
||||
async memo => hook.fn(memo, opts.args),);
|
||||
async memo => hook.fn(memo, opts.args)
|
||||
);
|
||||
}
|
||||
return tModify.promise(opts.initialValue);
|
||||
case ApplyPluginsType.event:
|
||||
// eslint-disable-next-line
|
||||
const tEvent = new AsyncSeriesWaterfallHook(['_']);
|
||||
const tEvent = new AsyncSeriesWaterfallHook(["_"]);
|
||||
for (const hook of hooks) {
|
||||
if (!this.isPluginEnable(hook.pluginId)) {
|
||||
continue;
|
||||
}
|
||||
tEvent.tapPromise({
|
||||
tEvent.tapPromise(
|
||||
{
|
||||
name: hook.pluginId,
|
||||
stage: hook.stage || 0,
|
||||
// @ts-ignore
|
||||
@ -406,20 +390,18 @@ export default class Service extends EventEmitter {
|
||||
},
|
||||
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}.`,
|
||||
`applyPlugin failed, type is not defined or is not matched, got ${opts.type}.`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async run({
|
||||
name,
|
||||
args = {}
|
||||
}) {
|
||||
async run({ name, args = {} }) {
|
||||
args._ = args._ || [];
|
||||
// shift the command itself
|
||||
if (args._[0] === name) args._.shift();
|
||||
@ -442,10 +424,7 @@ export default class Service extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
async runCommand({
|
||||
name,
|
||||
args = {}
|
||||
}) {
|
||||
async runCommand({ name, args = {} }) {
|
||||
assert(this.stage >= ServiceStage.init, 'service is not initialized.');
|
||||
|
||||
args._ = args._ || [];
|
||||
@ -457,9 +436,7 @@ export default class Service extends EventEmitter {
|
||||
: this.commands[name];
|
||||
assert(command, `run command failed, command ${name} does not exists.`);
|
||||
|
||||
const {
|
||||
fn
|
||||
} = command;
|
||||
const { fn } = command;
|
||||
return fn({
|
||||
args
|
||||
});
|
134
packages/fes-core/src/service/pluginAPI.js
Normal file
134
packages/fes-core/src/service/pluginAPI.js
Normal file
@ -0,0 +1,134 @@
|
||||
import assert from 'assert';
|
||||
import * as utils from '@umijs/utils';
|
||||
import { isValidPlugin, pathToObj } from './utils/pluginUtils';
|
||||
import { EnableBy, PluginType, ServiceStage } from './enums';
|
||||
import Logger from '../logger/logger';
|
||||
// TODO
|
||||
// 标准化 logger
|
||||
export default class PluginAPI {
|
||||
constructor(opts) {
|
||||
this.id = opts.id;
|
||||
this.key = opts.key;
|
||||
this.service = opts.service;
|
||||
this.utils = utils;
|
||||
this.logger = new Logger(`fes:plugin:${this.id || this.key}`);
|
||||
}
|
||||
|
||||
// TODO: reversed keys
|
||||
describe({
|
||||
id,
|
||||
key,
|
||||
config,
|
||||
enableBy
|
||||
} = {}) {
|
||||
const { plugins } = this.service;
|
||||
// this.id and this.key is generated automatically
|
||||
// so we need to diff first
|
||||
if (id && this.id !== id) {
|
||||
if (plugins[id]) {
|
||||
const name = plugins[id].isPreset ? 'preset' : 'plugin';
|
||||
throw new Error(
|
||||
`api.describe() failed, ${name} ${id} is already registered by ${plugins[id].path}.`,
|
||||
);
|
||||
}
|
||||
plugins[id] = plugins[this.id];
|
||||
plugins[id].id = id;
|
||||
delete plugins[this.id];
|
||||
this.id = id;
|
||||
}
|
||||
if (key && this.key !== key) {
|
||||
this.key = key;
|
||||
plugins[this.id].key = key;
|
||||
}
|
||||
|
||||
if (config) {
|
||||
plugins[this.id].config = config;
|
||||
}
|
||||
|
||||
plugins[this.id].enableBy = enableBy || EnableBy.register;
|
||||
}
|
||||
|
||||
register(hook) {
|
||||
assert(
|
||||
hook.key && typeof hook.key === 'string',
|
||||
`api.register() failed, hook.key must supplied and should be string, but got ${hook.key}.`,
|
||||
);
|
||||
assert(
|
||||
hook.fn && typeof hook.fn === 'function',
|
||||
`api.register() failed, hook.fn must supplied and should be function, but got ${hook.fn}.`,
|
||||
);
|
||||
this.service.hooksByPluginId[this.id] = (
|
||||
this.service.hooksByPluginId[this.id] || []
|
||||
).concat(hook);
|
||||
}
|
||||
|
||||
registerCommand(command) {
|
||||
const { name, alias } = command;
|
||||
assert(
|
||||
!this.service.commands[name],
|
||||
`api.registerCommand() failed, the command ${name} is exists.`,
|
||||
);
|
||||
this.service.commands[name] = command;
|
||||
if (alias) {
|
||||
this.service.commands[alias] = name;
|
||||
}
|
||||
}
|
||||
|
||||
// 在 preset 初始化阶段放后面,在插件注册阶段放前面
|
||||
registerPlugins(plugins) {
|
||||
assert(
|
||||
this.service.stage === ServiceStage.initPresets
|
||||
|| this.service.stage === ServiceStage.initPlugins,
|
||||
'api.registerPlugins() failed, it should only be used in registering stage.',
|
||||
);
|
||||
assert(
|
||||
Array.isArray(plugins),
|
||||
'api.registerPlugins() failed, plugins must be Array.',
|
||||
);
|
||||
const extraPlugins = plugins.map(plugin => (isValidPlugin(plugin)
|
||||
? (plugin)
|
||||
: pathToObj({
|
||||
type: PluginType.plugin,
|
||||
path: plugin,
|
||||
cwd: this.service.cwd
|
||||
})));
|
||||
if (this.service.stage === ServiceStage.initPresets) {
|
||||
this.service._extraPlugins.push(...extraPlugins);
|
||||
} else {
|
||||
this.service._extraPlugins.splice(0, 0, ...extraPlugins);
|
||||
}
|
||||
}
|
||||
|
||||
registerMethod({
|
||||
name,
|
||||
fn,
|
||||
exitsError = true
|
||||
}) {
|
||||
if (this.service.pluginMethods[name]) {
|
||||
if (exitsError) {
|
||||
throw new Error(
|
||||
`api.registerMethod() failed, method ${name} is already exist.`,
|
||||
);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.service.pluginMethods[name] = fn
|
||||
// 这里不能用 arrow function,this 需指向执行此方法的 PluginAPI
|
||||
// 否则 pluginId 会不会,导致不能正确 skip plugin
|
||||
|| function (hookFn) {
|
||||
const hook = {
|
||||
key: name,
|
||||
...(utils.lodash.isPlainObject(hookFn) ? hookFn : { fn: hookFn })
|
||||
};
|
||||
// @ts-ignore
|
||||
this.register(hook);
|
||||
};
|
||||
}
|
||||
|
||||
skipPlugins(pluginIds) {
|
||||
pluginIds.forEach((pluginId) => {
|
||||
this.service.skipPluginIds.add(pluginId);
|
||||
});
|
||||
}
|
||||
}
|
7
packages/fes-core/src/service/utils/isPromise.js
Normal file
7
packages/fes-core/src/service/utils/isPromise.js
Normal file
@ -0,0 +1,7 @@
|
||||
export default function isPromise(obj) {
|
||||
return (
|
||||
!!obj
|
||||
&& (typeof obj === 'object' || typeof obj === 'function')
|
||||
&& typeof obj.then === 'function'
|
||||
);
|
||||
}
|
18
packages/fes-core/src/service/utils/loadDotEnv.js
Normal file
18
packages/fes-core/src/service/utils/loadDotEnv.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { readFileSync, existsSync } from 'fs';
|
||||
import { parse } from 'dotenv';
|
||||
|
||||
/**
|
||||
* dotenv wrapper
|
||||
* @param envPath string
|
||||
*/
|
||||
export default function loadDotEnv(envPath) {
|
||||
if (existsSync(envPath)) {
|
||||
const parsed = parse(readFileSync(envPath, 'utf-8')) || {};
|
||||
Object.keys(parsed).forEach((key) => {
|
||||
// eslint-disable-next-line no-prototype-builtins
|
||||
if (!process.env.hasOwnProperty(key)) {
|
||||
process.env[key] = parsed[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
113
packages/fes-core/src/service/utils/pluginUtils.js
Normal file
113
packages/fes-core/src/service/utils/pluginUtils.js
Normal file
@ -0,0 +1,113 @@
|
||||
import {
|
||||
dirname, join, basename, relative, extname
|
||||
} from 'path';
|
||||
import {
|
||||
compatESModuleRequire,
|
||||
resolve,
|
||||
winPath,
|
||||
pkgUp,
|
||||
lodash
|
||||
} from '@umijs/utils';
|
||||
|
||||
const RE = {
|
||||
plugin: /^(@webank\/)?fes-plugin-/
|
||||
};
|
||||
|
||||
export function isPlugin(name) {
|
||||
const hasScope = name.charAt(0) === '@';
|
||||
const re = RE.plugin;
|
||||
if (hasScope) {
|
||||
return re.test(name.split('/')[1]) || re.test(name);
|
||||
}
|
||||
return re.test(name);
|
||||
}
|
||||
|
||||
export function getPlugins(opts) {
|
||||
return [
|
||||
// dependencies
|
||||
...opts.plugins,
|
||||
...Object.keys(opts.pkg.devDependencies || {})
|
||||
.concat(Object.keys(opts.pkg.dependencies || {}))
|
||||
.filter(isPlugin.bind(null)),
|
||||
...opts.userConfigPlugins
|
||||
].map(path => resolve.sync(path, {
|
||||
basedir: opts.cwd,
|
||||
extensions: ['.js', '.ts']
|
||||
}));
|
||||
}
|
||||
|
||||
// e.g.
|
||||
// initial-state -> initialState
|
||||
// webpack.css-loader -> webpack.cssLoader
|
||||
function nameToKey(name) {
|
||||
return name
|
||||
.split('.')
|
||||
.map(part => lodash.camelCase(part))
|
||||
.join('.');
|
||||
}
|
||||
|
||||
function pkgNameToKey(pkgName) {
|
||||
if (pkgName.charAt(0) === '@' && !pkgName.startsWith('@webank/')) {
|
||||
pkgName = pkgName.split('/')[1];
|
||||
}
|
||||
return nameToKey(pkgName.replace(RE.plugin, ''));
|
||||
}
|
||||
|
||||
export function pathToObj({ path, cwd }) {
|
||||
let pkg = null;
|
||||
let isPkgPlugin = false;
|
||||
const pkgJSONPath = pkgUp.sync({ cwd: path });
|
||||
if (pkgJSONPath) {
|
||||
// eslint-disable-next-line
|
||||
pkg = require(pkgJSONPath);
|
||||
isPkgPlugin = winPath(join(dirname(pkgJSONPath), pkg.main || 'index.js'))
|
||||
=== winPath(path);
|
||||
}
|
||||
|
||||
let id;
|
||||
if (isPkgPlugin) {
|
||||
id = pkg.name;
|
||||
} else if (winPath(path).startsWith(winPath(cwd))) {
|
||||
id = `./${winPath(relative(cwd, path))}`;
|
||||
} else if (pkgJSONPath) {
|
||||
id = winPath(join(pkg.name, relative(dirname(pkgJSONPath), path)));
|
||||
} else {
|
||||
id = winPath(path);
|
||||
}
|
||||
id = id.replace('@webank/fes-plugin-built-in/lib/plugins', '@@');
|
||||
id = id.replace(/\.js$/, '');
|
||||
|
||||
const key = isPkgPlugin
|
||||
? pkgNameToKey(pkg.name)
|
||||
: nameToKey(basename(path, extname(path)));
|
||||
|
||||
return {
|
||||
id,
|
||||
key,
|
||||
path: winPath(path),
|
||||
apply() {
|
||||
// use function to delay require
|
||||
try {
|
||||
// eslint-disable-next-line
|
||||
const ret = require(path);
|
||||
// use the default member for es modules
|
||||
return compatESModuleRequire(ret);
|
||||
} catch (e) {
|
||||
throw new Error(`Register ${path} failed, since ${e.message}`);
|
||||
}
|
||||
},
|
||||
defaultConfig: null
|
||||
};
|
||||
}
|
||||
|
||||
export function resolvePlugins(opts) {
|
||||
const plugins = getPlugins(opts);
|
||||
return plugins.map(path => pathToObj({
|
||||
path,
|
||||
cwd: opts.cwd
|
||||
}));
|
||||
}
|
||||
|
||||
export function isValidPlugin(plugin) {
|
||||
return plugin.id && plugin.key && plugin.apply;
|
||||
}
|
@ -10,4 +10,4 @@ export {
|
||||
createRouter
|
||||
} from 'vue-router';
|
||||
|
||||
export { default as Plugin, ApplyPluginsType } from './Plugin/Plugin';
|
||||
export { default as Plugin, ApplyPluginsType } from './plugin';
|
||||
|
@ -1,4 +1,4 @@
|
||||
// fes.config.js 只负责管理和 cli 相关的配置
|
||||
// fes.config.js 只负责管理 cli 相关的配置
|
||||
|
||||
|
||||
export default {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// fes.config.js 只负责管理和 cli 相关的配置
|
||||
// fes.config.js 只负责管理 cli 相关的配置
|
||||
|
||||
|
||||
module.exports = {
|
||||
|
24
yarn.lock
24
yarn.lock
@ -1404,14 +1404,6 @@
|
||||
pirates "^4.0.0"
|
||||
source-map-support "^0.5.9"
|
||||
|
||||
"@babel/runtime-corejs3@^7.11.2":
|
||||
version "7.12.1"
|
||||
resolved "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.1.tgz#51b9092befbeeed938335a109dbe0df51451e9dc"
|
||||
integrity sha512-umhPIcMrlBZ2aTWlWjUseW9LjQKxi1dpFlQS8DzsxB//5K+u6GLTC/JliPKHsd5kJVPIU6X/Hy0YvWOYPcMxBw==
|
||||
dependencies:
|
||||
core-js-pure "^3.0.0"
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@7.10.4":
|
||||
version "7.10.4"
|
||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.10.4.tgz#a6724f1a6b8d2f6ea5236dbfe58c7d7ea9c5eb99"
|
||||
@ -4930,7 +4922,7 @@ chardet@^0.7.0:
|
||||
resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
|
||||
integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
|
||||
|
||||
cheerio@1.0.0-rc.3, cheerio@^1.0.0-rc.3:
|
||||
cheerio@1.0.0-rc.3:
|
||||
version "1.0.0-rc.3"
|
||||
resolved "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz#094636d425b2e9c0f4eb91a46c05630c9a1a8bf6"
|
||||
integrity sha512-0td5ijfUPuubwLUu0OBoe98gZj8C/AA+RW3v67GPlGOrvxWjZmBXiBCRU+I8VEiNyJzjth40POfHiz2RB3gImA==
|
||||
@ -5619,11 +5611,6 @@ core-js-compat@^3.1.1, core-js-compat@^3.6.2:
|
||||
browserslist "^4.8.5"
|
||||
semver "7.0.0"
|
||||
|
||||
core-js-pure@^3.0.0:
|
||||
version "3.6.5"
|
||||
resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
|
||||
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
|
||||
|
||||
core-js@3.6.5, core-js@^3.0.0, core-js@^3.6.1:
|
||||
version "3.6.5"
|
||||
resolved "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a"
|
||||
@ -5742,15 +5729,6 @@ crypto-random-string@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
|
||||
integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
|
||||
|
||||
csp-html-webpack-plugin@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmjs.org/csp-html-webpack-plugin/-/csp-html-webpack-plugin-4.0.0.tgz#1ed2cd0dee23186587f9642084715b163345b59b"
|
||||
integrity sha512-1YqQefNG0SrZisysThlly2bgs4Ab/W91xOM17S8wd+6vTo3E0OdL+y4IAR0MKpthRluNGzFB3QhPqdOhkXAExg==
|
||||
dependencies:
|
||||
cheerio "^1.0.0-rc.3"
|
||||
lodash "^4.17.15"
|
||||
memory-fs "^0.5.0"
|
||||
|
||||
css-blank-pseudo@^0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5"
|
||||
|
Loading…
x
Reference in New Issue
Block a user