11import type * as rspack from '@rspack/core' ;
2-
32import { getInfrastructureLogger } from '../infrastructure-logger' ;
43import type { TsCheckerRspackPluginConfig } from '../plugin-config' ;
54import type { TsCheckerRspackPluginState } from '../plugin-state' ;
5+ import { sep } from 'node:path' ;
6+
7+ const addTrailingSep = ( dir : string ) => ( dir . endsWith ( sep ) ? dir : dir + sep ) ;
8+
9+ const isStrictSubdir = ( parent : string , child : string ) => {
10+ const parentDir = addTrailingSep ( parent ) ;
11+ const childDir = addTrailingSep ( child ) ;
12+ return parentDir !== childDir && childDir . startsWith ( parentDir ) ;
13+ } ;
14+
15+ /**
16+ * Excludes the Rspack output directory from watched dependencies
17+ * when the entire project is being watched.
18+ *
19+ * If `writeToDisk` is enabled and the build output path is not ignored,
20+ * emitted files in `output.path` may leading to an infinite rebuild loop.
21+ **/
22+ function excludeOutputPath (
23+ dependencies : NonNullable < TsCheckerRspackPluginState [ 'lastDependencies' ] > ,
24+ compiler : rspack . Compiler
25+ ) {
26+ const isContextIncluded = dependencies . dirs . includes ( compiler . context ) ;
27+ if ( ! isContextIncluded ) {
28+ return dependencies ;
29+ }
30+
31+ const outputPath =
32+ typeof compiler . options . output ?. path === 'string'
33+ ? compiler . options . output . path
34+ : compiler . outputPath ;
35+ if (
36+ ! outputPath ||
37+ // If output path is not a subdir of context, no need to exclude it
38+ ! isStrictSubdir ( compiler . context , outputPath ) ||
39+ // If output path is explicitly included in dirs, should not exclude it
40+ dependencies . dirs . includes ( outputPath )
41+ ) {
42+ return dependencies ;
43+ }
44+
45+ const excluded = new Set ( dependencies . excluded ) ;
46+ excluded . add ( outputPath ) ;
47+
48+ return {
49+ ...dependencies ,
50+ excluded : Array . from ( excluded ) ,
51+ } ;
52+ }
653
754function tapAfterCompileToAddDependencies (
855 compiler : rspack . Compiler ,
@@ -21,9 +68,10 @@ function tapAfterCompileToAddDependencies(
2168
2269 debug ( `Got dependencies from the getDependenciesWorker.` , dependencies ) ;
2370 if ( dependencies ) {
24- state . lastDependencies = dependencies ;
71+ const sanitizedDependencies = excludeOutputPath ( dependencies , compiler ) ;
72+ state . lastDependencies = sanitizedDependencies ;
2573
26- dependencies . files . forEach ( ( file ) => {
74+ sanitizedDependencies . files . forEach ( ( file ) => {
2775 compilation . fileDependencies . add ( file ) ;
2876 } ) ;
2977 }
0 commit comments