mikser-io-live 6.1.1 → 6.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/index.js +1 -0
- package/lib/client.js +9 -3
- package/lib/paths.js +15 -0
- package/package.json +1 -1
- package/test/inject.test.js +37 -1
package/index.js
CHANGED
|
@@ -27,6 +27,7 @@ import { existsSync, statSync } from 'node:fs'
|
|
|
27
27
|
import { readFile } from 'node:fs/promises'
|
|
28
28
|
|
|
29
29
|
import { clientScript } from './lib/client.js'
|
|
30
|
+
export { samePage } from './lib/paths.js'
|
|
30
31
|
|
|
31
32
|
// Where the snippet goes, in preference order. `</head>` is the fallback for
|
|
32
33
|
// a document with no closing body tag.
|
package/lib/client.js
CHANGED
|
@@ -7,8 +7,11 @@
|
|
|
7
7
|
// EventSource rather than a WebSocket. It reconnects on its own, survives a
|
|
8
8
|
// mikser restart without any retry logic here, needs no upgrade handshake, and
|
|
9
9
|
// mikser already has a `streaming: true` route kind for exactly this.
|
|
10
|
+
import { samePage } from './paths.js'
|
|
11
|
+
|
|
10
12
|
export function clientScript(path) {
|
|
11
13
|
return `<script data-mikser-live>(() => {
|
|
14
|
+
const samePage = ${samePage.toString()}
|
|
12
15
|
const source = new EventSource(${JSON.stringify(path)})
|
|
13
16
|
let boot = null
|
|
14
17
|
|
|
@@ -49,9 +52,12 @@ export function clientScript(path) {
|
|
|
49
52
|
// Anything else: reload, but only if this page is among what changed. A
|
|
50
53
|
// build that rerendered forty other pages is not a reason to interrupt
|
|
51
54
|
// the one being looked at.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
//
|
|
56
|
+
// Compared after normalising both sides, because one page has three URLs.
|
|
57
|
+
// /about, /about/ and /about/index.html are all served, and the watcher
|
|
58
|
+
// only ever reports the third — so a plain comparison reloaded two of them
|
|
59
|
+
// and silently never reloaded the one people actually type or link to.
|
|
60
|
+
if (paths.some((p) => samePage(p, location.pathname))) location.reload()
|
|
55
61
|
})
|
|
56
62
|
})()</script>`
|
|
57
63
|
}
|
package/lib/paths.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Is a changed path the page a browser is looking at?
|
|
2
|
+
//
|
|
3
|
+
// One page has three URLs. /about, /about/ and /about/index.html are all
|
|
4
|
+
// served, and the watcher only ever reports the third — so comparing them
|
|
5
|
+
// literally reloads two of them and silently never reloads the one people
|
|
6
|
+
// actually type or link to.
|
|
7
|
+
//
|
|
8
|
+
// Lives here, alone, because it is needed on both sides: the browser decides
|
|
9
|
+
// with it, and the tests check it. The snippet inlines THIS function's source
|
|
10
|
+
// rather than carrying its own copy, so the two cannot drift into disagreeing
|
|
11
|
+
// about which page you are on.
|
|
12
|
+
export function samePage(a, b) {
|
|
13
|
+
const norm = (p) => String(p).replace(/\/index\.html$/, '/').replace(/(.)\/$/, '$1')
|
|
14
|
+
return norm(a) === norm(b)
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mikser-io-live",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.2",
|
|
4
4
|
"description": "Live reload for mikser-io, mounted on mikser's own HTTP server. Reloads from the build report rather than by watching files, so a CSS edit swaps the stylesheet in place and a build that touched other pages does not interrupt the one you are looking at.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
package/test/inject.test.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { describe, it } from 'node:test'
|
|
4
4
|
import assert from 'node:assert/strict'
|
|
5
5
|
|
|
6
|
-
import { injectionPoint, injectInto } from '../index.js'
|
|
6
|
+
import { injectionPoint, injectInto, samePage } from '../index.js'
|
|
7
7
|
import { clientScript } from '../lib/client.js'
|
|
8
8
|
|
|
9
9
|
describe('finding somewhere to put the snippet', () => {
|
|
@@ -95,3 +95,39 @@ describe('what it will and will not touch', () => {
|
|
|
95
95
|
assert.match(clientScript('/live'), /&&/)
|
|
96
96
|
})
|
|
97
97
|
})
|
|
98
|
+
|
|
99
|
+
describe('deciding whether a change is THIS page', () => {
|
|
100
|
+
// One page, three URLs. The watcher reports the file it saw —
|
|
101
|
+
// /about/index.html — and a browser may be sitting on any of the three.
|
|
102
|
+
it('treats every spelling of a page as the same page', () => {
|
|
103
|
+
for (const here of ['/about', '/about/', '/about/index.html']) {
|
|
104
|
+
assert.equal(samePage(here, '/about/index.html'), true, here)
|
|
105
|
+
}
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('treats the root the same way', () => {
|
|
109
|
+
for (const here of ['/', '/index.html']) {
|
|
110
|
+
assert.equal(samePage(here, '/index.html'), true, here)
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('still says no to a different page', () => {
|
|
115
|
+
// Over-matching would reload every browser on every build, which is
|
|
116
|
+
// the behaviour this whole comparison exists to avoid.
|
|
117
|
+
assert.equal(samePage('/contact/', '/about/index.html'), false)
|
|
118
|
+
assert.equal(samePage('/', '/about/index.html'), false)
|
|
119
|
+
assert.equal(samePage('/aboutus/', '/about/index.html'), false)
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
describe('the browser and the tests agree', () => {
|
|
124
|
+
it('the snippet uses the same comparison, not a copy of it', () => {
|
|
125
|
+
// Two implementations of "is this my page" is the shape that produced
|
|
126
|
+
// the bug: the tests would keep passing while the browser used
|
|
127
|
+
// something subtly different. The snippet inlines this function's
|
|
128
|
+
// own source.
|
|
129
|
+
const script = clientScript('/live')
|
|
130
|
+
assert.ok(script.includes(samePage.toString()),
|
|
131
|
+
'the client must carry THIS function, not a second version of it')
|
|
132
|
+
})
|
|
133
|
+
})
|