Skip to content

Commit

Permalink
feat(angular): add module-federation-dev-ssr builder (#13496)
Browse files Browse the repository at this point in the history
  • Loading branch information
Coly010 committed Nov 30, 2022
1 parent 4e672b2 commit 0ce6735
Show file tree
Hide file tree
Showing 13 changed files with 1,090 additions and 243 deletions.
89 changes: 89 additions & 0 deletions docs/generated/packages/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -3941,6 +3941,95 @@
"aliases": [],
"hidden": false,
"path": "/packages/angular/src/builders/module-federation-dev-server/schema.json"
},
{
"name": "module-federation-dev-ssr",
"implementation": "/packages/angular/src/builders/module-federation-dev-ssr/module-federation-dev-ssr.impl.ts",
"schema": {
"$schema": "http://json-schema.org/draft-07/schema",
"title": "Module Federation SSR Dev Server Target",
"description": "SSR Dev Server target options for Module Federation host applications.",
"type": "object",
"properties": {
"browserTarget": {
"type": "string",
"description": "Browser target to build.",
"pattern": ".+:.+(:.+)?"
},
"serverTarget": {
"type": "string",
"description": "Server target to build.",
"pattern": ".+:.+(:.+)?"
},
"host": {
"type": "string",
"description": "Host to listen on.",
"default": "localhost"
},
"port": {
"type": "number",
"default": 4200,
"description": "Port to start the development server at. Default is 4200. Pass 0 to get a dynamically assigned port."
},
"publicHost": {
"type": "string",
"description": "The URL that the browser client should use to connect to the development server. Use for a complex dev server setup, such as one with reverse proxies."
},
"open": {
"type": "boolean",
"description": "Opens the url in default browser.",
"default": false,
"alias": "o"
},
"progress": {
"type": "boolean",
"description": "Log progress to the console while building."
},
"inspect": {
"type": "boolean",
"description": "Launch the development server in inspector mode and listen on address and port '127.0.0.1:9229'.",
"default": false
},
"ssl": {
"type": "boolean",
"description": "Serve using HTTPS.",
"default": false
},
"sslKey": {
"type": "string",
"description": "SSL key to use for serving HTTPS."
},
"sslCert": {
"type": "string",
"description": "SSL certificate to use for serving HTTPS."
},
"proxyConfig": {
"type": "string",
"description": "Proxy configuration file."
},
"devRemotes": {
"type": "array",
"items": { "type": "string" },
"description": "List of remote applications to run in development mode (i.e. using serve target)."
},
"skipRemotes": {
"type": "array",
"items": { "type": "string" },
"description": "List of remote applications to not automatically serve, either statically or in development mode. This can be useful for multi-repository module federation setups where the host application uses a remote application from an external repository."
},
"verbose": {
"type": "boolean",
"description": "Adds more details to output logging."
}
},
"additionalProperties": false,
"required": ["browserTarget", "serverTarget"],
"presets": []
},
"description": "The module-federation-dev-ssr executor is reserved exclusively for use with host Module Federation applications that use SSR. It allows the user to specify which remote applications should be served with the host.",
"aliases": [],
"hidden": false,
"path": "/packages/angular/src/builders/module-federation-dev-ssr/schema.json"
}
]
}
3 changes: 2 additions & 1 deletion docs/packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"webpack-browser",
"webpack-dev-server",
"webpack-server",
"module-federation-dev-server"
"module-federation-dev-server",
"module-federation-dev-ssr"
],
"generators": [
"add-linting",
Expand Down
23 changes: 12 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,19 @@
"lint": "nx workspace-lint"
},
"devDependencies": {
"@angular-devkit/architect": "~0.1500.0",
"@angular-devkit/build-angular": "~15.0.0",
"@angular-devkit/core": "~15.0.0",
"@angular-devkit/schematics": "~15.0.0",
"@angular-devkit/architect": "~0.1500.1",
"@angular-devkit/build-angular": "~15.0.1",
"@angular-devkit/core": "~15.0.1",
"@angular-devkit/schematics": "~15.0.1",
"@angular-eslint/eslint-plugin": "~15.0.0",
"@angular-eslint/eslint-plugin-template": "~15.0.0",
"@angular-eslint/template-parser": "~15.0.0",
"@angular/cli": "~15.0.0",
"@angular/common": "~15.0.0",
"@angular/compiler": "~15.0.0",
"@angular/compiler-cli": "~15.0.0",
"@angular/core": "~15.0.0",
"@angular/router": "~15.0.0",
"@angular/cli": "~15.0.1",
"@angular/common": "~15.0.1",
"@angular/compiler": "~15.0.1",
"@angular/compiler-cli": "~15.0.1",
"@angular/core": "~15.0.1",
"@angular/router": "~15.0.1",
"@babel/core": "^7.15.0",
"@babel/helper-create-regexp-features-plugin": "^7.14.5",
"@babel/preset-typescript": "^7.15.0",
Expand All @@ -52,6 +52,7 @@
"@ngrx/effects": "~14.0.0",
"@ngrx/router-store": "~14.0.0",
"@ngrx/store": "~14.0.0",
"@nguniversal/builders": "~15.0.0",
"@nrwl/cypress": "15.3.0-beta.6",
"@nrwl/devkit": "15.3.0-beta.6",
"@nrwl/eslint-plugin-nx": "15.3.0-beta.6",
Expand All @@ -73,7 +74,7 @@
"@rollup/plugin-image": "^2.1.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.0.4",
"@schematics/angular": "~15.0.0",
"@schematics/angular": "~15.0.1",
"@storybook/addon-essentials": "~6.5.9",
"@storybook/angular": "^6.5.12",
"@storybook/builder-webpack5": "~6.5.9",
Expand Down
5 changes: 5 additions & 0 deletions packages/angular/executors.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@
"schema": "./src/builders/module-federation-dev-server/schema.json",
"description": "The module-federation-dev-server executor is reserved exclusively for use with host Module Federation applications. It allows the user to specify which remote applications should be served with the host."
},
"module-federation-dev-ssr": {
"implementation": "./src/builders/module-federation-dev-ssr/module-federation-dev-ssr.impl",
"schema": "./src/builders/module-federation-dev-ssr/schema.json",
"description": "The module-federation-dev-ssr executor is reserved exclusively for use with host Module Federation applications that use SSR. It allows the user to specify which remote applications should be served with the host."
},
"file-server": {
"implementation": "./src/executors/file-server/compat",
"schema": "./src/executors/file-server/schema.json",
Expand Down
1 change: 1 addition & 0 deletions packages/angular/executors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './src/builders/module-federation-dev-server/module-federation-dev-server.impl';
export * from './src/builders/module-federation-dev-ssr/module-federation-dev-ssr.impl';
export * from './src/builders/webpack-browser/webpack-browser.impl';
export * from './src/builders/webpack-dev-server/webpack-dev-server.impl';
export * from './src/builders/webpack-server/webpack-server.impl';
Expand Down
1 change: 1 addition & 0 deletions packages/angular/ng-package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"@nrwl/",
"@angular-devkit",
"@angular-eslint/",
"@nguniversal/builders",
"@schematics",
"@phenomnomnominal/tsquery",
"@typescript-eslint/",
Expand Down
5 changes: 3 additions & 2 deletions packages/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"migrations": "./migrations.json"
},
"dependencies": {
"@angular-devkit/schematics": "~15.0.0",
"@angular-devkit/schematics": "~15.0.1",
"@nguniversal/builders": "~15.0.0",
"@nrwl/cypress": "file:../cypress",
"@nrwl/devkit": "file:../devkit",
"@nrwl/jest": "file:../jest",
Expand All @@ -48,7 +49,7 @@
"@nrwl/webpack": "file:../webpack",
"@nrwl/workspace": "file:../workspace",
"@phenomnomnominal/tsquery": "4.1.1",
"@schematics/angular": "~15.0.0",
"@schematics/angular": "~15.0.1",
"chalk": "4.1.0",
"chokidar": "^3.5.1",
"http-server": "^14.1.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,140 +1,19 @@
import type { Schema } from './schema';
import {
ProjectConfiguration,
readCachedProjectGraph,
Remotes,
workspaceRoot,
Workspaces,
} from '@nrwl/devkit';
import { scheduleTarget } from 'nx/src/adapter/ngcli-adapter';
import { BuilderContext, createBuilder } from '@angular-devkit/architect';
import { JsonObject } from '@angular-devkit/core';
import { join } from 'path';
import { executeWebpackDevServerBuilder } from '../webpack-dev-server/webpack-dev-server.impl';
import { existsSync, readFileSync } from 'fs';
import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph';

function getDynamicRemotes(
project: ProjectConfiguration,
context: BuilderContext,
workspaceProjects: Record<string, ProjectConfiguration>,
remotesToSkip: Set<string>
): string[] {
// check for dynamic remotes
// we should only check for dynamic based on what we generate
// and fallback to empty array

const standardPathToGeneratedMFManifestJson = join(
context.workspaceRoot,
project.sourceRoot,
'assets/module-federation.manifest.json'
);
if (!existsSync(standardPathToGeneratedMFManifestJson)) {
return [];
}

const moduleFederationManifestJson = readFileSync(
standardPathToGeneratedMFManifestJson,
'utf-8'
);

if (!moduleFederationManifestJson) {
return [];
}

// This should have shape of
// {
// "remoteName": "remoteLocation",
// }
const parsedManifest = JSON.parse(moduleFederationManifestJson);
if (
!Object.keys(parsedManifest).every(
(key) =>
typeof key === 'string' && typeof parsedManifest[key] === 'string'
)
) {
return [];
}

const dynamicRemotes = Object.entries(parsedManifest)
.map(([remoteName]) => remoteName)
.filter((r) => !remotesToSkip.has(r));
const invalidDynamicRemotes = dynamicRemotes.filter(
(remote) => !workspaceProjects[remote]
);
if (invalidDynamicRemotes.length) {
throw new Error(
invalidDynamicRemotes.length === 1
? `Invalid dynamic remote configured in "${standardPathToGeneratedMFManifestJson}": ${invalidDynamicRemotes[0]}.`
: `Invalid dynamic remotes configured in "${standardPathToGeneratedMFManifestJson}": ${invalidDynamicRemotes.join(
', '
)}.`
);
}

return dynamicRemotes;
}

function getStaticRemotes(
project: ProjectConfiguration,
context: BuilderContext,
workspaceProjects: Record<string, ProjectConfiguration>,
remotesToSkip: Set<string>
): string[] {
const mfConfigPath = join(
context.workspaceRoot,
project.root,
'module-federation.config.js'
);

let mfeConfig: { remotes: Remotes };
try {
mfeConfig = require(mfConfigPath);
} catch {
throw new Error(
`Could not load ${mfConfigPath}. Was this project generated with "@nrwl/angular:host"?`
);
}

const remotesConfig = mfeConfig.remotes.length > 0 ? mfeConfig.remotes : [];
const staticRemotes = remotesConfig
.map((remoteDefinition) =>
Array.isArray(remoteDefinition) ? remoteDefinition[0] : remoteDefinition
)
.filter((r) => !remotesToSkip.has(r));

const invalidStaticRemotes = staticRemotes.filter(
(remote) => !workspaceProjects[remote]
);
if (invalidStaticRemotes.length) {
throw new Error(
invalidStaticRemotes.length === 1
? `Invalid static remote configured in "${mfConfigPath}": ${invalidStaticRemotes[0]}.`
: `Invalid static remotes configured in "${mfConfigPath}": ${invalidStaticRemotes.join(
', '
)}.`
);
}

return staticRemotes;
}

function validateDevRemotes(
options: Schema,
workspaceProjects: Record<string, ProjectConfiguration>
): void {
const invalidDevRemotes = options.devRemotes?.filter(
(remote) => !workspaceProjects[remote]
);

if (invalidDevRemotes.length) {
throw new Error(
invalidDevRemotes.length === 1
? `Invalid dev remote provided: ${invalidDevRemotes[0]}.`
: `Invalid dev remotes provided: ${invalidDevRemotes.join(', ')}.`
);
}
}
import {
getDynamicRemotes,
getStaticRemotes,
validateDevRemotes,
} from '../utilities/module-federation';

export function executeModuleFederationDevServerBuilder(
schema: Schema,
Expand Down

1 comment on commit 0ce6735

@vercel
Copy link

@vercel vercel bot commented on 0ce6735 Nov 30, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-git-master-nrwl.vercel.app
nx-dev-nrwl.vercel.app
nx.dev
nx-five.vercel.app

Please sign in to comment.