@remix-run/node-hmr 0.0.0 → 0.1.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.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +306 -2
  3. package/dist/index.d.ts +128 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +107 -0
  6. package/dist/lib/browser-events.d.ts +99 -0
  7. package/dist/lib/browser-events.d.ts.map +1 -0
  8. package/dist/lib/browser-events.js +11 -0
  9. package/dist/lib/events.d.ts +29 -0
  10. package/dist/lib/events.d.ts.map +1 -0
  11. package/dist/lib/events.js +32 -0
  12. package/dist/lib/hmr-analysis.d.ts +17 -0
  13. package/dist/lib/hmr-analysis.d.ts.map +1 -0
  14. package/dist/lib/hmr-analysis.js +130 -0
  15. package/dist/lib/module-store.d.ts +27 -0
  16. package/dist/lib/module-store.d.ts.map +1 -0
  17. package/dist/lib/module-store.js +161 -0
  18. package/dist/lib/process-state.d.ts +3 -0
  19. package/dist/lib/process-state.d.ts.map +1 -0
  20. package/dist/lib/process-state.js +7 -0
  21. package/dist/lib/runner.d.ts +62 -0
  22. package/dist/lib/runner.d.ts.map +1 -0
  23. package/dist/lib/runner.js +1046 -0
  24. package/dist/lib/runtime-api.d.ts +7 -0
  25. package/dist/lib/runtime-api.d.ts.map +1 -0
  26. package/dist/lib/runtime-api.js +1 -0
  27. package/dist/lib/runtime.d.ts +46 -0
  28. package/dist/lib/runtime.d.ts.map +1 -0
  29. package/dist/lib/runtime.js +374 -0
  30. package/dist/register.d.ts +2 -0
  31. package/dist/register.d.ts.map +1 -0
  32. package/dist/register.js +317 -0
  33. package/dist/runtime.d.ts +26 -0
  34. package/dist/runtime.d.ts.map +1 -0
  35. package/dist/runtime.js +32 -0
  36. package/dist/runtime.node-hmr.d.ts +27 -0
  37. package/dist/runtime.node-hmr.d.ts.map +1 -0
  38. package/dist/runtime.node-hmr.js +33 -0
  39. package/dist/types.d.ts +36 -0
  40. package/package.json +55 -5
  41. package/src/index.ts +244 -0
  42. package/src/lib/browser-events.ts +123 -0
  43. package/src/lib/events.ts +61 -0
  44. package/src/lib/hmr-analysis.ts +178 -0
  45. package/src/lib/module-store.ts +228 -0
  46. package/src/lib/process-state.ts +9 -0
  47. package/src/lib/runner.ts +1427 -0
  48. package/src/lib/runtime-api.ts +9 -0
  49. package/src/lib/runtime.ts +534 -0
  50. package/src/register.ts +401 -0
  51. package/src/runtime.node-hmr.ts +40 -0
  52. package/src/runtime.ts +40 -0
  53. package/src/types.d.ts +36 -0
