Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support only build specified environment #3059

Merged
merged 17 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions e2e/cases/cli/specified-environment/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { execSync } from 'node:child_process';
import path from 'node:path';
import { globContentJSON } from '@e2e/helper';
import { expect, test } from '@playwright/test';

test('should only build specified environment when using --environment option', async () => {
execSync('npx rsbuild build --environment web2', {
cwd: __dirname,
});

const files = await globContentJSON(path.join(__dirname, 'dist'));
const outputFiles = Object.keys(files);

expect(
outputFiles.find((item) => item.includes('web1/index.html')),
).toBeFalsy();
expect(
outputFiles.find((item) => item.includes('web2/index.html')),
).toBeTruthy();
});
20 changes: 20 additions & 0 deletions e2e/cases/cli/specified-environment/rsbuild.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { defineConfig } from '@rsbuild/core';

export default defineConfig({
environments: {
web1: {
output: {
distPath: {
root: 'dist/web1',
},
},
},
web2: {
output: {
distPath: {
root: 'dist/web2',
},
},
},
},
});
1 change: 1 addition & 0 deletions e2e/cases/cli/specified-environment/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('hello!');
4 changes: 2 additions & 2 deletions packages/compat/webpack/src/initConfigs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
type CreateRsbuildOptions,
type InspectConfigOptions,
type PluginManager,
type ResolvedCreateRsbuildOptions,
logger,
} from '@rsbuild/core';
import { inspectConfig } from './inspectConfig';
Expand All @@ -12,7 +12,7 @@ import { generateWebpackConfig } from './webpackConfig';
export type InitConfigsOptions = {
context: InternalContext;
pluginManager: PluginManager;
rsbuildOptions: Required<CreateRsbuildOptions>;
rsbuildOptions: ResolvedCreateRsbuildOptions;
};

