- feat(react): add remote rspack module federation support - feat(react): add host rspack module federation support - feat(react): add federate module rspack module federation support - fix(react): migration test <!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> We do not have an option to generate a react host and remote with rspack ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> Add rspack as an option when generating host and remote ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
337 lines
11 KiB
TypeScript
337 lines
11 KiB
TypeScript
import 'nx/src/internal-testing-utils/mock-project-graph';
|
|
|
|
import { ProjectGraph, readJson, readNxJson } from '@nx/devkit';
|
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
|
import { Linter } from '@nx/eslint';
|
|
import remote from './remote';
|
|
import { getRootTsConfigPathInTree } from '@nx/js';
|
|
|
|
jest.mock('@nx/devkit', () => {
|
|
const original = jest.requireActual('@nx/devkit');
|
|
return {
|
|
...original,
|
|
readCachedProjectGraph: jest.fn().mockImplementation(
|
|
(): ProjectGraph => ({
|
|
dependencies: {},
|
|
nodes: {
|
|
test: {
|
|
name: 'test',
|
|
type: 'app',
|
|
data: {
|
|
root: 'test',
|
|
sourceRoot: 'test/src',
|
|
targets: {
|
|
build: {
|
|
executor: '@nx/webpack:webpack',
|
|
outputs: ['{options.outputPath}'],
|
|
defaultConfiguration: 'production',
|
|
options: {
|
|
compiler: 'babel',
|
|
outputPath: 'dist/test',
|
|
index: 'test/src/index.html',
|
|
baseHref: '/',
|
|
main: `test/src/main.tsx`,
|
|
tsConfig: 'test/tsconfig.app.json',
|
|
assets: ['test/src/favicon.ico', 'src/assets'],
|
|
styles: [`test/src/styles.css`],
|
|
scripts: [],
|
|
webpackConfig: 'test/webpack.config.js',
|
|
},
|
|
configurations: {
|
|
development: {
|
|
extractLicenses: false,
|
|
optimization: false,
|
|
sourceMap: true,
|
|
vendorChunk: true,
|
|
},
|
|
production: {
|
|
fileReplacements: [
|
|
{
|
|
replace: `test/src/environments/environment.ts`,
|
|
with: `test/src/environments/environment.prod.ts`,
|
|
},
|
|
],
|
|
optimization: true,
|
|
outputHashing: 'all',
|
|
sourceMap: false,
|
|
namedChunks: false,
|
|
extractLicenses: true,
|
|
vendorChunk: false,
|
|
},
|
|
},
|
|
},
|
|
serve: {
|
|
executor: '@nx/webpack:dev-server',
|
|
defaultConfiguration: 'development',
|
|
options: {
|
|
buildTarget: `test:build`,
|
|
hmr: true,
|
|
},
|
|
configurations: {
|
|
development: {
|
|
buildTarget: `test:build:development`,
|
|
},
|
|
production: {
|
|
buildTarget: `test:build:production`,
|
|
hmr: false,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
),
|
|
};
|
|
});
|
|
|
|
describe('remote generator', () => {
|
|
// TODO(@jaysoo): Turn this back to adding the plugin
|
|
let originalEnv: string;
|
|
|
|
beforeEach(() => {
|
|
originalEnv = process.env.NX_ADD_PLUGINS;
|
|
process.env.NX_ADD_PLUGINS = 'false';
|
|
});
|
|
|
|
afterEach(() => {
|
|
process.env.NX_ADD_PLUGINS = originalEnv;
|
|
});
|
|
|
|
describe('bundler=webpack', () => {
|
|
it('should create the remote with the correct config files', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
await remote(tree, {
|
|
name: 'test',
|
|
devServerPort: 4201,
|
|
e2eTestRunner: 'cypress',
|
|
linter: Linter.EsLint,
|
|
skipFormat: true,
|
|
style: 'css',
|
|
unitTestRunner: 'jest',
|
|
projectNameAndRootFormat: 'as-provided',
|
|
typescriptConfiguration: false,
|
|
bundler: 'webpack',
|
|
});
|
|
|
|
expect(tree.exists('test/webpack.config.js')).toBeTruthy();
|
|
expect(tree.exists('test/webpack.config.prod.js')).toBeTruthy();
|
|
expect(tree.exists('test/module-federation.config.js')).toBeTruthy();
|
|
|
|
expect(tree.read('test/webpack.config.js', 'utf-8')).toMatchSnapshot();
|
|
expect(
|
|
tree.read('test/webpack.config.prod.js', 'utf-8')
|
|
).toMatchSnapshot();
|
|
expect(
|
|
tree.read('test/module-federation.config.js', 'utf-8')
|
|
).toMatchSnapshot();
|
|
|
|
const tsconfigJson = readJson(tree, getRootTsConfigPathInTree(tree));
|
|
expect(tsconfigJson.compilerOptions.paths['test/Module']).toEqual([
|
|
'test/src/remote-entry.ts',
|
|
]);
|
|
});
|
|
|
|
it('should create the remote with the correct config files when --js=true', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
await remote(tree, {
|
|
name: 'test',
|
|
devServerPort: 4201,
|
|
e2eTestRunner: 'cypress',
|
|
linter: Linter.EsLint,
|
|
skipFormat: true,
|
|
style: 'css',
|
|
unitTestRunner: 'jest',
|
|
projectNameAndRootFormat: 'as-provided',
|
|
typescriptConfiguration: false,
|
|
js: true,
|
|
bundler: 'webpack',
|
|
});
|
|
|
|
expect(tree.exists('test/webpack.config.js')).toBeTruthy();
|
|
expect(tree.exists('test/webpack.config.prod.js')).toBeTruthy();
|
|
expect(tree.exists('test/module-federation.config.js')).toBeTruthy();
|
|
|
|
expect(tree.read('test/webpack.config.js', 'utf-8')).toMatchSnapshot();
|
|
expect(
|
|
tree.read('test/webpack.config.prod.js', 'utf-8')
|
|
).toMatchSnapshot();
|
|
expect(
|
|
tree.read('test/module-federation.config.js', 'utf-8')
|
|
).toMatchSnapshot();
|
|
|
|
const tsconfigJson = readJson(tree, getRootTsConfigPathInTree(tree));
|
|
expect(tsconfigJson.compilerOptions.paths['test/Module']).toEqual([
|
|
'test/src/remote-entry.js',
|
|
]);
|
|
});
|
|
|
|
it('should create the remote with the correct config files when --typescriptConfiguration=true', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
await remote(tree, {
|
|
name: 'test',
|
|
devServerPort: 4201,
|
|
e2eTestRunner: 'cypress',
|
|
linter: Linter.EsLint,
|
|
skipFormat: false,
|
|
style: 'css',
|
|
unitTestRunner: 'jest',
|
|
projectNameAndRootFormat: 'as-provided',
|
|
typescriptConfiguration: true,
|
|
bundler: 'webpack',
|
|
});
|
|
|
|
expect(tree.exists('test/webpack.config.ts')).toBeTruthy();
|
|
expect(tree.exists('test/webpack.config.prod.ts')).toBeTruthy();
|
|
expect(tree.exists('test/module-federation.config.ts')).toBeTruthy();
|
|
|
|
expect(tree.read('test/webpack.config.ts', 'utf-8')).toMatchSnapshot();
|
|
expect(
|
|
tree.read('test/webpack.config.prod.ts', 'utf-8')
|
|
).toMatchSnapshot();
|
|
expect(
|
|
tree.read('test/module-federation.config.ts', 'utf-8')
|
|
).toMatchSnapshot();
|
|
});
|
|
|
|
it('should install @nx/web for the file-server executor', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
await remote(tree, {
|
|
name: 'test',
|
|
devServerPort: 4201,
|
|
e2eTestRunner: 'cypress',
|
|
linter: Linter.EsLint,
|
|
skipFormat: true,
|
|
style: 'css',
|
|
unitTestRunner: 'jest',
|
|
projectNameAndRootFormat: 'as-provided',
|
|
bundler: 'webpack',
|
|
});
|
|
|
|
const packageJson = readJson(tree, 'package.json');
|
|
expect(packageJson.devDependencies['@nx/web']).toBeDefined();
|
|
});
|
|
|
|
it('should not set the remote as the default project', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
await remote(tree, {
|
|
name: 'test',
|
|
devServerPort: 4201,
|
|
e2eTestRunner: 'cypress',
|
|
linter: Linter.EsLint,
|
|
skipFormat: true,
|
|
style: 'css',
|
|
unitTestRunner: 'jest',
|
|
projectNameAndRootFormat: 'as-provided',
|
|
bundler: 'webpack',
|
|
});
|
|
|
|
const { defaultProject } = readNxJson(tree);
|
|
expect(defaultProject).toBeUndefined();
|
|
});
|
|
|
|
it('should generate a remote-specific server.ts file for --ssr', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
|
|
await remote(tree, {
|
|
name: 'test',
|
|
devServerPort: 4201,
|
|
e2eTestRunner: 'cypress',
|
|
linter: Linter.EsLint,
|
|
skipFormat: true,
|
|
style: 'css',
|
|
unitTestRunner: 'jest',
|
|
ssr: true,
|
|
projectNameAndRootFormat: 'as-provided',
|
|
bundler: 'webpack',
|
|
});
|
|
|
|
const mainFile = tree.read('test/server.ts', 'utf-8');
|
|
expect(mainFile).toContain(`join(process.cwd(), 'dist/test/browser')`);
|
|
expect(mainFile).toContain('nx.server.ready');
|
|
});
|
|
|
|
it('should generate correct remote with config files when using --ssr', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
|
|
await remote(tree, {
|
|
name: 'test',
|
|
devServerPort: 4201,
|
|
e2eTestRunner: 'cypress',
|
|
linter: Linter.EsLint,
|
|
skipFormat: true,
|
|
style: 'css',
|
|
unitTestRunner: 'jest',
|
|
ssr: true,
|
|
projectNameAndRootFormat: 'as-provided',
|
|
typescriptConfiguration: false,
|
|
bundler: 'webpack',
|
|
});
|
|
|
|
expect(tree.exists('test/webpack.server.config.js')).toBeTruthy();
|
|
expect(
|
|
tree.exists('test/module-federation.server.config.js')
|
|
).toBeTruthy();
|
|
|
|
expect(
|
|
tree.read('test/webpack.server.config.js', 'utf-8')
|
|
).toMatchSnapshot();
|
|
expect(
|
|
tree.read('test/module-federation.server.config.js', 'utf-8')
|
|
).toMatchSnapshot();
|
|
});
|
|
|
|
it('should generate correct remote with config files when using --ssr and --typescriptConfiguration=true', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
|
|
await remote(tree, {
|
|
name: 'test',
|
|
devServerPort: 4201,
|
|
e2eTestRunner: 'cypress',
|
|
linter: Linter.EsLint,
|
|
skipFormat: false,
|
|
style: 'css',
|
|
unitTestRunner: 'jest',
|
|
ssr: true,
|
|
projectNameAndRootFormat: 'as-provided',
|
|
typescriptConfiguration: true,
|
|
bundler: 'webpack',
|
|
});
|
|
|
|
expect(tree.exists('test/webpack.server.config.ts')).toBeTruthy();
|
|
expect(
|
|
tree.exists('test/module-federation.server.config.ts')
|
|
).toBeTruthy();
|
|
|
|
expect(
|
|
tree.read('test/webpack.server.config.ts', 'utf-8')
|
|
).toMatchSnapshot();
|
|
expect(
|
|
tree.read('test/module-federation.server.config.ts', 'utf-8')
|
|
).toMatchSnapshot();
|
|
});
|
|
|
|
it('should throw an error if invalid remotes names are provided and --dynamic is set to true', async () => {
|
|
const tree = createTreeWithEmptyWorkspace();
|
|
const name = 'invalid-dynamic-remote-name';
|
|
await expect(
|
|
remote(tree, {
|
|
name,
|
|
devServerPort: 4209,
|
|
dynamic: true,
|
|
e2eTestRunner: 'cypress',
|
|
linter: Linter.EsLint,
|
|
skipFormat: false,
|
|
style: 'css',
|
|
unitTestRunner: 'jest',
|
|
ssr: true,
|
|
projectNameAndRootFormat: 'as-provided',
|
|
typescriptConfiguration: true,
|
|
bundler: 'webpack',
|
|
})
|
|
).rejects.toThrowError(`Invalid remote name provided: ${name}.`);
|
|
});
|
|
});
|
|
});
|