Skip to content

Commit

Permalink
feat: 添加插件集
Browse files Browse the repository at this point in the history
  • Loading branch information
winixt committed Dec 19, 2020
1 parent 7607868 commit 442daeb
Show file tree
Hide file tree
Showing 66 changed files with 230 additions and 84 deletions.
2 changes: 1 addition & 1 deletion .fatherrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const headPkgs = [
"fes-runtime",
"fes-core",
"fes",
"fes-plugin-built-in",
"fes-preset-built-in",
"fes-plugin-request",
"fes-plugin-access",
"fes-plugin-model",
Expand Down
4 changes: 2 additions & 2 deletions packages/fes-core/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import Logger from './logger';
import Service from './service';
import PluginAPI from './service/pluginAPI';
import { PluginType } from './service/enums';
import { isPlugin } from './service/utils/pluginUtils';
import { isPluginOrPreset } from './service/utils/pluginUtils';

export {
Config,
Service,
PluginAPI,
isPlugin,
isPluginOrPreset,
PluginType,
Logger
};
92 changes: 85 additions & 7 deletions packages/fes-core/src/service/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ import { EventEmitter } from 'events';
import assert from 'assert';
import { AsyncSeriesWaterfallHook } from 'tapable';
import { existsSync } from 'fs';
import { BabelRegister } from '@umijs/utils';
import { resolvePlugins } from './utils/pluginUtils';
import { BabelRegister, lodash } from '@umijs/utils';
import { resolvePresets, pathToObj, resolvePlugins } from './utils/pluginUtils';
import loadDotEnv from './utils/loadDotEnv';
import isPromise from './utils/isPromise';
import PluginAPI from './pluginAPI';
import {
ApplyPluginsType,
ConfigChangeType,
EnableBy,
PluginType,
ServiceStage
} from './enums';
import Config from '../config';
Expand All @@ -21,7 +22,6 @@ import getPaths from './getPaths';
// TODO
// 1. duplicated key
// 2. Logger
// 3. 支持插件集?
export default class Service extends EventEmitter {
cwd;

Expand All @@ -41,9 +41,14 @@ export default class Service extends EventEmitter {
// plugin methods
pluginMethods = {};

// initial presets and plugins from arguments, config, process.env, and package.json
initialPresets = [];

// initial plugins from arguments, config, process.env, and package.json
initialPlugins = [];

_extraPresets = [];

_extraPlugins = [];

// user config
Expand Down Expand Up @@ -111,6 +116,11 @@ export default class Service extends EventEmitter {
pkg: this.pkg,
cwd: this.cwd
};
this.initialPresets = resolvePresets({
...baseOpts,
presets: opts.presets || [],
userConfigPresets: this.userConfig.presets || []
});
this.initialPlugins = resolvePlugins({
...baseOpts,
plugins: opts.plugins || [],
Expand Down Expand Up @@ -140,8 +150,7 @@ export default class Service extends EventEmitter {

async init() {
this.setStage(ServiceStage.init);
// we should have the final hooksByPluginId which is added with api.register()
await this.initPlugins();
await this.initPresetsAndPlugins();

// hooksByPluginId -> hooks
// hooks is mapped with hook key, prepared for applyPlugins()
Expand Down Expand Up @@ -199,8 +208,14 @@ export default class Service extends EventEmitter {
});
}

async initPlugins() {
async initPresetsAndPlugins() {
this.setStage(ServiceStage.initPresets);
this._extraPlugins = [];
while (this.initialPresets.length) {
// eslint-disable-next-line
await this.initPreset(this.initialPresets.shift());
}

this.setStage(ServiceStage.initPlugins);
this._extraPlugins.push(...this.initialPlugins);
while (this._extraPlugins.length) {
Expand Down Expand Up @@ -248,6 +263,7 @@ export default class Service extends EventEmitter {
'env',
'args',
'hasPlugins',
'hasPresets',
'setConfig'
].includes(prop)
) {
Expand All @@ -268,6 +284,61 @@ export default class Service extends EventEmitter {
return ret || {};
}

async initPreset(preset) {
const { id, key, apply } = preset;
preset.isPreset = true;

const api = this.getPluginAPI({ id, key, service: this });

// register before apply
this.registerPlugin(preset);
const { presets, plugins } = await this.applyAPI({
api,
apply
});

// register extra presets and plugins
if (presets) {
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
})),
);
}

// 深度优先
const extraPresets = lodash.clone(this._extraPresets);
this._extraPresets = [];
while (extraPresets.length) {
// eslint-disable-next-line
await this.initPreset(extraPresets.shift());
}

if (plugins) {
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
})),
);
}
}


