Skip to content

Commit 76c5c68

Browse files
committed
fix: wait for watch hmr baseline outputs
1 parent 7fa2a29 commit 76c5c68

2 files changed

Lines changed: 142 additions & 9 deletions

File tree

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { mkdtemp, rm, writeFile } from 'node:fs/promises'
2+
import os from 'node:os'
3+
import path from 'node:path'
4+
import { afterEach, describe, expect, it, vi } from 'vitest'
5+
import { waitForClassMutationBaselineOutputs } from '../../../tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/mutations/class'
6+
import type {
7+
CliOptions,
8+
WatchCase,
9+
WatchSession,
10+
} from '../../../tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/types'
11+
12+
function createOptions(): CliOptions {
13+
return {
14+
caseName: 'all',
15+
timeoutMs: 1000,
16+
pollMs: 10,
17+
skipBuild: true,
18+
quietSass: true,
19+
}
20+
}
21+
22+
describe('watch-hmr class baseline', () => {
23+
let tempDir = ''
24+
25+
afterEach(async () => {
26+
if (tempDir) {
27+
await rm(tempDir, { recursive: true, force: true })
28+
}
29+
})
30+
31+
it('waits for temporarily empty baseline outputs before mutating content', async () => {
32+
tempDir = await mkdtemp(path.join(os.tmpdir(), 'weapp-tw-class-baseline-'))
33+
const outputWxml = path.join(tempDir, 'index.wxml')
34+
const outputJs = path.join(tempDir, 'index.js')
35+
const outputStyle = path.join(tempDir, 'app.wxss')
36+
37+
await Promise.all([
38+
writeFile(outputWxml, '', 'utf8'),
39+
writeFile(outputJs, '', 'utf8'),
40+
writeFile(outputStyle, '.ready{}', 'utf8'),
41+
])
42+
43+
const session: WatchSession = {
44+
child: {} as WatchSession['child'],
45+
ensureRunning: vi.fn(),
46+
lastCompileSuccessAt: vi.fn(() => 0),
47+
logs: vi.fn(() => ''),
48+
stop: vi.fn(async () => {}),
49+
}
50+
const watchCase = {
51+
label: 'demo/uni-app-vite-tailwindcss-v3',
52+
outputWxml,
53+
outputJs,
54+
} as WatchCase
55+
56+
const refillOutputs = async () => {
57+
await Promise.all([
58+
writeFile(outputWxml, '<view class="ready"></view>', 'utf8'),
59+
writeFile(outputJs, 'export default {}', 'utf8'),
60+
])
61+
}
62+
setTimeout(() => {
63+
void refillOutputs()
64+
}, 30)
65+
66+
const outputs = await waitForClassMutationBaselineOutputs(
67+
watchCase,
68+
createOptions(),
69+
session,
70+
'content',
71+
[outputStyle],
72+
)
73+
74+
expect(outputs.wxml).toContain('ready')
75+
expect(outputs.js).toContain('export default')
76+
expect(outputs.globalStyle).toContain('.ready')
77+
expect(session.ensureRunning).toHaveBeenCalled()
78+
})
79+
})

tools/weapp-tailwindcss-scripts/src/watch-hmr-regression/mutations/class.ts

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,58 @@ interface RoundOutputs {
5959
globalStyle: string
6060
}
6161

62+
export async function waitForClassMutationBaselineOutputs(
63+
watchCase: WatchCase,
64+
options: CliOptions,
65+
session: WatchSession,
66+
mutationKind: 'template' | 'script' | 'content',
67+
globalStyleOutputs: string[],
68+
): Promise<RoundOutputs> {
69+
let resolvedOutputs: RoundOutputs | undefined
70+
let lastReason = 'outputs are not ready'
71+
const waitStartedAt = Date.now()
72+
73+
await waitFor(
74+
async () => {
75+
const [wxml, js, globalStyle, hasGlobalStyleOutputs] = await Promise.all([
76+
readFileIfExists(watchCase.outputWxml),
77+
readFileIfExists(watchCase.outputJs),
78+
readJoinedOutputFiles(globalStyleOutputs),
79+
hasResolvedOutputFiles(globalStyleOutputs),
80+
])
81+
82+
if (wxml && js && hasGlobalStyleOutputs) {
83+
resolvedOutputs = {
84+
wxml,
85+
js,
86+
globalStyle,
87+
}
88+
return true
89+
}
90+
91+
lastReason = [
92+
wxml ? undefined : 'wxml',
93+
js ? undefined : 'js',
94+
hasGlobalStyleOutputs ? undefined : 'global style',
95+
].filter(Boolean).join(', ')
96+
return false
97+
},
98+
{
99+
timeoutMs: options.timeoutMs,
100+
pollMs: options.pollMs,
101+
message: `[${watchCase.label}] baseline outputs are missing for ${mutationKind}: ${lastReason}`,
102+
onTick: session.ensureRunning,
103+
},
104+
waitStartedAt,
105+
)
106+
107+
if (!resolvedOutputs) {
108+
throw new Error(`[${watchCase.label}] baseline outputs failed to resolve for ${mutationKind}`)
109+
}
110+
111+
return resolvedOutputs
112+
}
113+
62114
function collectBgHexTruncationNeedles(classTokens: string[]) {
63115
const needles: string[] = []
64116
for (const token of classTokens) {
@@ -401,15 +453,17 @@ export async function runClassMutation(
401453
? [watchCase.outputWxml, watchCase.outputJs, ...globalStyleOutputs]
402454
: [watchCase.outputWxml, watchCase.outputJs]
403455

404-
const [baselineWxml, baselineJs, baselineGlobalStyle] = await Promise.all([
405-
readFileIfExists(watchCase.outputWxml),
406-
readFileIfExists(watchCase.outputJs),
407-
readJoinedOutputFiles(globalStyleOutputs),
408-
])
409-
410-
if (!baselineWxml || !baselineJs || !await hasResolvedOutputFiles(globalStyleOutputs)) {
411-
throw new Error(`[${watchCase.label}] baseline outputs are missing for ${mutationKind}`)
412-
}
456+
const {
457+
wxml: baselineWxml,
458+
js: baselineJs,
459+
globalStyle: baselineGlobalStyle,
460+
} = await waitForClassMutationBaselineOutputs(
461+
watchCase,
462+
options,
463+
session,
464+
mutationKind,
465+
globalStyleOutputs,
466+
)
413467

414468
const verifyClassLiteralIn = mutation.verifyClassLiteralIn ?? []
415469
const forbidBgHexTruncationIn = mutation.forbidBgHexTruncationIn ?? []

0 commit comments

Comments
 (0)