Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions e2e/cases/javascript-api/dev-server-restart/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ test('should watch loaded config dependencies for restart', async () => {
.toEqual({
action: 'dev',
filePath: configDep,
options: {},
});
} finally {
await server.close();
Expand Down
1 change: 1 addition & 0 deletions e2e/cases/javascript-api/restart-option/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ test('createRsbuild should support a restart function', async () => {
context: {
action: 'dev',
filePath: watchedFile,
options: {},
},
calls: ['onRestart', 'onCloseDevServer'],
});
Expand Down
110 changes: 110 additions & 0 deletions e2e/cases/javascript-api/restart-preserve-options/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import fs from 'node:fs';
import path from 'node:path';
import { expect, test } from '@e2e/helper';
import { createRsbuild, type RestartContext } from '@rsbuild/core';
import { getRandomPort } from '@rstackjs/test-utils';

const watchedFile = path.join(import.meta.dirname, 'test-temp-watch.txt');

test.beforeEach(() => {
fs.writeFileSync(watchedFile, '1');
});

test.afterAll(() => {
fs.rmSync(watchedFile, { force: true });
});

test('should preserve startDevServer options after restart', async () => {
let restartContext: RestartContext | undefined;
const rsbuild = await createRsbuild({
cwd: import.meta.dirname,
config: {
dev: {
watchFiles: {
paths: watchedFile,
type: 'restart',
},
},
server: {
port: await getRandomPort(),
},
},
restart: (context) => {
restartContext = context;
return true;
},
});

const { server } = await rsbuild.startDevServer({ getPortSilently: true });
let version = 1;

try {
await expect
.poll(
() => {
if (!restartContext) {
fs.writeFileSync(watchedFile, String(++version));
}
return restartContext;
},
{ timeout: 5_000 },
)
.toEqual({
action: 'dev',
filePath: watchedFile,
options: {
getPortSilently: true,
},
});
} finally {
await server.close();
}
});

test('should preserve build options after restart', async () => {
let restartContext: RestartContext | undefined;
const rsbuild = await createRsbuild({
cwd: import.meta.dirname,
config: {
dev: {
watchFiles: {
paths: watchedFile,
type: 'restart',
},
},
},
restart: (context) => {
restartContext = context;
return true;
},
});

const buildReady = new Promise<void>((resolve) => {
rsbuild.onAfterBuild(() => resolve());
});
const result = await rsbuild.build({ watch: true });
await buildReady;
let version = 1;

try {
await expect
.poll(
() => {
if (!restartContext) {
fs.writeFileSync(watchedFile, String(++version));
}
return restartContext;
},
{ timeout: 5_000 },
)
.toEqual({
action: 'build',
filePath: watchedFile,
options: {
watch: true,
},
});
} finally {
await result.close();
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('restart preserve options');
1 change: 1 addition & 0 deletions e2e/cases/javascript-api/restart-watch-files/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const expectRestart = async (rsbuild: RsbuildInstance, action: RestartContext['a
.toEqual({
action,
filePath: watchedFile,
options: action === 'build' ? { watch: true } : {},
});
};

Expand Down
8 changes: 6 additions & 2 deletions packages/core/src/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ export const RSPACK_BUILD_ERROR = 'Rspack build failed.';

export const build = async (
initOptions: InitConfigsOptions,
{ watch }: BuildOptions = {},
buildOptions: BuildOptions = {},
): Promise<ReturnType<Build>> => {
const { watch } = buildOptions;
const { context } = initOptions;
const { logger } = context;
const { compiler, rspackConfigs } = await createCompiler(initOptions);
Expand Down Expand Up @@ -84,7 +85,10 @@ export const build = async (
restartWatcher = watchFilesForRestart({
watchFiles: context.normalizedConfig!.dev.watchFiles,
context,
action: 'build',
restartContext: {
action: 'build',
options: buildOptions,
},
});
}

Expand Down
10 changes: 5 additions & 5 deletions packages/core/src/cli/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createRsbuild } from '../createRsbuild';
import { ensureAbsolutePath } from '../helpers/path';
import { loadConfig as baseLoadConfig } from '../loadConfig';
import { defaultLogger } from '../logger';
import type { RestartContext, RsbuildInstance } from '../types';
import type { RestartFn, RsbuildInstance } from '../types';
import type { CommonOptions } from './commands';

export type CommandName = 'dev' | 'build' | 'preview' | 'inspect';
Expand Down Expand Up @@ -113,7 +113,7 @@ const loadConfig = async (root: string) => {
return result;
};

const restart = async ({ action }: RestartContext): Promise<boolean> => {
const restart: RestartFn = async (context) => {
const rsbuild = await init({ isRestart: true });

// Skip restarting if the config cannot be loaded, for example while the
Expand All @@ -122,10 +122,10 @@ const restart = async ({ action }: RestartContext): Promise<boolean> => {
return false;
}

if (action === 'build') {
await rsbuild.build({ watch: true });
if (context.action === 'build') {
await rsbuild.build(context.options);
} else {
await rsbuild.startDevServer();
await rsbuild.startDevServer(context.options);
}
return true;
};
Expand Down
22 changes: 16 additions & 6 deletions packages/core/src/createRsbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ import type {
RsbuildPlugin,
RsbuildPlugins,
StartDevServer,
StartDevServerOptions,
} from './types';

function applyDefaultPlugins(pluginManager: PluginManager, context: InternalContext) {
Expand Down Expand Up @@ -253,17 +252,24 @@ export async function createRsbuild(options: CreateRsbuildOptions = {}): Promise
return startPreviewServer(context, config, options);
};

const build: Build = async (options) => {
const build: Build = async (options = {}) => {
context.action = 'build';

if (!getNodeEnv()) {
setNodeEnv('production');
}

return baseBuild({ context, pluginManager, rsbuildOptions: resolvedOptions }, options);
return baseBuild(
{
context,
pluginManager,
rsbuildOptions: resolvedOptions,
},
{ ...options },
);
};

const startDevServer: StartDevServer = async (options?: StartDevServerOptions) => {
const startDevServer: StartDevServer = async (options = {}) => {
context.action = 'dev';

if (!getNodeEnv()) {
Expand All @@ -272,10 +278,14 @@ export async function createRsbuild(options: CreateRsbuildOptions = {}): Promise

const config = await initRsbuildConfig({ context, pluginManager });
const server = await baseCreateDevServer(
{ context, pluginManager, rsbuildOptions: resolvedOptions },
{
context,
pluginManager,
rsbuildOptions: resolvedOptions,
},
createCompiler,
config,
options,
{ ...options },
);

return server.listen();
Expand Down
24 changes: 15 additions & 9 deletions packages/core/src/restart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@ const clearConsole = () => {
};

export const requestRestart = ({
filePath,
clear = true,
action,
logger,
restartContext,
restartManager,
}: RestartContext & {
}: {
clear?: boolean;
logger: Logger;
restartContext: RestartContext;
restartManager: RestartManager;
}): Promise<boolean> => {
const { action, filePath } = restartContext;

if (restartManager.canRestart) {
if (clear) {
clearConsole();
Expand All @@ -38,17 +40,17 @@ export const requestRestart = ({
}
}

return restartManager.requestRestart({ action, filePath });
return restartManager.requestRestart(restartContext);
};

export function watchFilesForRestart({
watchFiles,
context,
action,
restartContext,
}: {
watchFiles: WatchFiles[];
context: InternalContext;
action: RestartContext['action'];
restartContext: RestartContext;
}): WatchFilesResult | undefined {
const defaultFiles = context.configFile
? [context.configFile, ...context.configFileDependencies]
Expand Down Expand Up @@ -99,8 +101,10 @@ export function watchFilesForRestart({

try {
const restarted = await requestRestart({
action,
filePath: absoluteFilePath,
restartContext: {
...restartContext,
filePath: absoluteFilePath,
},
logger,
restartManager,
});
Expand All @@ -109,7 +113,9 @@ export function watchFilesForRestart({
if (restarted) {
await close();
} else if (restartManager.canRestart) {
logger.error(action === 'build' ? 'Restart build failed.' : 'Restart server failed.');
logger.error(
restartContext.action === 'build' ? 'Restart build failed.' : 'Restart server failed.',
);
}
} catch (error) {
logger.error(error);
Expand Down
13 changes: 9 additions & 4 deletions packages/core/src/server/devServer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { Server } from 'node:http';
import type { Http2SecureServer } from 'node:http2';
import { color } from '../helpers';
import { color, pick } from '../helpers';
import { getPublicPathFromCompiler, isMultiCompiler } from '../helpers/compiler';
import { requestRestart, watchFilesForRestart } from '../restart';
import type {
Expand Down Expand Up @@ -85,8 +85,13 @@ export async function createDevServer<
options: Options,
createCompiler: CreateCompiler,
config: NormalizedConfig,
{ getPortSilently, runCompile = true }: CreateDevServerOptions = {},
devServerOptions: CreateDevServerOptions = {},
): Promise<RsbuildDevServer> {
const { getPortSilently, runCompile = true } = devServerOptions;
const restartContext = {
action: 'dev' as const,
options: pick(devServerOptions, ['getPortSilently']),
};
const { context } = options;
const { logger } = context;
logger.debug('create dev server');
Expand Down Expand Up @@ -228,7 +233,7 @@ export async function createDevServer<
// Request a manual restart and close the old watcher only after it succeeds.
const restartServer = async () => {
const restarted = await requestRestart({
action: 'dev',
restartContext,
clear: false,
logger,
restartManager: context.restartManager,
Expand Down Expand Up @@ -455,7 +460,7 @@ export async function createDevServer<
state.restartWatcher = watchFilesForRestart({
watchFiles: config.dev.watchFiles,
context,
action: 'dev',
restartContext,
});

logger.debug('create dev server done');
Expand Down
Loading