async initPlugin(plugin) {
const { id, key, apply } = plugin;

Expand Down Expand Up @@ -319,10 +390,17 @@ export default class Service extends EventEmitter {
return true;
}

hasPresets(presetIds) {
return presetIds.every((presetId) => {
const preset = this.plugins[presetId];
return preset && preset.isPreset && this.isPluginEnable(presetId);
});
}

hasPlugins(pluginIds) {
return pluginIds.every((pluginId) => {
const plugin = this.plugins[pluginId];
return plugin && this.isPluginEnable(pluginId);
return plugin && !plugin.isPreset && this.isPluginEnable(pluginId);
});
}

Expand Down
20 changes: 20 additions & 0 deletions packages/fes-core/src/service/pluginAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,26 @@ export default class PluginAPI {
}
}

registerPresets(presets) {
assert(
this.service.stage === ServiceStage.initPresets,
'api.registerPresets() failed, it should only used in presets.',
);
assert(
Array.isArray(presets),
'api.registerPresets() failed, presets must be Array.',
);
const extraPresets = presets.map(preset => (isValidPlugin(preset)
? (preset)
: pathToObj({
type: PluginType.preset,
path: preset,
cwd: this.service.cwd
})));
// 插到最前面,下个 while 循环优先执行
this.service._extraPresets.splice(0, 0, ...extraPresets);
}

registerMethod({
name,
fn,
Expand Down
48 changes: 35 additions & 13 deletions packages/fes-core/src/service/utils/pluginUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,37 @@ import {
lodash
} from '@umijs/utils';

import { PluginType } from '../enums';

const RE = {
plugin: /^(@webank\/)?fes-plugin-/
[PluginType.plugin]: /^(@webank\/)?fes-plugin-/,
[PluginType.preset]: /^(@webank\/)?fes-preset-/
};

export function isPlugin(name) {
export function isPluginOrPreset(type, name) {
const hasScope = name.charAt(0) === '@';
const re = RE.plugin;
const re = RE[type];
if (hasScope) {
return re.test(name.split('/')[1]) || re.test(name);
}
return re.test(name);
}

export function getPlugins(opts) {
export function getPluginsOrPresets(type, opts) {
const upperCaseType = type.toUpperCase();
return [
// dependencies
...opts.plugins,
// opts
...((opts[type === PluginType.preset ? 'presets' : 'plugins']) || []),
// env
...(process.env[`FES_${upperCaseType}S`] || '').split(',').filter(Boolean),
...Object.keys(opts.pkg.devDependencies || {})
.concat(Object.keys(opts.pkg.dependencies || {}))
.filter(isPlugin.bind(null)),
...opts.userConfigPlugins
.filter(isPluginOrPreset.bind(null, type)),
// user config
...((opts[
type === PluginType.preset ? 'userConfigPresets' : 'userConfigPlugins'
]) || [])
].map(path => resolve.sync(path, {
basedir: opts.cwd,
extensions: ['.js', '.ts']
Expand All @@ -46,14 +56,14 @@ function nameToKey(name) {
.join('.');
}

function pkgNameToKey(pkgName) {
function pkgNameToKey(pkgName, type) {
if (pkgName.charAt(0) === '@' && !pkgName.startsWith('@webank/')) {
pkgName = pkgName.split('/')[1];
}
return nameToKey(pkgName.replace(RE.plugin, ''));
return nameToKey(pkgName.replace(RE[type], ''));
}

export function pathToObj({ path, cwd }) {
export function pathToObj({ path, type, cwd }) {
let pkg = null;
let isPkgPlugin = false;
const pkgJSONPath = pkgUp.sync({ cwd: path });
Expand All @@ -74,11 +84,11 @@ export function pathToObj({ path, cwd }) {
} else {
id = winPath(path);
}
id = id.replace('@webank/fes-plugin-built-in/lib/plugins', '@@');
id = id.replace('@webank/fes-preset-built-in/lib/plugins', '@@');
id = id.replace(/\.js$/, '');

const key = isPkgPlugin
? pkgNameToKey(pkg.name)
? pkgNameToKey(pkg.name, type)
: nameToKey(basename(path, extname(path)));

return {
Expand All @@ -100,10 +110,22 @@ export function pathToObj({ path, cwd }) {
};
}

export function resolvePresets(opts) {
const type = PluginType.preset;
const presets = [...getPluginsOrPresets(type, opts)];
return presets.map(path => pathToObj({
type,
path,
cwd: opts.cwd
}));
}

export function resolvePlugins(opts) {
const plugins = getPlugins(opts);
const type = PluginType.plugin;
const plugins = getPluginsOrPresets(type, opts);
return plugins.map(path => pathToObj({
path,
type,
cwd: opts.cwd
}));
}
Expand Down
53 changes: 0 additions & 53 deletions packages/fes-plugin-built-in/src/index.js

This file was deleted.

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@webank/fes-plugin-built-in",
"name": "@webank/fes-preset-built-in",
"version": "2.0.0",
"description": "@webank/fes-plugin-built-in",
"description": "@webank/fes-preset-built-in",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": [
Expand Down
Loading

0 comments on commit 442daeb

Please sign in to comment.