Skip to main content

v4 插件迁移:更新文件夹结构

¥v4 plugin migration: Updating the folder structure

本指南是 v4 插件迁移指南 的一部分,旨在帮助你将插件从 Strapi v3.6.x 迁移到 v4.0.x。

¥This guide is part of the v4 plugin migration guide designed to help you migrate a plugin from Strapi v3.6.x to v4.0.x.

🤓 v3/v4 比较

Strapi v3 插件需要特定的文件夹结构。

¥Strapi v3 plugins required a specific folder structure.

在 Strapi v4 中,插件是使用编程 API 开发的,这为文件夹结构提供了灵活性。

¥In Strapi v4, plugins are developed using a programmatic API, which gives flexibility in the folder structure.

Strapi v4 插件的文件夹结构应满足以下要求:

¥The folder structure of a Strapi v4 plugin should meet the following requirements:

  • 插件文件夹的根目录应包括:

    ¥The root of the plugin folder should include:

    • strapi-server.js 入口文件,如果插件与 Strapi 的后端交互(请参阅 服务器 API

      ¥a strapi-server.js entry file, if the plugin interacts with Strapi's back-end (see Server API)

    • strapi-admin.js 条目文件,如果插件与 Strapi 的管理面板交互(请参阅 管理面板 API)。

      ¥a strapi-admin.js entry file, if the plugin interacts with Strapi's admin panel (see Admin Panel API).

  • strapi-admin.jsstrapi-server.js 应该导出插件的接口。

    ¥strapi-admin.js and strapi-server.js should export the plugin's interface.

只要满足这些要求,文件夹结构的其余部分就由你决定。

¥As long as these requirements are met, the rest of the folder structure is up to you.

Example of a Strapi v4 plugin structure
my-plugin
├─ admin
│ └─ src
│ ├─ components
│ ├─ pages
│ ├─ // more folders and files
│ └─ index.js
├─ server
│ ├─ config
│ ├─ content-types
│ ├─ controllers
│ ├─ middlewares
│ ├─ policies
│ ├─ routes
│ ├─ services
│ ├─ bootstrap.js
│ ├─ destroy.js
│ ├─ register.js
│ ├─ // more folders and files
│ └─ index.js
├─ strapi-admin.js // require('./admin')
└─ strapi-server.js // require('./server')

Strapi v3 插件的文件夹结构可以迁移到 v4 插件 automaticallymanually

¥The folder structure of a Strapi v3 plugin can be migrated to a v4 plugin either automatically or manually.

自动更新文件夹结构

¥Updating folder structure automatically

提醒

codemod 创建了一个新的 Strapi v4 插件,保留了 Strapi v3 插件。我们建议在删除 v3 版本之前确认 v4 版本的插件正常工作。

¥The codemod creates a new Strapi v4 plugin, leaving the Strapi v3 plugin in place. We recommend confirming the v4 version of the plugin is working properly before deleting the v3 version.

codemod 可用于自动更新 Strapi v4 插件的文件夹结构。codemod 执行以下操作:

¥A codemod can be used to automatically update the folder structure of a plugin for Strapi v4. The codemod performs the following actions:

  • 创建 2 个入口文件:strapi-server.jsstrapi-admin.js

    ¥creation of 2 entry files: strapi-server.js and strapi-admin.js,

  • 将文件和文件夹分别组织到 serveradmin 文件夹中,

    ¥organization of files and folders into a server and an admin folders, respectively,

  • modelscontentTypes 的转换,

    ¥conversion of models to contentTypes,

  • 并将 services 导出为函数。

    ¥and export of services as functions.

要执行 codemod,请在终端中运行以下命令:

¥To execute the codemod, run the following commands in a terminal:

npx @strapi/codemods migrate:plugin <path-to-v3-plugin> [path-for-v4-plugin]

手动更新文件夹结构

¥Updating folder structure manually

手动更新文件夹结构需要移动和更新多个文件和文件夹的内容。以下小节描述了这些步骤。

¥Manually updating the folder structure requires moving and updating the content of multiple files and folders. These steps are described in the following subsections.

✏️ 注意

以文件夹结构为例,只要有 strapi-server.jsstrapi-admin.js 存在并导出插件接口,就可以自由组织文件和文件夹。

¥The folder structure is given as an example, and files and folders can be organized freely as long as strapi-server.js or strapi-admin.js exist and export the plugin interface.

创建 server 文件夹

¥Creating a server folder

server 文件夹包含插件后端的所有代码。要在插件文件夹的根目录中创建它,请在终端中运行以下命令:

¥The server folder includes all the code for the back end of the plugin. To create it at the root of the plugin folder, run the following command in a terminal:

cd <my-plugin-folder-name>
mkdir server

移动控制器、服务和中间件

¥Moving controllers, services, and middlewares

🤓 v3/v4 比较

在 Strapi v3 中,插件的控制器、服务和中间件必须遵循严格的文件夹结构约定。

¥In Strapi v3, controllers, services, and middlewares of a plugin must follow a strict folder structure convention.

在 Strapi v4 中,插件文件和文件夹的组织非常灵活。但是,建议在 server 文件夹内为每种类型的后端元素(例如 controllersservicesmiddlewares)创建专用文件夹(请参阅 项目结构)。

¥In Strapi v4, the organization of files and folders for plugins is flexible. However, it is recommended to create dedicated folders for every type of back-end element (e.g. controllers, services, and middlewares) inside a server folder (see project structure).

要将插件的控制器、服务和中间件更新到 Strapi v4,请在 server 文件夹中创建特定的子文件夹。

¥To update the controllers, services, and middlewares of a plugin to Strapi v4, create specific sub-folders in a server folder.

Strapi v4 中的插件文件和文件夹应满足 2 个要求:

¥Plugin files and folders in Strapi v4 should meet 2 requirements:

  • server/<subfolder-name>/<element-name> 中的每个文件(例如 server/controllers/my-controller.js)应该:

    ¥Each file in the server/<subfolder-name>/<element-name> (e.g. server/controllers/my-controller.js) should:

    • 导出一个以 strapi 实例(对象)作为参数的函数

      ¥export a function taking the strapi instance (object) as a parameter

    • 并返回一个对象。

      ¥and return an object.

  • 每个 server/<subfolder-name> 文件夹应包含一个导出该文件夹中所有文件的 index.js 文件。

    ¥Each of the server/<subfolder-name> folders should include an index.js file that exports all files in the folder.

Example of files and folder for Strapi v4 plugin controllers
./src/plugins/my-plugin/server/controllers/my-controllerA.js

module.exports = ({ strapi }) => ({
doSomething(ctx) {
ctx.body = { message: "HelloWorld" };
},
});
./src/plugins/my-plugin/server/controllers/index.js

"use strict";



const myControllerA = require("./my-controllerA");




const myControllerB = require("./my-controllerB");



module.exports = {
myControllerA,
myControllerB,
};

移动 bootstrap 功能

¥Moving the bootstrap function

🤓 v3/v4 比较

Strapi v3 为每个插件都有一个专用的 config/functions 文件夹。

¥Strapi v3 has a dedicated config/functions folder for each plugin.

在 Strapi v4 中,插件不一定存在 config 文件夹,bootstrap 函数 和其他生命周期函数可以在其他地方声明。

¥In Strapi v4, the config folder does not necessarily exist for a plugin and the bootstrap function and other lifecycle functions can be declared elsewhere.

要将插件的 bootstrap 功能更新为 Strapi v4:

¥To update the plugin's bootstrap function to Strapi v4:

  • bootstrap() 功能从 server/config/functions/bootstrap.js 移至 server/bootstrap.js

    ¥move the bootstrap() function from server/config/functions/bootstrap.js to server/bootstrap.js

  • strapi 实例(对象)作为参数传递

    ¥pass the strapi instance (object) as a parameter

./src/plugins/my-plugin/server/bootstrap.js

"use strict";

module.exports = ({ strapi }) => ({
// bootstrap the plugin
});

移动路由

¥Moving routes

🤓 v3/v4 比较

Strapi v3 在特定 config/routes.json 文件中声明插件的路由。

¥Strapi v3 declares routes for a plugin in a specific config/routes.json file.

在 Strapi v4 中,插件不一定存在 config 文件夹,并且 插件路由 可以在 server/routes/index.json 文件中声明。

¥In Strapi v4, the config folder does not necessarily exist for a plugin and plugin routes can be declared in a server/routes/index.json file.

要将插件路由更新到 Strapi v4,请将路由从 config/routes.json 移动到 server/routes/index.json

¥To update plugin routes to Strapi v4, move routes from config/routes.json to server/routes/index.json.

Strapi v4 中的路由应满足 2 个要求:

¥Routes in Strapi v4 should meet 2 requirements:

  • 路由应返回指定 admincontent-api 路由的数组或对象。

    ¥Routes should return an array or an object specifying admin or content-api routes.

  • 路由处理程序名称应与控制器导出的大小写相同。

    ¥Routes handler names should match the same casing as the controller exports.

Example of controllers export and routes in a Strapi v4 plugin
./src/plugins/my-plugin/server/controllers/index.js

"use strict";



const myControllerA = require("./my-controllerA");




const myControllerB = require("./my-controllerB");



module.exports = {
myControllerA,
myControllerB,
};
./src/plugins/my-plugin/server/routes/index.js

module.exports = [
{
method: "GET",
path: "/my-controller-a",
// Camel case handler to match export in server/controllers/index.js
handler: "myControllerA.doSomething",
config: { policies: [] },
},
];

搬家政策

¥Moving policies

🤓 v3/v4 比较

Strapi v3 声明了特定 config/policies 文件夹中插件的策略。

¥Strapi v3 declares policies for a plugin in a specific config/policies folder.

在 Strapi v4 中,插件不一定存在 config 文件夹,并且 插件政策 可以在 server/policies 下找到的专用文件中声明。

¥In Strapi v4, the config folder does not necessarily exist for a plugin and plugin policies can be declared in dedicated files found under server/policies.

要将插件策略更新到 Strapi v4:

¥To update plugin policies to Strapi v4:

  1. 将政策从 config/policies 移至 server/policies/<policy-name>.js

    ¥Move policies from config/policies to server/policies/<policy-name>.js

  2. index.js 文件添加到 server/policies 文件夹并确保它导出该文件夹中的所有文件。

    ¥Add an index.js file to the server/policies folder and make sure it exports all files in the folder.

将模型转换为内容类型

¥Converting models to content-types

🤓 v3/v4 比较

Strapi v3 在 models 文件夹中找到的 <model-name>.settings.json 文件中声明插件模型。

¥Strapi v3 declares plugin models in <model-name>.settings.json files found in a models folder.

在 Strapi v4 中,插件内容类型server/content-types/<contentTypeName> 文件夹中的 schema.json 文件中声明。schema.json 文件引入了一些新属性(请参阅 模式文档)。

¥In Strapi v4, plugin content-types are declared in schema.json files found in a server/content-types/<contentTypeName> folder. The schema.json files introduce some new properties (see schema documentation).

要将 Strapi v3 模型转换为 v4 内容类型:

¥To convert Strapi v3 models to v4 content-types:

  1. models 文件夹移到 server 文件夹下,并将 models 重命名为 content-types

    ¥Move the models folder under the server folder and rename models to content-types:

    mv models/ server/content-types/
  2. 将每个模型的 <modelName>.settings.json 文件移动/重命名为 server/content-types/<contentTypeName>/schema.json 文件。

    ¥Move/rename each model's <modelName>.settings.json file to server/content-types/<contentTypeName>/schema.json files.

  3. 在每个 <contentTypeName>/schema.json 文件中,更新 info 对象,现在需要声明 3 个新的 singularNamepluralNamedisplayName 键并遵守一些大小写格式约定:

    ¥In each <contentTypeName>/schema.json file, update the info object, which now requires declaring the 3 new singularName, pluralName and displayName keys and respecting some case-formatting conventions:

    ./src/plugins/my-plugin/content-types/<content-type-name>/schema.json

    // ...
    "info": {
    "singularName": "content-type-name", // kebab-case required
    "pluralName": "content-type-names", // kebab-case required
    "displayName": "Content-type name",
    "name": "Content-type name",
    };
    // ...
  4. (可选)如果 Strapi v3 模型使用 <model-name>.js 中找到的生命周期钩子,请将文件移动/重命名为 server/content-types/<contentTypeName>/lifecycle.js,否则删除该文件。

    ¥(optional) If the Strapi v3 model uses lifecycle hooks found in <model-name>.js, move/rename the file to server/content-types/<contentTypeName>/lifecycle.js, otherwise delete the file.

  5. 为每个内容类型创建一个 index.js 文件以导出架构和(可选)生命周期钩子:

    ¥Create an index.js file for each content-type to export the schema and, optionally, lifecycle hooks:

    ./src/plugins/my-plugin/server/content-types/<content-type-name>/index.js

    const schema = require("./schema.json");
    const lifecycles = require("./lifecycles.js"); // optional

    module.exports = {
    schema,
    lifecycles, // optional
    };
  6. 创建 server/content-types/index.js 文件。

    ¥Create a server/content-types/index.js file.

  7. server/content-types/index.js 中,导出所有内容类型并确保每个内容类型的密钥与内容类型的 schema.json 文件的 info 对象中找到的 singularName 匹配:

    ¥In server/content-types/index.js, export all content-types and make sure the key of each content-type matches the singularName found in the info object of the content-type’s schema.json file:

    ./src/plugins/my-plugin/server/content-types/content-type-a/schema.json

    "info": {
    "singularName": "content-type-a", // kebab-case required
    "pluralName": "content-type-as", // kebab-case required
    "displayName": "Content-Type A",
    "name": "Content-Type A",
    };
    ./src/plugins/my-plugin/server/content-types/index.js

    "use strict";

    const contentTypeA = require("./content-type-a");
    const contentTypeB = require("./content-type-b");

    module.exports = {
    // Key names should match info.singularName key values found in corresponding schema.json files
    "content-type-a": contentTypeA,
    "content-type-b": contentTypeB,
    };
✏️ 注意

将 Strapi v3 模型转换为 v4 内容类型还需要更新 getter 和可选的关系(请参阅 插件后端迁移文档)。

¥Converting Strapi v3 models to v4 content-types also requires updating getters and, optionally, relations (see plugin back end migration documentation).

创建入口文件

¥Creating entry files

🤓 v3/v4 比较

Strapi v3 插件使用严格的文件夹结构约定。

¥Strapi v3 plugins use a strict folder structure convention.

在 Strapi v4 中,插件的文件夹结构非常灵活。但是,每个插件至少需要一个 strapi-server.js 入口文件或 strapi-admin.js 入口文件。这 2 个入口文件分别用于利用插件后端的 服务器 API 和插件前端的 管理面板 API

¥In Strapi v4, the folder structure for plugins is flexible. However, each plugin needs at least a strapi-server.js entry file or a strapi-admin.js entry file. The 2 entry files are used to take advantage of, respectively, the Server API for the back end of the plugin and the Admin Panel API for the front end of the plugin.

要将插件更新到 Strapi v4:

¥To update the plugin to Strapi v4:

  • 如果插件与 Strapi 的后端交互,请在插件文件夹的根目录下创建 strapi-server.js 后端入口文件。该文件应需要所有必需的文件并导出后端插件接口(参见 迁移插件的后端)。

    ¥If the plugin interacts with Strapi's backend, create the strapi-server.js back-end entry file at the root of the plugin folder. The file should require all necessary files and export the back-end plugin interface (see migrating the back end of a plugin).

Example strapi-server.js and server/index.js entry files
```js title="./src/plugins/my-plugin/strapi-server.js"

"use strict";

module.exports = require('./server');
```

```js title="./src/plugins/my-plugin/server/index.js"

"use strict";

const register = require('./register');
const bootstrap = require('./bootstrap');
const destroy = require('./destroy');
const config = require('./config');
const contentTypes = require('./content-types');
const controllers = require('./controllers');
const routes = require('./routes');
const middlewares = require('./middlewares');
const policies = require('./policies');
const services = require('./services');

module.exports = {
register,
bootstrap,
destroy,
config,
controllers,
routes,
services,
contentTypes,
policies,
middlewares,
};
```
  • 如果插件与 Strapi 的管理面板交互,请在插件文件夹的根目录下创建 strapi-admin.js 前端入口文件。该文件应需要所有必需的文件并导出前端插件接口(参见 迁移插件的前端)。

    ¥If the plugin interacts with Strapi's admin panel, create the strapi-admin.js front-end entry file at the root of the plugin folder. The file should require all necessary files and export the front-end plugin interface (see migrating the front end of a plugin).

Example strapi-admin.js entry file
```jsx title="./src/plugins/my-plugin/strapi-admin.js"

"use strict";

module.exports = require("./admin/src").default;
```