Skip to content

Commit

Permalink
fix: use require.resolve to find plugins (#12528)
Browse files Browse the repository at this point in the history
  • Loading branch information
czubocha committed May 23, 2024
1 parent 88911ee commit ab7ba48
Showing 1 changed file with 24 additions and 74 deletions.
98 changes: 24 additions & 74 deletions lib/classes/plugin-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import utils from '@serverlessinc/sf-core/src/utils.js';
import ServerlessError from '../serverless-error.js';
import renderCommandHelp from '../cli/render-help/command.js';
import tokenizeException from '../utils/tokenize-exception.js';
import { fileURLToPath, pathToFileURL } from 'url';
import { fileURLToPath } from 'url';
// Load Plugins
import pluginPackage from '../plugins/package/package.js';
import pluginDeploy from '../plugins/deploy.js';
Expand Down Expand Up @@ -59,6 +59,7 @@ import pluginAwsDeployFunction from '../plugins/aws/deploy-function.js';
import pluginAwsDeployList from '../plugins/aws/deploy-list.js';
import pluginAwsInvokeLocal from '../plugins/aws/invoke-local/index.js';
import pluginEsbuild from '../plugins/esbuild/index.js';
import { createRequire } from 'module';

const { log, getPluginWriters, readFile } = utils;

Expand Down Expand Up @@ -173,11 +174,9 @@ class PluginManager {

this.cliOptions = {};
this.cliCommands = [];
this.pluginIndependentCommands = new Set(['help', 'plugin']);

this.plugins = [];
this.externalPlugins = new Set();
this.localPluginsPaths = [];
this.commands = {};
this.aliases = {};
this.hooks = {};
Expand Down Expand Up @@ -254,7 +253,6 @@ class PluginManager {
const reorderedServicePlugins = this.sortServicePlugins(resolvedServicePlugins);
reorderedServicePlugins.filter(Boolean).forEach((Plugin) => this.addPlugin(Plugin));

isRegisteringExternalPlugins = false;
isRegisteringExternalPlugins = true;
return this.asyncPluginInit();
}
Expand All @@ -268,64 +266,39 @@ class PluginManager {
* @returns
*/
async requireServicePlugin(serviceDir, pluginListedName, legacyLocalPluginsPath) {
/**
* Check the Service directory for the plugin.
* This will check in the node_modules of the service directory
* and in the service directory itself.
*/
const serviceDirRequire = async (dir, module) => {
const logger = log.get('sls:plugins:load');
// Attempt to construct the full path for local modules or node_modules
const fullPath = path.resolve(dir, module);
const logger = log.get('sls:plugins:load');

const require = async (dir, module) => {
try {
// Convert the path to a URL and dynamically import the module
const moduleUrl = pathToFileURL(fullPath).href;
await import(moduleUrl);
return moduleUrl; // Return URL if module can be imported successfully
const require = createRequire(path.resolve(dir, 'require-resolver'));
return require.resolve(module);
} catch (error) {
logger.debug(`Failed to import module ${module} from ${fullPath} due to '${error}'\nTrying to import 'main' file from ${dir}/node_modules/${module}/package.json`);
// If direct path import fails, try resolving under node_modules
const packageJsonPath = path.resolve(dir, 'node_modules', module, 'package.json');
try {
const packageJson = await readFile(packageJsonPath);
let { main } = JSON.parse(packageJson);
if (!main) {
main = 'plugin.js';
}
const pluginPath = path.resolve(dir, 'node_modules', module, main);
const pluginUrl = pathToFileURL(pluginPath).href;
await import(pluginUrl);
return pluginUrl; // Return URL if module can be imported successfully
} catch (error) {
logger.debug(`Failed to import module ${module} due to '${error}'`);
throw Object.assign(new Error('Plugin not found'), { code: 'PLUGIN_NOT_FOUND' });
}
logger.debug(`Failed to resolve path for module ${module} from ${dir} due to '${error}'`);
return null
}
};

const localPluginPath = await serviceDirRequire(serviceDir, pluginListedName);

/**
* Check the Service directory for the plugin.
* This will check in the node_modules of the service directory
* and in the service directory itself.
*/
const localPluginPath = await require(serviceDir, pluginListedName);
if (localPluginPath) {
if (pluginListedName.startsWith('./')) {
this.localPluginsPaths.push({
resolvedPath: fileURLToPath(localPluginPath),
inputPath: pluginListedName,
});
}
return import(localPluginPath);
return await import(localPluginPath);
}

/**
* Search in the Framework's node_modules
*/
const externalPluginPath = await (async () => {
try {
return await import(pluginListedName);
} catch (error) {
throw Object.assign(new Error('Plugin not found'), { code: 'PLUGIN_NOT_FOUND' });
}
})();
return import(externalPluginPath);
const externalPluginPath = await require(fileURLToPath(import.meta.url), pluginListedName);
if (!externalPluginPath) {
throw new ServerlessError(
`Serverless plugin "${pluginListedName}" not found.`,
'PLUGIN_NOT_FOUND'
);
}
return await import(externalPluginPath);
}

async resolveServicePlugins(servicePlugs) {
Expand Down Expand Up @@ -386,29 +359,6 @@ class PluginManager {
return [...prioritized, ...rest];
}

getLocalPluginsPathPatterns() {
return this.localPluginsPaths
.map(({ resolvedPath, inputPath }) => {
const absoluteInputPath = path.resolve(this.serverless.serviceDir, inputPath);
if (
absoluteInputPath === resolvedPath ||
absoluteInputPath + path.extname(resolvedPath) === resolvedPath
) {
return path.relative(this.serverless.serviceDir, resolvedPath);
}

if (resolvedPath.startsWith(absoluteInputPath + path.sep)) {
return path.relative(
this.serverless.serviceDir,
path.join(path.dirname(resolvedPath), '/**')
);
}

return null;
})
.filter((v) => v !== null);
}

parsePluginsObject(servicePlugs) {
let localPath =
this.serverless &&
Expand Down

0 comments on commit ab7ba48

Please sign in to comment.