UNPKG

@strapi/strapi

Version:

An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MySQL, MariaDB, PostgreSQL, SQLite

1 lines 12.4 kB
{"version":3,"file":"plugins.mjs","sources":["../../../../src/node/core/plugins.ts"],"sourcesContent":["import os from 'node:os';\nimport path from 'node:path';\nimport fs from 'node:fs';\nimport camelCase from 'lodash/camelCase';\nimport { env } from '@strapi/utils';\nimport { getModule, PackageJson } from './dependencies';\nimport { convertModulePathToSystemPath, convertSystemPathToModulePath, loadFile } from './files';\nimport type { BaseContext } from '../types';\nimport { isError } from './errors';\n\ninterface LocalPluginMeta {\n name: string;\n /**\n * camelCased version of the plugin name\n */\n importName: string;\n /**\n * The path to the plugin, relative to the app's root directory\n * in system format\n */\n path: string;\n /**\n * The path to the plugin, relative to the runtime directory\n * in module format (i.e. with forward slashes) because thats\n * where it should be used as an import\n */\n modulePath: string;\n type: 'local';\n}\n\ninterface ModulePluginMeta {\n name: string;\n /**\n * camelCased version of the plugin name\n */\n importName: string;\n /**\n * Modules don't have a path because we never resolve them to their node_modules\n * because we simply do not require it.\n */\n path?: never;\n /**\n * The path to the plugin, relative to the app's root directory\n * in module format (i.e. with forward slashes)\n */\n modulePath: string;\n type: 'module';\n}\n\ntype PluginMeta = LocalPluginMeta | ModulePluginMeta;\n\ninterface StrapiPlugin extends PackageJson {\n strapi: {\n description?: string;\n displayName?: string;\n kind: 'plugin';\n name?: string;\n required?: boolean;\n };\n}\n\nconst validatePackageHasStrapi = (\n pkg: PackageJson\n): pkg is PackageJson & { strapi: Record<string, unknown> } =>\n 'strapi' in pkg &&\n typeof pkg.strapi === 'object' &&\n !Array.isArray(pkg.strapi) &&\n pkg.strapi !== null;\n\nconst validatePackageIsPlugin = (pkg: PackageJson): pkg is StrapiPlugin =>\n validatePackageHasStrapi(pkg) && pkg.strapi.kind === 'plugin';\n\nconst getEnabledPlugins = async ({\n cwd,\n logger,\n runtimeDir,\n strapi,\n}: Pick<BaseContext, 'cwd' | 'logger' | 'strapi' | 'runtimeDir'>): Promise<\n Record<string, PluginMeta>\n> => {\n const plugins: Record<string, PluginMeta> = {};\n\n /**\n * This is the list of dependencies that are installed in the user's project.\n * It will include libraries like \"react\", so we need to collect the ones that\n * are plugins.\n */\n const deps = strapi.config.get('info.dependencies', {});\n\n logger.debug(\"Dependencies from user's project\", os.EOL, deps);\n\n for (const dep of Object.keys(deps)) {\n const pkg = await getModule(dep, cwd);\n\n if (pkg && validatePackageIsPlugin(pkg)) {\n const name = pkg.strapi.name || pkg.name;\n\n if (!name) {\n /**\n * Unlikely to happen, but you never know.\n */\n throw Error(\n \"You're trying to import a plugin that doesn't have a name – check the package.json of that plugin!\"\n );\n }\n\n plugins[name] = {\n name,\n importName: camelCase(name),\n type: 'module',\n modulePath: dep,\n };\n }\n }\n\n const userPluginsFile = await loadUserPluginsFile(strapi.dirs.app.config);\n\n logger.debug(\"User's plugins file\", os.EOL, userPluginsFile);\n\n for (const [userPluginName, userPluginConfig] of Object.entries(userPluginsFile)) {\n if (userPluginConfig.enabled && userPluginConfig.resolve) {\n const sysPath = convertModulePathToSystemPath(userPluginConfig.resolve);\n plugins[userPluginName] = {\n name: userPluginName,\n importName: camelCase(userPluginName),\n type: 'local',\n /**\n * User plugin paths are resolved from the entry point\n * of the app, because that's how you import them.\n */\n modulePath: convertSystemPathToModulePath(path.relative(runtimeDir, sysPath)),\n path: sysPath,\n };\n }\n }\n\n return plugins;\n};\n\nconst PLUGIN_CONFIGS = ['plugins.js', 'plugins.mjs', 'plugins.ts'];\n\ntype UserPluginConfigFile = Record<string, { enabled: boolean; resolve: string }>;\n\nconst loadUserPluginsFile = async (root: string): Promise<UserPluginConfigFile> => {\n for (const file of PLUGIN_CONFIGS) {\n const filePath = path.join(root, file);\n const configFile = await loadFile(filePath);\n\n if (configFile) {\n /**\n * Configs can be a function or they can be just an object!\n */\n return typeof configFile === 'function' ? configFile({ env }) : configFile;\n }\n }\n\n return {};\n};\n\nconst getMapOfPluginsWithAdmin = (plugins: Record<string, PluginMeta>) => {\n /**\n * This variable stores the import paths for plugins.\n * The keys are the module paths of the plugins, and the values are the paths\n * to the admin part of the plugins, which is either loaded from the\n * package.json exports or from the legacy strapi-admin.js file.\n */\n const pluginImportPaths: Record<string, string> = {};\n\n return Object.values(plugins)\n .filter((plugin) => {\n if (!plugin) {\n return false;\n }\n\n /**\n * There are two ways a plugin should be imported, either it's local to the strapi app,\n * or it's an actual npm module that's installed and resolved via node_modules.\n *\n * We first check if the plugin is local to the strapi app, using a regular `fs.existsSync` because\n * the pathToPlugin will be relative i.e. `/Users/my-name/strapi-app/src/plugins/my-plugin`.\n *\n * If the file doesn't exist well then it's probably a node_module, so instead we use `require.resolve`\n * which will resolve the path to the module in node_modules. If it fails with the specific code `MODULE_NOT_FOUND`\n * then it doesn't have an admin part to the package.\n */\n try {\n const localPluginPath = plugin.path;\n if (localPluginPath) {\n // Here we are loading a locally installed plugin\n const packageJsonPath = path.join(localPluginPath, 'package.json');\n\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));\n const localAdminPath = packageJson?.exports?.['./strapi-admin']?.import;\n\n if (localAdminPath) {\n pluginImportPaths[plugin.modulePath] = localAdminPath;\n return true;\n }\n }\n\n // Check if legacy admin file exists in local plugin\n if (fs.existsSync(path.join(localPluginPath, 'strapi-admin.js'))) {\n pluginImportPaths[plugin.modulePath] = 'strapi-admin';\n return true;\n }\n }\n\n // This plugin is a module, so we need to check if it has a strapi-admin export\n if (require.resolve(`${plugin.modulePath}/strapi-admin`)) {\n pluginImportPaths[plugin.modulePath] = 'strapi-admin';\n return true;\n }\n\n return false;\n } catch (err) {\n if (\n isError(err) &&\n 'code' in err &&\n (err.code === 'MODULE_NOT_FOUND' || err.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED')\n ) {\n /**\n * the plugin does not contain FE code, so we\n * don't want to import it anyway\n */\n return false;\n }\n\n throw err;\n }\n })\n .map((plugin) => ({\n ...plugin,\n modulePath: `${plugin.modulePath}/${pluginImportPaths[plugin.modulePath]}`,\n }));\n};\n\nexport { getEnabledPlugins, getMapOfPluginsWithAdmin };\nexport type { PluginMeta, LocalPluginMeta, ModulePluginMeta };\n"],"names":["validatePackageHasStrapi","pkg","strapi","Array","isArray","validatePackageIsPlugin","kind","getEnabledPlugins","cwd","logger","runtimeDir","plugins","deps","config","get","debug","os","EOL","dep","Object","keys","getModule","name","Error","importName","camelCase","type","modulePath","userPluginsFile","loadUserPluginsFile","dirs","app","userPluginName","userPluginConfig","entries","enabled","resolve","sysPath","convertModulePathToSystemPath","convertSystemPathToModulePath","path","relative","PLUGIN_CONFIGS","root","file","filePath","join","configFile","loadFile","env","getMapOfPluginsWithAdmin","pluginImportPaths","values","filter","plugin","localPluginPath","packageJsonPath","fs","existsSync","packageJson","JSON","parse","readFileSync","localAdminPath","exports","import","require","err","isError","code","map"],"mappings":"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"}