feat(rspack): add NxAppRspackPlugin and NxReactRspackPlugin (#28987)

- feat(rspack): add NxAppRspackPlugin
- feat(rspack): add NxReactRspackPlugin

<!-- 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 currently do not have rspack plugins to encapsulate our app, web and
react support for Rspack. This leads to issues with defining configs
that are supported by Crystal


## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
Add and expose two plugins, `NxAppRspackPlugin` and
`NxReactRspackPlugin`, to support building configs that are supported by
crystal

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Colum Ferry 2024-11-19 21:01:10 +00:00 committed by GitHub
parent 2c53e742db
commit 09a01eb30c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 87 additions and 3 deletions

View File

@ -0,0 +1,2 @@
export { NxAppRspackPlugin } from './src/plugins/nx-app-rspack-plugin/nx-app-rspack-plugin';
export type { NxAppRspackPluginOptions } from './src/plugins/utils/models';

View File

@ -0,0 +1 @@
export { NxReactRspackPlugin } from './src/plugins/nx-react-rspack-plugin/nx-react-rspack-plugin';

View File

@ -0,0 +1,56 @@
import type { Compiler } from '@rspack/core';
import type {
NormalizedNxAppRspackPluginOptions,
NxAppRspackPluginOptions,
} from '../utils/models';
import { normalizeOptions } from '../utils/plugins/normalize-options';
import { applyBaseConfig } from '../utils/apply-base-config';
import { applyWebConfig } from '../utils/apply-web-config';
import { deleteOutputDir } from '../utils/delete-output-path';
/**
* This plugin provides features to build Node and Web applications.
* - TS Support (including tsconfig paths
* - Assets handling
* - Stylesheets handling
* - index.html and package.json generation
*
* Web-only features, such as stylesheets and images, are only supported when `target` is `web` or `webworker`.
*/
export class NxAppRspackPlugin {
private readonly options: NormalizedNxAppRspackPluginOptions;
constructor(options: NxAppRspackPluginOptions = {}) {
// If we're building inferred targets, skip normalizing the build options
if (!global.NX_GRAPH_CREATION) {
this.options = normalizeOptions(options);
}
}
apply(compiler: Compiler) {
// Default's to web
const target = this.options.target ?? compiler.options.target;
this.options.outputPath ??= compiler.options.output?.path;
if (typeof target === 'string') {
this.options.target = target;
}
applyBaseConfig(this.options, compiler.options, {
useNormalizedEntry: true,
});
if (compiler.options.target) {
this.options.target = compiler.options.target;
}
if (this.options.target === 'web' || this.options.target === 'webworker') {
applyWebConfig(this.options, compiler.options, {
useNormalizedEntry: true,
});
}
if (this.options.deleteOutputPath) {
deleteOutputDir(this.options.root, this.options.outputPath);
}
}
}

View File

@ -0,0 +1,10 @@
import type { Compiler } from '@rspack/core';
import { applyReactConfig } from '../utils/apply-react-config';
export class NxReactRspackPlugin {
constructor(private options: { svgr?: boolean } = {}) {}
apply(compiler: Compiler) {
applyReactConfig(this.options, compiler.options);
}
}

View File

@ -7,6 +7,7 @@ import {
HtmlRspackPlugin, HtmlRspackPlugin,
CssExtractRspackPlugin, CssExtractRspackPlugin,
EnvironmentPlugin, EnvironmentPlugin,
RspackOptionsNormalized,
} from '@rspack/core'; } from '@rspack/core';
import { instantiateScriptPlugins } from './instantiate-script-plugins'; import { instantiateScriptPlugins } from './instantiate-script-plugins';
import { join, resolve } from 'path'; import { join, resolve } from 'path';
@ -21,7 +22,7 @@ import { NormalizedNxAppRspackPluginOptions } from './models';
export function applyWebConfig( export function applyWebConfig(
options: NormalizedNxAppRspackPluginOptions, options: NormalizedNxAppRspackPluginOptions,
config: Configuration = {}, config: Partial<RspackOptionsNormalized | Configuration> = {},
{ {
useNormalizedEntry, useNormalizedEntry,
}: { }: {
@ -351,7 +352,7 @@ export function applyWebConfig(
}); });
config.optimization = !isProd config.optimization = !isProd
? undefined ? {}
: { : {
...(config.optimization ?? {}), ...(config.optimization ?? {}),
minimizer: [...(config.optimization?.minimizer ?? []), ...minimizer], minimizer: [...(config.optimization?.minimizer ?? []), ...minimizer],

View File

@ -0,0 +1,14 @@
import { rmSync } from 'fs';
import { resolve } from 'path';
/**
* Delete an output directory, but error out if it's the root of the project.
*/
export function deleteOutputDir(root: string, outputPath: string) {
const resolvedOutputPath = resolve(root, outputPath);
if (resolvedOutputPath === root) {
throw new Error('Output path MUST not be project root directory!');
}
rmSync(resolvedOutputPath, { recursive: true, force: true });
}

View File

@ -124,7 +124,7 @@ export function normalizeOptions(
sourceMap: combinedPluginAndMaybeExecutorOptions.sourceMap ?? !isProd, sourceMap: combinedPluginAndMaybeExecutorOptions.sourceMap ?? !isProd,
sourceRoot, sourceRoot,
styles: combinedPluginAndMaybeExecutorOptions.styles ?? [], styles: combinedPluginAndMaybeExecutorOptions.styles ?? [],
target: combinedPluginAndMaybeExecutorOptions.target, target: combinedPluginAndMaybeExecutorOptions.target ?? 'web',
targetName, targetName,
vendorChunk: combinedPluginAndMaybeExecutorOptions.vendorChunk ?? !isProd, vendorChunk: combinedPluginAndMaybeExecutorOptions.vendorChunk ?? !isProd,
}; };