-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(react): Add federate-module generator
- Loading branch information
1 parent
d1310e3
commit f9c3f63
Showing
12 changed files
with
445 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
118 changes: 118 additions & 0 deletions
118
docs/generated/packages/react/generators/federate-module.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
{ | ||
"name": "federate-module", | ||
"factory": "./src/generators/federate-module/federate-module#federateModuleGenerator", | ||
"schema": { | ||
"$schema": "http://json-schema.org/draft-04/schema", | ||
"cli": "nx", | ||
"$id": "NxReactFederateModule", | ||
"title": "Federate Module", | ||
"description": "Creat a federated module, which can be loaded by a remote host", | ||
"examples": [ | ||
{ | ||
"command": "nx g federate-module --path=libs/ui/src/component/my-cmp.ts --remote=my-remote-app", | ||
"description": "Create a federated module called my-remote-app, that exposes my-cmp from libs/ui/src/component/my-cmp.ts" | ||
} | ||
], | ||
"type": "object", | ||
"properties": { | ||
"name": { | ||
"description": "The name of the module.", | ||
"type": "string", | ||
"$default": { "$source": "argv", "index": 0 }, | ||
"x-prompt": "What name would you like to use for the module?", | ||
"pattern": "^[a-zA-Z][^:]*$" | ||
}, | ||
"path": { | ||
"type": "string", | ||
"description": "The path to the module to be federated", | ||
"x-prompt": "What is the path to the module to be federated?" | ||
}, | ||
"remote": { | ||
"type": "string", | ||
"description": "The name of the remote", | ||
"x-prompt": "What is/should the remote be named?" | ||
}, | ||
"projectNameAndRootFormat": { | ||
"description": "Whether to generate the project name and root directory as provided (`as-provided`) or generate them composing their values and taking the configured layout into account (`derived`).", | ||
"type": "string", | ||
"enum": ["as-provided", "derived"] | ||
}, | ||
"style": { | ||
"description": "The file extension to be used for style files.", | ||
"type": "string", | ||
"default": "css", | ||
"alias": "s", | ||
"x-prompt": { | ||
"message": "Which stylesheet format would you like to use?", | ||
"type": "list", | ||
"items": [ | ||
{ "value": "css", "label": "CSS" }, | ||
{ | ||
"value": "scss", | ||
"label": "SASS(.scss) [ http://sass-lang.com ]" | ||
}, | ||
{ | ||
"value": "less", | ||
"label": "LESS [ http://lesscss.org ]" | ||
}, | ||
{ | ||
"value": "styled-components", | ||
"label": "styled-components [ https://styled-components.com ]" | ||
}, | ||
{ | ||
"value": "@emotion/styled", | ||
"label": "emotion [ https://emotion.sh ]" | ||
}, | ||
{ | ||
"value": "styled-jsx", | ||
"label": "styled-jsx [ https://www.npmjs.com/package/styled-jsx ]" | ||
}, | ||
{ | ||
"value": "styl", | ||
"label": "DEPRECATD: Stylus(.styl) [ http://stylus-lang.com ]" | ||
}, | ||
{ "value": "none", "label": "None" } | ||
] | ||
} | ||
}, | ||
"linter": { | ||
"description": "The tool to use for running lint checks.", | ||
"type": "string", | ||
"enum": ["eslint"], | ||
"default": "eslint" | ||
}, | ||
"skipFormat": { | ||
"description": "Skip formatting files.", | ||
"type": "boolean", | ||
"default": false, | ||
"x-priority": "internal" | ||
}, | ||
"unitTestRunner": { | ||
"type": "string", | ||
"enum": ["jest", "none"], | ||
"description": "Test runner to use for unit tests.", | ||
"default": "jest" | ||
}, | ||
"e2eTestRunner": { | ||
"type": "string", | ||
"enum": ["cypress", "none"], | ||
"description": "Test runner to use for end to end (e2e) tests.", | ||
"default": "cypress" | ||
}, | ||
"host": { | ||
"type": "string", | ||
"description": "The host / shell application for this remote.", | ||
"x-priority": "important" | ||
} | ||
}, | ||
"required": ["name"], | ||
"additionalProperties": false, | ||
"presets": [] | ||
}, | ||
"description": "Federate a module.", | ||
"hidden": false, | ||
"implementation": "/packages/react/src/generators/federate-module/federate-module#federateModuleGenerator.ts", | ||
"aliases": [], | ||
"path": "/packages/react/src/generators/federate-module/schema.json", | ||
"type": "generator" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 6 additions & 0 deletions
6
packages/react/src/generators/federate-module/federate-module.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// TODO | ||
describe('federate-module', () => { | ||
it('should work', () => { | ||
expect(true).toEqual(true); | ||
}); | ||
}); |
27 changes: 27 additions & 0 deletions
27
packages/react/src/generators/federate-module/federate-module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Tree } from '@nx/devkit'; | ||
import { Schema } from './schema'; | ||
|
||
import { remoteGeneratorInternal } from '../remote/remote'; | ||
import { addPathToExposes, checkRemoteExists, getRemote } from './lib/utils'; | ||
|
||
export async function federateModuleGenerator(tree: Tree, schema: Schema) { | ||
// Check remote exists | ||
let remote = await checkRemoteExists(tree, schema.remote); | ||
if (!remote) { | ||
// create remote | ||
await remoteGeneratorInternal(tree, { | ||
name: schema.remote, | ||
e2eTestRunner: schema.e2eTestRunner, | ||
skipFormat: schema.skipFormat, | ||
linter: schema.linter, | ||
style: schema.style, | ||
unitTestRunner: schema.unitTestRunner, | ||
host: schema.host, | ||
projectNameAndRootFormat: schema.projectNameAndRootFormat ?? 'derived', | ||
}); | ||
} | ||
|
||
remote = await getRemote(schema.remote); | ||
// add path to exposes property | ||
addPathToExposes(tree, remote.root, schema.name, schema.path); | ||
} |
124 changes: 124 additions & 0 deletions
124
packages/react/src/generators/federate-module/lib/utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { | ||
ChangeType, | ||
ProjectGraph, | ||
StringChange, | ||
Tree, | ||
applyChangesToString, | ||
createProjectGraphAsync, | ||
joinPathFragments, | ||
readCachedProjectGraph, | ||
} from '@nx/devkit'; | ||
import { join, isAbsolute } from 'path'; | ||
import { ensureTypescript } from '@nx/js/src/utils/typescript/ensure-typescript'; | ||
import * as ts from 'typescript'; | ||
import { findNodes } from '@nx/js'; | ||
|
||
let tsModule: typeof import('typescript'); | ||
|
||
if (!tsModule) { | ||
tsModule = ensureTypescript(); | ||
} | ||
|
||
/** | ||
* Adds a Module Federation path to the exposes property of the module federation config | ||
* The assumption here is made the we will only update a TypeScript Module Federation file namely 'module-federation.config.ts' | ||
* @param tree Tree for the workspace | ||
* @param projectPath Project path relative to the workspace | ||
* @param moduleName The name of the module to expose | ||
* @param modulePath The path to the module to expose | ||
*/ | ||
export function addPathToExposes(tree, projectPath, moduleName, modulePath) { | ||
if (isAbsolute(modulePath)) { | ||
throw new Error( | ||
`Module path: ${modulePath} must be relative to the project ${projectPath}` | ||
); | ||
} | ||
const moduleFederationConfigPath = joinPathFragments( | ||
projectPath, | ||
'module-federation.config.ts' | ||
); | ||
const configCode = tree.read(moduleFederationConfigPath).toString(); | ||
const source = tsModule.createSourceFile( | ||
moduleFederationConfigPath, | ||
configCode, | ||
tsModule.ScriptTarget.Latest, | ||
true | ||
); | ||
|
||
tree.write( | ||
moduleFederationConfigPath, | ||
applyChangesToString( | ||
configCode, | ||
addExposesToConfig(source, moduleName, modulePath) | ||
) | ||
); | ||
} | ||
|
||
/** | ||
* | ||
* @param tree The workspace tree | ||
* @param remoteName The name of the remote to check | ||
* @returns Remote ProjectConfig if it exists, false otherwise | ||
*/ | ||
export async function checkRemoteExists(tree: Tree, remoteName: string) { | ||
const remote = await getRemote(remoteName); | ||
const hasModuleFederationConfig = tree.exists( | ||
join(remote.root, 'module-federation.config.ts') | ||
); | ||
return remote && hasModuleFederationConfig ? remote : false; | ||
} | ||
|
||
export async function getRemote(remoteName: string) { | ||
let projectGraph: ProjectGraph; | ||
try { | ||
projectGraph = readCachedProjectGraph(); | ||
} catch (e) { | ||
projectGraph = await createProjectGraphAsync(); | ||
} | ||
|
||
const remote = projectGraph.nodes[remoteName]?.data; | ||
return remote; | ||
} | ||
|
||
export function addExposesToConfig( | ||
source: ts.SourceFile, | ||
moduleName: string, | ||
modulePath: string | ||
) { | ||
if (tsModule) { | ||
tsModule = ensureTypescript(); | ||
} | ||
|
||
const assignments = findNodes( | ||
source, | ||
tsModule.SyntaxKind.PropertyAssignment | ||
) as ts.PropertyAssignment[]; | ||
|
||
const exposesAssignment = assignments.find( | ||
(s) => s.name.getText() === 'exposes' | ||
); | ||
|
||
if (exposesAssignment) { | ||
const arrayExpression = | ||
exposesAssignment.initializer as ts.ArrayLiteralExpression; | ||
|
||
if (!arrayExpression.elements) return []; | ||
|
||
const lastElement = | ||
arrayExpression.elements[arrayExpression.elements.length - 1]; | ||
return [ | ||
lastElement | ||
? { | ||
type: ChangeType.Insert, | ||
index: lastElement.end, | ||
text: `,`, | ||
} | ||
: null, | ||
{ | ||
type: ChangeType.Insert, | ||
index: exposesAssignment.end - 1, | ||
text: `'${moduleName}': '${modulePath}',\n`, | ||
}, | ||
].filter(Boolean) as StringChange[]; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
export interface Schema { | ||
name: string; | ||
path: string; | ||
remote: string; | ||
projectNameAndRootFormat?: ProjectNameAndRootFormat; | ||
e2eTestRunner?: 'cypress' | 'none'; | ||
host?: string; | ||
linter?: Linter; | ||
skipFormat?: boolean; | ||
style?: SupportedStyles; | ||
unitTestRunner?: 'jest' | 'vitest' | 'none'; | ||
} |
Oops, something went wrong.