chore: replace plugin cli with external strapi/sdk-plugin package

This commit is contained in:
Ben Irvin 2024-05-28 08:24:20 +02:00 committed by GitHub
parent 79490c1229
commit 04c4983e3d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
29 changed files with 140 additions and 2016 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
```

View File

@ -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.

View File

@ -1,5 +0,0 @@
{
"label": "plugin",
"collapsible": true,
"collapsed": true
}

View File

@ -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,
];

View File

@ -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 };

View File

@ -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<InitOptions, 'silent' | 'debug'>;
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<string, string>;
dependencies: Record<string, string>;
devDependencies: Record<string, string>;
peerDependencies: Record<string, string>;
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<string, unknown> =>
Boolean(value) && !Array.isArray(value) && typeof value === 'object';
const resolveLatestVerisonOfDeps = async (
deps: Record<string, string>
): Promise<Record<string, string>> => {
const latestDeps: Record<string, string> = {};
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;
};

View File

@ -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;

View File

@ -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 (
<Switch>
<Route index element={<HomePage />} />
<Route path="*" element={<Page.Error />} />
</Switch>
);
};
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 (
<Main>
<h1>Welcome to {formatMessage({ id: getTranslation("plugin.name") })}</h1>
</Main>
)
}
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 };

View File

@ -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 };

View File

@ -1,11 +0,0 @@
import { TemplateFile } from '@strapi/pack-up';
import { outdent } from 'outdent';
const eslintIgnoreFile: TemplateFile = {
name: '.eslintignore',
contents: outdent`
dist
`,
};
export { eslintIgnoreFile };

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -1 +0,0 @@
export { default as command } from './command';

View File

@ -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 };

View File

@ -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 };

View File

@ -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 };

View File

@ -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;
};

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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"