@@ -0,0 +1,228 @@
1
+ export interface ModuleRecord {
2
+ filePath: string
3
+ hmr: {
4
+ acceptedDeps: string[]
5
+ selfAccepting: boolean
6
+ usesImportMetaHot: boolean
7
+ }
8
+ url: string
9
+ }
10
+
11
+ export interface HotUpdateBoundary {
12
+ acceptedDependencyUrl: string
13
+ invalidatedUrls: Record<string, number>
14
+ updateHandlerUrl: string
15
+ }
16
+
17
+ export interface ModuleStore {
18
+ addDependency(importerUrl: string, dependencyUrl: string): void
19
+ findHotUpdateBoundaries(url: string, timestamp: number): HotUpdateBoundary[] | null
20
+ findHotUpdateBoundariesFromImporters(url: string, timestamp: number): HotUpdateBoundary[] | null
21
+ getModule(url: string): ModuleRecord | undefined
22
+ getModulesForFile(filePath: string): readonly ModuleRecord[]
23
+ getReachableFilePaths(entryUrl: string): ReadonlySet<string>
24
+ reset(): void
25
+ setAcceptedDependencies(url: string, acceptedDependencies: string[]): void
26
+ setModule(module: ModuleRecord): void
27
+ }
28
+
29
+ export function createModuleStore(): ModuleStore {
30
+ let modulesByUrl = new Map<string, ModuleRecord>()
31
+ let modulesByFilePath = new Map<string, Map<string, ModuleRecord>>()
32
+ let dependenciesByImporterUrl = new Map<string, Set<string>>()
33
+ let importersByDependencyUrl = new Map<string, Set<string>>()
34
+
35
+ return {
36
+ addDependency(importerUrl, dependencyUrl) {
37
+ addToIndexedSet(dependenciesByImporterUrl, importerUrl, dependencyUrl)
38
+ addToIndexedSet(importersByDependencyUrl, dependencyUrl, importerUrl)
39
+ },
40
+
41
+ findHotUpdateBoundaries(url, timestamp) {
42
+ return findPropagation(url, timestamp)
43
+ },
44
+
45
+ findHotUpdateBoundariesFromImporters(url, timestamp) {
46
+ return findPropagationFromImporters(url, timestamp, new Set([url]), [url])
47
+ },
48
+
49
+ getModule(url) {
50
+ return modulesByUrl.get(url)
51
+ },
52
+
53
+ getModulesForFile(filePath) {
54
+ return [...(modulesByFilePath.get(filePath)?.values() ?? [])]
55
+ },
56
+
57
+ getReachableFilePaths(entryUrl) {
58
+ let reachableFilePaths = new Set<string>()
59
+ let visitedUrls = new Set<string>()
60
+ visit(entryUrl)
61
+ return reachableFilePaths
62
+
63
+ function visit(url: string): void {
64
+ if (visitedUrls.has(url)) return
65
+
66
+ let module = modulesByUrl.get(url)
67
+ if (module === undefined) return
68
+
69
+ visitedUrls.add(url)
70
+ reachableFilePaths.add(module.filePath)
71
+ for (let dependencyUrl of dependenciesByImporterUrl.get(url) ?? []) {
72
+ visit(dependencyUrl)
73
+ }
74
+ }
75
+ },
76
+
77
+ reset() {
78
+ modulesByUrl = new Map()
79
+ modulesByFilePath = new Map()
80
+ dependenciesByImporterUrl = new Map()
81
+ importersByDependencyUrl = new Map()
82
+ },
83
+
84
+ setAcceptedDependencies(url, acceptedDependencies) {
85
+ let module = modulesByUrl.get(url)
86
+ if (module !== undefined) {
87
+ module.hmr.acceptedDeps = acceptedDependencies
88
+ }
89
+ },
90
+
91
+ setModule(module) {
92
+ let previousModule = modulesByUrl.get(module.url)
93
+ if (previousModule !== undefined) {
94
+ removeModuleFromFileIndex(previousModule)
95
+ }
96
+ removeImporterDependencies(module.url)
97
+
98
+ modulesByUrl.set(module.url, module)
99
+ let fileModules = modulesByFilePath.get(module.filePath) ?? new Map()
100
+ fileModules.set(module.url, module)
101
+ modulesByFilePath.set(module.filePath, fileModules)
102
+ },
103
+ }
104
+
105
+ function removeModuleFromFileIndex(module: ModuleRecord): void {
106
+ let fileModules = modulesByFilePath.get(module.filePath)
107
+ if (fileModules === undefined) return
108
+
109
+ fileModules.delete(module.url)
110
+ if (fileModules.size === 0) {
111
+ modulesByFilePath.delete(module.filePath)
112
+ }
113
+ }
114
+
115
+ function removeImporterDependencies(importerUrl: string): void {
116
+ let dependencies = dependenciesByImporterUrl.get(importerUrl)
117
+ if (dependencies === undefined) return
118
+
119
+ for (let dependencyUrl of dependencies) {
120
+ removeFromIndexedSet(importersByDependencyUrl, dependencyUrl, importerUrl)
121
+ }
122
+ dependenciesByImporterUrl.delete(importerUrl)
123
+ }
124
+
125
+ function findPropagation(
126
+ url: string,
127
+ timestamp: number,
128
+ traversedUrls: ReadonlySet<string> = new Set(),
129
+ invalidatedUrls: string[] = [url],
130
+ ): HotUpdateBoundary[] | null {
131
+ if (traversedUrls.has(url)) return null
132
+
133
+ let nextTraversedUrls = new Set(traversedUrls)
134
+ nextTraversedUrls.add(url)
135
+
136
+ let module = modulesByUrl.get(url)
137
+ if (module === undefined) return null
138
+
139
+ if (module.hmr.selfAccepting) {
140
+ return [createHotUpdateBoundary(url, url, invalidatedUrls, timestamp)]
141
+ }
142
+
143
+ return findPropagationFromImporters(url, timestamp, nextTraversedUrls, invalidatedUrls)
144
+ }
145
+
146
+ function findPropagationFromImporters(
147
+ url: string,
148
+ timestamp: number,
149
+ traversedUrls: ReadonlySet<string>,
150
+ invalidatedUrls: string[],
151
+ ): HotUpdateBoundary[] | null {
152
+ let importerUrls = importersByDependencyUrl.get(url)
153
+ if (importerUrls === undefined || importerUrls.size === 0) return null
154
+
155
+ let importers = [...importerUrls]
156
+ .map((importerUrl) => modulesByUrl.get(importerUrl))
157
+ .filter((importer): importer is ModuleRecord => importer !== undefined)
158
+ if (importers.length === 0) return null
159
+
160
+ let boundaries: HotUpdateBoundary[] = []
161
+ for (let importer of importers) {
162
+ if (importer.hmr.acceptedDeps.includes(url)) {
163
+ boundaries.push(createHotUpdateBoundary(url, importer.url, invalidatedUrls, timestamp))
164
+ continue
165
+ }
166
+
167
+ let importerUpdates = findPropagation(importer.url, timestamp, traversedUrls, [
168
+ ...invalidatedUrls,
169
+ importer.url,
170
+ ])
171
+ if (importerUpdates === null) return null
172
+ boundaries.push(...importerUpdates)
173
+ }
174
+
175
+ return deduplicateHotUpdateBoundaries(boundaries)
176
+ }
177
+ }
178
+
179
+ function createHotUpdateBoundary(
180
+ acceptedDependencyUrl: string,
181
+ updateHandlerUrl: string,
182
+ invalidatedUrls: readonly string[],
183
+ timestamp: number,
184
+ ): HotUpdateBoundary {
185
+ let invalidationTimestamps: Record<string, number> = {}
186
+ for (let invalidatedUrl of invalidatedUrls) {
187
+ invalidationTimestamps[invalidatedUrl] = timestamp
188
+ }
189
+
190
+ return {
191
+ acceptedDependencyUrl,
192
+ invalidatedUrls: invalidationTimestamps,
193
+ updateHandlerUrl,
194
+ }
195
+ }
196
+
197
+ function deduplicateHotUpdateBoundaries(
198
+ boundaries: readonly HotUpdateBoundary[],
199
+ ): HotUpdateBoundary[] {
200
+ let boundaryByKey = new Map<string, HotUpdateBoundary>()
201
+ let result: HotUpdateBoundary[] = []
202
+ for (let boundary of boundaries) {
203
+ let key = `${boundary.updateHandlerUrl}\0${boundary.acceptedDependencyUrl}`
204
+ let existingBoundary = boundaryByKey.get(key)
205
+ if (existingBoundary !== undefined) {
206
+ Object.assign(existingBoundary.invalidatedUrls, boundary.invalidatedUrls)
207
+ continue
208
+ }
209
+ boundaryByKey.set(key, boundary)
210
+ result.push(boundary)
211
+ }
212
+ return result
213
+ }
214
+
215
+ function addToIndexedSet(map: Map<string, Set<string>>, key: string, value: string): void {
216
+ let values = map.get(key) ?? new Set()
217
+ values.add(value)
218
+ map.set(key, values)
219
+ }
220
+
221
+ function removeFromIndexedSet(map: Map<string, Set<string>>, key: string, value: string): void {
222
+ let values = map.get(key)
223
+ if (values === undefined) return
224
+ values.delete(value)
225
+ if (values.size === 0) {
226
+ map.delete(key)
227
+ }
228
+ }
@@ -0,0 +1,9 @@
1
+ let nodeHmrParentProcess = false
2
+
3
+ export function hasNodeHmrParentProcess(): boolean {
4
+ return nodeHmrParentProcess
5
+ }
6
+
7
+ export function markNodeHmrParentProcess(): void {
8
+ nodeHmrParentProcess = true
9
+ }