Skip to content

Commit

Permalink
feat(nf): add remove schematic
Browse files Browse the repository at this point in the history
  • Loading branch information
manfredsteyer committed Sep 10, 2023
1 parent af94e15 commit 53a9aa7
Show file tree
Hide file tree
Showing 5 changed files with 240 additions and 12 deletions.
11 changes: 8 additions & 3 deletions libs/native-federation/collection.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
{
"$schema": "../../node_modules/@angular-devkit/schematics/collection-schema.json",
"name": "module-federation",
"name": "native-federation",
"version": "0.0.1",
"schematics": {
"ng-add": {
"factory": "./src/schematics/init/schematic",
"schema": "./src/schematics/init/schema.json",
"description": "Initialize an angular project for webpack module federation"
"description": "Initialize an angular project for native federation"
},
"init": {
"factory": "./src/schematics/init/schematic",
"schema": "./src/schematics/init/schema.json",
"description": "Initialize an angular project for webpack module federation"
"description": "Initialize an angular project for native federation"
},
"remove": {
"factory": "./src/schematics/remove/schematic",
"schema": "./src/schematics/remove/schema.json",
"description": "Removes native federation"
}
}
}
42 changes: 33 additions & 9 deletions libs/native-federation/src/schematics/init/schematic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
mergeWith,
template,
move,
noop,
} from '@angular-devkit/schematics';

