@stati/core 1.3.1 → 1.4.0
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/dist/config/loader.d.ts +7 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +17 -12
- package/dist/constants.d.ts +71 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +78 -0
- package/dist/core/build.d.ts +1 -1
- package/dist/core/build.d.ts.map +1 -1
- package/dist/core/build.js +94 -69
- package/dist/core/content.d.ts +1 -1
- package/dist/core/content.d.ts.map +1 -1
- package/dist/core/content.js +10 -5
- package/dist/core/dev.d.ts +1 -7
- package/dist/core/dev.d.ts.map +1 -1
- package/dist/core/dev.js +202 -141
- package/dist/core/invalidate.d.ts +1 -1
- package/dist/core/invalidate.d.ts.map +1 -1
- package/dist/core/invalidate.js +3 -3
- package/dist/core/isg/build-lock.d.ts.map +1 -1
- package/dist/core/isg/build-lock.js +4 -2
- package/dist/core/isg/builder.d.ts +1 -1
- package/dist/core/isg/builder.d.ts.map +1 -1
- package/dist/core/isg/deps.d.ts +1 -1
- package/dist/core/isg/deps.d.ts.map +1 -1
- package/dist/core/isg/deps.js +59 -78
- package/dist/core/isg/hash.d.ts.map +1 -1
- package/dist/core/isg/hash.js +26 -17
- package/dist/core/isg/manifest.d.ts +1 -1
- package/dist/core/isg/manifest.d.ts.map +1 -1
- package/dist/core/isg/manifest.js +21 -8
- package/dist/core/isg/ttl.d.ts +1 -1
- package/dist/core/isg/ttl.d.ts.map +1 -1
- package/dist/core/isg/ttl.js +6 -9
- package/dist/core/isg/validation.d.ts +1 -1
- package/dist/core/isg/validation.d.ts.map +1 -1
- package/dist/core/markdown.d.ts +1 -1
- package/dist/core/markdown.d.ts.map +1 -1
- package/dist/core/navigation.d.ts +1 -1
- package/dist/core/navigation.d.ts.map +1 -1
- package/dist/core/preview.d.ts +19 -0
- package/dist/core/preview.d.ts.map +1 -0
- package/dist/core/preview.js +163 -0
- package/dist/core/templates.d.ts +1 -1
- package/dist/core/templates.d.ts.map +1 -1
- package/dist/core/templates.js +28 -105
- package/dist/core/utils/fs.d.ts +37 -0
- package/dist/core/utils/fs.d.ts.map +1 -0
- package/dist/core/utils/fs.js +86 -0
- package/dist/core/utils/partials.d.ts +24 -0
- package/dist/core/utils/partials.d.ts.map +1 -0
- package/dist/core/utils/partials.js +85 -0
- package/dist/core/utils/paths.d.ts +67 -0
- package/dist/core/utils/paths.d.ts.map +1 -0
- package/dist/core/utils/paths.js +86 -0
- package/dist/core/utils/template-discovery.d.ts +34 -0
- package/dist/core/utils/template-discovery.d.ts.map +1 -0
- package/dist/core/utils/template-discovery.js +111 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/tests/utils/test-mocks.d.ts +69 -0
- package/dist/tests/utils/test-mocks.d.ts.map +1 -0
- package/dist/tests/utils/test-mocks.js +125 -0
- package/dist/types/config.d.ts +178 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +1 -0
- package/dist/types/content.d.ts +124 -0
- package/dist/types/content.d.ts.map +1 -0
- package/dist/types/content.js +4 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/isg.d.ts +103 -0
- package/dist/types/isg.d.ts.map +1 -0
- package/dist/types/isg.js +4 -0
- package/dist/types/logging.d.ts +113 -0
- package/dist/types/logging.d.ts.map +1 -0
- package/dist/types/logging.js +4 -0
- package/dist/types/navigation.d.ts +43 -0
- package/dist/types/navigation.d.ts.map +1 -0
- package/dist/types/navigation.js +4 -0
- package/dist/types.d.ts +10 -10
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/core/dev.js
CHANGED
|
@@ -5,30 +5,15 @@ import { readFile, stat } from 'fs/promises';
|
|
|
5
5
|
import { WebSocketServer } from 'ws';
|
|
6
6
|
import chokidar from 'chokidar';
|
|
7
7
|
import { build } from './build.js';
|
|
8
|
+
import { invalidate } from './invalidate.js';
|
|
8
9
|
import { loadConfig } from '../config/loader.js';
|
|
9
10
|
import { loadCacheManifest, saveCacheManifest } from './isg/manifest.js';
|
|
11
|
+
import { resolveDevPaths, resolveCacheDir } from './utils/paths.js';
|
|
12
|
+
import { DEFAULT_DEV_PORT, DEFAULT_DEV_HOST, TEMPLATE_EXTENSION } from '../constants.js';
|
|
10
13
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* @param options - Development server configuration options
|
|
14
|
-
* @returns Promise resolving to a DevServer instance
|
|
14
|
+
* Loads and validates configuration for the dev server.
|
|
15
15
|
*/
|
|
16
|
-
|
|
17
|
-
const { port = 3000, host = 'localhost', open = false, configPath, logger = {
|
|
18
|
-
info: (msg) => console.log(msg),
|
|
19
|
-
success: (msg) => console.log(msg),
|
|
20
|
-
error: (msg) => console.error(msg),
|
|
21
|
-
warning: (msg) => console.warn(msg),
|
|
22
|
-
building: (msg) => console.log(msg),
|
|
23
|
-
processing: (msg) => console.log(msg),
|
|
24
|
-
stats: (msg) => console.log(msg),
|
|
25
|
-
}, } = options;
|
|
26
|
-
const url = `http://${host}:${port}`;
|
|
27
|
-
let httpServer = null;
|
|
28
|
-
let wsServer = null;
|
|
29
|
-
let watcher = null;
|
|
30
|
-
let config;
|
|
31
|
-
let isBuilding = false;
|
|
16
|
+
async function loadDevConfig(configPath, logger) {
|
|
32
17
|
// Load configuration
|
|
33
18
|
try {
|
|
34
19
|
if (configPath) {
|
|
@@ -36,141 +21,177 @@ export async function createDevServer(options = {}) {
|
|
|
36
21
|
// This is a limitation of the current loadConfig implementation
|
|
37
22
|
logger.info?.(`Loading config from: ${configPath}`);
|
|
38
23
|
}
|
|
39
|
-
config = await loadConfig(process.cwd());
|
|
24
|
+
const config = await loadConfig(process.cwd());
|
|
25
|
+
const { outDir, srcDir, staticDir } = resolveDevPaths(config);
|
|
26
|
+
return { config, outDir, srcDir, staticDir };
|
|
40
27
|
}
|
|
41
28
|
catch (error) {
|
|
42
29
|
logger.error?.(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
30
|
throw error;
|
|
44
31
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Performs an initial build to ensure dist/ exists
|
|
35
|
+
*/
|
|
36
|
+
async function performInitialBuild(configPath, logger) {
|
|
37
|
+
try {
|
|
38
|
+
// Clear cache to ensure fresh build on dev server start
|
|
39
|
+
logger.info?.('Clearing cache for fresh development build...');
|
|
40
|
+
await invalidate();
|
|
41
|
+
await build({
|
|
42
|
+
logger,
|
|
43
|
+
force: false,
|
|
44
|
+
clean: false,
|
|
45
|
+
...(configPath && { configPath }),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
logger.error?.(`Initial build failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Performs incremental rebuild when files change, using ISG logic for smart rebuilds
|
|
55
|
+
*/
|
|
56
|
+
async function performIncrementalRebuild(changedPath, configPath, logger, wsServer, isBuildingRef) {
|
|
57
|
+
if (isBuildingRef.value) {
|
|
58
|
+
logger.info?.('Build in progress, skipping...');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
isBuildingRef.value = true;
|
|
62
|
+
const startTime = Date.now();
|
|
63
|
+
// Create a quiet logger for dev builds that suppresses verbose output
|
|
64
|
+
const devLogger = {
|
|
65
|
+
info: () => { }, // Suppress info messages
|
|
66
|
+
success: () => { }, // Suppress success messages
|
|
67
|
+
error: logger.error || (() => { }),
|
|
68
|
+
warning: logger.warning || (() => { }),
|
|
69
|
+
building: () => { }, // Suppress building messages
|
|
70
|
+
processing: () => { }, // Suppress processing messages
|
|
71
|
+
stats: () => { }, // Suppress stats messages
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
const relativePath = changedPath
|
|
75
|
+
.replace(process.cwd(), '')
|
|
76
|
+
.replace(/\\/g, '/')
|
|
77
|
+
.replace(/^\//, '');
|
|
78
|
+
// Check if the changed file is a template/partial
|
|
79
|
+
if (changedPath.endsWith(TEMPLATE_EXTENSION) || changedPath.includes('_partials')) {
|
|
80
|
+
await handleTemplateChange(changedPath, configPath, devLogger);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
// Content or static file changed - use normal rebuild
|
|
53
84
|
await build({
|
|
54
|
-
logger,
|
|
85
|
+
logger: devLogger,
|
|
55
86
|
force: false,
|
|
56
87
|
clean: false,
|
|
57
88
|
...(configPath && { configPath }),
|
|
58
89
|
});
|
|
59
90
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
91
|
+
// Notify all connected clients to reload
|
|
92
|
+
if (wsServer) {
|
|
93
|
+
wsServer.clients.forEach((client) => {
|
|
94
|
+
const ws = client;
|
|
95
|
+
if (ws.readyState === 1) {
|
|
96
|
+
// WebSocket.OPEN
|
|
97
|
+
ws.send(JSON.stringify({ type: 'reload' }));
|
|
98
|
+
}
|
|
99
|
+
});
|
|
63
100
|
}
|
|
101
|
+
const duration = Date.now() - startTime;
|
|
102
|
+
logger.info?.(`⚡ ${relativePath} rebuilt in ${duration}ms`);
|
|
64
103
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
104
|
+
catch (error) {
|
|
105
|
+
const duration = Date.now() - startTime;
|
|
106
|
+
logger.error?.(`❌ Rebuild failed after ${duration}ms: ${error instanceof Error ? error.message : String(error)}`);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
isBuildingRef.value = false;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Handles template/partial file changes by invalidating affected pages
|
|
114
|
+
*/
|
|
115
|
+
async function handleTemplateChange(templatePath, configPath, logger) {
|
|
116
|
+
const cacheDir = resolveCacheDir();
|
|
117
|
+
try {
|
|
118
|
+
// Load existing cache manifest
|
|
119
|
+
const cacheManifest = await loadCacheManifest(cacheDir);
|
|
120
|
+
if (!cacheManifest) {
|
|
121
|
+
// No cache exists, perform full rebuild
|
|
122
|
+
await build({
|
|
123
|
+
logger,
|
|
124
|
+
force: false,
|
|
125
|
+
clean: false,
|
|
126
|
+
...(configPath && { configPath }),
|
|
127
|
+
});
|
|
71
128
|
return;
|
|
72
129
|
}
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const relativePath = changedPath
|
|
87
|
-
.replace(process.cwd(), '')
|
|
88
|
-
.replace(/\\/g, '/')
|
|
89
|
-
.replace(/^\//, '');
|
|
90
|
-
// Check if the changed file is a template/partial
|
|
91
|
-
if (changedPath.endsWith('.eta') || changedPath.includes('_partials')) {
|
|
92
|
-
await handleTemplateChange(changedPath, devLogger);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
// Content or static file changed - use normal rebuild
|
|
96
|
-
await build({
|
|
97
|
-
logger: devLogger,
|
|
98
|
-
force: false,
|
|
99
|
-
clean: false,
|
|
100
|
-
...(configPath && { configPath }),
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
// Notify all connected clients to reload
|
|
104
|
-
if (wsServer) {
|
|
105
|
-
wsServer.clients.forEach((client) => {
|
|
106
|
-
const ws = client;
|
|
107
|
-
if (ws.readyState === 1) {
|
|
108
|
-
// WebSocket.OPEN
|
|
109
|
-
ws.send(JSON.stringify({ type: 'reload' }));
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
const duration = Date.now() - startTime;
|
|
114
|
-
logger.info?.(`⚡ ${relativePath} rebuilt in ${duration}ms`);
|
|
115
|
-
}
|
|
116
|
-
catch (error) {
|
|
117
|
-
const duration = Date.now() - startTime;
|
|
118
|
-
logger.error?.(`❌ Rebuild failed after ${duration}ms: ${error instanceof Error ? error.message : String(error)}`);
|
|
119
|
-
}
|
|
120
|
-
finally {
|
|
121
|
-
isBuilding = false;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Handles template/partial file changes by invalidating affected pages
|
|
126
|
-
*/
|
|
127
|
-
async function handleTemplateChange(templatePath, buildLogger) {
|
|
128
|
-
const cacheDir = join(process.cwd(), '.stati');
|
|
129
|
-
const effectiveLogger = buildLogger || logger;
|
|
130
|
-
try {
|
|
131
|
-
// Load existing cache manifest
|
|
132
|
-
let cacheManifest = await loadCacheManifest(cacheDir);
|
|
133
|
-
if (!cacheManifest) {
|
|
134
|
-
// No cache exists, perform full rebuild
|
|
135
|
-
await build({
|
|
136
|
-
logger: effectiveLogger,
|
|
137
|
-
force: false,
|
|
138
|
-
clean: false,
|
|
139
|
-
...(configPath && { configPath }),
|
|
140
|
-
});
|
|
141
|
-
return;
|
|
142
|
-
}
|
|
143
|
-
// Find pages that depend on this template
|
|
144
|
-
const affectedPages = [];
|
|
145
|
-
for (const [pagePath, entry] of Object.entries(cacheManifest.entries)) {
|
|
146
|
-
if (entry.deps.some((dep) => dep.includes(posix.normalize(templatePath.replace(/\\/g, '/'))))) {
|
|
147
|
-
affectedPages.push(pagePath);
|
|
148
|
-
// Remove from cache to force rebuild
|
|
149
|
-
delete cacheManifest.entries[pagePath];
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
if (affectedPages.length > 0) {
|
|
153
|
-
// Save updated cache manifest
|
|
154
|
-
await saveCacheManifest(cacheDir, cacheManifest);
|
|
155
|
-
// Perform incremental rebuild (only affected pages will be rebuilt)
|
|
156
|
-
await build({
|
|
157
|
-
logger: effectiveLogger,
|
|
158
|
-
force: false,
|
|
159
|
-
clean: false,
|
|
160
|
-
...(configPath && { configPath }),
|
|
161
|
-
});
|
|
130
|
+
// Find pages that depend on this template
|
|
131
|
+
const affectedPages = [];
|
|
132
|
+
const normalizedTemplatePath = posix.normalize(templatePath.replace(/\\/g, '/'));
|
|
133
|
+
for (const [pagePath, entry] of Object.entries(cacheManifest.entries)) {
|
|
134
|
+
if (entry.deps.some((dep) => {
|
|
135
|
+
const normalizedDep = posix.normalize(dep.replace(/\\/g, '/'));
|
|
136
|
+
// Use endsWith for more precise matching to avoid false positives
|
|
137
|
+
return (normalizedDep === normalizedTemplatePath ||
|
|
138
|
+
normalizedDep.endsWith('/' + normalizedTemplatePath));
|
|
139
|
+
})) {
|
|
140
|
+
affectedPages.push(pagePath);
|
|
141
|
+
// Remove from cache to force rebuild
|
|
142
|
+
delete cacheManifest.entries[pagePath];
|
|
162
143
|
}
|
|
163
144
|
}
|
|
164
|
-
|
|
165
|
-
//
|
|
145
|
+
if (affectedPages.length > 0) {
|
|
146
|
+
// Save updated cache manifest
|
|
147
|
+
await saveCacheManifest(cacheDir, cacheManifest);
|
|
148
|
+
// Perform incremental rebuild (only affected pages will be rebuilt)
|
|
166
149
|
await build({
|
|
167
|
-
logger
|
|
150
|
+
logger,
|
|
168
151
|
force: false,
|
|
169
152
|
clean: false,
|
|
170
153
|
...(configPath && { configPath }),
|
|
171
154
|
});
|
|
172
155
|
}
|
|
156
|
+
else {
|
|
157
|
+
// If no affected pages were found but a template changed,
|
|
158
|
+
// force a full rebuild to ensure changes are reflected
|
|
159
|
+
// This can happen if dependency tracking missed something
|
|
160
|
+
await build({
|
|
161
|
+
logger,
|
|
162
|
+
force: true,
|
|
163
|
+
clean: false,
|
|
164
|
+
...(configPath && { configPath }),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
173
167
|
}
|
|
168
|
+
catch {
|
|
169
|
+
// Fallback to full rebuild
|
|
170
|
+
await build({
|
|
171
|
+
logger,
|
|
172
|
+
force: false,
|
|
173
|
+
clean: false,
|
|
174
|
+
...(configPath && { configPath }),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
export async function createDevServer(options = {}) {
|
|
179
|
+
const { port = DEFAULT_DEV_PORT, host = DEFAULT_DEV_HOST, open = false, configPath, logger = {
|
|
180
|
+
info: (msg) => console.log(msg),
|
|
181
|
+
success: (msg) => console.log(msg),
|
|
182
|
+
error: (msg) => console.error(msg),
|
|
183
|
+
warning: (msg) => console.warn(msg),
|
|
184
|
+
building: (msg) => console.log(msg),
|
|
185
|
+
processing: (msg) => console.log(msg),
|
|
186
|
+
stats: (msg) => console.log(msg),
|
|
187
|
+
}, } = options;
|
|
188
|
+
const url = `http://${host}:${port}`;
|
|
189
|
+
let httpServer = null;
|
|
190
|
+
let wsServer = null;
|
|
191
|
+
let watcher = null;
|
|
192
|
+
const isBuildingRef = { value: false };
|
|
193
|
+
// Load configuration
|
|
194
|
+
const { config: _config, outDir, srcDir, staticDir } = await loadDevConfig(configPath, logger);
|
|
174
195
|
/**
|
|
175
196
|
* Gets MIME type for a file based on its extension
|
|
176
197
|
*/
|
|
@@ -243,11 +264,21 @@ export async function createDevServer(options = {}) {
|
|
|
243
264
|
filePath = indexPath;
|
|
244
265
|
}
|
|
245
266
|
catch {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
267
|
+
// If no index.html in directory, try to serve corresponding .html file
|
|
268
|
+
// For example: /examples/ -> examples.html
|
|
269
|
+
const directoryName = requestPath.replace(/\/$/, ''); // Remove trailing slash
|
|
270
|
+
const fallbackPath = join(outDir, `${directoryName}.html`);
|
|
271
|
+
try {
|
|
272
|
+
await stat(fallbackPath);
|
|
273
|
+
filePath = fallbackPath;
|
|
274
|
+
}
|
|
275
|
+
catch {
|
|
276
|
+
return {
|
|
277
|
+
content: '404 - Directory listing not available',
|
|
278
|
+
mimeType: 'text/plain',
|
|
279
|
+
statusCode: 404,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
251
282
|
}
|
|
252
283
|
}
|
|
253
284
|
const mimeType = getMimeType(filePath);
|
|
@@ -269,6 +300,36 @@ export async function createDevServer(options = {}) {
|
|
|
269
300
|
};
|
|
270
301
|
}
|
|
271
302
|
catch {
|
|
303
|
+
// File not found, try some fallback strategies for pretty URLs
|
|
304
|
+
if (requestPath.endsWith('/')) {
|
|
305
|
+
// For requests ending with /, try the corresponding .html file
|
|
306
|
+
const pathWithoutSlash = requestPath.slice(0, -1);
|
|
307
|
+
const htmlPath = join(outDir, `${pathWithoutSlash}.html`);
|
|
308
|
+
try {
|
|
309
|
+
const stats = await stat(htmlPath);
|
|
310
|
+
if (stats.isFile()) {
|
|
311
|
+
const mimeType = getMimeType(htmlPath);
|
|
312
|
+
const content = await readFile(htmlPath);
|
|
313
|
+
if (mimeType === 'text/html') {
|
|
314
|
+
const html = content.toString('utf-8');
|
|
315
|
+
const injectedHtml = injectLiveReloadScript(html);
|
|
316
|
+
return {
|
|
317
|
+
content: injectedHtml,
|
|
318
|
+
mimeType,
|
|
319
|
+
statusCode: 200,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
return {
|
|
323
|
+
content,
|
|
324
|
+
mimeType,
|
|
325
|
+
statusCode: 200,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
// Continue to 404
|
|
331
|
+
}
|
|
332
|
+
}
|
|
272
333
|
// File not found
|
|
273
334
|
return {
|
|
274
335
|
content: '404 - File not found',
|
|
@@ -281,7 +342,7 @@ export async function createDevServer(options = {}) {
|
|
|
281
342
|
url,
|
|
282
343
|
async start() {
|
|
283
344
|
// Perform initial build
|
|
284
|
-
await
|
|
345
|
+
await performInitialBuild(configPath, logger);
|
|
285
346
|
// Create HTTP server
|
|
286
347
|
httpServer = createServer(async (req, res) => {
|
|
287
348
|
const requestPath = req.url || '/';
|
|
@@ -311,7 +372,7 @@ export async function createDevServer(options = {}) {
|
|
|
311
372
|
path: '/__ws',
|
|
312
373
|
});
|
|
313
374
|
wsServer.on('connection', (ws) => {
|
|
314
|
-
logger.info?.('
|
|
375
|
+
logger.info?.('Browser connected for live reload');
|
|
315
376
|
const websocket = ws;
|
|
316
377
|
websocket.on('close', () => {
|
|
317
378
|
logger.info?.('Browser disconnected from live reload');
|
|
@@ -334,13 +395,13 @@ export async function createDevServer(options = {}) {
|
|
|
334
395
|
ignoreInitial: true,
|
|
335
396
|
});
|
|
336
397
|
watcher.on('change', (path) => {
|
|
337
|
-
void
|
|
398
|
+
void performIncrementalRebuild(path, configPath, logger, wsServer, isBuildingRef);
|
|
338
399
|
});
|
|
339
400
|
watcher.on('add', (path) => {
|
|
340
|
-
void
|
|
401
|
+
void performIncrementalRebuild(path, configPath, logger, wsServer, isBuildingRef);
|
|
341
402
|
});
|
|
342
403
|
watcher.on('unlink', (path) => {
|
|
343
|
-
void
|
|
404
|
+
void performIncrementalRebuild(path, configPath, logger, wsServer, isBuildingRef);
|
|
344
405
|
});
|
|
345
406
|
logger.success?.(`Dev server running at ${url}`);
|
|
346
407
|
logger.info?.(`\nServing from:`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invalidate.d.ts","sourceRoot":"","sources":["../../src/core/invalidate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"invalidate.d.ts","sourceRoot":"","sources":["../../src/core/invalidate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGpD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,0CAA0C;IAC1C,gBAAgB,EAAE,MAAM,CAAC;IACzB,iCAAiC;IACjC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,2CAA2C;IAC3C,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAkC9D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAkC9F;AAiLD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAoD5E"}
|
package/dist/core/invalidate.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { join } from 'path';
|
|
2
1
|
import { loadCacheManifest, saveCacheManifest } from './isg/manifest.js';
|
|
2
|
+
import { resolveCacheDir } from './utils/paths.js';
|
|
3
3
|
/**
|
|
4
4
|
* Parses an invalidation query string into individual query terms.
|
|
5
5
|
* Supports space-separated values and quoted strings.
|
|
@@ -281,9 +281,9 @@ function matchesAge(entry, ageValue) {
|
|
|
281
281
|
* ```
|
|
282
282
|
*/
|
|
283
283
|
export async function invalidate(query) {
|
|
284
|
-
const cacheDir =
|
|
284
|
+
const cacheDir = resolveCacheDir();
|
|
285
285
|
// Load existing cache manifest
|
|
286
|
-
|
|
286
|
+
const cacheManifest = await loadCacheManifest(cacheDir);
|
|
287
287
|
if (!cacheManifest) {
|
|
288
288
|
// No cache to invalidate
|
|
289
289
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-lock.d.ts","sourceRoot":"","sources":["../../../src/core/isg/build-lock.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"build-lock.d.ts","sourceRoot":"","sources":["../../../src/core/isg/build-lock.ts"],"names":[],"mappings":"AAWA;;GAEG;AACH,UAAU,SAAS;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAS;gBAEb,QAAQ,EAAE,MAAM;IAI5B;;;;;;;;;;;;;;;;;;;OAmBG;IACG,WAAW,CAAC,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAoDrF;;;;;;;OAOG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBlC;;;;;;;;;;;OAWG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAiBpC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAY9C;;;OAGG;YACW,eAAe;IAQ7B;;OAEG;YACW,cAAc;IAc5B;;OAEG;YACW,YAAY;IAY1B;;OAEG;YACW,gBAAgB;IAY9B;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,aAAa,CAAC,CAAC,EACnC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACzB,OAAO,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,OAAO,CAAC,CAAC,CAAC,CASZ"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import
|
|
2
|
-
const { writeFile, readFile, pathExists, remove, ensureDir } = fse;
|
|
1
|
+
import { writeFile, readFile, pathExists, remove, ensureDir } from '../utils/fs.js';
|
|
3
2
|
import { join, dirname } from 'path';
|
|
4
3
|
import { hostname } from 'os';
|
|
5
4
|
/**
|
|
@@ -178,6 +177,9 @@ export class BuildLockManager {
|
|
|
178
177
|
async readLockFile() {
|
|
179
178
|
try {
|
|
180
179
|
const content = await readFile(this.lockPath, 'utf-8');
|
|
180
|
+
if (!content) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
181
183
|
return JSON.parse(content);
|
|
182
184
|
}
|
|
183
185
|
catch {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PageModel, CacheEntry, StatiConfig } from '../../types.js';
|
|
1
|
+
import type { PageModel, CacheEntry, StatiConfig } from '../../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Determines if a page should be rebuilt based on ISG logic.
|
|
4
4
|
* Checks content changes, dependency changes, TTL expiration, and freeze status.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/core/isg/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"builder.d.ts","sourceRoot":"","sources":["../../../src/core/isg/builder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAmE/E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,UAAU,GAAG,SAAS,EAC7B,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,IAAI,GACR,OAAO,CAAC,OAAO,CAAC,CAgKlB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,IAAI,GACf,OAAO,CAAC,UAAU,CAAC,CA2ErB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,UAAU,EACjB,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,EACnB,UAAU,EAAE,IAAI,GACf,OAAO,CAAC,UAAU,CAAC,CAUrB"}
|
package/dist/core/isg/deps.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/core/isg/deps.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deps.d.ts","sourceRoot":"","sources":["../../../src/core/isg/deps.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKnE;;GAEG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;aAE9B,eAAe,EAAE,MAAM,EAAE;gBAAzB,eAAe,EAAE,MAAM,EAAE,EACzC,OAAO,EAAE,MAAM;CAKlB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,yBAAyB,CAC7C,IAAI,EAAE,SAAS,EACf,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAoCnB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAiDnB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASxB"}
|