@abreen/tada 1.11.3 → 1.13.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 +65 -64
- package/bin/tada.ts +61 -66
- package/build/build-manifest.ts +14 -3
- package/build/bundle.ts +0 -1
- package/build/config-files.ts +183 -0
- package/build/config-loader.ts +159 -0
- package/build/copy.ts +0 -83
- package/build/generate-content-assets.ts +75 -160
- package/build/globals.ts +48 -89
- package/build/log.ts +27 -18
- package/build/pagefind.ts +33 -26
- package/build/pipeline.ts +98 -79
- package/build/reachability.ts +51 -248
- package/build/serve.ts +35 -6
- package/build/site-variables.ts +20 -11
- package/build/source-model.ts +400 -0
- package/build/{watch/records.ts → source-records.ts} +111 -49
- package/build/template-globals.ts +91 -0
- package/build/templates.ts +50 -40
- package/build/test-helpers.ts +15 -0
- package/build/toc-plugin.ts +5 -1
- package/build/types.d.ts +9 -1
- package/build/util.ts +8 -0
- package/build/utils/code.ts +6 -16
- package/build/utils/content-files.ts +57 -126
- package/build/utils/final-html.ts +239 -0
- package/build/utils/markdown.ts +237 -17
- package/build/utils/paths.ts +2 -1
- package/build/utils/render.ts +108 -99
- package/build/validate-config-links.ts +91 -14
- package/build/watch/assets.ts +0 -2
- package/build/watch/build-full.ts +14 -15
- package/build/watch/build-incremental.ts +15 -8
- package/build/watch/compiler-types.d.ts +6 -1
- package/build/watch/compiler.ts +27 -15
- package/build/watch/index.ts +2 -7
- package/build/watch/planner.ts +32 -16
- package/build/watch/reload.ts +4 -0
- package/build/watch/runtime.ts +29 -45
- package/build/watch/snapshot.ts +50 -402
- package/build/watch/validation.ts +6 -3
- package/build/watch-reachability-state.ts +16 -23
- package/build/watch-reload-client.ts +11 -4
- package/init/content/index.md +1 -1
- package/init/content/labs/02/index.md +61 -0
- package/init/content/labs/02/selection_sort.py +23 -0
- package/init/content/labs/index.md +4 -2
- package/init/content/lectures/01/index.md +1 -1
- package/init/content/markdown.md +1 -1
- package/package.json +3 -4
- package/src/code/index.ts +46 -18
- package/src/code.scss +2 -1
- package/src/globals.ts +47 -0
- package/src/index.ts +1 -0
- package/src/navigate/index.ts +2 -5
- package/src/navigate/lifecycle.ts +3 -1
- package/src/navigate/runtime.ts +6 -5
- package/src/page-update/index.ts +20 -16
- package/src/search/index.ts +53 -25
- package/src/slides/index.ts +467 -0
- package/src/slides/style.scss +104 -0
- package/src/style.scss +8 -3
- package/src/timezone/index.ts +16 -20
- package/src/top/index.ts +2 -4
- package/src/trace/index.ts +91 -7
- package/src/trace/style.scss +1 -1
- package/src/util.ts +6 -2
- package/templates/_author.html +2 -2
- package/templates/_heading.html +1 -1
- package/templates/_nav.html +2 -2
- package/templates/_theme.scss +3 -3
- package/templates/_top.html +14 -14
- package/templates/default.html +8 -0
- package/types/dev.d.ts +1 -1
- package/types/site-variables.d.ts +4 -5
- package/watch/fs-commit.ts +63 -10
- package/build/apply-base-path-plugin.ts +0 -186
- package/build/content-watch.ts +0 -104
- package/build/validate-internal-links-plugin.ts +0 -207
|
@@ -1,14 +1,16 @@
|
|
|
1
|
-
import { compileTemplates,
|
|
1
|
+
import { compileTemplates, config } from '../templates';
|
|
2
2
|
import { getDevSiteVariables } from '../site-variables';
|
|
3
|
+
import { createContentRecord, createPublicRecord } from '../source-records';
|
|
3
4
|
import { getDistDir } from '../util';
|
|
4
5
|
import type { CompilerBuildResult } from '../../watch/types';
|
|
5
6
|
import {
|
|
7
|
+
collectHtmlAnalysisByPath,
|
|
6
8
|
collectHtmlAssetsByPath,
|
|
7
9
|
createSnapshot,
|
|
8
|
-
scanProject,
|
|
9
10
|
type TadaSourceRecord,
|
|
10
11
|
type TadaSnapshot,
|
|
11
12
|
} from './snapshot';
|
|
13
|
+
import { scanProject } from '../source-model';
|
|
12
14
|
import type {
|
|
13
15
|
TadaBuildMeta,
|
|
14
16
|
TraceCache,
|
|
@@ -22,19 +24,16 @@ import {
|
|
|
22
24
|
removeDirIfExists,
|
|
23
25
|
writeAssets,
|
|
24
26
|
} from './assets';
|
|
25
|
-
import { createPublicRecord, renderContentRecord } from './records';
|
|
26
27
|
import {
|
|
27
28
|
diagnosticsFromMessages,
|
|
28
29
|
validateConfig,
|
|
29
|
-
|
|
30
|
+
validateProjectConfigLinks,
|
|
30
31
|
} from './validation';
|
|
31
32
|
|
|
32
33
|
export async function buildFull({
|
|
33
|
-
wsPort,
|
|
34
34
|
traceCache,
|
|
35
35
|
traceOptions,
|
|
36
36
|
}: {
|
|
37
|
-
wsPort: number;
|
|
38
37
|
traceCache: TraceCache;
|
|
39
38
|
traceOptions: WatchTraceOptions;
|
|
40
39
|
}): Promise<CompilerBuildResult<TadaSnapshot, TadaBuildMeta>> {
|
|
@@ -52,16 +51,12 @@ export async function buildFull({
|
|
|
52
51
|
compileTemplates(siteVariables);
|
|
53
52
|
await ensureHighlighter(siteVariables);
|
|
54
53
|
|
|
55
|
-
const assetFiles = await bundleWatchAssets(
|
|
56
|
-
outputDir,
|
|
57
|
-
siteVariables,
|
|
58
|
-
wsPort,
|
|
59
|
-
);
|
|
54
|
+
const assetFiles = await bundleWatchAssets(outputDir, siteVariables);
|
|
60
55
|
await populateStaticAssets(outputDir, siteVariables);
|
|
61
56
|
|
|
62
57
|
const contentRecords = new Map<string, TadaSourceRecord>();
|
|
63
58
|
for (const filePath of scan.contentFiles) {
|
|
64
|
-
const record =
|
|
59
|
+
const record = createContentRecord({
|
|
65
60
|
filePath,
|
|
66
61
|
siteVariables,
|
|
67
62
|
scan,
|
|
@@ -72,6 +67,7 @@ export async function buildFull({
|
|
|
72
67
|
cachedTraceSourceDir: distDir,
|
|
73
68
|
});
|
|
74
69
|
if (record.outputs.size > 0) {
|
|
70
|
+
writeAssets(outputDir, record.outputs);
|
|
75
71
|
contentRecords.set(filePath, record);
|
|
76
72
|
}
|
|
77
73
|
}
|
|
@@ -83,7 +79,7 @@ export async function buildFull({
|
|
|
83
79
|
publicRecords.set(filePath, record);
|
|
84
80
|
}
|
|
85
81
|
|
|
86
|
-
const linkDiagnostics =
|
|
82
|
+
const linkDiagnostics = validateProjectConfigLinks(scan.validTargets);
|
|
87
83
|
if (linkDiagnostics.length > 0) {
|
|
88
84
|
removeDirIfExists(outputDir);
|
|
89
85
|
return { ok: false, diagnostics: linkDiagnostics };
|
|
@@ -92,8 +88,8 @@ export async function buildFull({
|
|
|
92
88
|
const nextSnapshot = createSnapshot({
|
|
93
89
|
siteVariables,
|
|
94
90
|
assetFiles,
|
|
95
|
-
navData:
|
|
96
|
-
authorsData:
|
|
91
|
+
navData: config('nav'),
|
|
92
|
+
authorsData: config('authors'),
|
|
97
93
|
scan,
|
|
98
94
|
contentRecords,
|
|
99
95
|
publicRecords,
|
|
@@ -109,6 +105,9 @@ export async function buildFull({
|
|
|
109
105
|
},
|
|
110
106
|
meta: {
|
|
111
107
|
htmlAssetsByPath: collectHtmlAssetsByPath(nextSnapshot.contentRecords),
|
|
108
|
+
htmlAnalysisByPath: collectHtmlAnalysisByPath(
|
|
109
|
+
nextSnapshot.contentRecords,
|
|
110
|
+
),
|
|
112
111
|
siteVariables,
|
|
113
112
|
},
|
|
114
113
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { compileTemplates,
|
|
1
|
+
import { compileTemplates, config } from '../templates';
|
|
2
2
|
import { getDistDir } from '../util';
|
|
3
|
+
import { createContentRecord, createPublicRecord } from '../source-records';
|
|
3
4
|
import type { CompilerBuildResult } from '../../watch/types';
|
|
4
5
|
import type {
|
|
5
6
|
TadaBuildMeta,
|
|
@@ -8,6 +9,7 @@ import type {
|
|
|
8
9
|
} from './compiler-types';
|
|
9
10
|
import type { TadaWatchPlan } from './planner';
|
|
10
11
|
import {
|
|
12
|
+
collectHtmlAnalysisByPath,
|
|
11
13
|
collectHtmlAssetsByPath,
|
|
12
14
|
createSnapshot,
|
|
13
15
|
type TadaSnapshot,
|
|
@@ -17,13 +19,13 @@ import {
|
|
|
17
19
|
ensureHighlighter,
|
|
18
20
|
makeTempBuildDir,
|
|
19
21
|
removeDirIfExists,
|
|
22
|
+
writeAssets,
|
|
20
23
|
} from './assets';
|
|
21
24
|
import { computeMutations } from './mutations';
|
|
22
|
-
import { createPublicRecord, renderContentRecord } from './records';
|
|
23
25
|
import {
|
|
24
26
|
diagnosticsFromMessages,
|
|
25
27
|
validateConfig,
|
|
26
|
-
|
|
28
|
+
validateProjectConfigLinks,
|
|
27
29
|
} from './validation';
|
|
28
30
|
|
|
29
31
|
export async function buildIncremental({
|
|
@@ -62,7 +64,7 @@ export async function buildIncremental({
|
|
|
62
64
|
|
|
63
65
|
for (const sourcePath of plan.contentToRender) {
|
|
64
66
|
nextContentRecords.delete(sourcePath);
|
|
65
|
-
const record =
|
|
67
|
+
const record = createContentRecord({
|
|
66
68
|
filePath: sourcePath,
|
|
67
69
|
siteVariables,
|
|
68
70
|
scan: plan.scan,
|
|
@@ -71,9 +73,9 @@ export async function buildIncremental({
|
|
|
71
73
|
traceCache,
|
|
72
74
|
traceToolAvailability: traceOptions.toolAvailability,
|
|
73
75
|
cachedTraceSourceDir: getDistDir(),
|
|
74
|
-
persistOutputs: false,
|
|
75
76
|
});
|
|
76
77
|
if (record.outputs.size > 0) {
|
|
78
|
+
writeAssets(outputDir, record.outputs);
|
|
77
79
|
nextContentRecords.set(sourcePath, record);
|
|
78
80
|
}
|
|
79
81
|
}
|
|
@@ -87,14 +89,16 @@ export async function buildIncremental({
|
|
|
87
89
|
const nextSnapshot = createSnapshot({
|
|
88
90
|
siteVariables,
|
|
89
91
|
assetFiles: snapshot.assetFiles,
|
|
90
|
-
navData:
|
|
91
|
-
authorsData:
|
|
92
|
+
navData: config('nav'),
|
|
93
|
+
authorsData: config('authors'),
|
|
92
94
|
scan: plan.scan,
|
|
93
95
|
contentRecords: nextContentRecords,
|
|
94
96
|
publicRecords: nextPublicRecords,
|
|
95
97
|
});
|
|
96
98
|
|
|
97
|
-
const linkDiagnostics =
|
|
99
|
+
const linkDiagnostics = validateProjectConfigLinks(
|
|
100
|
+
nextSnapshot.validTargets,
|
|
101
|
+
);
|
|
98
102
|
if (linkDiagnostics.length > 0) {
|
|
99
103
|
removeDirIfExists(outputDir);
|
|
100
104
|
return { ok: false, diagnostics: linkDiagnostics };
|
|
@@ -124,6 +128,9 @@ export async function buildIncremental({
|
|
|
124
128
|
commit: { kind: 'apply-mutations', rootDir: getDistDir(), mutations },
|
|
125
129
|
meta: {
|
|
126
130
|
htmlAssetsByPath: collectHtmlAssetsByPath(nextSnapshot.contentRecords),
|
|
131
|
+
htmlAnalysisByPath: collectHtmlAnalysisByPath(
|
|
132
|
+
nextSnapshot.contentRecords,
|
|
133
|
+
),
|
|
127
134
|
siteVariables,
|
|
128
135
|
},
|
|
129
136
|
};
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
HtmlOutputAnalysis,
|
|
3
|
+
SiteVariables,
|
|
4
|
+
TraceToolAvailability,
|
|
5
|
+
} from '../types';
|
|
2
6
|
|
|
3
7
|
export interface TraceCacheEntry {
|
|
4
8
|
manifestUrl: string;
|
|
@@ -11,6 +15,7 @@ export type TraceCache = Map<string, TraceCacheEntry>;
|
|
|
11
15
|
|
|
12
16
|
export interface TadaBuildMeta {
|
|
13
17
|
htmlAssetsByPath: Map<string, string>;
|
|
18
|
+
htmlAnalysisByPath: Map<string, HtmlOutputAnalysis>;
|
|
14
19
|
siteVariables: SiteVariables;
|
|
15
20
|
}
|
|
16
21
|
|
package/build/watch/compiler.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
+
import {
|
|
3
|
+
getProjectConfigBaseName,
|
|
4
|
+
getSiteConfigBaseName,
|
|
5
|
+
getSupportedConfigFilePaths,
|
|
6
|
+
} from '../config-files';
|
|
2
7
|
import { getDevSiteVariables } from '../site-variables';
|
|
3
|
-
import {
|
|
8
|
+
import { getProjectConfigDir } from '../templates';
|
|
4
9
|
import { getContentDir, getPublicDir } from '../util';
|
|
5
10
|
import type {
|
|
6
11
|
ChangeBatch,
|
|
@@ -18,7 +23,8 @@ import type {
|
|
|
18
23
|
} from './compiler-types';
|
|
19
24
|
import { checkTraceToolAvailability, isTraceSourceFile } from '../utils/trace';
|
|
20
25
|
import { createTadaWatchPlan, type TadaWatchPlan } from './planner';
|
|
21
|
-
import { scanProject,
|
|
26
|
+
import { scanProject, updateProjectScan } from '../source-model';
|
|
27
|
+
import type { TadaSnapshot } from './snapshot';
|
|
22
28
|
|
|
23
29
|
export function invalidateTraceCacheForBatch(
|
|
24
30
|
traceCache: TraceCache,
|
|
@@ -32,15 +38,15 @@ export function invalidateTraceCacheForBatch(
|
|
|
32
38
|
}
|
|
33
39
|
}
|
|
34
40
|
|
|
35
|
-
export class TadaWatchCompiler
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
export class TadaWatchCompiler implements WatchCompiler<
|
|
42
|
+
TadaSnapshot,
|
|
43
|
+
TadaWatchPlan,
|
|
44
|
+
TadaBuildMeta
|
|
45
|
+
> {
|
|
39
46
|
private traceCache: TraceCache;
|
|
40
47
|
private traceOptions: WatchTraceOptions;
|
|
41
48
|
|
|
42
|
-
constructor(
|
|
43
|
-
this.wsPort = wsPort;
|
|
49
|
+
constructor() {
|
|
44
50
|
this.traceCache = new Map();
|
|
45
51
|
this.traceOptions = { toolAvailability: checkTraceToolAvailability() };
|
|
46
52
|
}
|
|
@@ -48,18 +54,26 @@ export class TadaWatchCompiler
|
|
|
48
54
|
getWatchTargets(): WatchTarget[] {
|
|
49
55
|
const contentDir = getContentDir();
|
|
50
56
|
const publicDir = getPublicDir();
|
|
51
|
-
const
|
|
57
|
+
const projectConfigDir = path.resolve(getProjectConfigDir());
|
|
52
58
|
const configFilePaths = new Set([
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
59
|
+
...getSupportedConfigFilePaths('.', getSiteConfigBaseName('dev')).map(
|
|
60
|
+
filePath => path.resolve(filePath),
|
|
61
|
+
),
|
|
62
|
+
...getSupportedConfigFilePaths(
|
|
63
|
+
projectConfigDir,
|
|
64
|
+
getProjectConfigBaseName('nav'),
|
|
65
|
+
).map(filePath => path.resolve(filePath)),
|
|
66
|
+
...getSupportedConfigFilePaths(
|
|
67
|
+
projectConfigDir,
|
|
68
|
+
getProjectConfigBaseName('authors'),
|
|
69
|
+
).map(filePath => path.resolve(filePath)),
|
|
56
70
|
]);
|
|
57
71
|
|
|
58
72
|
return [
|
|
59
73
|
{ path: contentDir },
|
|
60
74
|
{ path: publicDir },
|
|
61
75
|
{
|
|
62
|
-
path:
|
|
76
|
+
path: projectConfigDir,
|
|
63
77
|
chokidar: { depth: 0 },
|
|
64
78
|
filter: filePath => configFilePaths.has(path.resolve(filePath)),
|
|
65
79
|
},
|
|
@@ -70,7 +84,6 @@ export class TadaWatchCompiler
|
|
|
70
84
|
CompilerBuildResult<TadaSnapshot, TadaBuildMeta>
|
|
71
85
|
> {
|
|
72
86
|
return buildFull({
|
|
73
|
-
wsPort: this.wsPort,
|
|
74
87
|
traceCache: this.traceCache,
|
|
75
88
|
traceOptions: this.traceOptions,
|
|
76
89
|
});
|
|
@@ -96,7 +109,6 @@ export class TadaWatchCompiler
|
|
|
96
109
|
): Promise<CompilerBuildResult<TadaSnapshot, TadaBuildMeta>> {
|
|
97
110
|
if (plan.kind === 'full' || !snapshot) {
|
|
98
111
|
return buildFull({
|
|
99
|
-
wsPort: this.wsPort,
|
|
100
112
|
traceCache: this.traceCache,
|
|
101
113
|
traceOptions: this.traceOptions,
|
|
102
114
|
});
|
package/build/watch/index.ts
CHANGED
|
@@ -3,19 +3,14 @@ import { runWatchEngine } from '../../watch/engine';
|
|
|
3
3
|
import { TadaWatchCompiler } from './compiler';
|
|
4
4
|
import { TadaWatchRuntime } from './runtime';
|
|
5
5
|
|
|
6
|
-
export async function runWatch(options: {
|
|
7
|
-
httpPort?: number;
|
|
8
|
-
wsPort?: number;
|
|
9
|
-
}): Promise<void> {
|
|
10
|
-
const wsPort = options.wsPort ?? 35729;
|
|
6
|
+
export async function runWatch(options: { httpPort?: number }): Promise<void> {
|
|
11
7
|
const runtime = new TadaWatchRuntime({
|
|
12
|
-
wsPort,
|
|
13
8
|
httpPort: options.httpPort,
|
|
14
9
|
distDir: getDistDir(),
|
|
15
10
|
});
|
|
16
11
|
|
|
17
12
|
await runWatchEngine({
|
|
18
|
-
compiler: new TadaWatchCompiler(
|
|
13
|
+
compiler: new TadaWatchCompiler(),
|
|
19
14
|
onEvent: event => runtime.onEvent(event),
|
|
20
15
|
debounceMs: 300,
|
|
21
16
|
});
|
package/build/watch/planner.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
1
|
import path from 'path';
|
|
3
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
getProjectConfigBaseName,
|
|
4
|
+
getSiteConfigBaseName,
|
|
5
|
+
getSupportedConfigFilePaths,
|
|
6
|
+
} from '../config-files';
|
|
7
|
+
import { loadProjectConfig } from '../config-loader';
|
|
8
|
+
import { getProjectConfigDir } from '../templates';
|
|
4
9
|
import type { ChangeBatch } from '../../watch/types';
|
|
5
10
|
import type { TadaProjectScan, TadaSnapshot } from './snapshot';
|
|
6
11
|
|
|
@@ -13,13 +18,6 @@ export interface TadaWatchPlan {
|
|
|
13
18
|
publicToRemove: Set<string>;
|
|
14
19
|
}
|
|
15
20
|
|
|
16
|
-
function readJsonFile(filePath: string): unknown {
|
|
17
|
-
if (!fs.existsSync(filePath)) {
|
|
18
|
-
return undefined;
|
|
19
|
-
}
|
|
20
|
-
return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
21
|
-
}
|
|
22
|
-
|
|
23
21
|
export function diffAuthorKeys(previous: unknown, next: unknown): Set<string> {
|
|
24
22
|
const previousMap =
|
|
25
23
|
previous && typeof previous === 'object'
|
|
@@ -70,10 +68,24 @@ export function createTadaWatchPlan({
|
|
|
70
68
|
const publicToRender = new Set<string>();
|
|
71
69
|
const contentToRemove = new Set<string>();
|
|
72
70
|
const publicToRemove = new Set<string>();
|
|
73
|
-
const
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
71
|
+
const projectConfigDir = getProjectConfigDir();
|
|
72
|
+
const siteConfigPaths = new Set(
|
|
73
|
+
getSupportedConfigFilePaths('.', getSiteConfigBaseName('dev')).map(
|
|
74
|
+
filePath => path.resolve(filePath),
|
|
75
|
+
),
|
|
76
|
+
);
|
|
77
|
+
const navPaths = new Set(
|
|
78
|
+
getSupportedConfigFilePaths(
|
|
79
|
+
projectConfigDir,
|
|
80
|
+
getProjectConfigBaseName('nav'),
|
|
81
|
+
).map(filePath => path.resolve(filePath)),
|
|
82
|
+
);
|
|
83
|
+
const authorsPaths = new Set(
|
|
84
|
+
getSupportedConfigFilePaths(
|
|
85
|
+
projectConfigDir,
|
|
86
|
+
getProjectConfigBaseName('authors'),
|
|
87
|
+
).map(filePath => path.resolve(filePath)),
|
|
88
|
+
);
|
|
77
89
|
|
|
78
90
|
if (!snapshot) {
|
|
79
91
|
return {
|
|
@@ -88,7 +100,7 @@ export function createTadaWatchPlan({
|
|
|
88
100
|
|
|
89
101
|
for (const change of batch.changes) {
|
|
90
102
|
const resolvedPath = path.resolve(change.path);
|
|
91
|
-
if (resolvedPath
|
|
103
|
+
if (siteConfigPaths.has(resolvedPath) || navPaths.has(resolvedPath)) {
|
|
92
104
|
return {
|
|
93
105
|
kind: 'full',
|
|
94
106
|
scan,
|
|
@@ -102,8 +114,12 @@ export function createTadaWatchPlan({
|
|
|
102
114
|
|
|
103
115
|
for (const change of batch.changes) {
|
|
104
116
|
const resolvedPath = path.resolve(change.path);
|
|
105
|
-
if (resolvedPath
|
|
106
|
-
const nextAuthorsData =
|
|
117
|
+
if (authorsPaths.has(resolvedPath)) {
|
|
118
|
+
const nextAuthorsData = loadProjectConfig(
|
|
119
|
+
projectConfigDir,
|
|
120
|
+
'authors',
|
|
121
|
+
snapshot.siteVariables,
|
|
122
|
+
)?.value;
|
|
107
123
|
if (snapshot.authorsData === undefined || nextAuthorsData === undefined) {
|
|
108
124
|
return {
|
|
109
125
|
kind: 'full',
|
package/build/watch/runtime.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import WebSocket, { WebSocketServer } from 'ws';
|
|
3
2
|
import { B } from '../colors';
|
|
4
3
|
import { makeLogger, printFlair } from '../log';
|
|
5
4
|
import { startServer } from '../serve';
|
|
@@ -7,6 +6,12 @@ import { WatchPagefindRunner } from '../pagefind';
|
|
|
7
6
|
import type { TadaBuildMeta } from './compiler-types';
|
|
8
7
|
import type { TadaSnapshot } from './snapshot';
|
|
9
8
|
import type { WatchLifecycleEvent } from '../../watch/types';
|
|
9
|
+
import {
|
|
10
|
+
WATCH_RELOAD_MESSAGE_REBUILDING,
|
|
11
|
+
WATCH_RELOAD_MESSAGE_RELOAD,
|
|
12
|
+
WATCH_RELOAD_PATH,
|
|
13
|
+
WATCH_RELOAD_TOPIC,
|
|
14
|
+
} from './reload';
|
|
10
15
|
|
|
11
16
|
const log = makeLogger(import.meta.url);
|
|
12
17
|
const wslog = makeLogger('WebSocket');
|
|
@@ -22,65 +27,45 @@ function describeChange(kind: 'add' | 'change' | 'unlink'): string {
|
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
export class TadaWatchRuntime {
|
|
25
|
-
private wsPort: number;
|
|
26
30
|
private httpPort: number | undefined;
|
|
27
31
|
private distDir: string;
|
|
28
|
-
private
|
|
32
|
+
private server: Bun.Server<undefined> | null;
|
|
29
33
|
private lastBuildFailed: boolean;
|
|
30
|
-
private serveStarted: boolean;
|
|
31
34
|
private pagefindRunner: WatchPagefindRunner | undefined;
|
|
32
35
|
private pagefindSiteVariablesKey: string | undefined;
|
|
33
36
|
|
|
34
|
-
constructor({
|
|
35
|
-
wsPort,
|
|
36
|
-
httpPort,
|
|
37
|
-
distDir,
|
|
38
|
-
}: {
|
|
39
|
-
wsPort: number;
|
|
40
|
-
httpPort?: number;
|
|
41
|
-
distDir: string;
|
|
42
|
-
}) {
|
|
43
|
-
this.wsPort = wsPort;
|
|
37
|
+
constructor({ httpPort, distDir }: { httpPort?: number; distDir: string }) {
|
|
44
38
|
this.httpPort = httpPort;
|
|
45
39
|
this.distDir = distDir;
|
|
40
|
+
this.server = null;
|
|
46
41
|
this.lastBuildFailed = false;
|
|
47
|
-
this.serveStarted = false;
|
|
48
42
|
this.pagefindSiteVariablesKey = undefined;
|
|
49
|
-
this.wss = new WebSocketServer({ port: wsPort });
|
|
50
|
-
|
|
51
|
-
this.wss.on('connection', conn => {
|
|
52
|
-
wslog.debug`WebSocket client connected`;
|
|
53
|
-
conn.on('close', () => {
|
|
54
|
-
wslog.debug`WebSocket client disconnected`;
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
this.wss.on('listening', () => {
|
|
59
|
-
wslog.debug`WebSocket server listening at ws://localhost:${this.wsPort}`;
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
this.wss.on('error', err => {
|
|
63
|
-
wslog.error`WebSocket server error: ${err.message}`;
|
|
64
|
-
});
|
|
65
43
|
}
|
|
66
44
|
|
|
67
45
|
private broadcast(message: string): void {
|
|
68
|
-
if (!this.
|
|
46
|
+
if (!this.server) {
|
|
69
47
|
return;
|
|
70
48
|
}
|
|
71
|
-
|
|
72
|
-
if (client.readyState === WebSocket.OPEN) {
|
|
73
|
-
client.send(message);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
49
|
+
this.server.publish(WATCH_RELOAD_TOPIC, message);
|
|
76
50
|
}
|
|
77
51
|
|
|
78
52
|
private ensureServerStarted(): void {
|
|
79
|
-
if (this.
|
|
53
|
+
if (this.server) {
|
|
80
54
|
return;
|
|
81
55
|
}
|
|
82
|
-
this.
|
|
83
|
-
|
|
56
|
+
this.server = startServer({
|
|
57
|
+
port: this.httpPort,
|
|
58
|
+
distDir: this.distDir,
|
|
59
|
+
watchReload: {
|
|
60
|
+
onClientOpen: () => {
|
|
61
|
+
wslog.debug`WebSocket client connected`;
|
|
62
|
+
},
|
|
63
|
+
onClientClose: () => {
|
|
64
|
+
wslog.debug`WebSocket client disconnected`;
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
wslog.debug`WebSocket server listening at ws://localhost:${this.server.port}${WATCH_RELOAD_PATH}`;
|
|
84
69
|
}
|
|
85
70
|
|
|
86
71
|
async onEvent(
|
|
@@ -92,7 +77,7 @@ export class TadaWatchRuntime {
|
|
|
92
77
|
for (const change of event.batch?.changes || []) {
|
|
93
78
|
log.event`${B`${path.basename(change.path)}`} ${describeChange(change.kind)}`;
|
|
94
79
|
}
|
|
95
|
-
this.broadcast(
|
|
80
|
+
this.broadcast(WATCH_RELOAD_MESSAGE_REBUILDING);
|
|
96
81
|
}
|
|
97
82
|
return;
|
|
98
83
|
case 'build-succeeded': {
|
|
@@ -101,7 +86,7 @@ export class TadaWatchRuntime {
|
|
|
101
86
|
printFlair();
|
|
102
87
|
this.ensureServerStarted();
|
|
103
88
|
if (!event.initial && (event.changed || recoveredFromFailure)) {
|
|
104
|
-
this.broadcast(
|
|
89
|
+
this.broadcast(WATCH_RELOAD_MESSAGE_RELOAD);
|
|
105
90
|
}
|
|
106
91
|
if (event.meta && event.changed) {
|
|
107
92
|
if (event.meta.siteVariables.features.search !== false) {
|
|
@@ -110,14 +95,13 @@ export class TadaWatchRuntime {
|
|
|
110
95
|
!this.pagefindRunner ||
|
|
111
96
|
this.pagefindSiteVariablesKey !== siteVariablesKey
|
|
112
97
|
) {
|
|
113
|
-
this.pagefindRunner = new WatchPagefindRunner(
|
|
114
|
-
event.meta.siteVariables,
|
|
115
|
-
);
|
|
98
|
+
this.pagefindRunner = new WatchPagefindRunner();
|
|
116
99
|
this.pagefindSiteVariablesKey = siteVariablesKey;
|
|
117
100
|
}
|
|
118
101
|
this.pagefindRunner.update(
|
|
119
102
|
this.distDir,
|
|
120
103
|
event.meta.htmlAssetsByPath,
|
|
104
|
+
event.meta.htmlAnalysisByPath,
|
|
121
105
|
);
|
|
122
106
|
setImmediate(() => this.pagefindRunner!.run());
|
|
123
107
|
} else {
|