diff --git a/docs/docs/docs/01-core/strapi/commands/plugin/00-overview.md b/docs/docs/docs/01-core/strapi/commands/plugin/00-overview.md deleted file mode 100644 index d38b0cbd4c..0000000000 --- a/docs/docs/docs/01-core/strapi/commands/plugin/00-overview.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -title: Introduction -description: An intro into the plugin commands of the Strapi CLI -tags: - - CLI - - commands - - plugins ---- - -:::caution -This is an experimental API that is subject to change at any moment, hence why it is not documented in the [Strapi documentation](https://docs.strapi.io/dev-docs/cli). -::: - -## Available Commands - -- [plugin:init](./03-init.md) - Create a new plugin -- [plugin:build](./01-build.md) - Build a plugin for publishing -- [plugin:watch](./02-watch.md) - Watch & compile a plugin in local development -- [plugin:verify](./04-check.md) - Verify the build output of the plugin before publication - -## Setting up your package - -In order to build/watch/check a plugin you need to have a `package.json` that must contain the following fields: - -- `name` -- `version` - -In regards to the export keys of your package.json because a plugin _typically_ has both a server and client -side output we recommend doing the following: - -```json -{ - "name": "@strapi/plugin", - "version": "1.0.0", - "exports": { - "./strapi-admin": { - "types": "./dist/admin/src/index.d.ts", - "source": "./admin/src/index.ts", - "import": "./dist/admin/index.mjs", - "require": "./dist/admin/index.js", - "default": "./dist/admin/index.js" - }, - "./strapi-server": { - "types": "./dist/server/src/index.d.ts", - "source": "./server/src/index.ts", - "import": "./dist/server/index.mjs", - "require": "./dist/server/index.js", - "default": "./dist/server/index.js" - }, - "./package.json": "./package.json" - } -} -``` - -We don't use `main`, `module` or `types` on the root level of the package.json because of the aforementioned reason (plugins don't have one entry). -If you've not written your plugin in typescript, you can omit the `types` value of an export map. This is the minimum setup required to build a plugin. diff --git a/docs/docs/docs/01-core/strapi/commands/plugin/01-build.md b/docs/docs/docs/01-core/strapi/commands/plugin/01-build.md deleted file mode 100644 index d0b819e855..0000000000 --- a/docs/docs/docs/01-core/strapi/commands/plugin/01-build.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: plugin:build -description: An in depth look at the plugin:build command of the Strapi CLI -tags: - - CLI - - commands - - plugins - - building ---- - -The `plugin:build` command is used to build plugins in a CJS/ESM compatible format that can be instantly published to NPM. -This is done by using `pack-up` underneath and a specific configuration, for this command we _do not_ look for a `packup.config` file. - -## Usage - -```bash -strapi plugin:build -``` - -### Options - -```bash -Bundle your strapi plugin for publishing. - -Options: - --force Automatically answer "yes" to all prompts, including potentially destructive requests, and run non-interactively. - -d, --debug Enable debugging mode with verbose logs (default: false) - --silent Don't log anything (default: false) - --sourcemap produce sourcemaps (default: false) - --minify minify the output (default: false) - -h, --help Display help for command -``` - -## How it works - -The command sequence can be visualised as follows: - -- Load package.json -- Validate that package.json against a `yup` schema -- Validate the ordering of an export map if `pkg.exports` is defined -- Create a set of "bundles" to build ignoring the package.json exports map that is _specifically_ set up for strapi-plugins. -- Pass the created config to `pack-up`'s build API. -- Finish diff --git a/docs/docs/docs/01-core/strapi/commands/plugin/02-watch.md b/docs/docs/docs/01-core/strapi/commands/plugin/02-watch.md deleted file mode 100644 index e8774710f7..0000000000 --- a/docs/docs/docs/01-core/strapi/commands/plugin/02-watch.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: plugin:watch -description: An in depth look at the plugin:watch command of the Strapi CLI -tags: - - CLI - - commands - - plugins - - building ---- - -The `plugin:watch` command is used to watch plugin source files and compile them to production viable assets in real-time. -This is done by using `pack-up` underneath and a specific configuration, for this command we _do not_ look for a `packup.config` file. - -## Usage - -```bash -strapi plugin:watch -``` - -### Options - -```bash -Watch & compile your strapi plugin for local development. - -Options: - -d, --debug Enable debugging mode with verbose logs (default: false) - --silent Don't log anything (default: false) - -h, --help Display help for command -``` - -## How it works - -The command sequence can be visualised as follows: - -- Load package.json -- Validate that package.json against a `yup` schema -- Validate the ordering of an export map if `pkg.exports` is defined -- Create a set of "bundles" to build ignoring the package.json exports map that is _specifically_ set up for strapi-plugins. -- Pass the created config to `pack-up`'s watch API. -- Run's indefinitely diff --git a/docs/docs/docs/01-core/strapi/commands/plugin/03-init.md b/docs/docs/docs/01-core/strapi/commands/plugin/03-init.md deleted file mode 100644 index 2be2fbe375..0000000000 --- a/docs/docs/docs/01-core/strapi/commands/plugin/03-init.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -title: plugin:init -description: An in depth look at the plugin:init command of the Strapi CLI -tags: - - CLI - - commands - - plugins - - initialization ---- - -The `plugin:init` command is used to create a plugin, by default in `src/plugins` – because this is the strapi CLI we assume we're in a user app by default. This is done by using `pack-up` underneath and a unique template configuration. - -## Usage - -```bash -strapi plugin:init [path] -``` - -### Options - -```bash -Create a new plugin at a given path. - -Options: - -d, --debug Enable debugging mode with verbose logs (default: false) - --silent Don't log anything (default: false) - -h, --help Display help for command -``` - -## How it works - -The command sequence can be visualised as follows: - -- Ask the user a series of questions via prompts -- Generate a plugin folder structure based on that template diff --git a/docs/docs/docs/01-core/strapi/commands/plugin/04-check.md b/docs/docs/docs/01-core/strapi/commands/plugin/04-check.md deleted file mode 100644 index 8797fd3a5d..0000000000 --- a/docs/docs/docs/01-core/strapi/commands/plugin/04-check.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -title: plugin:verify -description: An in depth look at the plugin:verify command of the Strapi CLI -tags: - - CLI - - commands - - plugins ---- - -The `plugin:verify` command is simply a utility wrapper around the `pack-up` api [`check`](../../../../05-utils/pack-up/01-commands/03-check.mdx). -It is used to verify the output of your plugin before publishing it. - -## Usage - -```bash -strapi plugin:verify [path] -``` - -### Options - -```bash -Verify the output of your plugin before publishing it. - -Options: - -d, --debug Enable debugging mode with verbose logs (default: false) - --silent Don't log anything (default: false) - -h, --help Display help for command -``` diff --git a/docs/docs/docs/01-core/strapi/commands/plugin/05-link-watch.md b/docs/docs/docs/01-core/strapi/commands/plugin/05-link-watch.md deleted file mode 100644 index 68d0809256..0000000000 --- a/docs/docs/docs/01-core/strapi/commands/plugin/05-link-watch.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: plugin:watch:link -description: An in depth look at the plugin:watch:link command of the Strapi CLI -tags: - - CLI - - commands - - plugins ---- - -The `plugin:watch:link` command recompiles your plugin and pushes those changes to your local yalc registry to simulate using your plugin as a node_module in another project. - -## Usage - -```bash -strapi plugin:watch:link -``` - -### Options - -```bash -Recompiles your plugin automatically on changes and runs yalc push --publish - -Options: - -d, --debug Enable debugging mode with verbose logs (default: false) - --silent Don't log anything (default: false) - -h, --help Display help for command -``` - -## Why yalc? - -npm link & yarn link unfortunately can easily break the [rules of hooks](https://legacy.reactjs.org/docs/hooks-rules.html) due to the way packages are resolved using symlinks. - -Yalc bypass this problem as it more closely resembles installing a dependency as normal. diff --git a/docs/docs/docs/01-core/strapi/commands/plugin/_category_.json b/docs/docs/docs/01-core/strapi/commands/plugin/_category_.json deleted file mode 100644 index e74aeb452c..0000000000 --- a/docs/docs/docs/01-core/strapi/commands/plugin/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "label": "plugin", - "collapsible": true, - "collapsed": true -} diff --git a/packages/core/strapi/src/cli/commands/index.ts b/packages/core/strapi/src/cli/commands/index.ts index 973797ce92..47db2b0c7a 100644 --- a/packages/core/strapi/src/cli/commands/index.ts +++ b/packages/core/strapi/src/cli/commands/index.ts @@ -25,11 +25,6 @@ import exportCommand from './export/command'; import importCommand from './import/command'; import transferCommand from './transfer/command'; -import { command as buildPluginCommand } from './plugin/build'; -import { command as initPluginCommand } from './plugin/init'; -import { command as linkWatchPluginCommand } from './plugin/link-watch'; -import { command as watchPluginCommand } from './plugin/watch'; -import { command as verifyPluginCommand } from './plugin/verify'; import { StrapiCommand } from '../types'; export const commands: StrapiCommand[] = [ @@ -59,12 +54,4 @@ export const commands: StrapiCommand[] = [ exportCommand, importCommand, transferCommand, - /** - * Plugins - */ - buildPluginCommand, - initPluginCommand, - linkWatchPluginCommand, - watchPluginCommand, - verifyPluginCommand, ]; diff --git a/packages/core/strapi/src/cli/commands/plugin/build.ts b/packages/core/strapi/src/cli/commands/plugin/build.ts deleted file mode 100644 index 7af80b31db..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/build.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { createCommand } from 'commander'; -import boxen from 'boxen'; -import chalk from 'chalk'; -import { BuildCLIOptions, ConfigBundle, build } from '@strapi/pack-up'; - -import { forceOption } from '../../utils/commander'; -import { runAction } from '../../utils/helpers'; -import { Export, loadPkg, validatePkg } from '../../utils/pkg'; -import type { CLIContext, StrapiCommand } from '../../types'; - -interface ActionOptions extends BuildCLIOptions { - force?: boolean; -} - -const action = async ( - { force, ...opts }: ActionOptions, - _cmd: unknown, - { logger, cwd }: CLIContext -) => { - try { - /** - * ALWAYS set production for using plugin build CLI. - */ - process.env.NODE_ENV = 'production'; - - const pkg = await loadPkg({ cwd, logger }); - const pkgJson = await validatePkg({ pkg }); - - if (!pkgJson.exports['./strapi-admin'] && !pkgJson.exports['./strapi-server']) { - throw new Error( - 'You need to have either a strapi-admin or strapi-server export in your package.json' - ); - } - - const bundles: ConfigBundle[] = []; - - if (pkgJson.exports['./strapi-admin']) { - const exp = pkgJson.exports['./strapi-admin'] as Export; - - const bundle: ConfigBundle = { - source: exp.source, - import: exp.import, - require: exp.require, - runtime: 'web', - }; - - if (exp.types) { - bundle.types = exp.types; - // TODO: should this be sliced from the source path...? - bundle.tsconfig = './admin/tsconfig.build.json'; - } - - bundles.push(bundle); - } - - if (pkgJson.exports['./strapi-server']) { - const exp = pkgJson.exports['./strapi-server'] as Export; - - const bundle: ConfigBundle = { - source: exp.source, - import: exp.import, - require: exp.require, - runtime: 'node', - }; - - if (exp.types) { - bundle.types = exp.types; - // TODO: should this be sliced from the source path...? - bundle.tsconfig = './server/tsconfig.build.json'; - } - - bundles.push(bundle); - } - - await build({ - cwd, - configFile: false, - config: { - bundles, - dist: './dist', - /** - * ignore the exports map of a plugin, because we're streamlining the - * process and ensuring the server package and admin package are built - * with the correct runtime and their individual tsconfigs - */ - exports: {}, - }, - ...opts, - }); - } catch (err) { - logger.error( - 'There seems to be an unexpected error, try again with --debug for more information \n' - ); - if (err instanceof Error && err.stack) { - console.log( - chalk.red( - boxen(err.stack, { - padding: 1, - align: 'left', - }) - ) - ); - } - process.exit(1); - } -}; - -/** - * `$ strapi plugin:build` - */ -const command: StrapiCommand = ({ ctx }) => { - return createCommand('plugin:build') - .description('Bundle your strapi plugin for publishing.') - .addOption(forceOption) - .option('-d, --debug', 'Enable debugging mode with verbose logs', false) - .option('--silent', "Don't log anything", false) - .option('--sourcemap', 'produce sourcemaps', false) - .option('--minify', 'minify the output', false) - .action((...args) => runAction('plugin:build', action)(...args, ctx)); -}; - -export { command }; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/action.ts b/packages/core/strapi/src/cli/commands/plugin/init/action.ts deleted file mode 100644 index d2aa160808..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/action.ts +++ /dev/null @@ -1,537 +0,0 @@ -import path from 'node:path'; -import boxen from 'boxen'; -import chalk from 'chalk'; -import getLatestVersion from 'get-latest-version'; -import gitUrlParse from 'git-url-parse'; -import { - InitOptions, - definePackageFeature, - definePackageOption, - defineTemplate, - init, - TemplateFile, -} from '@strapi/pack-up'; -import { outdent } from 'outdent'; - -import { CLIContext } from '../../../types'; -import { gitIgnoreFile } from './files/gitIgnore'; - -type ActionOptions = Pick; - -export default async ( - packagePath: string, - { silent, debug }: ActionOptions, - { logger, cwd }: CLIContext -) => { - try { - /** - * Create the package // plugin - */ - await init({ - path: packagePath, - cwd, - silent, - debug, - template: PLUGIN_TEMPLATE, - }); - - logger.info("Don't forget to enable your plugin in your configuration files."); - } catch (err) { - logger.error( - 'There seems to be an unexpected error, try again with --debug for more information \n' - ); - if (err instanceof Error && err.stack) { - logger.log( - chalk.red( - boxen(err.stack, { - padding: 1, - align: 'left', - }) - ) - ); - } - process.exit(1); - } -}; - -const PACKAGE_NAME_REGEXP = /^(?:@(?:[a-z0-9-*~][a-z0-9-*._~]*)\/)?[a-z0-9-~][a-z0-9-._~]*$/i; - -interface PackageExport { - types?: string; - require: string; - import: string; - source: string; - default: string; -} - -interface PluginPackageJson { - name?: string; - description?: string; - version?: string; - keywords?: string[]; - type: 'commonjs'; - license?: string; - repository?: { - type: 'git'; - url: string; - }; - bugs?: { - url: string; - }; - homepage?: string; - author?: string; - exports: { - './strapi-admin'?: PackageExport; - './strapi-server'?: PackageExport; - './package.json': `${string}.json`; - }; - files: string[]; - scripts: Record; - dependencies: Record; - devDependencies: Record; - peerDependencies: Record; - strapi: { - name?: string; - displayName?: string; - description?: string; - kind: 'plugin'; - }; -} - -const PLUGIN_TEMPLATE = defineTemplate(async ({ logger, gitConfig, packagePath }) => { - let repo: { - source?: string; - owner?: string; - name?: string; - }; - - const [packageFolder] = packagePath.split(path.sep).slice(-1); - - return { - prompts: [ - definePackageOption({ - name: 'repo', - type: 'text', - message: 'git url', - validate(v) { - if (!v) { - return true; - } - - try { - const result = gitUrlParse(v); - - repo = { source: result.source, owner: result.owner, name: result.name }; - - return true; - } catch (err) { - return 'invalid git url'; - } - }, - }), - definePackageOption({ - name: 'pkgName', - type: 'text', - message: 'plugin name', - initial: () => repo?.name ?? '', - validate(v) { - if (!v) { - return 'package name is required'; - } - - const match = PACKAGE_NAME_REGEXP.exec(v); - - if (!match) { - return 'invalid package name'; - } - - return true; - }, - }), - definePackageOption({ - name: 'displayName', - type: 'text', - message: 'plugin display name', - }), - definePackageOption({ - name: 'description', - type: 'text', - message: 'plugin description', - }), - definePackageOption({ - name: 'authorName', - type: 'text', - message: 'plugin author name', - initial: gitConfig?.user?.name, - }), - definePackageOption({ - name: 'authorEmail', - type: 'text', - message: 'plugin author email', - initial: gitConfig?.user?.email, - }), - definePackageOption({ - name: 'license', - type: 'text', - message: 'plugin license', - initial: 'MIT', - validate(v) { - if (!v) { - return 'license is required'; - } - - return true; - }, - }), - definePackageOption({ - name: 'client-code', - type: 'confirm', - message: 'register with the admin panel?', - initial: true, - }), - definePackageOption({ - name: 'server-code', - type: 'confirm', - message: 'register with the server?', - initial: true, - }), - definePackageFeature({ - name: 'editorconfig', - initial: true, - optional: true, - }), - definePackageFeature({ - name: 'eslint', - initial: true, - optional: true, - }), - definePackageFeature({ - name: 'prettier', - initial: true, - optional: true, - }), - definePackageFeature({ - name: 'typescript', - initial: true, - optional: true, - }), - ], - async getFiles(answers) { - const author: string[] = []; - - const files: TemplateFile[] = []; - - // package.json - const pkgJson: PluginPackageJson = { - version: '0.0.0', - keywords: [], - type: 'commonjs', - exports: { - './package.json': './package.json', - }, - files: ['dist'], - scripts: { - build: 'strapi plugin:build', - watch: 'strapi plugin:watch', - 'watch:link': 'strapi plugin:watch:link', - verify: 'strapi plugin:verify', - }, - dependencies: {}, - devDependencies: { - /** - * We set * as a default version, but further down - * we try to resolve each package to their latest - * version, failing that we leave the fallback of *. - */ - '@strapi/strapi': '*', - prettier: '*', - }, - peerDependencies: { - '@strapi/strapi': '^4.0.0', - }, - strapi: { - kind: 'plugin', - }, - }; - - if (Array.isArray(answers)) { - for (const ans of answers) { - const { name, answer } = ans; - - switch (name) { - case 'pkgName': { - pkgJson.name = String(answer); - pkgJson.strapi.name = String(answer); - break; - } - case 'description': { - pkgJson.description = String(answer) ?? undefined; - pkgJson.strapi.description = String(answer) ?? undefined; - break; - } - case 'displayName': { - pkgJson.strapi.displayName = String(answer) ?? undefined; - break; - } - case 'authorName': { - author.push(String(answer)); - break; - } - case 'authorEmail': { - if (answer) { - author.push(`<${answer}>`); - } - break; - } - case 'license': { - pkgJson.license = String(answer); - break; - } - case 'client-code': { - if (answer) { - pkgJson.exports['./strapi-admin'] = { - source: './admin/src/index.js', - import: './dist/admin/index.mjs', - require: './dist/admin/index.js', - default: './dist/admin/index.js', - }; - - pkgJson.dependencies = { - ...pkgJson.dependencies, - '@strapi/design-system': '*', - '@strapi/icons': '*', - }; - - pkgJson.devDependencies = { - ...pkgJson.devDependencies, - react: '*', - 'react-dom': '*', - 'react-router-dom': '*', - 'styled-components': '*', - }; - - pkgJson.peerDependencies = { - ...pkgJson.peerDependencies, - react: '^17.0.0 || ^18.0.0', - 'react-dom': '^17.0.0 || ^18.0.0', - 'react-router-dom': '^6.0.0', - 'styled-components': '^6.0.0', - }; - } - - break; - } - case 'server-code': { - if (answer) { - pkgJson.exports['./strapi-server'] = { - source: './server/src/index.js', - import: './dist/server/index.mjs', - require: './dist/server/index.js', - default: './dist/server/index.js', - }; - - pkgJson.files.push('./strapi-server.js'); - - files.push({ - name: 'strapi-server.js', - contents: outdent` - 'use strict'; - - module.exports = require('./dist/server'); - `, - }); - } - - break; - } - case 'typescript': { - const isTypescript = Boolean(answer); - - if (isTypescript) { - if (isRecord(pkgJson.exports['./strapi-admin'])) { - pkgJson.exports['./strapi-admin'].source = './admin/src/index.ts'; - - pkgJson.exports['./strapi-admin'] = { - types: './dist/admin/src/index.d.ts', - ...pkgJson.exports['./strapi-admin'], - }; - - pkgJson.scripts = { - ...pkgJson.scripts, - 'test:ts:front': 'run -T tsc -p admin/tsconfig.json', - }; - - pkgJson.devDependencies = { - ...pkgJson.devDependencies, - '@types/react': '*', - '@types/react-dom': '*', - }; - - const { adminTsconfigFiles } = await import('./files/typescript'); - - files.push(adminTsconfigFiles.tsconfigBuildFile, adminTsconfigFiles.tsconfigFile); - } - - if (isRecord(pkgJson.exports['./strapi-server'])) { - pkgJson.exports['./strapi-server'].source = './server/src/index.ts'; - - pkgJson.exports['./strapi-server'] = { - types: './dist/server/src/index.d.ts', - ...pkgJson.exports['./strapi-server'], - }; - - pkgJson.scripts = { - ...pkgJson.scripts, - 'test:ts:back': 'run -T tsc -p server/tsconfig.json', - }; - - const { serverTsconfigFiles } = await import('./files/typescript'); - - files.push( - serverTsconfigFiles.tsconfigBuildFile, - serverTsconfigFiles.tsconfigFile - ); - } - - pkgJson.devDependencies = { - ...pkgJson.devDependencies, - '@strapi/typescript-utils': '*', - typescript: '*', - }; - } - - /** - * This is where we add all the source files regardless - * of whether they are typescript or javascript. - */ - if (isRecord(pkgJson.exports['./strapi-admin'])) { - files.push({ - name: isTypescript ? 'admin/src/pluginId.ts' : 'admin/src/pluginId.js', - contents: outdent` - export const PLUGIN_ID = '${pkgJson.name!.replace(/^strapi-plugin-/i, '')}'; - `, - }); - - if (isTypescript) { - const { adminTypescriptFiles } = await import('./files/admin'); - - files.push(...adminTypescriptFiles); - } else { - const { adminJavascriptFiles } = await import('./files/admin'); - - files.push(...adminJavascriptFiles); - } - } - - if (isRecord(pkgJson.exports['./strapi-server'])) { - if (isTypescript) { - const { serverTypescriptFiles } = await import('./files/server'); - - files.push(...serverTypescriptFiles(packageFolder)); - } else { - const { serverJavascriptFiles } = await import('./files/server'); - - files.push(...serverJavascriptFiles(packageFolder)); - } - } - - break; - } - case 'eslint': { - if (answer) { - const { eslintIgnoreFile } = await import('./files/eslint'); - - files.push(eslintIgnoreFile); - } - - break; - } - case 'prettier': { - if (answer) { - const { prettierFile, prettierIgnoreFile } = await import('./files/prettier'); - - files.push(prettierFile, prettierIgnoreFile); - } - break; - } - case 'editorconfig': { - if (answer) { - const { editorConfigFile } = await import('./files/editorConfig'); - - files.push(editorConfigFile); - } - break; - } - default: - break; - } - } - } - - if (repo) { - pkgJson.repository = { - type: 'git', - url: `git+ssh://git@${repo.source}/${repo.owner}/${repo.name}.git`, - }; - pkgJson.bugs = { - url: `https://${repo.source}/${repo.owner}/${repo.name}/issues`, - }; - pkgJson.homepage = `https://${repo.source}/${repo.owner}/${repo.name}#readme`; - } - - pkgJson.author = author.filter(Boolean).join(' ') ?? undefined; - - try { - pkgJson.devDependencies = await resolveLatestVerisonOfDeps(pkgJson.devDependencies); - pkgJson.dependencies = await resolveLatestVerisonOfDeps(pkgJson.dependencies); - pkgJson.peerDependencies = await resolveLatestVerisonOfDeps(pkgJson.peerDependencies); - } catch (err) { - if (err instanceof Error) { - logger.error(err.message); - } else { - logger.error(err); - } - } - - files.push({ - name: 'package.json', - contents: outdent` - ${JSON.stringify(pkgJson, null, 2)} - `, - }); - - files.push({ - name: 'README.md', - contents: outdent` - # ${pkgJson.name} - - ${pkgJson.description ?? ''} - `, - }); - - files.push(gitIgnoreFile); - - return files; - }, - }; -}); - -const isRecord = (value: unknown): value is Record => - Boolean(value) && !Array.isArray(value) && typeof value === 'object'; - -const resolveLatestVerisonOfDeps = async ( - deps: Record -): Promise> => { - const latestDeps: Record = {}; - - for (const [name, version] of Object.entries(deps)) { - try { - const latestVersion = await getLatestVersion(name, version); - latestDeps[name] = latestVersion ? `^${latestVersion}` : '*'; - } catch (err) { - latestDeps[name] = '*'; - } - } - - return latestDeps; -}; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/command.ts b/packages/core/strapi/src/cli/commands/plugin/init/command.ts deleted file mode 100644 index 5ca50f653f..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/command.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { StrapiCommand } from '../../../types'; -import action from './action'; - -/** - * `$ strapi plugin:init` - */ -const command: StrapiCommand = ({ command, ctx }) => { - command - .command('plugin:init') - .description('Create a new plugin at a given path') - .argument('[path]', 'path to the plugin', './src/plugins/my-plugin') - .option('-d, --debug', 'Enable debugging mode with verbose logs', false) - .option('--silent', "Don't log anything", false) - .action((path, options) => { - return action(path, options, ctx); - }); -}; - -export default command; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/files/admin.ts b/packages/core/strapi/src/cli/commands/plugin/init/files/admin.ts deleted file mode 100644 index d0805612f2..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/files/admin.ts +++ /dev/null @@ -1,286 +0,0 @@ -import { TemplateFile } from '@strapi/pack-up'; -import { outdent } from 'outdent'; - -const PLUGIN_ICON_CODE = outdent` -import { Puzzle } from '@strapi/icons'; - -const PluginIcon = Puzzle; - -export { PluginIcon }; -`; - -const APP_CODE = outdent` -import { Page } from '@strapi/strapi/admin'; -import { Switch, Route } from 'react-router-dom'; - -import { PLUGIN_ID } from '../pluginId'; - -import { HomePage } from './HomePage'; - -const App = () => { - return ( - - } /> - } /> - - ); -}; - -export { App }; -`; - -const HOMEPAGE_CODE = outdent` - import { Main } from '@strapi/design-system'; - import { useIntl } from 'react-intl'; - - import { getTranslation } from '../utils/getTranslation'; - - const HomePage = () => { - const { formatMessage } = useIntl(); - - return ( -
-

Welcome to {formatMessage({ id: getTranslation("plugin.name") })}

-
- ) - } - - export { HomePage }; -`; - -const TYPESCRIPT: TemplateFile[] = [ - { - name: 'admin/src/index.ts', - contents: outdent` - import { prefixPluginTranslations } from './utils/prefixPluginTranslations'; - import { PLUGIN_ID } from './pluginId'; - import { Initializer } from './components/Initializer'; - import { PluginIcon } from './components/PluginIcon'; - - export default { - register(app: any) { - app.addMenuLink({ - to: \`plugins/\${PLUGIN_ID}\`, - icon: PluginIcon, - intlLabel: { - id: \`\${PLUGIN_ID}.plugin.name\`, - defaultMessage: PLUGIN_ID, - }, - Component: async () => { - const { App } = await import('./pages/App'); - - return App; - }, - }); - - app.registerPlugin({ - id: PLUGIN_ID, - initializer: Initializer, - isReady: false, - name: PLUGIN_ID, - }); - }, - - async registerTrads(app: any) { - const { locales } = app; - - const importedTranslations = await Promise.all( - (locales as string[]).map((locale) => { - return import(\`./translations/\${locale}.json\`) - .then(({ default: data }) => { - return { - data: prefixPluginTranslations(data, PLUGIN_ID), - locale, - }; - }) - .catch(() => { - return { - data: {}, - locale, - }; - }); - }) - ); - - return importedTranslations; - }, - }; - `, - }, - { - name: 'admin/src/components/PluginIcon.tsx', - contents: PLUGIN_ICON_CODE, - }, - { - name: 'admin/src/components/Initializer.tsx', - contents: outdent` - import { useEffect, useRef } from 'react'; - - import { PLUGIN_ID } from '../pluginId'; - - type InitializerProps = { - setPlugin: (id: string) => void; - }; - - const Initializer = ({ setPlugin }: InitializerProps) => { - const ref = useRef(setPlugin); - - useEffect(() => { - ref.current(PLUGIN_ID); - }, []); - - return null; - }; - - export { Initializer }; - `, - }, - { - name: 'admin/src/pages/App.tsx', - contents: APP_CODE, - }, - { - name: 'admin/src/pages/HomePage.tsx', - contents: HOMEPAGE_CODE, - }, - { - name: 'admin/src/utils/getTranslation.ts', - contents: outdent` - import { PLUGIN_ID } from '../pluginId'; - - const getTranslation = (id: string) => \`\${PLUGIN_ID}.\${id}\`; - - export { getTranslation }; - `, - }, - { - name: 'admin/src/translations/en.json', - contents: outdent` - {} - `, - }, - { - /** - * TODO: remove this when we release design-system V2 - */ - name: 'admin/custom.d.ts', - contents: outdent` - declare module '@strapi/design-system/*'; - declare module '@strapi/design-system'; - `, - }, -]; - -const JAVASCRIPT: TemplateFile[] = [ - { - name: 'admin/src/index.js', - contents: outdent` - import { prefixPluginTranslations } from './utils/prefixPluginTranslations'; - import { PLUGIN_ID } from './pluginId'; - import { Initializer } from './components/Initializer'; - import { PluginIcon } from './components/PluginIcon'; - - export default { - register(app) { - app.addMenuLink({ - to: \`plugins/\${PluginIcon}\`, - icon: PluginIcon, - intlLabel: { - id: \`\${PLUGIN_ID}.plugin.name\`, - defaultMessage: PLUGIN_ID, - }, - Component: async () => { - const { App } = await import('./pages/App'); - - return App; - }, - }); - - app.registerPlugin({ - id: PLUGIN_ID, - initializer: Initializer, - isReady: false, - name: PLUGIN_ID, - }); - }, - - async registerTrads(app) { - const { locales } = app; - - const importedTranslations = await Promise.all( - locales.map((locale) => { - return import(\`./translations/\${locale}.json\`) - .then(({ default: data }) => { - return { - data: prefixPluginTranslations(data, PLUGIN_ID), - locale, - }; - }) - .catch(() => { - return { - data: {}, - locale, - }; - }); - }) - ); - - return importedTranslations; - }, - }; - `, - }, - { - name: 'admin/src/components/PluginIcon.jsx', - contents: PLUGIN_ICON_CODE, - }, - { - name: 'admin/src/components/Initializer.jsx', - contents: outdent` - import { useEffect, useRef } from 'react'; - - import { PLUGIN_ID } from '../pluginId'; - - /** - * @type {import('react').FC<{ setPlugin: (id: string) => void }>} - */ - const Initializer = ({ setPlugin }) => { - const ref = useRef(setPlugin); - - useEffect(() => { - ref.current(PLUGIN_ID); - }, []); - - return null; - }; - - export { Initializer }; - `, - }, - { - name: 'admin/src/pages/App.jsx', - contents: APP_CODE, - }, - { - name: 'admin/src/pages/HomePage.jsx', - contents: HOMEPAGE_CODE, - }, - { - name: 'admin/src/utils/getTranslation.js', - contents: outdent` - import { PLUGIN_ID } from '../pluginId'; - - const getTranslation = (id) => \`\${PLUGIN_ID}.\${id}\`; - - export { getTranslation }; - `, - }, - { - name: 'admin/src/translations/en.json', - contents: outdent` - {} - `, - }, -]; - -export { TYPESCRIPT as adminTypescriptFiles, JAVASCRIPT as adminJavascriptFiles }; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/files/editorConfig.ts b/packages/core/strapi/src/cli/commands/plugin/init/files/editorConfig.ts deleted file mode 100644 index f5e8a94389..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/files/editorConfig.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { TemplateFile } from '@strapi/pack-up'; -import { outdent } from 'outdent'; - -const editorConfigFile: TemplateFile = { - name: '.editorconfig', - contents: outdent` - root = true - - [*] - indent_style = space - indent_size = 2 - end_of_line = lf - charset = utf-8 - trim_trailing_whitespace = true - insert_final_newline = true - - [{package.json,*.yml}] - indent_style = space - indent_size = 2 - - [*.md] - trim_trailing_whitespace = false - `, -}; - -export { editorConfigFile }; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/files/eslint.ts b/packages/core/strapi/src/cli/commands/plugin/init/files/eslint.ts deleted file mode 100644 index 9781f08fac..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/files/eslint.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { TemplateFile } from '@strapi/pack-up'; -import { outdent } from 'outdent'; - -const eslintIgnoreFile: TemplateFile = { - name: '.eslintignore', - contents: outdent` - dist - `, -}; - -export { eslintIgnoreFile }; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/files/gitIgnore.ts b/packages/core/strapi/src/cli/commands/plugin/init/files/gitIgnore.ts deleted file mode 100644 index 45f9c8d546..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/files/gitIgnore.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { TemplateFile } from '@strapi/pack-up'; -import { outdent } from 'outdent'; - -const gitIgnoreFile: TemplateFile = { - name: '.gitignore', - contents: outdent` - # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - - # dependencies - node_modules - .pnp - .pnp.js - - # testing - coverage - - # production - dist - - # misc - .DS_Store - *.pem - - # debug - npm-debug.log* - yarn-debug.log* - yarn-error.log* - - # local env files - .env - `, -}; - -export { gitIgnoreFile }; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/files/prettier.ts b/packages/core/strapi/src/cli/commands/plugin/init/files/prettier.ts deleted file mode 100644 index c001feb635..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/files/prettier.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { TemplateFile } from '@strapi/pack-up'; -import { outdent } from 'outdent'; - -const prettierFile: TemplateFile = { - name: '.prettierrc', - contents: outdent` - { - "endOfLine": 'lf', - "tabWidth": 2, - "printWidth": 100, - "singleQuote": true, - "trailingComma": 'es5', - } - `, -}; - -const prettierIgnoreFile: TemplateFile = { - name: '.prettierignore', - contents: outdent` - dist - coverage - `, -}; - -export { prettierFile, prettierIgnoreFile }; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/files/server.ts b/packages/core/strapi/src/cli/commands/plugin/init/files/server.ts deleted file mode 100644 index 128ef8e245..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/files/server.ts +++ /dev/null @@ -1,360 +0,0 @@ -import { TemplateFile } from '@strapi/pack-up'; -import { outdent } from 'outdent'; - -const TYPESCRIPT = (pluginName: string): TemplateFile[] => [ - { - name: 'server/src/index.ts', - contents: outdent` - /** - * Application methods - */ - import bootstrap from './bootstrap'; - import destroy from './destroy'; - import register from './register'; - - /** - * Plugin server methods - */ - import config from './config'; - import contentTypes from './content-types'; - import controllers from './controllers'; - import middlewares from './middlewares'; - import policies from './policies'; - import routes from './routes'; - import services from './services'; - - export default { - bootstrap, - destroy, - register, - - config, - controllers, - contentTypes, - middlewares, - policies, - routes, - services, - }; - `, - }, - { - name: 'server/src/bootstrap.ts', - contents: outdent` - import type { Core } from '@strapi/strapi'; - - const bootstrap = ({ strapi }: { strapi: Core.Strapi }) => { - // bootstrap phase - }; - - export default bootstrap; - `, - }, - { - name: 'server/src/destroy.ts', - contents: outdent` - import type { Core } from '@strapi/strapi'; - - const destroy = ({ strapi }: { strapi: Core.Strapi }) => { - // destroy phase - }; - - export default destroy; - `, - }, - { - name: 'server/src/register.ts', - contents: outdent` - import type { Core } from '@strapi/strapi'; - - const register = ({ strapi }: { strapi: Core.Strapi }) => { - // register phase - }; - - export default register; - `, - }, - { - name: 'server/src/config/index.ts', - contents: outdent` - export default { - default: {}, - validator() {}, - }; - `, - }, - { - name: 'server/src/content-types/index.ts', - contents: outdent` - export default {}; - `, - }, - { - name: 'server/src/controllers/index.ts', - contents: outdent` - import controller from './controller'; - - export default { - controller, - }; - `, - }, - { - name: 'server/src/controllers/controller.ts', - contents: outdent` - import type { Core } from '@strapi/strapi'; - - const controller = ({ strapi }: { strapi: Core.Strapi }) => ({ - index(ctx) { - ctx.body = strapi - .plugin('${pluginName}') - // the name of the service file & the method. - .service('service') - .getWelcomeMessage(); - }, - }); - - export default controller - `, - }, - { - name: 'server/src/middlewares/index.ts', - contents: outdent` - export default {}; - `, - }, - { - name: 'server/src/policies/index.ts', - contents: outdent` - export default {}; - `, - }, - { - name: 'server/src/routes/index.ts', - contents: outdent` - export default [ - { - method: 'GET', - path: '/', - // name of the controller file & the method. - handler: 'controller.index', - config: { - policies: [], - }, - }, - ]; - `, - }, - { - name: 'server/src/services/index.ts', - contents: outdent` - import service from './service'; - - export default { - service, - }; - `, - }, - { - name: 'server/src/services/service.ts', - contents: outdent` - import type { Core } from '@strapi/strapi'; - - const service = ({ strapi }: { strapi: Core.Strapi }) => ({ - getWelcomeMessage() { - return 'Welcome to Strapi 🚀'; - }, - }); - - export default service - `, - }, -]; - -const JAVASCRIPT = (pluginName: string): TemplateFile[] => [ - { - name: 'server/src/index.ts', - contents: outdent` - 'use strict'; - - /** - * Application methods - */ - const bootstrap = require('./bootstrap'); - const destroy = require('./destroy'); - const register = require('./register'); - - /** - * Plugin server methods - */ - const config = require('./config'); - const contentTypes = require('./content-types'); - const controllers = require('./controllers'); - const middlewares = require('./middlewares'); - const policies = require('./policies'); - const routes = require('./routes'); - const services = require('./services'); - - module.exports = { - bootstrap, - destroy, - register, - - config, - controllers, - contentTypes, - middlewares, - policies, - routes, - services, - }; - `, - }, - { - name: 'server/src/bootstrap.ts', - contents: outdent` - 'use strict'; - - const bootstrap = ({ strapi }) => { - // bootstrap phase - }; - - module.exports = bootstrap; - `, - }, - { - name: 'server/src/destroy.ts', - contents: outdent` - 'use strict'; - - const destroy = ({ strapi }) => { - // destroy phase - }; - - module.exports = destroy; - `, - }, - { - name: 'server/src/register.ts', - contents: outdent` - 'use strict'; - - const register = ({ strapi }) => { - // register phase - }; - - module.exports = register; - `, - }, - { - name: 'server/src/config/index.ts', - contents: outdent` - 'use strict'; - - module.exports = { - default: {}, - validator() {}, - }; - `, - }, - { - name: 'server/src/content-types/index.ts', - contents: outdent` - 'use strict'; - - module.exports = {}; - `, - }, - { - name: 'server/src/controllers/index.ts', - contents: outdent` - 'use strict'; - - const controller = require('./controller'); - - module.exports = { - controller, - }; - `, - }, - { - name: 'server/src/controllers/controller.ts', - contents: outdent` - 'use strict'; - - const controller = ({ strapi }) => ({ - index(ctx) { - ctx.body = strapi - .plugin('${pluginName}') - // the name of the service file & the method. - .service('service') - .getWelcomeMessage(); - }, - }); - - module.exports = controller - `, - }, - { - name: 'server/src/middlewares/index.ts', - contents: outdent` - 'use strict'; - - module.exports = {}; - `, - }, - { - name: 'server/src/policies/index.ts', - contents: outdent` - 'use strict'; - - module.exports = {}; - `, - }, - { - name: 'server/src/routes/index.ts', - contents: outdent` - 'use strict'; - - module.exports = [ - { - method: 'GET', - path: '/', - // name of the controller file & the method. - handler: 'controller.index', - config: { - policies: [], - }, - }, - ]; - `, - }, - { - name: 'server/src/services/index.ts', - contents: outdent` - 'use strict'; - - const service = require('./service'); - - module.exports = { - service, - }; - `, - }, - { - name: 'server/src/services/service.ts', - contents: outdent` - 'use strict'; - - const service = ({ strapi }) => ({ - getWelcomeMessage() { - return 'Welcome to Strapi 🚀'; - }, - }); - - module.exports = service - `, - }, -]; - -export { TYPESCRIPT as serverTypescriptFiles, JAVASCRIPT as serverJavascriptFiles }; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/files/typescript.ts b/packages/core/strapi/src/cli/commands/plugin/init/files/typescript.ts deleted file mode 100644 index 46f9de2d47..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/files/typescript.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { TemplateFile } from '@strapi/pack-up'; -import { outdent } from 'outdent'; - -interface TsConfigFiles { - tsconfigFile: TemplateFile; - tsconfigBuildFile: TemplateFile; -} - -const ADMIN: TsConfigFiles = { - tsconfigFile: { - name: 'admin/tsconfig.json', - contents: outdent` - { - "extends": "@strapi/typescript-utils/tsconfigs/admin", - "include": ["./src", "./custom.d.ts"], - "compilerOptions": { - "rootDir": "../", - "baseUrl": ".", - }, - } - `, - }, - tsconfigBuildFile: { - name: 'admin/tsconfig.build.json', - contents: outdent` - { - "extends": "./tsconfig", - "include": ["./src", "./custom.d.ts"], - "exclude": ["**/*.test.ts", "**/*.test.tsx"], - "compilerOptions": { - "rootDir": "../", - "baseUrl": ".", - "outDir": "./dist", - } - } - `, - }, -}; - -const SERVER: TsConfigFiles = { - tsconfigFile: { - name: 'server/tsconfig.json', - contents: outdent` - { - "extends": "@strapi/typescript-utils/tsconfigs/server", - "include": ["./src"], - "compilerOptions": { - "rootDir": "../", - "baseUrl": ".", - }, - } - `, - }, - tsconfigBuildFile: { - name: 'server/tsconfig.build.json', - contents: outdent` - { - "extends": "./tsconfig", - "include": ["./src"], - "exclude": ["**/*.test.ts"], - "compilerOptions": { - "rootDir": "../", - "baseUrl": ".", - "outDir": "./dist", - } - } - `, - }, -}; - -export { ADMIN as adminTsconfigFiles, SERVER as serverTsconfigFiles }; diff --git a/packages/core/strapi/src/cli/commands/plugin/init/index.ts b/packages/core/strapi/src/cli/commands/plugin/init/index.ts deleted file mode 100644 index 2fb7a39697..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/init/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as command } from './command'; diff --git a/packages/core/strapi/src/cli/commands/plugin/link-watch.ts b/packages/core/strapi/src/cli/commands/plugin/link-watch.ts deleted file mode 100644 index c88bb6b02f..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/link-watch.ts +++ /dev/null @@ -1,107 +0,0 @@ -import boxen from 'boxen'; -import chalk from 'chalk'; -import concurrently from 'concurrently'; -import fs from 'node:fs/promises'; -import path from 'node:path'; -import nodemon from 'nodemon'; -import { outdent } from 'outdent'; - -import { runAction } from '../../utils/helpers'; -import type { CLIContext, StrapiCommand } from '../../types'; -import { loadPkg, validatePkg } from '../../utils/pkg'; - -interface ActionOptions {} - -const action = async (_opts: ActionOptions, _cmd: unknown, { cwd, logger }: CLIContext) => { - try { - const outDir = './dist'; - const extensions = 'ts,js,png,svg,gif,jpeg,css'; - - nodemon({ - watch: [outDir], - ext: extensions, - exec: 'yalc push --changed', - }); - - const folder = path.join(cwd, outDir); - - if (!(await pathExists(folder))) { - await fs.mkdir(folder); - } - - const pkg = await loadPkg({ cwd, logger }); - const pkgJson = await validatePkg({ pkg }); - - concurrently(['npm run watch']); - - nodemon - .on('start', () => { - logger.info( - outdent` - Watching ${outDir} for changes to files with extensions: ${extensions} - - To use this package in Strapi, in a separate shell run: - cd /path/to/strapi/project - - Then run one of the commands below based on the package manager used in that project: - - ## yarn - ${chalk.greenBright(`yarn dlx yalc add --link ${pkgJson.name} && yarn install`)} - - ## npm - ${chalk.greenBright( - `npx yalc add ${pkgJson.name} && npx yalc link ${pkgJson.name} && npm install` - )} - `.trimStart() - ); - }) - .on('quit', () => { - process.exit(); - }) - .on('restart', (files) => { - logger.info('Found changes in files:', chalk.magentaBright(files)); - logger.info('Pushing new yalc package...'); - }); - } catch (err) { - logger.error( - 'There seems to be an unexpected error, try again with --debug for more information \n' - ); - if (err instanceof Error && err.stack) { - console.log( - chalk.red( - boxen(err.stack, { - padding: 1, - align: 'left', - }) - ) - ); - } - process.exit(1); - } -}; - -/** - * @internal - */ -const pathExists = async (path: string) => { - try { - await fs.access(path); - return true; - } catch (error) { - return false; - } -}; - -/** - * `$ strapi plugin:watch:link` - */ -const command: StrapiCommand = ({ command, ctx }) => { - command - .command('plugin:watch:link') - .description('Recompiles your plugin automatically on changes and runs yalc push --publish') - .option('-d, --debug', 'Enable debugging mode with verbose logs', false) - .option('--silent', "Don't log anything", false) - .action((...args) => runAction('plugin:watch:link', action)(...args, ctx)); -}; - -export { command }; diff --git a/packages/core/strapi/src/cli/commands/plugin/verify.ts b/packages/core/strapi/src/cli/commands/plugin/verify.ts deleted file mode 100644 index 8857748772..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/verify.ts +++ /dev/null @@ -1,46 +0,0 @@ -import boxen from 'boxen'; -import chalk from 'chalk'; -import { CheckOptions, check } from '@strapi/pack-up'; - -import { runAction } from '../../utils/helpers'; -import type { StrapiCommand, CLIContext } from '../../types'; - -type ActionOptions = CheckOptions; - -const action = async (opts: ActionOptions, _cmd: unknown, { cwd, logger }: CLIContext) => { - try { - await check({ - cwd, - ...opts, - }); - } catch (err) { - logger.error( - 'There seems to be an unexpected error, try again with --debug for more information \n' - ); - if (err instanceof Error && err.stack) { - console.log( - chalk.red( - boxen(err.stack, { - padding: 1, - align: 'left', - }) - ) - ); - } - process.exit(1); - } -}; - -/** - * `$ strapi plugin:verify` - */ -const command: StrapiCommand = ({ command, ctx }) => { - command - .command('plugin:verify') - .description('Verify the output of your plugin before publishing it.') - .option('-d, --debug', 'Enable debugging mode with verbose logs', false) - .option('--silent', "Don't log anything", false) - .action((...args) => runAction('plugin:verify', action)(...args, ctx)); -}; - -export { command }; diff --git a/packages/core/strapi/src/cli/commands/plugin/watch.ts b/packages/core/strapi/src/cli/commands/plugin/watch.ts deleted file mode 100644 index ac071e383d..0000000000 --- a/packages/core/strapi/src/cli/commands/plugin/watch.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { createCommand } from 'commander'; -import boxen from 'boxen'; -import chalk from 'chalk'; -import { ConfigBundle, WatchCLIOptions, watch } from '@strapi/pack-up'; - -import { runAction } from '../../utils/helpers'; -import { Export, loadPkg, validatePkg } from '../../utils/pkg'; -import type { StrapiCommand, CLIContext } from '../../types'; - -type ActionOptions = WatchCLIOptions; - -const action = async (opts: ActionOptions, _cmd: unknown, { cwd, logger }: CLIContext) => { - try { - const pkg = await loadPkg({ cwd, logger }); - const pkgJson = await validatePkg({ pkg }); - - if (!pkgJson.exports['./strapi-admin'] && !pkgJson.exports['./strapi-server']) { - throw new Error( - 'You need to have either a strapi-admin or strapi-server export in your package.json' - ); - } - - const bundles: ConfigBundle[] = []; - - if (pkgJson.exports['./strapi-admin']) { - const exp = pkgJson.exports['./strapi-admin'] as Export; - - const bundle: ConfigBundle = { - source: exp.source, - import: exp.import, - require: exp.require, - runtime: 'web', - }; - - if (exp.types) { - bundle.types = exp.types; - // TODO: should this be sliced from the source path...? - bundle.tsconfig = './admin/tsconfig.build.json'; - } - - bundles.push(bundle); - } - - if (pkgJson.exports['./strapi-server']) { - const exp = pkgJson.exports['./strapi-server'] as Export; - - const bundle: ConfigBundle = { - source: exp.source, - import: exp.import, - require: exp.require, - runtime: 'node', - }; - - if (exp.types) { - bundle.types = exp.types; - // TODO: should this be sliced from the source path...? - bundle.tsconfig = './server/tsconfig.build.json'; - } - - bundles.push(bundle); - } - - await watch({ - cwd, - configFile: false, - config: { - bundles, - dist: './dist', - /** - * ignore the exports map of a plugin, because we're streamlining the - * process and ensuring the server package and admin package are built - * with the correct runtime and their individual tsconfigs - */ - exports: {}, - }, - ...opts, - }); - } catch (err) { - logger.error( - 'There seems to be an unexpected error, try again with --debug for more information \n' - ); - if (err instanceof Error && err.stack) { - console.log( - chalk.red( - boxen(err.stack, { - padding: 1, - align: 'left', - }) - ) - ); - } - process.exit(1); - } -}; - -/** - * `$ strapi plugin:watch` - */ -const command: StrapiCommand = ({ ctx }) => { - return createCommand('plugin:watch') - .description('Watch & compile your strapi plugin for local development.') - .option('-d, --debug', 'Enable debugging mode with verbose logs', false) - .option('--silent', "Don't log anything", false) - .action((...args) => runAction('plugin:watch', action)(...args, ctx)); -}; - -export { command }; diff --git a/packages/core/strapi/src/cli/index.ts b/packages/core/strapi/src/cli/index.ts index 2c9d64f048..91a8461e34 100644 --- a/packages/core/strapi/src/cli/index.ts +++ b/packages/core/strapi/src/cli/index.ts @@ -54,6 +54,42 @@ const createCLI = async (argv: string[], command = new Command()) => { } }); + // TODO v6: remove these deprecation notices + const deprecatedCommands = [ + { name: 'plugin:init', message: 'Please use `npx @strapi/sdk-plugin init` instead.' }, + { + name: 'plugin:verify', + message: 'After migrating your plugin to v5, use `strapi-plugin verify`', + }, + { + name: 'plugin:watch', + message: 'After migrating your plugin to v5, use `strapi-plugin watch`', + }, + { + name: 'plugin:watch:link', + message: 'After migrating your plugin to v5, use `strapi-plugin watch:link`', + }, + { + name: 'plugin:build', + message: 'After migrating your plugin to v5, use `strapi-plugin build`', + }, + ]; + + // Add hidden commands for deprecatedCommands that output a warning that the command has been removed. + deprecatedCommands.forEach(({ name, message }) => { + const deprecated = new Command(name) + .command(name) + .description('(deprecated)') + .action(() => { + console.warn( + `The command ${name} has been deprecated. See the Strapi 5 migration guide for more information.` + ); + if (message) { + console.warn(message); + } + }); + command.addCommand(deprecated, { hidden: true }); + }); return command; }; diff --git a/packages/plugins/cloud/package.json b/packages/plugins/cloud/package.json index eb25f4f4ed..b96ebcc20c 100644 --- a/packages/plugins/cloud/package.json +++ b/packages/plugins/cloud/package.json @@ -29,9 +29,9 @@ "dist/" ], "scripts": { - "build": "strapi plugin:build --force", + "build": "strapi-plugin build", "clean": "run -T rimraf ./dist", - "develop": "strapi plugin:watch", + "develop": "strapi-plugin watch", "lint": "run -T eslint .", "test:ts:front": "run -T tsc -p admin/tsconfig.json" }, @@ -41,6 +41,7 @@ "react-intl": "6.6.2" }, "devDependencies": { + "@strapi/sdk-plugin": "^5.0.0", "@strapi/strapi": "5.0.0-beta.8", "eslint-config-custom": "5.0.0-beta.8", "react": "18.3.1", diff --git a/packages/plugins/color-picker/package.json b/packages/plugins/color-picker/package.json index ceb80d6f2f..19ed62b1c8 100644 --- a/packages/plugins/color-picker/package.json +++ b/packages/plugins/color-picker/package.json @@ -42,7 +42,7 @@ "strapi-server.js" ], "scripts": { - "build": "strapi plugin:build --force", + "build": "strapi-plugin build", "clean": "run -T rimraf ./dist", "lint": "run -T eslint .", "test:front": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js", @@ -50,7 +50,7 @@ "test:front:watch": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js --watchAll", "test:front:watch:ce": "run -T cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll", "test:ts:front": "run -T tsc -p admin/tsconfig.json", - "watch": "strapi plugin:watch" + "watch": "strapi-plugin watch" }, "dependencies": { "@strapi/design-system": "2.0.0-beta.4", @@ -59,6 +59,7 @@ "react-intl": "6.6.2" }, "devDependencies": { + "@strapi/sdk-plugin": "^5.0.0", "@strapi/strapi": "5.0.0-beta.8", "@testing-library/react": "15.0.7", "@testing-library/user-event": "14.5.2", diff --git a/packages/plugins/documentation/package.json b/packages/plugins/documentation/package.json index e8f96e5ad4..f33021eab0 100644 --- a/packages/plugins/documentation/package.json +++ b/packages/plugins/documentation/package.json @@ -42,7 +42,7 @@ "strapi-server.js" ], "scripts": { - "build": "strapi plugin:build --force", + "build": "strapi-plugin build", "clean": "run -T rimraf ./dist", "lint": "run -T eslint .", "test:front": "run -T cross-env IS_EE=true jest --config ./jest.config.front.js", @@ -51,7 +51,7 @@ "test:ts:back": "run -T tsc --noEmit -p server/tsconfig.json", "test:unit": "run -T jest --verbose", "test:unit:watch": "run -T jest --watch", - "watch": "strapi plugin:watch" + "watch": "strapi-plugin watch" }, "dependencies": { "@reduxjs/toolkit": "1.9.7", @@ -76,6 +76,7 @@ "@apidevtools/swagger-parser": "^10.1.0", "@strapi/admin-test-utils": "5.0.0-beta.8", "@strapi/pack-up": "5.0.0", + "@strapi/sdk-plugin": "^5.0.0", "@strapi/strapi": "5.0.0-beta.8", "@strapi/types": "5.0.0-beta.8", "@testing-library/react": "15.0.7", diff --git a/packages/plugins/graphql/package.json b/packages/plugins/graphql/package.json index d61b53fb68..073c58f14a 100644 --- a/packages/plugins/graphql/package.json +++ b/packages/plugins/graphql/package.json @@ -42,10 +42,10 @@ "strapi-server.js" ], "scripts": { - "build": "strapi plugin:build --force", + "build": "strapi-plugin build", "clean": "run -T rimraf ./dist", "lint": "run -T eslint .", - "watch": "strapi plugin:watch" + "watch": "strapi-plugin watch" }, "dependencies": { "@apollo/server": "4.10.0", @@ -67,6 +67,7 @@ "pluralize": "8.0.0" }, "devDependencies": { + "@strapi/sdk-plugin": "^5.0.0", "@strapi/strapi": "5.0.0-beta.8", "@strapi/types": "5.0.0-beta.8", "@types/graphql-depth-limit": "1.1.5", diff --git a/packages/plugins/sentry/package.json b/packages/plugins/sentry/package.json index 9af73c19cb..d91b0c962c 100644 --- a/packages/plugins/sentry/package.json +++ b/packages/plugins/sentry/package.json @@ -42,12 +42,12 @@ "strapi-server.js" ], "scripts": { - "build": "strapi plugin:build --force", + "build": "strapi-plugin build", "clean": "run -T rimraf dist", "lint": "run -T eslint .", "test:unit": "run -T jest", "test:unit:watch": "run -T jest --watch", - "watch": "strapi plugin:watch" + "watch": "strapi-plugin watch" }, "dependencies": { "@sentry/node": "7.112.2", @@ -56,6 +56,7 @@ }, "devDependencies": { "@strapi/pack-up": "5.0.0", + "@strapi/sdk-plugin": "^5.0.0", "@strapi/strapi": "5.0.0-beta.8", "react": "18.3.1", "react-dom": "18.3.1", diff --git a/yarn.lock b/yarn.lock index d97fa7afb9..96e64fffc0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7743,6 +7743,37 @@ __metadata: languageName: node linkType: hard +"@strapi/pack-up@npm:>=5.0.1-alpha.1 <6.0.0": + version: 5.0.1-alpha.1 + resolution: "@strapi/pack-up@npm:5.0.1-alpha.1" + dependencies: + "@vitejs/plugin-react-swc": "npm:3.6.0" + boxen: "npm:5.1.2" + browserslist-to-esbuild: "npm:1.2.0" + chalk: "npm:4.1.2" + chokidar: "npm:3.6.0" + commander: "npm:8.3.0" + esbuild: "npm:0.20.2" + esbuild-register: "npm:3.5.0" + get-latest-version: "npm:5.1.0" + git-url-parse: "npm:13.1.1" + ini: "npm:4.1.2" + ora: "npm:5.4.1" + outdent: "npm:0.8.0" + pkg-up: "npm:3.1.0" + prettier: "npm:2.8.8" + prettier-plugin-packagejson: "npm:2.4.14" + prompts: "npm:2.4.2" + rxjs: "npm:7.8.1" + typescript: "npm:5.4.4" + vite: "npm:5.2.8" + yup: "npm:0.32.9" + bin: + pack-up: bin/pack-up.js + checksum: 4e928bff3a759c3196091553f1f57fa5f678fd1da0f0de138e425afdfb1e4279f9272e1dafb5da1767a4a891f928a89d1d2dd41434d63eaad82a1215195abc4c + languageName: node + linkType: hard + "@strapi/permissions@npm:5.0.0-beta.8, @strapi/permissions@workspace:packages/core/permissions": version: 0.0.0-use.local resolution: "@strapi/permissions@workspace:packages/core/permissions" @@ -7764,6 +7795,7 @@ __metadata: dependencies: "@strapi/design-system": "npm:2.0.0-beta.4" "@strapi/icons": "npm:2.0.0-beta.4" + "@strapi/sdk-plugin": "npm:^5.0.0" "@strapi/strapi": "npm:5.0.0-beta.8" eslint-config-custom: "npm:5.0.0-beta.8" react: "npm:18.3.1" @@ -7788,6 +7820,7 @@ __metadata: dependencies: "@strapi/design-system": "npm:2.0.0-beta.4" "@strapi/icons": "npm:2.0.0-beta.4" + "@strapi/sdk-plugin": "npm:^5.0.0" "@strapi/strapi": "npm:5.0.0-beta.8" "@testing-library/react": "npm:15.0.7" "@testing-library/user-event": "npm:14.5.2" @@ -7818,6 +7851,7 @@ __metadata: "@strapi/design-system": "npm:2.0.0-beta.4" "@strapi/icons": "npm:2.0.0-beta.4" "@strapi/pack-up": "npm:5.0.0" + "@strapi/sdk-plugin": "npm:^5.0.0" "@strapi/strapi": "npm:5.0.0-beta.8" "@strapi/types": "npm:5.0.0-beta.8" "@strapi/utils": "npm:5.0.0-beta.8" @@ -7868,6 +7902,7 @@ __metadata: "@koa/cors": "npm:5.0.0" "@strapi/design-system": "npm:2.0.0-beta.4" "@strapi/icons": "npm:2.0.0-beta.4" + "@strapi/sdk-plugin": "npm:^5.0.0" "@strapi/strapi": "npm:5.0.0-beta.8" "@strapi/types": "npm:5.0.0-beta.8" "@strapi/utils": "npm:5.0.0-beta.8" @@ -7909,6 +7944,7 @@ __metadata: "@strapi/design-system": "npm:2.0.0-beta.4" "@strapi/icons": "npm:2.0.0-beta.4" "@strapi/pack-up": "npm:5.0.0" + "@strapi/sdk-plugin": "npm:^5.0.0" "@strapi/strapi": "npm:5.0.0-beta.8" react: "npm:18.3.1" react-dom: "npm:18.3.1" @@ -8117,6 +8153,31 @@ __metadata: languageName: unknown linkType: soft +"@strapi/sdk-plugin@npm:^5.0.0": + version: 5.0.0 + resolution: "@strapi/sdk-plugin@npm:5.0.0" + dependencies: + "@strapi/pack-up": "npm:>=5.0.1-alpha.1 <6.0.0" + "@types/prompts": "npm:2.4.9" + boxen: "npm:5.1.2" + chalk: "npm:4.1.2" + commander: "npm:12.1.0" + concurrently: "npm:^8.2.2" + get-latest-version: "npm:5.1.0" + git-url-parse: "npm:13.1.1" + nodemon: "npm:^3.1.0" + ora: "npm:5.4.1" + outdent: "npm:0.8.0" + pkg-up: "npm:3.1.0" + prettier: "npm:2.8.8" + typescript: "npm:5.4.4" + yup: "npm:0.32.9" + bin: + strapi-plugin: bin/strapi-plugin.js + checksum: 715d2a2f6fadc28b22ef3b01ae9637d157a88c5228b4298acf03ca75cbe7de96b830fa0b135ff671431d4e9040c8d3f77a63e6da2fd43edc24804592ca662bba + languageName: node + linkType: hard + "@strapi/strapi@npm:5.0.0-beta.8, @strapi/strapi@workspace:packages/core/strapi": version: 0.0.0-use.local resolution: "@strapi/strapi@workspace:packages/core/strapi" @@ -12905,6 +12966,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:12.1.0": + version: 12.1.0 + resolution: "commander@npm:12.1.0" + checksum: cdaeb672d979816853a4eed7f1310a9319e8b976172485c2a6b437ed0db0a389a44cfb222bfbde772781efa9f215bdd1b936f80d6b249485b465c6cb906e1f93 + languageName: node + linkType: hard + "commander@npm:8.3.0, commander@npm:^8.3.0": version: 8.3.0 resolution: "commander@npm:8.3.0" @@ -13030,7 +13098,7 @@ __metadata: languageName: node linkType: hard -"concurrently@npm:8.2.2": +"concurrently@npm:8.2.2, concurrently@npm:^8.2.2": version: 8.2.2 resolution: "concurrently@npm:8.2.2" dependencies: @@ -22724,6 +22792,26 @@ __metadata: languageName: node linkType: hard +"nodemon@npm:^3.1.0": + version: 3.1.0 + resolution: "nodemon@npm:3.1.0" + dependencies: + chokidar: "npm:^3.5.2" + debug: "npm:^4" + ignore-by-default: "npm:^1.0.1" + minimatch: "npm:^3.1.2" + pstree.remy: "npm:^1.1.8" + semver: "npm:^7.5.3" + simple-update-notifier: "npm:^2.0.0" + supports-color: "npm:^5.5.0" + touch: "npm:^3.1.0" + undefsafe: "npm:^2.0.5" + bin: + nodemon: bin/nodemon.js + checksum: a8757f3eda5e11fbe0e50ef47177d5e86cf8a22e99723373100d37d5f25fb758280419c02d286210d242d0675adf5ef0d61052948f10c8318d656761d3dfa2b1 + languageName: node + linkType: hard + "noms@npm:0.0.0": version: 0.0.0 resolution: "noms@npm:0.0.0"