diff --git a/docs/frontend-plugins.md b/docs/frontend-plugins.md index 1e098efe..d4d7cb11 100644 --- a/docs/frontend-plugins.md +++ b/docs/frontend-plugins.md @@ -155,13 +155,22 @@ export default MyCustomComponent; ### 4\. Federation Configuration The core of the plugin is its Webpack configuration.
-All plugins should use this sample `webpack.config.js` as a base. +All plugins should use this `webpack.config.js` as a base. + +Disclaimer: +We try to not change this file.
+But in the future, it may evolve as the plugin system matures.
```javascript const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); -const { NativeFederationTypeScriptHost } = require('@module-federation/native-federation-typescript/webpack'); +const { + NativeFederationTypeScriptHost, +} = require('@module-federation/native-federation-typescript/webpack'); +const { + NativeFederationTypeScriptHost: NativeFederationTypeScriptHostCore, +} = require('@module-federation/native-federation-typescript'); module.exports = (env, argv) => { const dev = argv.mode !== 'production'; @@ -189,6 +198,24 @@ module.exports = (env, argv) => { }, }; + let mfTypesReady; + const ensureFederatedTypesPlugin = { + apply(compiler) { + compiler.hooks.beforeCompile.tapPromise( + 'EnsureFederatedTypes', + async () => { + if (!mfTypesReady) { + const downloader = NativeFederationTypeScriptHostCore.raw({ + moduleFederationConfig, + }); + mfTypesReady = downloader.writeBundle(); + } + await mfTypesReady; + }, + ); + }, + }; + return { devServer: { // The port should match the one in your plugin's configuration file @@ -198,7 +225,12 @@ module.exports = (env, argv) => { plugins: [ new ModuleFederationPlugin(moduleFederationConfig), // This plugin enables type-sharing for intellisense - ...(dev ? [NativeFederationTypeScriptHost({ moduleFederationConfig })] : []), + ...(dev + ? [ + ensureFederatedTypesPlugin, // ensures the zip is ready before the first compile + NativeFederationTypeScriptHost({ moduleFederationConfig }), + ] + : []), ], // ... other webpack config (output, module rules, etc.) }; @@ -232,8 +264,8 @@ In your plugin's `tsconfig.json`:
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. +The `NativeFederationTypeScriptHost` plugin in your webpack config will automatically download and unpack it ahead of the first compile,
+making the host's types available to your plugin and IDE. In development with this flag enabled, route changes may be slower because type generation and automatic exposure run during rebuilds; this does not affect production where navigations are instant.
@@ -554,4 +586,4 @@ Update the **`remote.url`** to the public-facing path that matches where you dep "message": "Hello from production!" } } -``` \ No newline at end of file +``` diff --git a/src/frontend/apps/impress-plugin/src/MyCustomComponent.tsx b/src/frontend/apps/impress-plugin/src/MyCustomComponent.tsx index cf863304..d58518f4 100644 --- a/src/frontend/apps/impress-plugin/src/MyCustomComponent.tsx +++ b/src/frontend/apps/impress-plugin/src/MyCustomComponent.tsx @@ -443,7 +443,7 @@ const MyCustomComponent: React.FC = ({ > - Loading plugin data... + Fake Loading... ) : ( diff --git a/src/frontend/apps/impress-plugin/src/ThemingDemo.tsx b/src/frontend/apps/impress-plugin/src/ThemingDemo.tsx index f551b609..f91d94e4 100644 --- a/src/frontend/apps/impress-plugin/src/ThemingDemo.tsx +++ b/src/frontend/apps/impress-plugin/src/ThemingDemo.tsx @@ -153,8 +153,7 @@ const ThemingDemo: React.FC = () => { color: 'var(--c--theme--colors--greyscale-600)', lineHeight: '1.4', }}> - 💡 This demo overrides primary-500, primary-600, and secondary-500 tokens. - Any component using these tokens will update! + 💡 This demo overrides primary-500, primary-600, and secondary-500 css variables. It only works with CSS. diff --git a/src/frontend/apps/impress-plugin/webpack.config.js b/src/frontend/apps/impress-plugin/webpack.config.js index bed2b656..c4adce30 100644 --- a/src/frontend/apps/impress-plugin/webpack.config.js +++ b/src/frontend/apps/impress-plugin/webpack.config.js @@ -1,6 +1,11 @@ const path = require('path'); -const { NativeFederationTypeScriptHost } = require('@module-federation/native-federation-typescript/webpack'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); +const { + NativeFederationTypeScriptHost, +} = require('@module-federation/native-federation-typescript/webpack'); +const { + NativeFederationTypeScriptHost: NativeFederationTypeScriptHostCore, +} = require('@module-federation/native-federation-typescript'); const moduleFederationConfig = { name: 'plugin_frontend', @@ -31,6 +36,24 @@ const moduleFederationConfig = { }, }; +let mfTypesReady; +const ensureFederatedTypesPlugin = { + apply(compiler) { + compiler.hooks.beforeCompile.tapPromise( + 'EnsureFederatedTypes', + async () => { + if (!mfTypesReady) { + const downloader = NativeFederationTypeScriptHostCore.raw({ + moduleFederationConfig, + }); + mfTypesReady = downloader.writeBundle(); + } + await mfTypesReady; + }, + ); + }, +}; + module.exports = (env, argv) => { const dev = argv.mode !== 'production'; @@ -70,10 +93,11 @@ module.exports = (env, argv) => { new ModuleFederationPlugin(moduleFederationConfig), ...(dev ? [ - NativeFederationTypeScriptHost({ - moduleFederationConfig, - }), - ] + ensureFederatedTypesPlugin, + NativeFederationTypeScriptHost({ + moduleFederationConfig, + }), + ] : []), ], }; diff --git a/src/frontend/apps/impress/next.config.js b/src/frontend/apps/impress/next.config.js index 3adf69bf..a9544b4c 100644 --- a/src/frontend/apps/impress/next.config.js +++ b/src/frontend/apps/impress/next.config.js @@ -28,9 +28,15 @@ const nextConfig = { NEXT_PUBLIC_BUILD_ID: buildId, }, webpack(config, { isServer, dev }) { - // Prevent rebuild loops by ignoring node_modules and build outputs + // Prevent rebuild loops by ignoring node_modules and generated types/outputs config.watchOptions = { - ignored: ['**/node_modules/**', '**/.next/**', '**/dist/**'], + ignored: [ + '**/node_modules/**', + '**/.next/**', + '**/dist/**', + '**/@mf-types/**', + '**/@mf-types.zip', + ], }; // Grab the existing rule that handles SVG imports