export async function initConfigs({
Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/cli/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type CommonOptions = {
open?: boolean | string;
host?: string;
port?: number;
environment?: string[];
};

export type BuildOptions = CommonOptions & {
Expand All @@ -39,6 +40,11 @@ const applyCommonOptions = (command: Command) => {
'--env-mode <mode>',
'specify the env mode to load the `.env.[mode]` file',
)
.option<string[]>(
'--environment <name>',
'specify the environment during multi-environment',
9aoy marked this conversation as resolved.
Show resolved Hide resolved
(str, prev) => (prev ? prev.concat(str.split(',')) : str.split(',')),
)
.option('--env-dir <dir>', 'specify the directory to load `.env` files');
};

Expand Down
1 change: 1 addition & 0 deletions packages/core/src/cli/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export async function init({
return createRsbuild({
cwd: root,
rsbuildConfig: config,
environment: commonOpts.environment,
});
} catch (err) {
if (isRestart) {
Expand Down
7 changes: 4 additions & 3 deletions packages/core/src/createContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { getHTMLPathByEntry } from './initPlugins';
import { logger } from './logger';
import type {
BundlerType,
CreateRsbuildOptions,
EnvironmentContext,
InternalContext,
NormalizedConfig,
NormalizedEnvironmentConfig,
ResolvedCreateRsbuildOptions,
RsbuildConfig,
RsbuildContext,
RsbuildEntry,
Expand All @@ -35,7 +35,7 @@ function getAbsoluteDistPath(
* Create context by config.
*/
async function createContextByConfig(
options: Required<CreateRsbuildOptions>,
options: ResolvedCreateRsbuildOptions,
bundlerType: BundlerType,
): Promise<RsbuildContext> {
const { cwd } = options;
Expand Down Expand Up @@ -210,7 +210,7 @@ export function createPublicContext(
* which can have a lot of overhead and take some side effects.
*/
export async function createContext(
options: Required<CreateRsbuildOptions>,
options: ResolvedCreateRsbuildOptions,
userRsbuildConfig: RsbuildConfig,
bundlerType: BundlerType,
): Promise<InternalContext> {
Expand All @@ -223,5 +223,6 @@ export async function createContext(
hooks: initHooks(),
config: { ...rsbuildConfig },
originalConfig: userRsbuildConfig,
specifiedEnvironments: options.environment,
};
}
8 changes: 6 additions & 2 deletions packages/core/src/createRsbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
InternalContext,
PluginManager,
PreviewServerOptions,
ResolvedCreateRsbuildOptions,
RsbuildInstance,
RsbuildProvider,
} from './types';
Expand Down Expand Up @@ -99,7 +100,7 @@ export async function createRsbuild(
): Promise<RsbuildInstance> {
const { rsbuildConfig = {} } = options;

const rsbuildOptions: Required<CreateRsbuildOptions> = {
const rsbuildOptions: ResolvedCreateRsbuildOptions = {
cwd: process.cwd(),
rsbuildConfig,
...options,
Expand Down Expand Up @@ -180,7 +181,10 @@ export async function createRsbuild(
if (rsbuildConfig.environments) {
await Promise.all(
Object.entries(rsbuildConfig.environments).map(async ([name, config]) => {
if (config.plugins) {
const isEnvironmentEnabled =
!rsbuildOptions.environment ||
rsbuildOptions.environment.includes(name);
if (config.plugins && isEnvironmentEnabled) {
const plugins = await Promise.all(config.plugins);
rsbuild.addPlugins(plugins, {
environment: name,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type {
CreateCompiler,
CreateCompilerOptions,
CreateRsbuildOptions,
ResolvedCreateRsbuildOptions,
CrossOrigin,
CSSLoaderOptions,
CSSModules,
Expand Down
78 changes: 51 additions & 27 deletions packages/core/src/provider/initConfigs.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import color from 'picocolors';
import { getDefaultEntry, normalizeConfig } from '../config';
import { JS_DIST_DIR } from '../constants';
import {
Expand All @@ -9,14 +10,14 @@ import { isDebug, logger } from '../logger';
import { mergeRsbuildConfig } from '../mergeConfig';
import { initPlugins } from '../pluginManager';
import type {
CreateRsbuildOptions,
InspectConfigOptions,
InternalContext,
MergedEnvironmentConfig,
ModifyEnvironmentConfigUtils,
NormalizedConfig,
NormalizedEnvironmentConfig,
PluginManager,
ResolvedCreateRsbuildOptions,
RsbuildEntry,
RspackConfig,
} from '../types';
Expand Down Expand Up @@ -62,12 +63,13 @@ async function modifyEnvironmentConfig(
export type InitConfigsOptions = {
context: InternalContext;
pluginManager: PluginManager;
rsbuildOptions: Required<CreateRsbuildOptions>;
rsbuildOptions: ResolvedCreateRsbuildOptions;
};

const initEnvironmentConfigs = (
normalizedConfig: NormalizedConfig,
rootPath: string,
specifiedEnvironments?: string[],
): Record<string, MergedEnvironmentConfig> => {
let defaultEntry: RsbuildEntry;
const getDefaultEntryWithMemo = () => {
Expand All @@ -80,6 +82,9 @@ const initEnvironmentConfigs = (
normalizedConfig;
const { assetPrefix, lazyCompilation } = dev;

const isEnvironmentEnabled = (name: string) =>
!specifiedEnvironments || specifiedEnvironments.includes(name);

const applyEnvironmentDefaultConfig = (config: MergedEnvironmentConfig) => {
if (!config.source.entry) {
config.source.entry = getDefaultEntryWithMemo();
Expand All @@ -94,35 +99,53 @@ const initEnvironmentConfigs = (
};

if (environments && Object.keys(environments).length) {
return Object.fromEntries(
Object.entries(environments).map(([name, config]) => {
const environmentConfig: MergedEnvironmentConfig = {
...(mergeRsbuildConfig(
{
...rsbuildSharedConfig,
dev: {
assetPrefix,
lazyCompilation,
},
} as unknown as MergedEnvironmentConfig,
config as unknown as MergedEnvironmentConfig,
) as unknown as MergedEnvironmentConfig),
};

return [name, applyEnvironmentDefaultConfig(environmentConfig)];
}),
const resolvedEnvironments = Object.fromEntries(
Object.entries(environments)
.filter(([name]) => isEnvironmentEnabled(name))
.map(([name, config]) => {
const environmentConfig: MergedEnvironmentConfig = {
...(mergeRsbuildConfig(
{
...rsbuildSharedConfig,
dev: {
assetPrefix,
lazyCompilation,
},
} as unknown as MergedEnvironmentConfig,
config as unknown as MergedEnvironmentConfig,
) as unknown as MergedEnvironmentConfig),
};

return [name, applyEnvironmentDefaultConfig(environmentConfig)];
}),
);

if (!Object.keys(resolvedEnvironments).length) {
logger.error(
`The current project is specified to run only in the ${color.yellow(specifiedEnvironments?.join(','))} environment, but the configuration of the corresponding environment was not found.`,
9aoy marked this conversation as resolved.
Show resolved Hide resolved
);
process.exit(1);
9aoy marked this conversation as resolved.
Show resolved Hide resolved
}
return resolvedEnvironments;
}

const defaultEnvironmentName = camelCase(rsbuildSharedConfig.output.target);

if (!isEnvironmentEnabled(defaultEnvironmentName)) {
logger.error(
`The current project is specified to run only in the ${color.yellow(specifiedEnvironments?.join(','))} environment, but the configuration of the corresponding environment was not found.`,
9aoy marked this conversation as resolved.
Show resolved Hide resolved
);
process.exit(1);
}

return {
[camelCase(rsbuildSharedConfig.output.target)]:
applyEnvironmentDefaultConfig({
...rsbuildSharedConfig,
dev: {
assetPrefix,
lazyCompilation,
},
} as MergedEnvironmentConfig),
[defaultEnvironmentName]: applyEnvironmentDefaultConfig({
...rsbuildSharedConfig,
dev: {
assetPrefix,
lazyCompilation,
},
} as MergedEnvironmentConfig),
};
};

Expand Down Expand Up @@ -151,6 +174,7 @@ export async function initRsbuildConfig({
const mergedEnvironments = initEnvironmentConfigs(
normalizeBaseConfig,
context.rootPath,
context.specifiedEnvironments,
);

const {
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/types/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,6 @@ export type InternalContext = RsbuildContext & {
getPluginAPI?: (environment?: string) => RsbuildPluginAPI;
/** The environment context. */
environments: Record<string, EnvironmentContext>;
/** Only build specified environment. */
specifiedEnvironments?: string[];
};
13 changes: 12 additions & 1 deletion packages/core/src/types/rsbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,17 @@ export type CreateRsbuildOptions = {
cwd?: string;
/** Configurations of Rsbuild. */
rsbuildConfig?: RsbuildConfig;
/** Only build specified environment. */
environment?: string[];
};

export type ResolvedCreateRsbuildOptions = {
9aoy marked this conversation as resolved.
Show resolved Hide resolved
/** The root path of current project. */
cwd: string;
/** Configurations of Rsbuild. */
rsbuildConfig: RsbuildConfig;
/** Only build specified environment. */
environment?: string[];
};

export type ProviderInstance<B extends 'rspack' | 'webpack' = 'rspack'> = {
Expand Down Expand Up @@ -104,7 +115,7 @@ export type RsbuildProvider<B extends 'rspack' | 'webpack' = 'rspack'> =
(options: {
context: InternalContext;
pluginManager: PluginManager;
rsbuildOptions: Required<CreateRsbuildOptions>;
rsbuildOptions: ResolvedCreateRsbuildOptions;
setCssExtractPlugin: (plugin: unknown) => void;
}) => Promise<ProviderInstance<B>>;

Expand Down
36 changes: 36 additions & 0 deletions packages/core/tests/environments.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,42 @@ describe('environment config', () => {
).toMatchSnapshot();
});

it('should support run specified environment', async () => {
process.env.NODE_ENV = 'development';

const pluginLogs: string[] = [];

const plugin: (pluginId: string) => RsbuildPlugin = (pluginId) => ({
name: 'test-environment',
setup: () => {
pluginLogs.push(`run plugin in ${pluginId}`);
},
});

const rsbuild = await createRsbuild({
rsbuildConfig: {
environments: {
web: {
plugins: [plugin('web')],
},
ssr: {
plugins: [plugin('ssr')],
},
},
},
environment: ['ssr'],
});

rsbuild.addPlugins([plugin('global')]);

const {
origin: { environmentConfigs },
} = await rsbuild.inspectConfig();

expect(Object.keys(environmentConfigs)).toEqual(['ssr']);
expect(pluginLogs).toEqual(['run plugin in ssr', 'run plugin in global']);
});

it('should normalize environment config correctly', async () => {
process.env.NODE_ENV = 'development';
const rsbuild = await createRsbuild({
Expand Down
2 changes: 1 addition & 1 deletion scripts/test-helper/src/rsbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export async function createStubRsbuild({
}
> {
const { createRsbuild } = await import('@rsbuild/core');
const rsbuildOptions: Required<CreateRsbuildOptions> = {
const rsbuildOptions = {
cwd: process.env.REBUILD_TEST_SUITE_CWD || process.cwd(),
rsbuildConfig,
...options,
Expand Down
Loading
Loading