@astroscope/boot 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -83,7 +83,7 @@ boot({ entry: "src/startup.ts" });
83
83
 
84
84
  ### `hmr`
85
85
 
86
- Re-run `onStartup` when the boot file changes during development. This is disabled by default to avoid side effects, because `onStartup` may perform operations that should only run once (e.g., database connections).
86
+ Re-run `onStartup` when the boot file changes during development. This is disabled by default to avoid side effects, because `onStartup` may perform operations that should only run once (e.g., database connections). Please ensure your `onShutdown` function destroys any resources created by `onStartup` to prevent leaks / unexpected behavior.
87
87
 
88
88
  - **Type**: `boolean`
89
89
  - **Default**: `false`
package/dist/index.cjs CHANGED
@@ -35,6 +35,51 @@ __export(index_exports, {
35
35
  module.exports = __toCommonJS(index_exports);
36
36
  var import_node_fs = __toESM(require("fs"), 1);
37
37
  var import_node_path = __toESM(require("path"), 1);
38
+
39
+ // src/ignored.ts
40
+ var ignoredSuffixes = [
41
+ // type definitions
42
+ ".d.ts",
43
+ ".d.mts",
44
+ ".d.cts",
45
+ // images
46
+ ".png",
47
+ ".jpg",
48
+ ".jpeg",
49
+ ".gif",
50
+ ".svg",
51
+ ".webp",
52
+ ".avif",
53
+ ".ico",
54
+ // fonts
55
+ ".woff",
56
+ ".woff2",
57
+ ".ttf",
58
+ ".otf",
59
+ ".eot",
60
+ // other static assets
61
+ ".pdf",
62
+ ".mp3",
63
+ ".mp4",
64
+ ".webm",
65
+ ".ogg",
66
+ ".wav",
67
+ // data/config that boot typically doesn't import
68
+ ".json",
69
+ ".yaml",
70
+ ".yml",
71
+ ".toml",
72
+ ".md",
73
+ ".mdx",
74
+ ".txt",
75
+ // styles (handled by Vite's CSS HMR)
76
+ ".css",
77
+ ".scss",
78
+ ".sass",
79
+ ".less"
80
+ ];
81
+
82
+ // src/index.ts
38
83
  function resolveEntry(entry) {
39
84
  if (entry) return entry;
40
85
  if (import_node_fs.default.existsSync("src/boot.ts")) return "src/boot.ts";
@@ -80,17 +125,49 @@ function boot(options = {}) {
80
125
  }
81
126
  });
82
127
  if (hmr) {
83
- server.watcher.on("change", async (changedPath) => {
84
- if (!changedPath.endsWith(entry)) return;
85
- logger.info("boot file changed, re-running onStartup...");
128
+ const bootModuleId = `/${entry}`;
129
+ const bootFilePath = import_node_path.default.resolve(server.config.root, entry);
130
+ const getBootDependencies = () => {
131
+ const deps = /* @__PURE__ */ new Set();
132
+ const bootModules = server.moduleGraph.getModulesByFile(bootFilePath);
133
+ const bootModule = bootModules ? [...bootModules][0] : void 0;
134
+ if (!bootModule) return deps;
135
+ const collectDeps = (mod, visited = /* @__PURE__ */ new Set()) => {
136
+ if (!mod?.file || visited.has(mod.file)) return;
137
+ visited.add(mod.file);
138
+ deps.add(mod.file);
139
+ for (const imported of mod.importedModules) {
140
+ collectDeps(imported, visited);
141
+ }
142
+ };
143
+ collectDeps(bootModule);
144
+ return deps;
145
+ };
146
+ const rerunBoot = async (changedFile) => {
147
+ logger.info(`boot dependency changed: ${changedFile}, rerunning hooks...`);
86
148
  try {
149
+ const oldModule = await server.ssrLoadModule(bootModuleId);
150
+ if (oldModule.onShutdown) {
151
+ await oldModule.onShutdown();
152
+ }
87
153
  server.moduleGraph.invalidateAll();
88
- const module2 = await server.ssrLoadModule(`/${entry}`);
89
- if (module2.onStartup) {
90
- await module2.onStartup();
154
+ const newModule = await server.ssrLoadModule(bootModuleId);
155
+ if (newModule.onStartup) {
156
+ await newModule.onStartup();
91
157
  }
92
158
  } catch (error) {
93
- logger.error(`Error running startup script: ${error}`);
159
+ logger.error(`Error during boot HMR: ${error}`);
160
+ }
161
+ };
162
+ const shouldIgnore = (filePath) => {
163
+ const path2 = filePath.toLowerCase();
164
+ return ignoredSuffixes.some((suffix) => path2.endsWith(suffix));
165
+ };
166
+ server.watcher.on("change", async (changedPath) => {
167
+ if (shouldIgnore(changedPath)) return;
168
+ const bootDeps = getBootDependencies();
169
+ if (bootDeps.has(changedPath)) {
170
+ await rerunBoot(changedPath);
94
171
  }
95
172
  });
96
173
  }
package/dist/index.d.cts CHANGED
@@ -5,12 +5,12 @@ interface BootOptions {
5
5
  * Path to the boot file relative to the project root.
6
6
  * @default "src/boot.ts"
7
7
  */
8
- entry?: string;
8
+ entry?: string | undefined;
9
9
  /**
10
10
  * Enable HMR for the boot file. When true, `onStartup` will re-run when the boot file changes.
11
11
  * @default false
12
12
  */
13
- hmr?: boolean;
13
+ hmr?: boolean | undefined;
14
14
  }
15
15
  /**
16
16
  * Astro integration for application lifecycle hooks.
package/dist/index.d.ts CHANGED
@@ -5,12 +5,12 @@ interface BootOptions {
5
5
  * Path to the boot file relative to the project root.
6
6
  * @default "src/boot.ts"
7
7
  */
8
- entry?: string;
8
+ entry?: string | undefined;
9
9
  /**
10
10
  * Enable HMR for the boot file. When true, `onStartup` will re-run when the boot file changes.
11
11
  * @default false
12
12
  */
13
- hmr?: boolean;
13
+ hmr?: boolean | undefined;
14
14
  }
15
15
  /**
16
16
  * Astro integration for application lifecycle hooks.
package/dist/index.js CHANGED
@@ -1,6 +1,51 @@
1
1
  // src/index.ts
2
2
  import fs from "fs";
3
3
  import path from "path";
4
+
5
+ // src/ignored.ts
6
+ var ignoredSuffixes = [
7
+ // type definitions
8
+ ".d.ts",
9
+ ".d.mts",
10
+ ".d.cts",
11
+ // images
12
+ ".png",
13
+ ".jpg",
14
+ ".jpeg",
15
+ ".gif",
16
+ ".svg",
17
+ ".webp",
18
+ ".avif",
19
+ ".ico",
20
+ // fonts
21
+ ".woff",
22
+ ".woff2",
23
+ ".ttf",
24
+ ".otf",
25
+ ".eot",
26
+ // other static assets
27
+ ".pdf",
28
+ ".mp3",
29
+ ".mp4",
30
+ ".webm",
31
+ ".ogg",
32
+ ".wav",
33
+ // data/config that boot typically doesn't import
34
+ ".json",
35
+ ".yaml",
36
+ ".yml",
37
+ ".toml",
38
+ ".md",
39
+ ".mdx",
40
+ ".txt",
41
+ // styles (handled by Vite's CSS HMR)
42
+ ".css",
43
+ ".scss",
44
+ ".sass",
45
+ ".less"
46
+ ];
47
+
48
+ // src/index.ts
4
49
  function resolveEntry(entry) {
5
50
  if (entry) return entry;
6
51
  if (fs.existsSync("src/boot.ts")) return "src/boot.ts";
@@ -46,17 +91,49 @@ function boot(options = {}) {
46
91
  }
47
92
  });
48
93
  if (hmr) {
49
- server.watcher.on("change", async (changedPath) => {
50
- if (!changedPath.endsWith(entry)) return;
51
- logger.info("boot file changed, re-running onStartup...");
94
+ const bootModuleId = `/${entry}`;
95
+ const bootFilePath = path.resolve(server.config.root, entry);
96
+ const getBootDependencies = () => {
97
+ const deps = /* @__PURE__ */ new Set();
98
+ const bootModules = server.moduleGraph.getModulesByFile(bootFilePath);
99
+ const bootModule = bootModules ? [...bootModules][0] : void 0;
100
+ if (!bootModule) return deps;
101
+ const collectDeps = (mod, visited = /* @__PURE__ */ new Set()) => {
102
+ if (!mod?.file || visited.has(mod.file)) return;
103
+ visited.add(mod.file);
104
+ deps.add(mod.file);
105
+ for (const imported of mod.importedModules) {
106
+ collectDeps(imported, visited);
107
+ }
108
+ };
109
+ collectDeps(bootModule);
110
+ return deps;
111
+ };
112
+ const rerunBoot = async (changedFile) => {
113
+ logger.info(`boot dependency changed: ${changedFile}, rerunning hooks...`);
52
114
  try {
115
+ const oldModule = await server.ssrLoadModule(bootModuleId);
116
+ if (oldModule.onShutdown) {
117
+ await oldModule.onShutdown();
118
+ }
53
119
  server.moduleGraph.invalidateAll();
54
- const module = await server.ssrLoadModule(`/${entry}`);
55
- if (module.onStartup) {
56
- await module.onStartup();
120
+ const newModule = await server.ssrLoadModule(bootModuleId);
121
+ if (newModule.onStartup) {
122
+ await newModule.onStartup();
57
123
  }
58
124
  } catch (error) {
59
- logger.error(`Error running startup script: ${error}`);
125
+ logger.error(`Error during boot HMR: ${error}`);
126
+ }
127
+ };
128
+ const shouldIgnore = (filePath) => {
129
+ const path2 = filePath.toLowerCase();
130
+ return ignoredSuffixes.some((suffix) => path2.endsWith(suffix));
131
+ };
132
+ server.watcher.on("change", async (changedPath) => {
133
+ if (shouldIgnore(changedPath)) return;
134
+ const bootDeps = getBootDependencies();
135
+ if (bootDeps.has(changedPath)) {
136
+ await rerunBoot(changedPath);
60
137
  }
61
138
  });
62
139
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astroscope/boot",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Startup and graceful shutdown hooks for Astro SSR",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -43,7 +43,7 @@
43
43
  "lint:fix": "eslint 'src/**/*.{ts,tsx}' --fix"
44
44
  },
45
45
  "devDependencies": {
46
- "astro": "^5.1.0",
46
+ "astro": "^5.16.9",
47
47
  "tsup": "^8.5.1",
48
48
  "typescript": "^5.9.3"
49
49
  },