Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions napi/angular-compiler/test/hmr-hot-update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3724,3 +3724,46 @@ describe('@ng/component endpoint resolves the styles per class', () => {
expect(body, 'a definitively styleless class must still be cleared').toContain('styles: []')
})
})

describe('a template edited while its component fails to compile', () => {
it('is compiled from the edited file once the component compiles again', async () => {
const dir = join(tempDir, 'src', 'stale')
mkdirSync(dir, { recursive: true })
const template = join(dir, 'stale.component.html')
const component = join(dir, 'stale.component.ts')
const source = `
import { Component } from '@angular/core';

@Component({ selector: 'app-stale', templateUrl: './stale.component.html' })
export class StaleComponent {}
`
writeFileSync(component, source)
writeFileSync(template, '<h1>Before</h1>')

const plugin = getAngularPlugin()
const server = await setupPluginWithServer(plugin)
const transform = async (code: string) => {
if (!plugin.transform || typeof plugin.transform === 'function') {
throw new Error('Expected plugin transform handler')
}
return (await plugin.transform.handler.call(
{ error() {}, warn() {}, addWatchFile() {} } as any,
code,
component,
)) as { code: string } | undefined
}

expect((await transform(source))?.code).toContain('Before')

// the component stops compiling, and its template is edited meanwhile
await transform(
source.replace('export class StaleComponent {}', 'export class StaleComponent { x = ; }'),
).catch(() => {})
writeFileSync(template, '<h1>After</h1>')
await callHandleHotUpdate(plugin, createMockHmrContext(template, [], server))

const fixed = (await transform(source))?.code
expect(fixed).toContain('After')
expect(fixed).not.toContain('Before')
})
})
7 changes: 7 additions & 0 deletions napi/angular-compiler/vite-plugin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,13 @@ export function angular(options: PluginOptions = {}): Plugin[] {
// anything below can preprocess one (see `compiledStyles`).
startStyleCycle()

// The file's cached contents are stale, whatever its role now. A
// template edited while its component fails to compile is not
// registered as the component's at that moment (the failed transform
// found no templateUrl), so the branches below would leave its old
// contents cached for the component's next transform.
resourceCache.delete(normalizePath(ctx.file))

if (!pluginOptions.liveReload) return

debugHmr('handleHotUpdate file=%s', ctx.file)
Expand Down