diff --git a/.changeset/fluffy-mirrors-swim.md b/.changeset/fluffy-mirrors-swim.md new file mode 100644 index 000000000000..5f904c4e90a1 --- /dev/null +++ b/.changeset/fluffy-mirrors-swim.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Simplify HMR handling diff --git a/packages/astro/src/core/compile/compile.ts b/packages/astro/src/core/compile/compile.ts index e431f1bb36d4..9e52e1473d36 100644 --- a/packages/astro/src/core/compile/compile.ts +++ b/packages/astro/src/core/compile/compile.ts @@ -12,7 +12,6 @@ export interface CompileProps { astroConfig: AstroConfig; viteConfig: ResolvedConfig; filename: string; - id: string | undefined; source: string; } @@ -25,7 +24,6 @@ export async function compile({ astroConfig, viteConfig, filename, - id: moduleId, source, }: CompileProps): Promise { const cssDeps = new Set(); @@ -37,7 +35,7 @@ export async function compile({ // use `sourcemap: "both"` so that sourcemap is included in the code // result passed to esbuild, but also available in the catch handler. transformResult = await transform(source, { - moduleId, + moduleId: filename, pathname: filename, projectRoot: astroConfig.root.toString(), site: astroConfig.site?.toString(), diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index 05d591f423a3..074709eef60b 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -102,7 +102,7 @@ export async function createVite( astroIntegrationsContainerPlugin({ settings, logging }), astroScriptsPageSSRPlugin({ settings }), astroHeadPropagationPlugin({ settings }), - astroScannerPlugin({ settings, logging }), + astroScannerPlugin({ settings }), astroInjectEnvTsPlugin({ settings, logging, fs }), ...(settings.config.experimental.contentCollections ? [ diff --git a/packages/astro/src/vite-plugin-astro/compile.ts b/packages/astro/src/vite-plugin-astro/compile.ts index e63c0605c310..c42ef34b77c2 100644 --- a/packages/astro/src/vite-plugin-astro/compile.ts +++ b/packages/astro/src/vite-plugin-astro/compile.ts @@ -7,7 +7,6 @@ import { getFileInfo } from '../vite-plugin-utils/index.js'; interface CachedFullCompilation { compileProps: CompileProps; - rawId: string; logging: LogOptions; } @@ -27,7 +26,6 @@ const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms; export async function cachedFullCompilation({ compileProps, - rawId, logging, }: CachedFullCompilation): Promise { let transformResult: CompileResult; @@ -37,7 +35,7 @@ export async function cachedFullCompilation({ transformResult = await cachedCompilation(compileProps); // Compile all TypeScript to JavaScript. // Also, catches invalid JS/TS in the compiled output before returning. - esbuildResult = await transformWithEsbuild(transformResult.code, rawId, { + esbuildResult = await transformWithEsbuild(transformResult.code, compileProps.filename, { loader: 'ts', target: 'esnext', sourcemap: 'external', @@ -51,7 +49,7 @@ export async function cachedFullCompilation({ } catch (err: any) { await enhanceCompileError({ err, - id: rawId, + id: compileProps.filename, source: compileProps.source, config: compileProps.astroConfig, logging: logging, @@ -59,7 +57,10 @@ export async function cachedFullCompilation({ throw err; } - const { fileId: file, fileUrl: url } = getFileInfo(rawId, compileProps.astroConfig); + const { fileId: file, fileUrl: url } = getFileInfo( + compileProps.filename, + compileProps.astroConfig + ); let SUFFIX = ''; SUFFIX += `\nconst $$file = ${JSON.stringify(file)};\nconst $$url = ${JSON.stringify( @@ -70,7 +71,7 @@ export async function cachedFullCompilation({ if (!compileProps.viteConfig.isProduction) { let i = 0; while (i < transformResult.scripts.length) { - SUFFIX += `import "${rawId}?astro&type=script&index=${i}&lang.ts";`; + SUFFIX += `import "${compileProps.filename}?astro&type=script&index=${i}&lang.ts";`; i++; } } diff --git a/packages/astro/src/vite-plugin-astro/index.ts b/packages/astro/src/vite-plugin-astro/index.ts index 80b1aca829fe..99f8763c57d1 100644 --- a/packages/astro/src/vite-plugin-astro/index.ts +++ b/packages/astro/src/vite-plugin-astro/index.ts @@ -4,20 +4,13 @@ import type { AstroSettings } from '../@types/astro'; import type { LogOptions } from '../core/logger/core.js'; import type { PluginMetadata as AstroPluginMetadata } from './types'; -import slash from 'slash'; -import { fileURLToPath } from 'url'; +import { normalizePath } from 'vite'; import { cachedCompilation, CompileProps, getCachedCompileResult } from '../core/compile/index.js'; -import { - isRelativePath, - prependForwardSlash, - removeLeadingForwardSlashWindows, - startsWithForwardSlash, -} from '../core/path.js'; -import { viteID } from '../core/util.js'; -import { normalizeFilename } from '../vite-plugin-utils/index.js'; +import { isRelativePath } from '../core/path.js'; import { cachedFullCompilation } from './compile.js'; import { handleHotUpdate } from './hmr.js'; -import { parseAstroRequest, ParsedRequestResult } from './query.js'; +import { parseAstroRequest } from './query.js'; +import { normalizeFilename } from '../vite-plugin-utils/index.js'; export { getAstroMetadata } from './metadata.js'; export type { AstroPluginMetadata }; @@ -27,77 +20,20 @@ interface AstroPluginOptions { } /** Transform .astro files for Vite */ -export default function astro({ settings, logging }: AstroPluginOptions): vite.Plugin { +export default function astro({ settings, logging }: AstroPluginOptions): vite.Plugin[] { const { config } = settings; let resolvedConfig: vite.ResolvedConfig; // Variables for determining if an id starts with /src... const srcRootWeb = config.srcDir.pathname.slice(config.root.pathname.length - 1); const isBrowserPath = (path: string) => path.startsWith(srcRootWeb) && srcRootWeb !== '/'; - const isFullFilePath = (path: string) => - path.startsWith(prependForwardSlash(slash(fileURLToPath(config.root)))); - - function relativeToRoot(pathname: string) { - const arg = startsWithForwardSlash(pathname) ? '.' + pathname : pathname; - const url = new URL(arg, config.root); - return slash(fileURLToPath(url)) + url.search; - } - function resolveRelativeFromAstroParent(id: string, parsedFrom: ParsedRequestResult): string { - const filename = normalizeFilename(parsedFrom.filename, config); - const resolvedURL = new URL(id, `file://${filename}`); - const resolved = resolvedURL.pathname; - if (isBrowserPath(resolved)) { - return relativeToRoot(resolved + resolvedURL.search); - } - return slash(fileURLToPath(resolvedURL)) + resolvedURL.search; - } - - return { + const prePlugin: vite.Plugin = { name: 'astro:build', enforce: 'pre', // run transforms before other plugins can configResolved(_resolvedConfig) { resolvedConfig = _resolvedConfig; }, - // note: don’t claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.glob, etc.) - async resolveId(id, from, opts) { - // If resolving from an astro subresource such as a hoisted script, - // we need to resolve relative paths ourselves. - if (from) { - const parsedFrom = parseAstroRequest(from); - const isAstroScript = parsedFrom.query.astro && parsedFrom.query.type === 'script'; - if (isAstroScript && isRelativePath(id)) { - return this.resolve(resolveRelativeFromAstroParent(id, parsedFrom), from, { - custom: opts.custom, - skipSelf: true, - }); - } - } - - // serve sub-part requests (*?astro) as virtual modules - const { query } = parseAstroRequest(id); - if (query.astro) { - // TODO: Try to remove these custom resolve so HMR is more predictable. - // Convert /src/pages/index.astro?astro&type=style to /Users/name/ - // Because this needs to be the id for the Vite CSS plugin to property resolve - // relative @imports. - if (query.type === 'style' && isBrowserPath(id)) { - return relativeToRoot(id); - } - // Strip `/@fs` from linked dependencies outside of root so we can normalize - // it in the condition below. This ensures that the style module shared the same is - // part of the same "file" as the main Astro module in the module graph. - // "file" refers to `moduleGraph.fileToModulesMap`. - if (query.type === 'style' && id.startsWith('/@fs')) { - id = removeLeadingForwardSlashWindows(id.slice(4)); - } - // Convert file paths to ViteID, meaning on Windows it omits the leading slash - if (isFullFilePath(id)) { - return viteID(new URL('file://' + id)); - } - return id; - } - }, async load(id, opts) { const parsedId = parseAstroRequest(id); const query = parsedId.query; @@ -105,7 +41,7 @@ export default function astro({ settings, logging }: AstroPluginOptions): vite.P return null; } // For CSS / hoisted scripts, the main Astro module should already be cached - const filename = normalizeFilename(parsedId.filename, config); + const filename = normalizePath(normalizeFilename(parsedId.filename, config.root)); const compileResult = getCachedCompileResult(config, filename); if (!compileResult) { return null; @@ -152,7 +88,7 @@ export default function astro({ settings, logging }: AstroPluginOptions): vite.P if (src.startsWith('/') && !isBrowserPath(src)) { const publicDir = config.publicDir.pathname.replace(/\/$/, '').split('/').pop() + '/'; throw new Error( - `\n\n