UNPKG

@nx/react

Version:

The React plugin for Nx contains executors and generators for managing React applications and libraries within an Nx workspace. It provides: - Integration with libraries such as Jest, Vitest, Playwright, Cypress, and Storybook. - Generators for applica

138 lines (137 loc) 6.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.consumerGenerator = consumerGenerator; const tslib_1 = require("tslib"); const devkit_1 = require("@nx/devkit"); const assert_supported_react_version_1 = require("../../utils/assert-supported-react-version"); const versions_1 = require("@nx/js/src/utils/versions"); const versions_2 = require("../../utils/versions"); const mfVersions = tslib_1.__importStar(require("../_utils/mf-versions")); const mf_dependencies_1 = require("../_utils/mf-dependencies"); const normalize_1 = require("../_utils/normalize"); const provider_1 = tslib_1.__importDefault(require("../provider/provider")); // `--mode=...` is rspack's portable equivalent of `NODE_ENV=...` and works on // Windows without a shell prefix. const BUNDLER_DEV_COMMAND = { vite: 'vite', rsbuild: 'rsbuild dev', rspack: 'rspack serve --mode=development', }; const BUNDLER_BUILD_COMMAND = { vite: 'vite build', rsbuild: 'rsbuild build', rspack: 'rspack build --mode=production', }; async function consumerGenerator(tree, schema) { (0, assert_supported_react_version_1.assertSupportedReactVersion)(tree); const opts = await (0, normalize_1.normalizeScaffoldOptions)(tree, { directory: schema.directory, surface: 'consumer', bundler: schema.bundler, port: schema.port, }); // When the user explicitly passes `--providerNames=p1,p2`, generate a // sibling provider app per entry and wire them into the consumer's // PROVIDERS list + App.tsx. When the flag is omitted, ship a placeholder // `my-provider` entry pointing at the per-bundler provider-default port // without generating an actual provider project. const providerNames = schema.providerNames?.length ? schema.providerNames : ['my-provider']; const shouldGenerateProviders = !!schema.providerNames?.length; const providerDefaultPort = (0, normalize_1.getDefaultPort)(opts.bundler, 'provider'); const providers = providerNames.map((name, i) => ({ name, // The federation container name the provider build emits. Must match the // provider's federation `name`, which is derived the same way (see // provider.ts / normalize.ts) - it strips chars that aren't valid in a JS // identifier, so a naive `alias.replace(/-/g, '_')` in the consumer would // diverge for names with dots/slashes/@ and loadRemote() would resolve the // URL but look up the wrong container. federationName: (0, normalize_1.toFederationName)((0, devkit_1.names)(name).fileName), componentName: `Provider${(0, devkit_1.names)(name).className}`, directory: (0, devkit_1.joinPathFragments)(opts.projectRoot, '..', name), port: providerDefaultPort + i, })); (0, devkit_1.addProjectConfiguration)(tree, opts.projectName, { root: opts.projectRoot, sourceRoot: (0, devkit_1.joinPathFragments)(opts.projectRoot, 'src'), projectType: 'application', targets: { serve: { executor: 'nx:run-commands', continuous: true, options: { command: BUNDLER_DEV_COMMAND[opts.bundler], cwd: opts.projectRoot, }, }, build: { executor: 'nx:run-commands', options: { command: BUNDLER_BUILD_COMMAND[opts.bundler], cwd: opts.projectRoot, }, }, }, }); const tasks = []; if (shouldGenerateProviders) { for (const p of providers) { tasks.push(await (0, provider_1.default)(tree, { directory: p.directory, bundler: opts.bundler, port: p.port, // Wire `nx serve <provider>` to also spin up this consumer. consumer: opts.projectName, })); } } // Point at `remoteEntry.js`, which every supported bundler emits at dev // time. `mf-manifest.json` is richer (https://module-federation.io/configure/manifest-fields) // but `@module-federation/vite` only emits it at build time, so a consumer // serving against a dev-mode vite provider would get the SPA-fallback HTML // and crash on JSON.parse. Swap to mf-manifest.json manually for prod if // you want the extra metadata. const remotes = providers.map((p) => ({ // `alias` is the key the consumer references (loadRemote/lazyProvider); // `name` is the provider's federation container name; `entry` is its // remoteEntry.js URL. alias: p.name, name: p.federationName, entry: `http://localhost:${p.port}/remoteEntry.js`, })); // Vite emits ESM `remoteEntry.js`; rspack/rsbuild emit UMD. The federation // runtime needs `type: 'module'` for ESM (else loads as a classic <script> // and the browser throws #RUNTIME-001) and NO type for UMD (else // #RUNTIME-002). We only generate same-bundler providers via --providerNames, // so a single per-consumer setting is correct. const remoteType = opts.bundler === 'vite' ? 'module' : null; const templateSubstitutions = { projectName: opts.projectName, federationName: opts.federationName, port: opts.port, bundler: opts.bundler, providers, remotes, remoteType, versions: { ...mfVersions, reactVersion: versions_2.reactVersion, reactDomVersion: versions_2.reactDomVersion, typesReactVersion: versions_2.typesReactVersion, typesReactDomVersion: versions_2.typesReactDomVersion, typescriptVersion: versions_1.typescriptVersion, }, tmpl: '', }; (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files', '_common'), opts.projectRoot, templateSubstitutions); (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files', opts.bundler), opts.projectRoot, templateSubstitutions); // Write deps into the workspace root package.json so bare bundler bins // resolve when nx invokes the generated run-commands serve target. const deps = (0, mf_dependencies_1.getConsumerDeps)(opts.bundler); tasks.push((0, devkit_1.addDependenciesToPackageJson)(tree, deps.dependencies, deps.devDependencies, undefined, true)); await (0, devkit_1.formatFiles)(tree); return (0, devkit_1.runTasksInSerial)(...tasks); } exports.default = consumerGenerator;