Skip to content

Commit 15ed34a

Browse files
committed
feat: support prune dep tree from specific project
1 parent 9639cad commit 15ed34a

6 files changed

Lines changed: 33 additions & 16 deletions

File tree

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,9 @@ interface projects {
104104
*/
105105
match?: (stdout: string) => boolean;
106106
/**
107-
* Whether to skip starting the current sub-project. Default is `false`.
108-
* Useful for sub-projects that do not need to be started.
107+
* 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.
108+
* 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.
109+
* When the value is `true`, the current sub-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.
109110
*/
110111
skip?: boolean;
111112
}

README.zh-CN.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,10 @@ interface Projects {
9999
match?: (stdout: string) => boolean;
100100
/**
101101
* 是否跳过当前子项目的启动,默认值为 `false`,通常用于跳过一些不需要启动的子项目。
102+
* 当值为 `prune` 时,会从指定项目进行剪枝,这意味着该项目以及他的所有直接和间接依赖都不会被插件启动。
103+
* 当值为 `true` 时,会跳过当前子项目的启动,但不会进行剪枝,这意味着该项目的直接和间接依赖仍然会被插件启动。
102104
*/
103-
skip?: boolean;
105+
skip?: 'prune' | boolean;
104106
}
105107
106108
// 例如,配置 lib1 子项目,用 build:watch 命令启动,匹配 watch success 日志

src/constant.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export const PACKAGE_JSON = 'package.json';
2-
export const DEBUG_LOG_TITLE = '[Rsbuild Workspace Dev Plugin]: ';
2+
export const PLUGIN_LOG_TITLE = '[Rsbuild Workspace Dev Plugin]: ';
33

44
export const RSLIB_READY_MESSAGE = 'build complete, watching for changes';
55
export const MODERN_MODULE_READY_MESSAGE = 'Watching for file changes';

src/logger.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import chalk from 'chalk';
2-
import { DEBUG_LOG_TITLE } from './constant.js';
2+
import { PLUGIN_LOG_TITLE } from './constant.js';
33
import { isDebug } from './utils.js';
44

55
enum LogType {
@@ -26,7 +26,7 @@ export class Logger {
2626
this.name = name;
2727
this.stdout = '';
2828
this.stderr = '';
29-
this.logTitle = DEBUG_LOG_TITLE;
29+
this.logTitle = PLUGIN_LOG_TITLE;
3030
}
3131

3232
appendLog(type: 'stdout' | 'stderr', log: string) {
@@ -71,7 +71,7 @@ export class Logger {
7171
}
7272
}
7373

74-
export const debugLog = (msg: string, prefix = DEBUG_LOG_TITLE) => {
74+
export const debugLog = (msg: string, prefix = PLUGIN_LOG_TITLE) => {
7575
if (isDebug) {
7676
console.log(prefix + msg);
7777
}

src/plugin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export function pluginWorkspaceDev(
1212
name: 'rsbuild-plugin-workspace-dev',
1313
async setup(api) {
1414
const rootPath = api.context.rootPath;
15-
api.onBeforeStartDevServer(async () => {
15+
api.modifyRsbuildConfig(async () => {
1616
const runner = new WorkspaceDevRunner({
1717
cwd: rootPath,
1818
...options,

src/workspace-dev.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import graphlib, { Graph } from 'graphlib';
44
import path from 'path';
55

66
import {
7-
DEBUG_LOG_TITLE,
87
MODERN_MODULE_READY_MESSAGE,
98
PACKAGE_JSON,
9+
PLUGIN_LOG_TITLE,
1010
RSLIB_READY_MESSAGE,
1111
TSUP_READY_MESSAGE,
1212
} from './constant.js';
@@ -27,7 +27,7 @@ export interface WorkspaceDevRunnerOptions {
2727
{
2828
match?: (stdout: string) => boolean;
2929
command?: string;
30-
skip?: boolean;
30+
skip?: boolean | 'prune';
3131
}
3232
>;
3333
startCurrent?: boolean;
@@ -86,7 +86,14 @@ export class WorkspaceDevRunner {
8686
packageJson,
8787
path: dir,
8888
};
89+
if (this.options.projects?.[name]?.skip === 'prune') {
90+
console.log(
91+
`${PLUGIN_LOG_TITLE} Prune project ${name} and its dependencies because it is marked as skip: prune`,
92+
);
93+
return;
94+
}
8995
this.graph.setNode(name, node);
96+
// this.visited[name] = this.options.projects?.[name]?.skip ? true : false;
9097
this.visited[name] = false;
9198
this.visiting[name] = false;
9299
this.matched[name] = false;
@@ -103,7 +110,10 @@ export class WorkspaceDevRunner {
103110
(p) => p.packageJson.name === depName,
104111
);
105112

106-
if (isInternalDep) {
113+
if (
114+
isInternalDep &&
115+
this.options.projects?.[depName]?.skip !== 'prune'
116+
) {
107117
this.graph.setEdge(packageName, depName);
108118
this.checkGraph();
109119
const depPackage = packages.find(
@@ -122,10 +132,13 @@ export class WorkspaceDevRunner {
122132
checkGraph() {
123133
const cycles = graphlib.alg.findCycles(this.graph);
124134
const nonSelfCycles = cycles.filter((c) => c.length !== 1);
125-
debugLog(`cycles check: ${cycles}`);
126-
if (nonSelfCycles.length) {
135+
const nonSkipCycles = nonSelfCycles.filter((group) => {
136+
const isSkip = group.some((node) => this.options.projects?.[node]?.skip);
137+
return !isSkip;
138+
});
139+
if (nonSkipCycles.length) {
127140
throw new Error(
128-
`${DEBUG_LOG_TITLE}Dependency graph do not allow cycles.`,
141+
`${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.`,
129142
);
130143
}
131144
}
@@ -143,7 +156,8 @@ export class WorkspaceDevRunner {
143156
const canStart = dependencies.every((dep) => {
144157
const selfStart = node === dep;
145158
const isVisiting = this.visiting[dep];
146-
const isVisited = selfStart || this.visited[dep];
159+
const skipDep = this.options.projects?.[dep]?.skip;
160+
const isVisited = selfStart || this.visited[dep] || skipDep;
147161
return isVisited && !isVisiting;
148162
});
149163

@@ -167,7 +181,7 @@ export class WorkspaceDevRunner {
167181
this.visited[node] = true;
168182
this.visiting[node] = false;
169183
debugLog(`Skip visit node: ${node}`);
170-
logger.emitLogOnce('stdout', `skip visit node: ${name}`);
184+
logger.emitLogOnce('stdout', `Skip visit node: ${name}`);
171185
return this.start().then(() => resolve());
172186
}
173187
this.visiting[node] = true;

0 commit comments

Comments
 (0)