feat(rspack): add convert-webpack generator (#28167)
<!-- 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 automated method for people to switch to rspack from webpack applications ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> We should have a generator that will convert webpack application projects to use rspack ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
12cbfc35da
commit
36556f6f23
@ -9941,6 +9941,14 @@
|
||||
"children": [],
|
||||
"isExternal": false,
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"id": "convert-webpack",
|
||||
"path": "/nx-api/rspack/generators/convert-webpack",
|
||||
"name": "convert-webpack",
|
||||
"children": [],
|
||||
"isExternal": false,
|
||||
"disableCollapsible": false
|
||||
}
|
||||
],
|
||||
"isExternal": false,
|
||||
|
||||
@ -3000,6 +3000,15 @@
|
||||
"originalFilePath": "/packages/rspack/src/generators/application/schema.json",
|
||||
"path": "/nx-api/rspack/generators/application",
|
||||
"type": "generator"
|
||||
},
|
||||
"/nx-api/rspack/generators/convert-webpack": {
|
||||
"description": "Convert a webpack application to use rspack.",
|
||||
"file": "generated/packages/rspack/generators/convert-webpack.json",
|
||||
"hidden": false,
|
||||
"name": "convert-webpack",
|
||||
"originalFilePath": "/packages/rspack/src/generators/convert-webpack/schema.json",
|
||||
"path": "/nx-api/rspack/generators/convert-webpack",
|
||||
"type": "generator"
|
||||
}
|
||||
},
|
||||
"path": "/nx-api/rspack"
|
||||
|
||||
@ -2970,6 +2970,15 @@
|
||||
"originalFilePath": "/packages/rspack/src/generators/application/schema.json",
|
||||
"path": "rspack/generators/application",
|
||||
"type": "generator"
|
||||
},
|
||||
{
|
||||
"description": "Convert a webpack application to use rspack.",
|
||||
"file": "generated/packages/rspack/generators/convert-webpack.json",
|
||||
"hidden": false,
|
||||
"name": "convert-webpack",
|
||||
"originalFilePath": "/packages/rspack/src/generators/convert-webpack/schema.json",
|
||||
"path": "rspack/generators/convert-webpack",
|
||||
"type": "generator"
|
||||
}
|
||||
],
|
||||
"githubRoot": "https://github.com/nrwl/nx/blob/master",
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
{
|
||||
"name": "convert-webpack",
|
||||
"factory": "./src/generators/convert-webpack/convert-webpack",
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "Rspack",
|
||||
"title": "Nx Webpack to Rspack Generator",
|
||||
"description": "Convert a Webpack project to Rspack.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project": {
|
||||
"type": "string",
|
||||
"description": "The name of the project.",
|
||||
"$default": { "$source": "argv", "index": 0 },
|
||||
"x-dropdown": "project",
|
||||
"x-prompt": "What is the name of the project to convert to rspack?",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
}
|
||||
},
|
||||
"presets": []
|
||||
},
|
||||
"description": "Convert a webpack application to use rspack.",
|
||||
"implementation": "/packages/rspack/src/generators/convert-webpack/convert-webpack.ts",
|
||||
"aliases": [],
|
||||
"hidden": false,
|
||||
"path": "/packages/rspack/src/generators/convert-webpack/schema.json",
|
||||
"type": "generator"
|
||||
}
|
||||
@ -697,6 +697,7 @@
|
||||
- [init](/nx-api/rspack/generators/init)
|
||||
- [preset](/nx-api/rspack/generators/preset)
|
||||
- [application](/nx-api/rspack/generators/application)
|
||||
- [convert-webpack](/nx-api/rspack/generators/convert-webpack)
|
||||
- [storybook](/nx-api/storybook)
|
||||
- [documents](/nx-api/storybook/documents)
|
||||
- [Overview](/nx-api/storybook/documents/overview)
|
||||
|
||||
@ -192,6 +192,57 @@ describe('React Rspack Module Federation', () => {
|
||||
}
|
||||
}, 500_000);
|
||||
|
||||
it('should generate host and remote apps in webpack, convert to rspack and use playwright for e2es', async () => {
|
||||
const shell = uniq('shell');
|
||||
const remote1 = uniq('remote1');
|
||||
|
||||
runCLI(
|
||||
`generate @nx/react:host ${shell} --remotes=${remote1} --bundler=webpack --e2eTestRunner=playwright --style=css --no-interactive --skipFormat`
|
||||
);
|
||||
|
||||
runCLI(
|
||||
`generate @nx/rspack:convert-webpack ${shell} --skipFormat --no-interactive`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nx/rspack:convert-webpack ${remote1} --skipFormat --no-interactive`
|
||||
);
|
||||
|
||||
updateFile(
|
||||
`apps/${shell}-e2e/src/example.spec.ts`,
|
||||
stripIndents`
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('should display welcome message', async ({page}) => {
|
||||
await page.goto("/");
|
||||
expect(await page.locator('h1').innerText()).toContain('Welcome');
|
||||
});
|
||||
|
||||
test('should load remote 1', async ({page}) => {
|
||||
await page.goto("/${remote1}");
|
||||
expect(await page.locator('h1').innerText()).toContain('${remote1}');
|
||||
});
|
||||
`
|
||||
);
|
||||
|
||||
if (runE2ETests()) {
|
||||
const e2eResultsSwc = await runCommandUntil(
|
||||
`e2e ${shell}-e2e`,
|
||||
(output) => output.includes('Successfully ran target e2e for project')
|
||||
);
|
||||
|
||||
await killProcessAndPorts(e2eResultsSwc.pid, readPort(shell));
|
||||
|
||||
const e2eResultsTsNode = await runCommandUntil(
|
||||
`e2e ${shell}-e2e`,
|
||||
(output) =>
|
||||
output.includes('Successfully ran target e2e for project'),
|
||||
{
|
||||
env: { NX_PREFER_TS_NODE: 'true' },
|
||||
}
|
||||
);
|
||||
await killProcessAndPorts(e2eResultsTsNode.pid, readPort(shell));
|
||||
}
|
||||
}, 500_000);
|
||||
|
||||
it('should have interop between webpack host and rspack remote', async () => {
|
||||
const shell = uniq('shell');
|
||||
const remote1 = uniq('remote1');
|
||||
|
||||
@ -26,6 +26,11 @@
|
||||
"aliases": ["app"],
|
||||
"x-type": "application",
|
||||
"description": "React application generator."
|
||||
},
|
||||
"convert-webpack": {
|
||||
"factory": "./src/generators/convert-webpack/convert-webpack",
|
||||
"schema": "./src/generators/convert-webpack/schema.json",
|
||||
"description": "Convert a webpack application to use rspack."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,451 @@
|
||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||
import { readProjectConfiguration } from '@nx/devkit';
|
||||
// nx-ignore-next-line
|
||||
import { applicationGenerator, hostGenerator } from '@nx/react';
|
||||
import convertWebpack from './convert-webpack';
|
||||
|
||||
describe('Convert webpack', () => {
|
||||
it('should convert basic webpack project to rspack', async () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
await applicationGenerator(tree, {
|
||||
directory: 'demo',
|
||||
bundler: 'webpack',
|
||||
e2eTestRunner: 'playwright',
|
||||
linter: 'none',
|
||||
style: 'css',
|
||||
addPlugin: false,
|
||||
});
|
||||
|
||||
// ACT
|
||||
await convertWebpack(tree, { project: 'demo' });
|
||||
|
||||
// ASSERT
|
||||
const project = readProjectConfiguration(tree, 'demo');
|
||||
|
||||
expect(tree.exists('demo/rspack.config.js')).toBeTruthy();
|
||||
expect(tree.read('demo/rspack.config.js', 'utf-8')).toMatchInlineSnapshot(`
|
||||
"const { withReact } = require('@nx/rspack');
|
||||
const { withNx } = require('@nx/rspack');
|
||||
const { composePlugins } = require('@nx/rspack');
|
||||
|
||||
// Nx plugins for webpack.
|
||||
module.exports = composePlugins(
|
||||
withNx(),
|
||||
withReact({
|
||||
// Uncomment this line if you don't want to use SVGR
|
||||
// See: https://react-svgr.com/
|
||||
// svgr: false
|
||||
}),
|
||||
(config) => {
|
||||
// Update the webpack config as needed here.
|
||||
// e.g. \`config.plugins.push(new MyPlugin())\`
|
||||
return config;
|
||||
}
|
||||
);
|
||||
"
|
||||
`);
|
||||
expect(project.targets.build).toMatchInlineSnapshot(`
|
||||
{
|
||||
"configurations": {
|
||||
"development": {
|
||||
"extractLicenses": false,
|
||||
"optimization": false,
|
||||
"sourceMap": true,
|
||||
"vendorChunk": true,
|
||||
},
|
||||
"production": {
|
||||
"extractLicenses": true,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "demo/src/environments/environment.ts",
|
||||
"with": "demo/src/environments/environment.prod.ts",
|
||||
},
|
||||
],
|
||||
"namedChunks": false,
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"vendorChunk": false,
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "production",
|
||||
"executor": "@nx/rspack:rspack",
|
||||
"options": {
|
||||
"assets": [
|
||||
"demo/src/favicon.ico",
|
||||
"demo/src/assets",
|
||||
],
|
||||
"baseHref": "/",
|
||||
"compiler": "babel",
|
||||
"index": "demo/src/index.html",
|
||||
"main": "demo/src/main.tsx",
|
||||
"outputPath": "dist/demo",
|
||||
"rspackConfig": "demo/rspack.config.js",
|
||||
"scripts": [],
|
||||
"styles": [
|
||||
"demo/src/styles.css",
|
||||
],
|
||||
"target": "web",
|
||||
"tsConfig": "demo/tsconfig.app.json",
|
||||
},
|
||||
"outputs": [
|
||||
"{options.outputPath}",
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(project.targets.serve).toMatchInlineSnapshot(`
|
||||
{
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "demo:build:development",
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "demo:build:production",
|
||||
"hmr": false,
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
"executor": "@nx/rspack:dev-server",
|
||||
"options": {
|
||||
"buildTarget": "demo:build",
|
||||
"hmr": true,
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('should convert react module federation webpack projects to rspack', async () => {
|
||||
// ARRANGE
|
||||
const tree = createTreeWithEmptyWorkspace();
|
||||
await hostGenerator(tree, {
|
||||
directory: 'demo',
|
||||
bundler: 'webpack',
|
||||
e2eTestRunner: 'playwright',
|
||||
remotes: ['remote1', 'remote2'],
|
||||
linter: 'none',
|
||||
style: 'css',
|
||||
addPlugin: false,
|
||||
unitTestRunner: 'none',
|
||||
typescriptConfiguration: true,
|
||||
});
|
||||
|
||||
// ACT
|
||||
await convertWebpack(tree, { project: 'demo' });
|
||||
await convertWebpack(tree, { project: 'remote1' });
|
||||
await convertWebpack(tree, { project: 'remote2' });
|
||||
|
||||
// ASSERT
|
||||
const project = readProjectConfiguration(tree, 'demo');
|
||||
|
||||
expect(tree.exists('demo/rspack.config.ts')).toBeTruthy();
|
||||
expect(tree.read('demo/rspack.config.ts', 'utf-8')).toMatchInlineSnapshot(`
|
||||
"import { withModuleFederation } from '@nx/rspack/module-federation';
|
||||
import { ModuleFederationConfig } from '@nx/rspack/module-federation';
|
||||
import { withReact } from '@nx/rspack';
|
||||
import { withNx } from '@nx/rspack';
|
||||
import { composePlugins } from '@nx/rspack';
|
||||
|
||||
import baseConfig from './module-federation.config';
|
||||
|
||||
const config: ModuleFederationConfig = {
|
||||
...baseConfig,
|
||||
};
|
||||
|
||||
// Nx plugins for webpack to build config object from Nx options and context.
|
||||
/**
|
||||
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support for Module Federation
|
||||
* The DTS Plugin can be enabled by setting dts: true
|
||||
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
||||
*/
|
||||
export default composePlugins(
|
||||
withNx(),
|
||||
withReact(),
|
||||
withModuleFederation(config, { dts: false })
|
||||
);
|
||||
"
|
||||
`);
|
||||
expect(project.targets.build).toMatchInlineSnapshot(`
|
||||
{
|
||||
"configurations": {
|
||||
"development": {
|
||||
"extractLicenses": false,
|
||||
"optimization": false,
|
||||
"sourceMap": true,
|
||||
"vendorChunk": true,
|
||||
},
|
||||
"production": {
|
||||
"extractLicenses": true,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "demo/src/environments/environment.ts",
|
||||
"with": "demo/src/environments/environment.prod.ts",
|
||||
},
|
||||
],
|
||||
"namedChunks": false,
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"rspackConfig": "demo/rspack.config.prod.ts",
|
||||
"sourceMap": false,
|
||||
"vendorChunk": false,
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "production",
|
||||
"executor": "@nx/rspack:rspack",
|
||||
"options": {
|
||||
"assets": [
|
||||
"demo/src/favicon.ico",
|
||||
"demo/src/assets",
|
||||
],
|
||||
"baseHref": "/",
|
||||
"compiler": "babel",
|
||||
"index": "demo/src/index.html",
|
||||
"main": "demo/src/main.ts",
|
||||
"outputPath": "dist/demo",
|
||||
"rspackConfig": "demo/rspack.config.ts",
|
||||
"scripts": [],
|
||||
"styles": [
|
||||
"demo/src/styles.css",
|
||||
],
|
||||
"target": "web",
|
||||
"tsConfig": "demo/tsconfig.app.json",
|
||||
},
|
||||
"outputs": [
|
||||
"{options.outputPath}",
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(project.targets.serve).toMatchInlineSnapshot(`
|
||||
{
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "demo:build:development",
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "demo:build:production",
|
||||
"hmr": false,
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
"executor": "@nx/rspack:module-federation-dev-server",
|
||||
"options": {
|
||||
"buildTarget": "demo:build",
|
||||
"hmr": true,
|
||||
"port": 4200,
|
||||
},
|
||||
}
|
||||
`);
|
||||
|
||||
const remote1 = readProjectConfiguration(tree, 'remote1');
|
||||
|
||||
expect(tree.exists('remote1/rspack.config.ts')).toBeTruthy();
|
||||
expect(tree.read('remote1/rspack.config.ts', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"import { withModuleFederation } from '@nx/rspack/module-federation';
|
||||
import { withReact } from '@nx/rspack';
|
||||
import { withNx } from '@nx/rspack';
|
||||
import { composePlugins } from '@nx/rspack';
|
||||
|
||||
import baseConfig from './module-federation.config';
|
||||
|
||||
const config = {
|
||||
...baseConfig,
|
||||
};
|
||||
|
||||
// Nx plugins for webpack to build config object from Nx options and context.
|
||||
/**
|
||||
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation
|
||||
* The DTS Plugin can be enabled by setting dts: true
|
||||
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
||||
*/
|
||||
export default composePlugins(
|
||||
withNx(),
|
||||
withReact(),
|
||||
withModuleFederation(config, { dts: false })
|
||||
);
|
||||
"
|
||||
`);
|
||||
expect(tree.exists('remote1/rspack.config.prod.ts')).toBeTruthy();
|
||||
expect(tree.read('remote1/rspack.config.prod.ts', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"export default require('./rspack.config');
|
||||
"
|
||||
`);
|
||||
expect(project.targets.build).toMatchInlineSnapshot(`
|
||||
{
|
||||
"configurations": {
|
||||
"development": {
|
||||
"extractLicenses": false,
|
||||
"optimization": false,
|
||||
"sourceMap": true,
|
||||
"vendorChunk": true,
|
||||
},
|
||||
"production": {
|
||||
"extractLicenses": true,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "demo/src/environments/environment.ts",
|
||||
"with": "demo/src/environments/environment.prod.ts",
|
||||
},
|
||||
],
|
||||
"namedChunks": false,
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"rspackConfig": "demo/rspack.config.prod.ts",
|
||||
"sourceMap": false,
|
||||
"vendorChunk": false,
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "production",
|
||||
"executor": "@nx/rspack:rspack",
|
||||
"options": {
|
||||
"assets": [
|
||||
"demo/src/favicon.ico",
|
||||
"demo/src/assets",
|
||||
],
|
||||
"baseHref": "/",
|
||||
"compiler": "babel",
|
||||
"index": "demo/src/index.html",
|
||||
"main": "demo/src/main.ts",
|
||||
"outputPath": "dist/demo",
|
||||
"rspackConfig": "demo/rspack.config.ts",
|
||||
"scripts": [],
|
||||
"styles": [
|
||||
"demo/src/styles.css",
|
||||
],
|
||||
"target": "web",
|
||||
"tsConfig": "demo/tsconfig.app.json",
|
||||
},
|
||||
"outputs": [
|
||||
"{options.outputPath}",
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(project.targets.serve).toMatchInlineSnapshot(`
|
||||
{
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "demo:build:development",
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "demo:build:production",
|
||||
"hmr": false,
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
"executor": "@nx/rspack:module-federation-dev-server",
|
||||
"options": {
|
||||
"buildTarget": "demo:build",
|
||||
"hmr": true,
|
||||
"port": 4200,
|
||||
},
|
||||
}
|
||||
`);
|
||||
|
||||
const remote2 = readProjectConfiguration(tree, 'remote2');
|
||||
|
||||
expect(tree.exists('remote2/rspack.config.ts')).toBeTruthy();
|
||||
expect(tree.read('remote2/rspack.config.ts', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"import { withModuleFederation } from '@nx/rspack/module-federation';
|
||||
import { withReact } from '@nx/rspack';
|
||||
import { withNx } from '@nx/rspack';
|
||||
import { composePlugins } from '@nx/rspack';
|
||||
|
||||
import baseConfig from './module-federation.config';
|
||||
|
||||
const config = {
|
||||
...baseConfig,
|
||||
};
|
||||
|
||||
// Nx plugins for webpack to build config object from Nx options and context.
|
||||
/**
|
||||
* DTS Plugin is disabled in Nx Workspaces as Nx already provides Typing support Module Federation
|
||||
* The DTS Plugin can be enabled by setting dts: true
|
||||
* Learn more about the DTS Plugin here: https://module-federation.io/configure/dts.html
|
||||
*/
|
||||
export default composePlugins(
|
||||
withNx(),
|
||||
withReact(),
|
||||
withModuleFederation(config, { dts: false })
|
||||
);
|
||||
"
|
||||
`);
|
||||
expect(tree.exists('remote2/rspack.config.prod.ts')).toBeTruthy();
|
||||
expect(tree.read('remote2/rspack.config.prod.ts', 'utf-8'))
|
||||
.toMatchInlineSnapshot(`
|
||||
"export default require('./rspack.config');
|
||||
"
|
||||
`);
|
||||
expect(project.targets.build).toMatchInlineSnapshot(`
|
||||
{
|
||||
"configurations": {
|
||||
"development": {
|
||||
"extractLicenses": false,
|
||||
"optimization": false,
|
||||
"sourceMap": true,
|
||||
"vendorChunk": true,
|
||||
},
|
||||
"production": {
|
||||
"extractLicenses": true,
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "demo/src/environments/environment.ts",
|
||||
"with": "demo/src/environments/environment.prod.ts",
|
||||
},
|
||||
],
|
||||
"namedChunks": false,
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"rspackConfig": "demo/rspack.config.prod.ts",
|
||||
"sourceMap": false,
|
||||
"vendorChunk": false,
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "production",
|
||||
"executor": "@nx/rspack:rspack",
|
||||
"options": {
|
||||
"assets": [
|
||||
"demo/src/favicon.ico",
|
||||
"demo/src/assets",
|
||||
],
|
||||
"baseHref": "/",
|
||||
"compiler": "babel",
|
||||
"index": "demo/src/index.html",
|
||||
"main": "demo/src/main.ts",
|
||||
"outputPath": "dist/demo",
|
||||
"rspackConfig": "demo/rspack.config.ts",
|
||||
"scripts": [],
|
||||
"styles": [
|
||||
"demo/src/styles.css",
|
||||
],
|
||||
"target": "web",
|
||||
"tsConfig": "demo/tsconfig.app.json",
|
||||
},
|
||||
"outputs": [
|
||||
"{options.outputPath}",
|
||||
],
|
||||
}
|
||||
`);
|
||||
expect(project.targets.serve).toMatchInlineSnapshot(`
|
||||
{
|
||||
"configurations": {
|
||||
"development": {
|
||||
"buildTarget": "demo:build:development",
|
||||
},
|
||||
"production": {
|
||||
"buildTarget": "demo:build:production",
|
||||
"hmr": false,
|
||||
},
|
||||
},
|
||||
"defaultConfiguration": "development",
|
||||
"executor": "@nx/rspack:module-federation-dev-server",
|
||||
"options": {
|
||||
"buildTarget": "demo:build",
|
||||
"hmr": true,
|
||||
"port": 4200,
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -0,0 +1,123 @@
|
||||
import {
|
||||
addDependenciesToPackageJson,
|
||||
formatFiles,
|
||||
getProjects,
|
||||
type Tree,
|
||||
updateProjectConfiguration,
|
||||
} from '@nx/devkit';
|
||||
import { Schema } from './schema';
|
||||
import {
|
||||
rspackCoreVersion,
|
||||
rspackDevServerVersion,
|
||||
} from '../../utils/versions';
|
||||
import { transformEsmConfigFile } from './lib/transform-esm';
|
||||
import { transformCjsConfigFile } from './lib/transform-cjs';
|
||||
|
||||
export default async function (tree: Tree, options: Schema) {
|
||||
const projects = getProjects(tree);
|
||||
if (!projects.has(options.project)) {
|
||||
throw new Error(
|
||||
`Could not find project '${options.project}'. Ensure you have specified the project you'd like to convert correctly.`
|
||||
);
|
||||
}
|
||||
const project = projects.get(options.project);
|
||||
|
||||
const webpackConfigsToConvert: [string, string][] = [];
|
||||
|
||||
for (const [targetName, target] of Object.entries(project.targets)) {
|
||||
if (target.executor === '@nx/webpack:webpack') {
|
||||
target.executor = '@nx/rspack:rspack';
|
||||
if (!target.options.target) {
|
||||
target.options.target = 'web';
|
||||
}
|
||||
const convertWebpackConfigOption = (options: Record<string, any>) => {
|
||||
if (!options.webpackConfig) {
|
||||
return;
|
||||
}
|
||||
const rspackConfigPath = options.webpackConfig.replace(
|
||||
/webpack(?!.*webpack)/,
|
||||
'rspack'
|
||||
);
|
||||
webpackConfigsToConvert.push([options.webpackConfig, rspackConfigPath]);
|
||||
|
||||
options.rspackConfig = rspackConfigPath;
|
||||
delete options.webpackConfig;
|
||||
};
|
||||
|
||||
if (target.options.webpackConfig) {
|
||||
convertWebpackConfigOption(target.options);
|
||||
}
|
||||
|
||||
if (target.configurations) {
|
||||
for (const [configurationName, configuration] of Object.entries(
|
||||
target.configurations
|
||||
)) {
|
||||
convertWebpackConfigOption(configuration);
|
||||
}
|
||||
}
|
||||
} else if (target.executor === '@nx/webpack:dev-server') {
|
||||
target.executor = '@nx/rspack:dev-server';
|
||||
} else if (target.executor === '@nx/webpack:ssr-dev-server') {
|
||||
target.executor = '@nx/rspack:dev-server';
|
||||
} else if (target.executor === '@nx/react:module-federation-dev-server') {
|
||||
target.executor = '@nx/rspack:module-federation-dev-server';
|
||||
} else if (
|
||||
target.executor === '@nx/react:module-federation-ssr-dev-server'
|
||||
) {
|
||||
target.executor = '@nx/rspack:module-federation-ssr-dev-server';
|
||||
} else if (
|
||||
target.executor === '@nx/react:module-federation-static-server'
|
||||
) {
|
||||
target.executor = '@nx/rspack:module-federation-static-server';
|
||||
}
|
||||
}
|
||||
|
||||
for (const [webpackConfigPath, rspackConfigPath] of webpackConfigsToConvert) {
|
||||
tree.rename(webpackConfigPath, rspackConfigPath);
|
||||
transformConfigFile(tree, rspackConfigPath);
|
||||
}
|
||||
|
||||
updateProjectConfiguration(tree, options.project, project);
|
||||
const installTask = addDependenciesToPackageJson(
|
||||
tree,
|
||||
{},
|
||||
{
|
||||
'@rspack/core': rspackCoreVersion,
|
||||
'@rspack/dev-server': rspackDevServerVersion,
|
||||
}
|
||||
);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return installTask;
|
||||
}
|
||||
|
||||
function transformConfigFile(tree: Tree, configPath: string) {
|
||||
transformEsmConfigFile(tree, configPath);
|
||||
transformCjsConfigFile(tree, configPath);
|
||||
cleanupEmptyImports(tree, configPath);
|
||||
replaceOfRequireOfLocalWebpackConfig(tree, configPath);
|
||||
}
|
||||
|
||||
function replaceOfRequireOfLocalWebpackConfig(tree: Tree, configPath: string) {
|
||||
const requireOfLocalWebpackConfig =
|
||||
/(?<=require\s*\(\s*['"][^'"]*)(webpack)(?!.*webpack)(?=[^'"]*['"]\s*\))/g;
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const newContents = configContents.replace(
|
||||
requireOfLocalWebpackConfig,
|
||||
'rspack'
|
||||
);
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function cleanupEmptyImports(tree: Tree, configPath: string) {
|
||||
const emptyImportRegex = /import\s*\{\s*\}\s*from\s*['"][^'"]+['"];/g;
|
||||
const emptyConstRequires =
|
||||
/(const|let)\s*\{\s*\}\s*=\s*require\s*\(\s*['"][^'"]+['"]\s*\);/g;
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
let newContents = configContents.replace(emptyImportRegex, '');
|
||||
newContents = newContents.replace(emptyConstRequires, '');
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
@ -0,0 +1,245 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
|
||||
export function transformCjsConfigFile(tree: Tree, configPath: string) {
|
||||
['@nx', '@nrwl'].forEach((scope: '@nx' | '@nrwl') => {
|
||||
transformComposePlugins(tree, configPath, scope);
|
||||
transformWithNx(tree, configPath, scope);
|
||||
transformWithWeb(tree, configPath, scope);
|
||||
transformWithReact(tree, configPath, scope);
|
||||
transformModuleFederationConfig(tree, configPath, scope);
|
||||
transformWithModuleFederation(tree, configPath, scope);
|
||||
transformWithModuleFederationSSR(tree, configPath, scope);
|
||||
});
|
||||
}
|
||||
|
||||
function transformComposePlugins(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_COMPOSE_PLUGINS_FROM_NX_WEBPACK = `VariableDeclaration:has(Identifier[name=composePlugins]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/webpack]`;
|
||||
const nodes = tsquery(ast, HAS_COMPOSE_PLUGINS_FROM_NX_WEBPACK);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const COMPOSE_PLUGINS_IMPORT =
|
||||
'VariableDeclaration:has(Identifier[name=composePlugins]) Identifier[name=composePlugins]';
|
||||
const composePluginsNodes = tsquery(ast, COMPOSE_PLUGINS_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = composePluginsNodes[0].getStart();
|
||||
let endIndex = composePluginsNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `const { composePlugins } = require('@nx/rspack');
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithNx(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_NX_FROM_NX_WEBPACK = `VariableDeclaration:has(Identifier[name=withNx]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/webpack]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_NX_FROM_NX_WEBPACK);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_NX_IMPORT =
|
||||
'VariableDeclaration:has(Identifier[name=withNx]) Identifier[name=withNx]';
|
||||
const withNxNodes = tsquery(ast, WITH_NX_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withNxNodes[0].getStart();
|
||||
let endIndex = withNxNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `const { withNx } = require('@nx/rspack');
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithWeb(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_WEB_FROM_NX_WEBPACK = `VariableDeclaration:has(Identifier[name=withWeb]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/webpack]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_WEB_FROM_NX_WEBPACK);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_WEB_IMPORT =
|
||||
'VariableDeclaration:has(Identifier[name=withWeb]) Identifier[name=withWeb]';
|
||||
const withWebNodes = tsquery(ast, WITH_WEB_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withWebNodes[0].getStart();
|
||||
let endIndex = withWebNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `const { withWeb } = require('@nx/rspack');
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithReact(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_REACT_FROM_NX_REACT = `VariableDeclaration:has(Identifier[name=withReact]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/react]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_REACT_FROM_NX_REACT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_REACT_IMPORT =
|
||||
'VariableDeclaration:has(Identifier[name=withReact]) Identifier[name=withReact]';
|
||||
const withReactNodes = tsquery(ast, WITH_REACT_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withReactNodes[0].getStart();
|
||||
let endIndex = withReactNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `const { withReact } = require('@nx/rspack');
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformModuleFederationConfig(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `VariableDeclaration:has(Identifier[name=ModuleFederationConfig]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/webpack]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_MODULE_FEDERATION_IMPORT =
|
||||
'VariableDeclaration:has(Identifier[name=ModuleFederationConfig]) Identifier[name=ModuleFederationConfig]';
|
||||
const withModuleFederationNodes = tsquery(ast, WITH_MODULE_FEDERATION_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withModuleFederationNodes[0].getStart();
|
||||
let endIndex = withModuleFederationNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `const { ModuleFederationConfig } = require('@nx/rspack/module-federation');
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithModuleFederation(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `VariableDeclaration:has(Identifier[name=withModuleFederation]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/react/module-federation]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_MODULE_FEDERATION_IMPORT =
|
||||
'VariableDeclaration:has(Identifier[name=withModuleFederation]) Identifier[name=withModuleFederation]';
|
||||
const withModuleFederationNodes = tsquery(ast, WITH_MODULE_FEDERATION_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withModuleFederationNodes[0].getStart();
|
||||
let endIndex = withModuleFederationNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `const { withModuleFederation } = require('@nx/rspack/module-federation');
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithModuleFederationSSR(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `VariableDeclaration:has(Identifier[name=withModuleFederationForSSR]) > CallExpression:has(Identifier[name=require]) StringLiteral[value=${scope}/react/module-federation]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_MODULE_FEDERATION_IMPORT =
|
||||
'VariableDeclaration:has(Identifier[name=withModuleFederationForSSR]) Identifier[name=withModuleFederationForSSR]';
|
||||
const withModuleFederationNodes = tsquery(ast, WITH_MODULE_FEDERATION_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withModuleFederationNodes[0].getStart();
|
||||
let endIndex = withModuleFederationNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `const { withModuleFederationForSSR } = require('@nx/rspack/module-federation');
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
@ -0,0 +1,245 @@
|
||||
import type { Tree } from '@nx/devkit';
|
||||
import { tsquery } from '@phenomnomnominal/tsquery';
|
||||
|
||||
export function transformEsmConfigFile(tree: Tree, configPath: string) {
|
||||
['@nx', '@nrwl'].forEach((scope: '@nx' | '@nrwl') => {
|
||||
transformComposePlugins(tree, configPath, scope);
|
||||
transformWithNx(tree, configPath, scope);
|
||||
transformWithWeb(tree, configPath, scope);
|
||||
transformWithReact(tree, configPath, scope);
|
||||
transformModuleFederationConfig(tree, configPath, scope);
|
||||
transformWithModuleFederation(tree, configPath, scope);
|
||||
transformWithModuleFederationSSR(tree, configPath, scope);
|
||||
});
|
||||
}
|
||||
|
||||
function transformComposePlugins(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_COMPOSE_PLUGINS_FROM_NX_WEBPACK = `ImportDeclaration:has(Identifier[name=composePlugins]) > StringLiteral[value=${scope}/webpack]`;
|
||||
const nodes = tsquery(ast, HAS_COMPOSE_PLUGINS_FROM_NX_WEBPACK);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const COMPOSE_PLUGINS_IMPORT =
|
||||
'ImportDeclaration:has(Identifier[name=composePlugins]) Identifier[name=composePlugins]';
|
||||
const composePluginsNodes = tsquery(ast, COMPOSE_PLUGINS_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = composePluginsNodes[0].getStart();
|
||||
let endIndex = composePluginsNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `import { composePlugins } from '@nx/rspack';
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithNx(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_NX_FROM_NX_WEBPACK = `ImportDeclaration:has(Identifier[name=withNx]) > StringLiteral[value=${scope}/webpack]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_NX_FROM_NX_WEBPACK);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_NX_IMPORT =
|
||||
'ImportDeclaration:has(Identifier[name=withNx]) Identifier[name=withNx]';
|
||||
const withNxNodes = tsquery(ast, WITH_NX_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withNxNodes[0].getStart();
|
||||
let endIndex = withNxNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `import { withNx } from '@nx/rspack';
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithWeb(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_WEB_FROM_NX_WEBPACK = `ImportDeclaration:has(Identifier[name=withWeb]) > StringLiteral[value=${scope}/webpack]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_WEB_FROM_NX_WEBPACK);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_WEB_IMPORT =
|
||||
'ImportDeclaration:has(Identifier[name=withWeb]) Identifier[name=withWeb]';
|
||||
const withWebNodes = tsquery(ast, WITH_WEB_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withWebNodes[0].getStart();
|
||||
let endIndex = withWebNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `import { withWeb } from '@nx/rspack';
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithReact(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_REACT_FROM_NX_REACT = `ImportDeclaration:has(Identifier[name=withReact]) > StringLiteral[value=${scope}/react]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_REACT_FROM_NX_REACT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_REACT_IMPORT =
|
||||
'ImportDeclaration:has(Identifier[name=withReact]) Identifier[name=withReact]';
|
||||
const withReactNodes = tsquery(ast, WITH_REACT_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withReactNodes[0].getStart();
|
||||
let endIndex = withReactNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `import { withReact } from '@nx/rspack';
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithModuleFederation(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `ImportDeclaration:has(Identifier[name=withModuleFederation]) > StringLiteral[value=${scope}/react/module-federation]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_MODULE_FEDERATION_IMPORT =
|
||||
'ImportDeclaration:has(Identifier[name=withModuleFederation]) Identifier[name=withModuleFederation]';
|
||||
const withModuleFederationNodes = tsquery(ast, WITH_MODULE_FEDERATION_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withModuleFederationNodes[0].getStart();
|
||||
let endIndex = withModuleFederationNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `import { withModuleFederation } from '@nx/rspack/module-federation';
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformModuleFederationConfig(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `ImportDeclaration:has(Identifier[name=ModuleFederationConfig]) > StringLiteral[value=${scope}/webpack]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_MODULE_FEDERATION_IMPORT =
|
||||
'ImportDeclaration:has(Identifier[name=ModuleFederationConfig]) Identifier[name=ModuleFederationConfig]';
|
||||
const withModuleFederationNodes = tsquery(ast, WITH_MODULE_FEDERATION_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withModuleFederationNodes[0].getStart();
|
||||
let endIndex = withModuleFederationNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `import { ModuleFederationConfig } from '@nx/rspack/module-federation';
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
|
||||
function transformWithModuleFederationSSR(
|
||||
tree: Tree,
|
||||
configPath: string,
|
||||
scope: '@nx' | '@nrwl'
|
||||
) {
|
||||
const configContents = tree.read(configPath, 'utf-8');
|
||||
const ast = tsquery.ast(configContents);
|
||||
|
||||
const HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT = `ImportDeclaration:has(Identifier[name=withModuleFederationForSSR]) > StringLiteral[value=${scope}/react/module-federation]`;
|
||||
const nodes = tsquery(ast, HAS_WITH_MODULE_FEDERATION_FROM_NX_REACT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const WITH_MODULE_FEDERATION_IMPORT =
|
||||
'ImportDeclaration:has(Identifier[name=withModuleFederationForSSR]) Identifier[name=withModuleFederationForSSR]';
|
||||
const withModuleFederationNodes = tsquery(ast, WITH_MODULE_FEDERATION_IMPORT);
|
||||
if (nodes.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const startIndex = withModuleFederationNodes[0].getStart();
|
||||
let endIndex = withModuleFederationNodes[0].getEnd();
|
||||
if (configContents.charAt(endIndex) === ',') {
|
||||
endIndex++;
|
||||
}
|
||||
|
||||
const newContents = `import { withModuleFederationForSSR } from '@nx/rspack/module-federation';
|
||||
${configContents.slice(0, startIndex)}${configContents.slice(endIndex)}`;
|
||||
|
||||
tree.write(configPath, newContents);
|
||||
}
|
||||
4
packages/rspack/src/generators/convert-webpack/schema.d.ts
vendored
Normal file
4
packages/rspack/src/generators/convert-webpack/schema.d.ts
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export interface Schema {
|
||||
project: string;
|
||||
skipFormat?: boolean;
|
||||
}
|
||||
26
packages/rspack/src/generators/convert-webpack/schema.json
Normal file
26
packages/rspack/src/generators/convert-webpack/schema.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/schema",
|
||||
"$id": "Rspack",
|
||||
"title": "Nx Webpack to Rspack Generator",
|
||||
"description": "Convert a Webpack project to Rspack.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"project": {
|
||||
"type": "string",
|
||||
"description": "The name of the project.",
|
||||
"$default": {
|
||||
"$source": "argv",
|
||||
"index": 0
|
||||
},
|
||||
"x-dropdown": "project",
|
||||
"x-prompt": "What is the name of the project to convert to rspack?",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"skipFormat": {
|
||||
"description": "Skip formatting files.",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"x-priority": "internal"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
export const nxVersion = require('../../package.json').version;
|
||||
export const rspackCoreVersion = '1.0.5';
|
||||
export const rspackDevServerVersion = '1.0.5';
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user