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 13.7 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\ntype UserPluginConfig = boolean | { enabled?: boolean; resolve?: string };\n\nconst isPluginConfigEnabled = (config: UserPluginConfig): boolean => {\n if (typeof config === 'boolean') {\n return config;\n }\n\n return config.enabled !== false;\n};\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 const userPluginsFile = await loadUserPluginsFile(strapi.dirs.app.config);\n\n logger.debug(\"User's plugins file\", os.EOL, userPluginsFile);\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 const userPluginConfig = userPluginsFile[name];\n\n if (userPluginConfig !== undefined && !isPluginConfigEnabled(userPluginConfig)) {\n continue;\n }\n\n plugins[name] = {\n name,\n importName: camelCase(name),\n type: 'module',\n modulePath: dep,\n };\n }\n }\n\n for (const [userPluginName, userPluginConfig] of Object.entries(userPluginsFile)) {\n /**\n * Local plugins must be explicitly enabled to be registered, matching the\n * server-side loader (`@strapi/core` get-enabled-plugins), which drops a\n * `{ resolve }` declaration without a truthy `enabled`. Treating an omitted\n * `enabled` as enabled here would bundle the plugin into the admin while the\n * server leaves it unloaded.\n */\n if (\n typeof userPluginConfig === 'object' &&\n userPluginConfig.enabled &&\n userPluginConfig.resolve\n ) {\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, UserPluginConfig>;\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","isPluginConfigEnabled","config","enabled","getEnabledPlugins","cwd","logger","runtimeDir","plugins","deps","get","debug","os","EOL","userPluginsFile","loadUserPluginsFile","dirs","app","dep","Object","keys","getModule","name","Error","userPluginConfig","undefined","importName","camelCase","type","modulePath","userPluginName","entries","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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"}