Skip to content

Commit

Permalink
feat: support pkg.eggPlugin.exports property
Browse files Browse the repository at this point in the history
e.g.:

```json
  "eggPlugin": {
    "name": "schedule",
    "exports": {
      "import": "./dist/esm",
      "require": "./dist/commonjs"
    }
  }
```
  • Loading branch information
fengmk2 committed Dec 17, 2024
1 parent 7811cce commit a840f92
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 48 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[![Test coverage][codecov-image]][codecov-url]
[![Known Vulnerabilities][snyk-image]][snyk-url]
[![npm download][download-image]][download-url]
[![Node.js Version](https://img.shields.io/node/v/@eggjs/core.svg?style=flat)](https://nodejs.org/en/download/)

[npm-image]: https://img.shields.io/npm/v/@eggjs/core.svg?style=flat-square
[npm-url]: https://npmjs.org/package/@eggjs/core
Expand Down
58 changes: 42 additions & 16 deletions src/loader/egg_loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { debuglog, inspect } from 'node:util';
import { isAsyncFunction, isClass, isGeneratorFunction, isObject } from 'is-type-of';
import { homedir } from 'node-homedir';
import type { Logger } from 'egg-logger';
import { getParamNames, readJSONSync } from 'utility';
import { getParamNames, readJSONSync, readJSON } from 'utility';
import { extend } from 'extend2';
import { Request, Response, Context, Application } from '@eggjs/koa';
import { pathMatching, type PathMatchingOptions } from 'egg-path-matching';
Expand Down Expand Up @@ -462,7 +462,7 @@ export class EggLoader {
plugin.path = this.getPluginPath(plugin);

// read plugin information from ${plugin.path}/package.json
this.#mergePluginConfig(plugin);
await this.#mergePluginConfig(plugin);

// disable the plugin that not match the serverEnv
if (env && plugin.env.length > 0 && !plugin.env.includes(env)) {
Expand Down Expand Up @@ -538,7 +538,7 @@ export class EggLoader {
for (const name in customPlugins) {
this.#normalizePluginConfig(customPlugins, name, configPath);
}
debug('Loaded custom plugins: %j', Object.keys(customPlugins));
debug('Loaded custom plugins: %o', customPlugins);
}
return customPlugins;
}
Expand Down Expand Up @@ -623,16 +623,18 @@ export class EggLoader {
// "strict": true, whether check plugin name, default to true.
// }
// }
#mergePluginConfig(plugin: EggPluginInfo) {
async #mergePluginConfig(plugin: EggPluginInfo) {
let pkg;
let config;
const pluginPackage = path.join(plugin.path!, 'package.json');
if (fs.existsSync(pluginPackage)) {
pkg = readJSONSync(pluginPackage);
if (await utils.existsPath(pluginPackage)) {
pkg = await readJSON(pluginPackage);
config = pkg.eggPlugin;
if (pkg.version) {
plugin.version = pkg.version;
}
// support commonjs and esm dist files
plugin.path = this.#formatPluginPathFromPackageJSON(plugin.path!, pkg);
}

const logger = this.options.logger;
Expand Down Expand Up @@ -712,9 +714,9 @@ export class EggLoader {
}

// Following plugins will be enabled implicitly.
// - configclient required by [hsfclient]
// - eagleeye required by [hsfclient]
// - diamond required by [hsfclient]
// - configclient required by [rpcClient]
// - monitor required by [rpcClient]
// - diamond required by [rpcClient]
if (implicitEnabledPlugins.length) {
let message = implicitEnabledPlugins
.map(name => ` - ${name} required by [${requireMap[name]}]`)
Expand Down Expand Up @@ -769,20 +771,43 @@ export class EggLoader {

#resolvePluginPath(plugin: EggPluginInfo) {
const name = plugin.package || plugin.name;

try {
// should find the plugin directory
// pnpm will lift the node_modules to the sibling directory
// 'node_modules/.pnpm/[email protected]/node_modules/yadan/node_modules',
// 'node_modules/.pnpm/[email protected]/node_modules', <- this is the sibling directory
// 'node_modules/.pnpm/[email protected]/node_modules/egg/node_modules',
// 'node_modules/.pnpm/[email protected]/node_modules', <- this is the sibling directory
const filePath = utils.resolvePath(`${name}/package.json`, { paths: [ ...this.lookupDirs ] });
return path.dirname(filePath);
} catch (err: any) {
const pluginPkgFile = utils.resolvePath(`${name}/package.json`, { paths: [ ...this.lookupDirs ] });
return path.dirname(pluginPkgFile);
} catch (err) {
debug('[resolvePluginPath] error: %o', err);
throw new Error(`Can not find plugin ${name} in "${[ ...this.lookupDirs ].join(', ')}"`);
throw new Error(`Can not find plugin ${name} in "${[ ...this.lookupDirs ].join(', ')}"`, {
cause: err,
});
}
}

#formatPluginPathFromPackageJSON(pluginPath: string, pluginPkg: {
eggPlugin?: {
exports?: {
import?: string;
require?: string;
};
};
}) {
if (pluginPkg.eggPlugin?.exports) {
if (typeof require === 'function') {
if (pluginPkg.eggPlugin.exports.require) {
pluginPath = path.join(pluginPath, pluginPkg.eggPlugin.exports.require);
}
} else {
if (pluginPkg.eggPlugin.exports.import) {
pluginPath = path.join(pluginPath, pluginPkg.eggPlugin.exports.import);
}
}
}
return pluginPath;
}

#extendPlugins(targets: Record<string, EggPluginInfo>, plugins: Record<string, EggPluginInfo>) {
Expand Down Expand Up @@ -1036,9 +1061,10 @@ export class EggLoader {
debug('loadExtend %s, filepaths: %j', name, filepaths);

const mergeRecord = new Map();
for (let filepath of filepaths) {
filepath = this.resolveModule(filepath)!;
for (const rawFilepath of filepaths) {
const filepath = this.resolveModule(rawFilepath)!;
if (!filepath) {
debug('loadExtend %o not found', rawFilepath);
continue;
}
if (filepath.endsWith('/index.js')) {
Expand Down
77 changes: 45 additions & 32 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { debuglog } from 'node:util';
import path from 'node:path';
import fs from 'node:fs';
import { stat } from 'node:fs/promises';
import BuiltinModule from 'node:module';
import { importResolve, importModule } from '@eggjs/utils';

Expand All @@ -18,14 +19,57 @@ const extensions = (Module as any)._extensions;
const extensionNames = Object.keys(extensions).concat([ '.cjs', '.mjs' ]);
debug('Module extensions: %j', extensionNames);

function getCalleeFromStack(withLine?: boolean, stackIndex?: number) {
stackIndex = stackIndex === undefined ? 2 : stackIndex;
const limit = Error.stackTraceLimit;
const prep = Error.prepareStackTrace;

Error.prepareStackTrace = prepareObjectStackTrace;
Error.stackTraceLimit = 5;

// capture the stack
const obj: any = {};
Error.captureStackTrace(obj);
let callSite = obj.stack[stackIndex];
let fileName = '';
if (callSite) {
// egg-mock will create a proxy
// https://github.com/eggjs/egg-mock/blob/master/lib/app.js#L174
fileName = callSite.getFileName();
/* istanbul ignore if */
if (fileName && fileName.endsWith('egg-mock/lib/app.js')) {
// TODO: add test
callSite = obj.stack[stackIndex + 1];
fileName = callSite.getFileName();
}
}

Error.prepareStackTrace = prep;
Error.stackTraceLimit = limit;

if (!callSite || !fileName) return '<anonymous>';
if (!withLine) return fileName;
return `${fileName}:${callSite.getLineNumber()}:${callSite.getColumnNumber()}`;
}

export default {
deprecated(message: string) {
// console.trace('[@eggjs/core:deprecated] %s', message);
console.warn('[@eggjs/core:deprecated] %s', message);
},

extensions,
extensionNames,

async existsPath(filepath: string) {
try {
await stat(filepath);
return true;
} catch {
return false;
}
},

async loadFile(filepath: string) {
try {
// if not js module, just return content buffer
Expand Down Expand Up @@ -55,38 +99,7 @@ export default {
return ctx ? fn.call(ctx, ...args) : fn(...args);
},

getCalleeFromStack(withLine?: boolean, stackIndex?: number) {
stackIndex = stackIndex === undefined ? 2 : stackIndex;
const limit = Error.stackTraceLimit;
const prep = Error.prepareStackTrace;

Error.prepareStackTrace = prepareObjectStackTrace;
Error.stackTraceLimit = 5;

// capture the stack
const obj: any = {};
Error.captureStackTrace(obj);
let callSite = obj.stack[stackIndex];
let fileName = '';
if (callSite) {
// egg-mock will create a proxy
// https://github.com/eggjs/egg-mock/blob/master/lib/app.js#L174
fileName = callSite.getFileName();
/* istanbul ignore if */
if (fileName && fileName.endsWith('egg-mock/lib/app.js')) {
// TODO: add test
callSite = obj.stack[stackIndex + 1];
fileName = callSite.getFileName();
}
}

Error.prepareStackTrace = prep;
Error.stackTraceLimit = limit;

if (!callSite || !fileName) return '<anonymous>';
if (!withLine) return fileName;
return `${fileName}:${callSite.getLineNumber()}:${callSite.getColumnNumber()}`;
},
getCalleeFromStack,

getResolvedFilename(filepath: string, baseDir: string) {
const reg = /[/\\]/g;
Expand Down

0 comments on commit a840f92

Please sign in to comment.