import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
Expand Down Expand Up @@ -51,16 +52,22 @@ export default function config(options: MfSchematicSchema): Rule {

const remoteMap = await generateRemoteMap(workspace, projectName);

if (options.type === 'dynamic-host') {
if (options.type === 'dynamic-host' && !tree.exists(manifestPath)) {
tree.create(manifestPath, JSON.stringify(remoteMap, null, '\t'));
}

const generateRule = await generateFederationConfig(
remoteMap,
projectRoot,
projectSourceRoot,
options
);
const federationConfigPath = path.join(projectRoot, 'federation.config.js');

const exists = tree.exists(federationConfigPath);

const generateRule = !exists
? await generateFederationConfig(
remoteMap,
projectRoot,
projectSourceRoot,
options
)
: noop;

updateWorkspaceConfig(tree, normalized, workspace, workspaceFileName);

Expand Down Expand Up @@ -104,9 +111,17 @@ function updateWorkspaceConfig(

projectConfig.architect.build = {
builder: '@angular-architects/native-federation:build',
options: {
target: `${projectName}:esbuild:production`,
options: {},
configurations: {
production: {
target: `${projectName}:esbuild:production`,
},
development: {
target: `${projectName}:esbuild:development`,
dev: true,
},
},
defaultConfiguration: 'production',
};

projectConfig.architect['serve-original'] = projectConfig.architect.serve;
Expand All @@ -121,6 +136,15 @@ function updateWorkspaceConfig(
},
};

const serveSsr = projectConfig.architect['serve-ssr'];
if (serveSsr && !serveSsr.options) {
serveSsr.options = {};
}

if (serveSsr) {
serveSsr.options.port = port;
}

// projectConfig.architect.serve.builder = serveBuilder;
// TODO: Register further builders when ready
tree.overwrite(workspaceFileName, JSON.stringify(workspace, null, '\t'));
Expand Down
3 changes: 3 additions & 0 deletions libs/native-federation/src/schematics/remove/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface MfSchematicSchema {
project: string;
}
17 changes: 17 additions & 0 deletions libs/native-federation/src/schematics/remove/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "mf",
"title": "",
"type": "object",
"properties": {
"project": {
"type": "string",
"description": "The project to add module federation",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "Project name (press enter for default project)"
}
}
}
179 changes: 179 additions & 0 deletions libs/native-federation/src/schematics/remove/schematic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { Rule, Tree, noop } from '@angular-devkit/schematics';

import { MfSchematicSchema } from './schema';

import * as path from 'path';

type NormalizedOptions = {
polyfills: string;
projectName: string;
projectRoot: string;
projectSourceRoot: string;
manifestPath: string;
projectConfig: any;
main: string;
};

export default function remove(options: MfSchematicSchema): Rule {
return async function (tree /*, context*/) {
const workspaceFileName = getWorkspaceFileName(tree);
const workspace = JSON.parse(tree.read(workspaceFileName).toString('utf8'));

const normalized = normalizeOptions(options, workspace);

const { polyfills, projectRoot } = normalized;

const bootstrapPath = path.join(projectRoot, 'src/bootstrap.ts');
const mainPath = path.join(projectRoot, 'src/main.ts');

makeMainSync(tree, bootstrapPath, mainPath);
updatePolyfills(tree, polyfills);
updateWorkspaceConfig(tree, normalized, workspace, workspaceFileName);
};
}

function makeMainSync(tree, bootstrapPath: string, mainPath: string) {
if (tree.exists(bootstrapPath) && tree.exists(mainPath)) {
tree.delete(mainPath);
tree.rename(bootstrapPath, mainPath);
}
}

function updateWorkspaceConfig(
tree: Tree,
options: NormalizedOptions,
workspace: any,
workspaceFileName: string
) {
const { projectConfig } = options;

if (!projectConfig?.architect?.build || !projectConfig?.architect?.serve) {
throw new Error(
`The project doen't have a build or serve target in angular.json!`
);
}

if (projectConfig.architect.esbuild) {
projectConfig.architect.build = projectConfig.architect.esbuild;
delete projectConfig.architect.esbuild;
}

if (projectConfig.architect['serve-original']) {
projectConfig.architect.serve = projectConfig.architect['serve-original'];
delete projectConfig.architect['serve-original'];
}

if (projectConfig.architect.serve) {
const conf = projectConfig.architect.serve.configurations;
conf.production.browserTarget = conf.production.browserTarget.replace(
':esbuild:',
':build:'
);
conf.development.browserTarget = conf.development.browserTarget.replace(
':esbuild:',
':build:'
);
}

tree.overwrite(workspaceFileName, JSON.stringify(workspace, null, '\t'));
}

function normalizeOptions(
options: MfSchematicSchema,
workspace: any
): NormalizedOptions {
if (!options.project) {
options.project = workspace.defaultProject;
}

const projects = Object.keys(workspace.projects);

if (!options.project && projects.length === 0) {
throw new Error(
`No default project found. Please specifiy a project name!`
);
}

if (!options.project) {
console.log(
'Using first configured project as default project: ' + projects[0]
);
options.project = projects[0];
}

const projectName = options.project;
const projectConfig = workspace.projects[projectName];

if (!projectConfig) {
throw new Error(`Project ${projectName} not found!`);
}

const projectRoot: string = projectConfig.root?.replace(/\\/g, '/');
const projectSourceRoot: string = projectConfig.sourceRoot?.replace(
/\\/g,
'/'
);

const manifestPath = path
.join(projectRoot, 'src/assets/federation.manifest.json')
.replace(/\\/g, '/');

const main = projectConfig.architect.build.options.main;

if (!projectConfig.architect.build.options.polyfills) {
projectConfig.architect.build.options.polyfills = [];
}

const polyfills = projectConfig.architect.build.options.polyfills;
return {
polyfills,
projectName,
projectRoot,
projectSourceRoot,
manifestPath,
projectConfig,
main,
};
}

function updatePolyfills(tree, polyfills: any) {
if (typeof polyfills === 'string') {
updatePolyfillsFile(tree, polyfills);
} else {
updatePolyfillsArray(tree, polyfills);
}
}

function updatePolyfillsFile(tree, polyfills: any) {
let polyfillsContent = tree.readText(polyfills);
if (polyfillsContent.includes('es-module-shims')) {
polyfillsContent = polyfillsContent.replace(
`import 'es-module-shims';`,
''
);
tree.overwrite(polyfills, polyfillsContent);
}
}

function updatePolyfillsArray(tree, polyfills: any) {
const polyfillsConfig = polyfills as string[];

const index = polyfillsConfig.findIndex((p) => p === 'es-module-shims');
if (index === -1) {
return;
}

polyfillsConfig.splice(index, 1);
}

export function getWorkspaceFileName(tree: Tree): string {
if (tree.exists('angular.json')) {
return 'angular.json';
}
if (tree.exists('workspace.json')) {
return 'workspace.json';
}
throw new Error(
"angular.json or workspace.json expected! Did you call this in your project's root?"
);
}

0 comments on commit 53a9aa7

Please sign in to comment.