refine documentation
This commit is contained in:
+61
-37
@@ -48,14 +48,17 @@ It's ideal for teams or third parties to add custom features.
|
||||
|
||||
**Limitations:**
|
||||
- Focused on DOM/UI customisations; you cannot add Next.js routes or other server-side features.
|
||||
- Runs client-side without direct host state access. Shared caches (e.g., React Query) only work if the dependency is also [shared as a singleton](#choosing-shared-dependencies "Learn about shared dependencies").
|
||||
- Host upgrades may require tweaking CSS selectors and matching versions for shared libraries.
|
||||
- Runs client-side without direct host state access. <br>
|
||||
Shared caches (e.g., React Query) only work if the dependency is also [shared as a singleton](#choosing-shared-dependencies "Learn about shared dependencies").
|
||||
- Host upgrades may require tweaking CSS selectors <br>
|
||||
and matching versions for shared libraries.
|
||||
|
||||
<br>
|
||||
|
||||
## Getting Started: Building Your First Plugin
|
||||
|
||||
A plugin is a standalone React application bundled with Webpack that exposes one or more components via [Module Federation](#4-federation-configuration "See the federation configuration").
|
||||
A plugin is a standalone React application bundled with Webpack <br>
|
||||
that exposes one or more components via [Module Federation](#4-federation-configuration "See the federation configuration").
|
||||
This guide walks you through creating your first plugin.
|
||||
|
||||
<br>
|
||||
@@ -63,27 +66,34 @@ This guide walks you through creating your first plugin.
|
||||
### 1. Prepare the Host Environment
|
||||
|
||||
Developing a plugin requires running the host application (Docs) in parallel.
|
||||
This live integration is essential for rendering your plugin, enabling hot-reloading, sharing types for Intellisense, and discovering the exact versions of [shared dependencies](#choosing-shared-dependencies "Learn about shared dependencies").
|
||||
This live integration is essential for rendering your plugin, enabling hot-reloading, sharing types for Intellisense, <br>
|
||||
and discovering the exact versions of [shared dependencies](#choosing-shared-dependencies "Learn about shared dependencies").
|
||||
|
||||
<br>
|
||||
|
||||
1. **Clone the repository locally**: If you haven't already, clone the Docs repository to your local machine and follow the initial setup instructions.
|
||||
2. **Set the development flag**: In the host application's `.env.development` file, set `NEXT_PUBLIC_DEVELOP_PLUGINS=true`.
|
||||
3. **Stop conflicting services**: If you are using the project's Docker setup, make sure the frontend service is stopped (`docker compose stop frontend-development`), as we will run the Docs frontend locally.
|
||||
4. **Run the host**: Navigate to `src/frontend/apps/impress`, run `yarn install`, and then `yarn dev`.
|
||||
5. **Check the logs**: On startup, the Next.js dev server will print the versions of all shared singleton libraries (e.g., React, styled-components).
|
||||
1. **Clone the repository locally**:<br>
|
||||
If you haven't already, clone the Docs repository to your local machine and follow the initial setup instructions.
|
||||
2. **Set the development flag**:<br>
|
||||
In the host application's `.env.development` file, set `NEXT_PUBLIC_DEVELOP_PLUGINS=true`.
|
||||
3. **Stop conflicting services**:<br>
|
||||
If you are using the project's Docker setup, make sure <br>
|
||||
the frontend service is stopped (`docker compose stop frontend-development`), as we will run the Docs frontend locally.
|
||||
4. **Run the host**:<br>
|
||||
Navigate to `src/frontend/apps/impress`, run `yarn install`, and then `yarn dev`.
|
||||
5. **Check the logs**:<br>
|
||||
On startup, the Next.js dev server will print the versions of all shared singleton libraries (e.g., React, styled-components). <br>
|
||||
You will need these exact versions for your plugin's `package.json`.
|
||||
|
||||
<br>
|
||||
|
||||
### 2. Scaffolding a New Plugin Project
|
||||
|
||||
Create a new, simple React project.
|
||||
Create a new, simple React project. <br>
|
||||
Your project should have a [`webpack.config.js`](#4-federation-configuration "See the federation configuration") and include dependencies for React, Webpack, and TypeScript.
|
||||
|
||||
<br>
|
||||
|
||||
A minimal `package.json` would look like this:
|
||||
A minimal `package.json` would look like this:<br>
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -118,7 +128,7 @@ A minimal `package.json` would look like this:
|
||||
|
||||
### 3\. Creating a Plugin Component
|
||||
|
||||
This is a React component that your `webpack.config.js` file exposes.
|
||||
This is a React component that your `webpack.config.js` file exposes. <br>
|
||||
This minimal example shows how to accept `props`, which can be passed from the [plugin configuration file](#plugin-configuration-file-reference "See the configuration file reference").
|
||||
|
||||
<br>
|
||||
@@ -144,7 +154,7 @@ export default MyCustomComponent;
|
||||
|
||||
### 4\. Federation Configuration
|
||||
|
||||
The core of the plugin is its Webpack configuration.
|
||||
The core of the plugin is its Webpack configuration. <br>
|
||||
All plugins should use this sample `webpack.config.js` as a base.
|
||||
|
||||
<br>
|
||||
@@ -201,7 +211,8 @@ module.exports = (env, argv) => {
|
||||
|
||||
### 5\. Enabling Type-Sharing for Intellisense
|
||||
|
||||
To get autocompletion for components and hooks exposed by the host, configure your plugin's `tsconfig.json` to find the host's types.
|
||||
To get autocompletion for components and hooks exposed by the host, <br>
|
||||
configure your plugin's `tsconfig.json` to find the host's types.
|
||||
|
||||
<br>
|
||||
|
||||
@@ -220,20 +231,24 @@ In your plugin's `tsconfig.json`:
|
||||
|
||||
<br>
|
||||
|
||||
When you run the host application with `NEXT_PUBLIC_DEVELOP_PLUGINS=true`, it generates a `@mf-types.zip` file.
|
||||
The `NativeFederationTypeScriptHost` plugin in your webpack config will automatically download and unpack it, making the host's types available to your plugin and IDE.
|
||||
When you run the host application with `NEXT_PUBLIC_DEVELOP_PLUGINS=true`, it generates a `@mf-types.zip` file. <br>
|
||||
The `NativeFederationTypeScriptHost` plugin in your webpack config will automatically download and unpack it, <br>
|
||||
making the host's types available to your plugin and IDE.
|
||||
|
||||
<br>
|
||||
|
||||
### 6\. Running and Configuring Your Plugin
|
||||
|
||||
With the host application already running (from step 1), you can now start your plugin's development server and configure the host to load it.
|
||||
With the host application already running (from step 1), <br>
|
||||
you can now start your plugin's development server and configure the host to load it.
|
||||
|
||||
<br>
|
||||
|
||||
1. **Start the plugin**: In your plugin's project directory, run `yarn dev`.
|
||||
2. **Configure the host**: Tell the host to load your plugin by editing its configuration file.
|
||||
When running Docs locally, this file is located at `src/backend/impress/configuration/plugins/default.json`.
|
||||
1. **Start the plugin**:<br>
|
||||
In your plugin's project directory, run `yarn dev`.
|
||||
2. **Configure the host**:<br>
|
||||
Tell the host to load your plugin by editing its configuration file. <br>
|
||||
When running Docs locally, this file is located at `src/backend/impress/configuration/plugins/default.json`. <br>
|
||||
Update it to point to your local plugin's `remoteEntry.js`.
|
||||
|
||||
<br>
|
||||
@@ -257,7 +272,7 @@ With the host application already running (from step 1), you can now start your
|
||||
|
||||
<br>
|
||||
|
||||
After changing the `target` to a valid CSS selector in the host's DOM, save the file.
|
||||
After changing the `target` to a valid CSS selector in the host's DOM, save the file. <br>
|
||||
The host application will automatically detect the change and inject your component, passing the `props` object along.
|
||||
|
||||
Your component should appear in the running host application after a reload.
|
||||
@@ -268,7 +283,7 @@ Your component should appear in the running host application after a reload.
|
||||
|
||||
### Host Exports
|
||||
|
||||
The host automatically exposes many of its components and hooks.
|
||||
The host automatically exposes many of its components and hooks. <br>
|
||||
You can import them in the plugin as if they were local modules, thanks to the [`remotes` configuration](#4-federation-configuration "See the remotes config in Webpack") in the `webpack.config.js`.
|
||||
|
||||
<br>
|
||||
@@ -287,14 +302,17 @@ Sharing dependencies is critical for performance and stability.
|
||||
|
||||
<br>
|
||||
|
||||
- **Minimal Shared Libraries**: Always share **`react`**, **`react-dom`**, **`styled-components`**, and **`@openfun/cunningham-react`** to use the same instances as the host.
|
||||
- **Sharing State**: Libraries that rely on a global context (like `@tanstack/react-query`) **must** be shared to access the host's state and cache.
|
||||
- **Discovering More Shared Libraries**: With `NEXT_PUBLIC_DEVELOP_PLUGINS=true`, [the host prints its shared dependency map to the Next.js dev server logs on startup](#1-prepare-the-host-environment "See how to prepare the host").
|
||||
- **Minimal Shared Libraries**:<br>
|
||||
Always share **`react`**, **`react-dom`**, **`styled-components`**, and **`@openfun/cunningham-react`** to use the same instances as the host.
|
||||
- **Sharing State**:<br>
|
||||
Libraries that rely on a global context (like `@tanstack/react-query`) **must** be shared to access the host's state and cache.
|
||||
- **Discovering More Shared Libraries**: With `NEXT_PUBLIC_DEVELOP_PLUGINS=true`, <br>
|
||||
[the host prints its shared dependency map to the Next.js dev server logs on startup](#1-prepare-the-host-environment "See how to prepare the host"). <br>
|
||||
You can use this to align versions and add more shared libraries to your plugin.
|
||||
|
||||
<br>
|
||||
|
||||
> **Important**: Both the host and the plugin must declare a dependency in [`moduleFederationConfig.shared`](#4-federation-configuration "See the federation configuration") for it to become a true singleton.
|
||||
> **Important**: Both the host and the plugin must declare a dependency in [`moduleFederationConfig.shared`](#4-federation-configuration "See the federation configuration") for it to become a true singleton. <br>
|
||||
> If a shared dependency is omitted from the plugin's config, Webpack will bundle a separate copy, breaking the singleton pattern.
|
||||
|
||||
<br>
|
||||
@@ -321,7 +339,8 @@ Common Errors:
|
||||
|
||||
- Build modular components with well-typed props.
|
||||
- Prefer using the host's exposed types and components over implementing new ones.
|
||||
- Keep shared dependency versions aligned with the host and re-test after host upgrades.
|
||||
- Keep shared dependency versions aligned with the host <br>
|
||||
and re-test after host upgrades.
|
||||
- Treat plugin bundles as untrusted: vet dependencies and avoid unsafe scripts.
|
||||
|
||||
<br>
|
||||
@@ -479,37 +498,42 @@ When you are ready to release your plugin, you need to create a production build
|
||||
|
||||
<br>
|
||||
|
||||
Run the build command in your plugin's directory:
|
||||
Run the build command in your plugin's directory:<br>
|
||||
|
||||
```bash
|
||||
yarn build
|
||||
```
|
||||
|
||||
This command bundles your code for production.
|
||||
Webpack will generate a **`dist`** folder (or similar) containing the **`remoteEntry.js`** file and other JavaScript chunks.
|
||||
The `remoteEntry.js` is the manifest that tells other applications what modules your plugin exposes.
|
||||
This command bundles your code for production. <br>
|
||||
Webpack will generate a **`dist`** folder (or similar) containing the **`remoteEntry.js`** file and other JavaScript chunks. <br>
|
||||
The `remoteEntry.js` is the manifest that tells other applications what modules your plugin exposes. <br>
|
||||
These are the files you will need for deployment.
|
||||
|
||||
<br>
|
||||
|
||||
The [`webpack.config.js` provided](#4-federation-configuration "See the federation configuration") is already configured to switch the `remotes` URL to the correct production path automatically, so no code changes are needed before building.
|
||||
The [`webpack.config.js` provided](#4-federation-configuration "See the federation configuration") is already configured to switch the `remotes` URL to the correct production path automatically, <br>
|
||||
so no code changes are needed before building.
|
||||
|
||||
<br>
|
||||
|
||||
## Deploying Docs with Plugins
|
||||
|
||||
To use plugins in a production environment, you need to deploy both the plugin assets and the configuration file.
|
||||
To use plugins in a production environment, you need to deploy both the plugin assets and the configuration file. <br>
|
||||
The recommended approach is to serve the plugin's static files from the same webserver that serves the host (docs frontend).
|
||||
|
||||
<br>
|
||||
|
||||
1. **Deploy Plugin Assets**: Copy the contents of your plugin's build output directory (e.g., `dist/`) into the frontend container's `/usr/share/nginx/html/assets` directory at a chosen path.
|
||||
For example, placing assets in `/usr/share/nginx/html/assets/plugins/my-plugin/` would make the plugin's **`remoteEntry.js`** available at `https://production.domain/assets/plugins/my-plugin/remoteEntry.js`.
|
||||
1. **Deploy Plugin Assets**: <br>
|
||||
Copy the contents of your plugin's build output directory (e.g., `dist/`) <br>
|
||||
into the frontend container's `/usr/share/nginx/html/assets` directory at a chosen path.<br>
|
||||
E.g.: Placing assets in `/usr/share/nginx/html/assets/plugins/my-plugin/` <br>
|
||||
would make the plugin's **`remoteEntry.js`** available at `https://production.domain/assets/plugins/my-plugin/remoteEntry.js`.
|
||||
|
||||
<br>
|
||||
|
||||
2. **Deploy Plugin Configuration**: The host's [plugin configuration file](#plugin-configuration-file-reference "See the configuration file reference") must be updated to point to the deployed assets.
|
||||
This file is typically managed via infrastructure methods (e.g., a Kubernetes configmap replacing `/app/impress/configuration/plugins/default.json` in the backend container).
|
||||
2. **Deploy Plugin Configuration**: The host's [plugin configuration file](#plugin-configuration-file-reference "See the configuration file reference") must be updated to point to the deployed assets. <br>
|
||||
This file is typically managed via infrastructure methods <br>
|
||||
(e.g., a Kubernetes configmap replacing `/app/impress/configuration/plugins/default.json` in the backend container).
|
||||
|
||||
<br>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user