Skip to content
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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,9 @@ interface projects {
*/
match?: (stdout: string) => boolean;
/**
* Whether to skip starting the current sub-project. Default is `false`.
* Useful for sub-projects that do not need to be started.
* Whether to skip starting the current sub-project. The default value is `false`, typically used to skip sub-projects that don't need to be started.
* When the value is `prune`, the specified project will be pruned, meaning that the project and all its direct and indirect dependencies will not be started by the plugin.
* When the value is `true`, the specified project will be skipped from starting, but no pruning will be performed, meaning that the project's direct and indirect dependencies will still be started by the plugin.
*/
skip?: boolean;
}
Expand Down
4 changes: 3 additions & 1 deletion README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,10 @@ interface Projects {
match?: (stdout: string) => boolean;
/**
* 是否跳过当前子项目的启动,默认值为 `false`,通常用于跳过一些不需要启动的子项目。
* 当值为 `prune` 时,会从指定项目进行剪枝,这意味着该项目以及他的所有直接和间接依赖都不会被插件启动。
* 当值为 `true` 时,会跳过指定项目的启动,但不会进行剪枝,这意味着该项目的直接和间接依赖仍然会被插件启动。
*/
skip?: boolean;
skip?: 'prune' | boolean;
}

// 例如,配置 lib1 子项目,用 build:watch 命令启动,匹配 watch success 日志
Expand Down
2 changes: 1 addition & 1 deletion src/constant.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const PACKAGE_JSON = 'package.json';
export const DEBUG_LOG_TITLE = '[Rsbuild Workspace Dev Plugin]: ';
export const PLUGIN_LOG_TITLE = '[Rsbuild Workspace Dev Plugin]: ';

export const RSLIB_READY_MESSAGE = 'build complete, watching for changes';
export const MODERN_MODULE_READY_MESSAGE = 'Watching for file changes';
Expand Down
6 changes: 3 additions & 3 deletions src/logger.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import chalk from 'chalk';
import { DEBUG_LOG_TITLE } from './constant.js';
import { PLUGIN_LOG_TITLE } from './constant.js';
import { isDebug } from './utils.js';

enum LogType {
Expand All @@ -26,7 +26,7 @@ export class Logger {
this.name = name;
this.stdout = '';
this.stderr = '';
this.logTitle = DEBUG_LOG_TITLE;
this.logTitle = PLUGIN_LOG_TITLE;
}

appendLog(type: 'stdout' | 'stderr', log: string) {
Expand Down Expand Up @@ -71,7 +71,7 @@ export class Logger {
}
}

export const debugLog = (msg: string, prefix = DEBUG_LOG_TITLE) => {
export const debugLog = (msg: string, prefix = PLUGIN_LOG_TITLE) => {
if (isDebug) {
console.log(prefix + msg);
}
Expand Down
2 changes: 1 addition & 1 deletion src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function pluginWorkspaceDev(
name: 'rsbuild-plugin-workspace-dev',
async setup(api) {
const rootPath = api.context.rootPath;
api.onBeforeStartDevServer(async () => {
api.modifyRsbuildConfig(async () => {
Comment thread
nyqykk marked this conversation as resolved.
Outdated
const runner = new WorkspaceDevRunner({
cwd: rootPath,
...options,
Expand Down
30 changes: 22 additions & 8 deletions src/workspace-dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import graphlib, { Graph } from 'graphlib';
import path from 'path';

import {
DEBUG_LOG_TITLE,
MODERN_MODULE_READY_MESSAGE,
PACKAGE_JSON,
PLUGIN_LOG_TITLE,
RSLIB_READY_MESSAGE,
TSUP_READY_MESSAGE,
} from './constant.js';
Expand All @@ -27,7 +27,7 @@ export interface WorkspaceDevRunnerOptions {
{
match?: (stdout: string) => boolean;
command?: string;
skip?: boolean;
skip?: boolean | 'prune';
}
>;
startCurrent?: boolean;
Expand Down Expand Up @@ -86,7 +86,14 @@ export class WorkspaceDevRunner {
packageJson,
path: dir,
};
if (this.options.projects?.[name]?.skip === 'prune') {
console.log(
Comment thread
chenjiahan marked this conversation as resolved.
Outdated
`${PLUGIN_LOG_TITLE} Prune project ${name} and its dependencies because it is marked as skip: prune`,
);
return;
}
this.graph.setNode(name, node);
// this.visited[name] = this.options.projects?.[name]?.skip ? true : false;
Comment thread
nyqykk marked this conversation as resolved.
Outdated
this.visited[name] = false;
this.visiting[name] = false;
this.matched[name] = false;
Expand All @@ -103,7 +110,10 @@ export class WorkspaceDevRunner {
(p) => p.packageJson.name === depName,
);

if (isInternalDep) {
if (
isInternalDep &&
this.options.projects?.[depName]?.skip !== 'prune'
) {
this.graph.setEdge(packageName, depName);
this.checkGraph();
const depPackage = packages.find(
Expand All @@ -122,10 +132,13 @@ export class WorkspaceDevRunner {
checkGraph() {
const cycles = graphlib.alg.findCycles(this.graph);
const nonSelfCycles = cycles.filter((c) => c.length !== 1);
debugLog(`cycles check: ${cycles}`);
if (nonSelfCycles.length) {
const nonSkipCycles = nonSelfCycles.filter((group) => {
const isSkip = group.some((node) => this.options.projects?.[node]?.skip);
return !isSkip;
});
if (nonSkipCycles.length) {
throw new Error(
`${DEBUG_LOG_TITLE}Dependency graph do not allow cycles.`,
`${PLUGIN_LOG_TITLE} Cycle dependency graph found: ${nonSkipCycles}, you should config projects in plugin options to skip someone, or fix the cycle dependency. Otherwise, a loop of dev will occur.`,
);
}
}
Expand All @@ -143,7 +156,8 @@ export class WorkspaceDevRunner {
const canStart = dependencies.every((dep) => {
const selfStart = node === dep;
const isVisiting = this.visiting[dep];
const isVisited = selfStart || this.visited[dep];
const skipDep = this.options.projects?.[dep]?.skip;
const isVisited = selfStart || this.visited[dep] || skipDep;
return isVisited && !isVisiting;
});

Expand All @@ -167,7 +181,7 @@ export class WorkspaceDevRunner {
this.visited[node] = true;
this.visiting[node] = false;
debugLog(`Skip visit node: ${node}`);
logger.emitLogOnce('stdout', `skip visit node: ${name}`);
logger.emitLogOnce('stdout', `Skip visit node: ${name}`);
return this.start().then(() => resolve());
}
this.visiting[node] = true;
Expand Down