Skip to content

Commit ee4f360

Browse files
authored
feat: Add watch configuration for dev (#5652)
Add `watch` property to app to allow watching specific directories for changes when running `sst dev`. closes #5003, closes #4233
1 parent 7b62ac3 commit ee4f360

File tree

4 files changed

+66
-24
lines changed

4 files changed

+66
-24
lines changed

cmd/sst/mosaic.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ func CmdMosaic(c *cli.Cli) error {
159159

160160
wg.Go(func() error {
161161
defer c.Cancel()
162-
return watcher.Start(c.Context, p.PathRoot())
162+
return watcher.Start(c.Context, watcher.WatchConfig{
163+
Root: p.PathRoot(),
164+
Watch: p.App().Watch,
165+
})
163166
})
164167

165168
server, err := server.New()
@@ -353,7 +356,6 @@ func CmdMosaic(c *cli.Cli) error {
353356
err = wg.Wait()
354357
slog.Info("done mosaic", "err", err)
355358
return err
356-
357359
}
358360

359361
func diff(a map[string]string, b map[string]string) bool {

cmd/sst/mosaic/watcher/watcher.go

Lines changed: 45 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,46 +16,69 @@ type FileChangedEvent struct {
1616
Path string
1717
}
1818

19-
func Start(ctx context.Context, root string) error {
19+
type WatchConfig struct {
20+
Root string
21+
Watch []string
22+
}
23+
24+
func Start(ctx context.Context, config WatchConfig) error {
2025
log := slog.Default().With("service", "watcher")
2126
defer log.Info("done")
22-
log.Info("starting watcher", "root", root)
27+
log.Info("starting watcher", "root", config.Root)
2328
watcher, err := fsnotify.NewWatcher()
2429
if err != nil {
2530
return err
2631
}
27-
err = watcher.AddWith(root)
32+
33+
err = watcher.AddWith(config.Root)
2834
if err != nil {
2935
return err
3036
}
31-
ignoreSubstrings := []string{"node_modules"}
3237

33-
err = filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
34-
if err != nil {
35-
return err
38+
matches := []string{}
39+
if len(config.Watch) == 0 {
40+
matches = append(matches, config.Root)
41+
} else {
42+
for _, watch := range config.Watch {
43+
pattern := filepath.Join(config.Root, watch)
44+
patternMatches, err := filepath.Glob(pattern)
45+
if err != nil {
46+
return err
47+
}
48+
matches = append(matches, patternMatches...)
3649
}
37-
if info.IsDir() {
38-
if strings.HasPrefix(info.Name(), ".") {
39-
return filepath.SkipDir
50+
}
51+
52+
ignoreSubstrings := []string{"node_modules"}
53+
for _, match := range matches {
54+
err = filepath.Walk(match, func(path string, info os.FileInfo, err error) error {
55+
if err != nil {
56+
return err
4057
}
41-
for _, substring := range ignoreSubstrings {
42-
if strings.Contains(path, substring) {
58+
if info.IsDir() {
59+
if strings.HasPrefix(info.Name(), ".") {
4360
return filepath.SkipDir
4461
}
62+
for _, substring := range ignoreSubstrings {
63+
if strings.Contains(path, substring) {
64+
return filepath.SkipDir
65+
}
66+
}
67+
68+
log.Info("watching", "path", path)
69+
err = watcher.Add(path)
70+
if err != nil {
71+
return err
72+
}
4573
}
46-
log.Info("watching", "path", path)
47-
err = watcher.Add(path)
48-
if err != nil {
49-
return err
50-
}
74+
return nil
75+
})
76+
if err != nil {
77+
return err
5178
}
52-
return nil
53-
})
54-
if err != nil {
55-
return err
5679
}
5780

58-
headFile := filepath.Join(root, ".git/HEAD")
81+
headFile := filepath.Join(config.Root, ".git/HEAD")
5982
watcher.Add(headFile)
6083
limiter := map[string]time.Time{}
6184
for {

pkg/project/project.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type App struct {
3535
Home string `json:"home"`
3636
Version string `json:"version"`
3737
Protect bool `json:"protect"`
38+
Watch []string `json:"watch"`
3839
// Deprecated: Backend is now Home
3940
Backend string `json:"backend"`
4041
// Deprecated: RemovalPolicy is now Removal

platform/src/config.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,22 @@ export interface App {
270270
* `sst dev`, it'll still get removed. To avoid this, check out the `removal` prop.
271271
*/
272272
protect?: boolean;
273+
274+
/**
275+
* Configure which directories should be watched for changes when running `sst dev`.
276+
* By default, all directories are watched (except node_modules and hidden directories).
277+
*
278+
* @example
279+
* ```ts
280+
* {
281+
* watch: ["packages/www", "packages/api"]
282+
* }
283+
* ```
284+
*
285+
* This will only watch the `packages/www` and `packages/api` directories.
286+
* The paths are relative to the project root.
287+
*/
288+
watch?: string[];
273289
}
274290

275291
export interface AppInput {

0 commit comments

Comments
 (0)