Home / File/ hmr.ts — astro Source File

hmr.ts — astro Source File

Architecture documentation for hmr.ts, a typescript file in the astro codebase. 5 imports, 0 dependents.

File typescript CoreAstro RenderingEngine 5 imports 3 functions

Entity Profile

Dependency Diagram

graph LR
  3edca240_218c_fab7_1690_9c4cda71a3a9["hmr.ts"]
  d3861967_b647_84d2_ff48_15013353bd56["../core/logger/core.js"]
  3edca240_218c_fab7_1690_9c4cda71a3a9 --> d3861967_b647_84d2_ff48_15013353bd56
  668b2d72_0336_6d81_ad0e_90aa3aae0ed7["./query.js"]
  3edca240_218c_fab7_1690_9c4cda71a3a9 --> 668b2d72_0336_6d81_ad0e_90aa3aae0ed7
  578ea01d_496b_3b43_98f2_7b2f0ce78d7e["../vite-plugin-astro/types.js"]
  3edca240_218c_fab7_1690_9c4cda71a3a9 --> 578ea01d_496b_3b43_98f2_7b2f0ce78d7e
  d25683f6_6ac0_f5eb_b4b1_ac7cda6eb3c8["./utils.js"]
  3edca240_218c_fab7_1690_9c4cda71a3a9 --> d25683f6_6ac0_f5eb_b4b1_ac7cda6eb3c8
  263e522e_1aa5_ebc3_e7d6_45ebc51671f7["vite"]
  3edca240_218c_fab7_1690_9c4cda71a3a9 --> 263e522e_1aa5_ebc3_e7d6_45ebc51671f7
  style 3edca240_218c_fab7_1690_9c4cda71a3a9 fill:#6366f1,stroke:#818cf8,color:#fff

Relationship Graph

Source Code

import type { HmrContext } from 'vite';
import type { Logger } from '../core/logger/core.js';
import { parseAstroRequest } from './query.js';
import type { CompileMetadata } from './types.js';
import { frontmatterRE } from './utils.js';

interface HandleHotUpdateOptions {
	logger: Logger;
	astroFileToCompileMetadata: Map<string, CompileMetadata>;
}

export async function handleHotUpdate(
	ctx: HmrContext,
	{ logger, astroFileToCompileMetadata }: HandleHotUpdateOptions,
) {
	// HANDLING 1: Invalidate compile metadata if CSS dependency updated
	//
	// If any `ctx.file` is part of a CSS dependency of any Astro file, invalidate its `astroFileToCompileMetadata`
	// so the next transform of the Astro file or Astro script/style virtual module will re-generate it
	for (const [astroFile, compileData] of astroFileToCompileMetadata) {
		const isUpdatedFileCssDep = compileData.css.some((css) => css.dependencies?.includes(ctx.file));
		if (isUpdatedFileCssDep) {
			astroFileToCompileMetadata.delete(astroFile);
		}
	}

	// HANDLING 2: Only invalidate Astro style virtual module if only style tags changed
	//
	// If only the style code has changed, e.g. editing the `color`, then we can directly invalidate
	// the Astro CSS virtual modules only. The main Astro module's JS result will be the same and doesn't
	// need to be invalidated.
	const oldCode = astroFileToCompileMetadata.get(ctx.file)?.originalCode;
	if (oldCode == null) return;
	const newCode = await ctx.read();

	if (isStyleOnlyChanged(oldCode, newCode)) {
		logger.debug('watch', 'style-only change');
		// Invalidate its `astroFileToCompileMetadata` so that the next transform of Astro style virtual module
		// will re-generate it
		astroFileToCompileMetadata.delete(ctx.file);
		return ctx.modules.filter((mod) => {
			if (!mod.id) {
				return false;
			}
			const { query } = parseAstroRequest(mod.id);
			// Only return the Astro styles that have changed, except inline style modules that are treated as SSR-only
			return query.astro && query.type === 'style' && !query.inline;
		});
	}
}

// Disable eslint as we're not sure how to improve this regex yet
// eslint-disable-next-line regexp/no-super-linear-backtracking
const scriptRE = /<script(?:\s.*?)?>.*?<\/script>/gs;
// eslint-disable-next-line regexp/no-super-linear-backtracking
const styleRE = /<style(?:\s.*?)?>.*?<\/style>/gs;

export function isStyleOnlyChanged(oldCode: string, newCode: string) {
	if (oldCode === newCode) return false;

	// Before we can regex-capture style tags, we remove the frontmatter and scripts
	// first as they could contain false-positive style tag matches. At the same time,
	// we can also compare if they have changed and early out.

	// Strip off and compare frontmatter
	let oldFrontmatter = '';
	let newFrontmatter = '';
	oldCode = oldCode.replace(frontmatterRE, (m) => ((oldFrontmatter = m), ''));
	newCode = newCode.replace(frontmatterRE, (m) => ((newFrontmatter = m), ''));
	if (oldFrontmatter !== newFrontmatter) return false;

	// Strip off and compare scripts
	const oldScripts: string[] = [];
	const newScripts: string[] = [];
	oldCode = oldCode.replace(scriptRE, (m) => (oldScripts.push(m), ''));
	newCode = newCode.replace(scriptRE, (m) => (newScripts.push(m), ''));
	if (!isArrayEqual(oldScripts, newScripts)) return false;

	// Finally, we can compare styles
	const oldStyles: string[] = [];
	const newStyles: string[] = [];
	oldCode = oldCode.replace(styleRE, (m) => (oldStyles.push(m), ''));
	newCode = newCode.replace(styleRE, (m) => (newStyles.push(m), ''));

	// Remaining of `oldCode` and `newCode` is the markup, return false if they're different
	if (oldCode !== newCode) return false;

	// Finally, check if only the style changed.
	// The length must also be the same for style only change. If style tags are added/removed,
	// we need to regenerate the main Astro file so that its CSS imports are also added/removed
	return oldStyles.length === newStyles.length && !isArrayEqual(oldStyles, newStyles);
}

function isArrayEqual(a: any[], b: any[]) {
	if (a.length !== b.length) {
		return false;
	}
	for (let i = 0; i < a.length; i++) {
		if (a[i] !== b[i]) {
			return false;
		}
	}
	return true;
}

Domain

Subdomains

Dependencies

  • ../core/logger/core.js
  • ../vite-plugin-astro/types.js
  • ./query.js
  • ./utils.js
  • vite

Frequently Asked Questions

What does hmr.ts do?
hmr.ts is a source file in the astro codebase, written in typescript. It belongs to the CoreAstro domain, RenderingEngine subdomain.
What functions are defined in hmr.ts?
hmr.ts defines 3 function(s): handleHotUpdate, isArrayEqual, isStyleOnlyChanged.
What does hmr.ts depend on?
hmr.ts imports 5 module(s): ../core/logger/core.js, ../vite-plugin-astro/types.js, ./query.js, ./utils.js, vite.
Where is hmr.ts in the architecture?
hmr.ts is located at packages/astro/src/vite-plugin-astro/hmr.ts (domain: CoreAstro, subdomain: RenderingEngine, directory: packages/astro/src/vite-plugin-astro).

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free