Fix HMR in static build + @import HMR (#2440)
* Fix HMR in static build + @import HMR * Changeset * Add a comment on what cleanUrl is doing * Running prettier * Improve comments on how the static build compilation works differently.
This commit is contained in:
parent
1d95ff58d9
commit
462e315956
5 changed files with 55 additions and 4 deletions
5
.changeset/angry-apricots-invite.md
Normal file
5
.changeset/angry-apricots-invite.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fixes HMR of CSS that is imported from astro, when using the static build flag
|
|
@ -229,6 +229,18 @@ export async function render(renderers: Renderer[], mod: ComponentInstance, ssrO
|
||||||
)
|
)
|
||||||
: new Set<SSRElement>();
|
: new Set<SSRElement>();
|
||||||
|
|
||||||
|
// Inject HMR scripts
|
||||||
|
if (mode === 'development' && astroConfig.buildOptions.experimentalStaticBuild) {
|
||||||
|
scripts.add({
|
||||||
|
props: { type: 'module', src: '/@vite/client' },
|
||||||
|
children: '',
|
||||||
|
});
|
||||||
|
scripts.add({
|
||||||
|
props: { type: 'module', src: new URL('../../runtime/client/hmr.js', import.meta.url).pathname },
|
||||||
|
children: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const result = createResult({ astroConfig, logging, origin, params, pathname, renderers, scripts });
|
const result = createResult({ astroConfig, logging, origin, params, pathname, renderers, scripts });
|
||||||
// Resolves specifiers in the inline hydrated scripts, such as "@astrojs/renderer-preact/client.js"
|
// Resolves specifiers in the inline hydrated scripts, such as "@astrojs/renderer-preact/client.js"
|
||||||
result.resolve = async (s: string) => {
|
result.resolve = async (s: string) => {
|
||||||
|
@ -249,7 +261,7 @@ export async function render(renderers: Renderer[], mod: ComponentInstance, ssrO
|
||||||
const tags: vite.HtmlTagDescriptor[] = [];
|
const tags: vite.HtmlTagDescriptor[] = [];
|
||||||
|
|
||||||
// dev only: inject Astro HMR client
|
// dev only: inject Astro HMR client
|
||||||
if (mode === 'development') {
|
if (mode === 'development' && !astroConfig.buildOptions.experimentalStaticBuild) {
|
||||||
tags.push({
|
tags.push({
|
||||||
tag: 'script',
|
tag: 'script',
|
||||||
attrs: { type: 'module' },
|
attrs: { type: 'module' },
|
||||||
|
|
|
@ -50,6 +50,13 @@ async function compile(config: AstroConfig, filename: string, source: string, vi
|
||||||
experimentalStaticExtraction: config.buildOptions.experimentalStaticBuild,
|
experimentalStaticExtraction: config.buildOptions.experimentalStaticBuild,
|
||||||
// TODO add experimental flag here
|
// TODO add experimental flag here
|
||||||
preprocessStyle: async (value: string, attrs: Record<string, string>) => {
|
preprocessStyle: async (value: string, attrs: Record<string, string>) => {
|
||||||
|
// When using this flag CSS is added via <link> and therefore goes
|
||||||
|
// through Vite's CSS pipeline. We don't need to transform here, it will be
|
||||||
|
// transformed on CSS requests.
|
||||||
|
if (config.buildOptions.experimentalStaticBuild) {
|
||||||
|
return { code: value };
|
||||||
|
}
|
||||||
|
|
||||||
const lang = `.${attrs?.lang || 'css'}`.toLowerCase();
|
const lang = `.${attrs?.lang || 'css'}`.toLowerCase();
|
||||||
try {
|
try {
|
||||||
const result = await transformWithVite({
|
const result = await transformWithVite({
|
||||||
|
|
|
@ -3,6 +3,7 @@ import type { AstroConfig } from '../@types/astro';
|
||||||
import type { LogOptions } from '../core/logger';
|
import type { LogOptions } from '../core/logger';
|
||||||
|
|
||||||
import esbuild from 'esbuild';
|
import esbuild from 'esbuild';
|
||||||
|
import npath from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { AstroDevServer } from '../core/dev/index.js';
|
import { AstroDevServer } from '../core/dev/index.js';
|
||||||
import { getViteTransform, TransformHook } from './styles.js';
|
import { getViteTransform, TransformHook } from './styles.js';
|
||||||
|
@ -29,6 +30,11 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
|
||||||
}
|
}
|
||||||
|
|
||||||
let viteTransform: TransformHook;
|
let viteTransform: TransformHook;
|
||||||
|
|
||||||
|
// Variables for determing if an id starts with /src...
|
||||||
|
const srcRootWeb = config.src.pathname.slice(config.projectRoot.pathname.length - 1);
|
||||||
|
const isBrowserPath = (path: string) => path.startsWith(srcRootWeb);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: '@astrojs/vite-plugin-astro',
|
name: '@astrojs/vite-plugin-astro',
|
||||||
enforce: 'pre', // run transforms before other plugins can
|
enforce: 'pre', // run transforms before other plugins can
|
||||||
|
@ -38,7 +44,16 @@ export default function astro({ config, logging }: AstroPluginOptions): vite.Plu
|
||||||
// note: don’t claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.globEager, etc.)
|
// note: don’t claim .astro files with resolveId() — it prevents Vite from transpiling the final JS (import.meta.globEager, etc.)
|
||||||
async resolveId(id) {
|
async resolveId(id) {
|
||||||
// serve sub-part requests (*?astro) as virtual modules
|
// serve sub-part requests (*?astro) as virtual modules
|
||||||
if (parseAstroRequest(id).query.astro) {
|
const { query } = parseAstroRequest(id);
|
||||||
|
if (query.astro) {
|
||||||
|
// 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)) {
|
||||||
|
const outId = npath.posix.join(config.projectRoot.pathname, id);
|
||||||
|
return outId;
|
||||||
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -199,6 +199,16 @@ function warnFailedFetch(err, path) {
|
||||||
socket.addEventListener('message', async ({ data }) => {
|
socket.addEventListener('message', async ({ data }) => {
|
||||||
handleMessage(JSON.parse(data));
|
handleMessage(JSON.parse(data));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This cleans up the query params and removes the `direct` param which is internal.
|
||||||
|
* Other query params are preserved.
|
||||||
|
*/
|
||||||
|
function cleanUrl(pathname) {
|
||||||
|
let url = new URL(pathname, location);
|
||||||
|
url.searchParams.delete('direct');
|
||||||
|
return url.pathname + url.search;
|
||||||
|
}
|
||||||
let isFirstUpdate = true;
|
let isFirstUpdate = true;
|
||||||
async function handleMessage(payload) {
|
async function handleMessage(payload) {
|
||||||
switch (payload.type) {
|
switch (payload.type) {
|
||||||
|
@ -230,11 +240,13 @@ async function handleMessage(payload) {
|
||||||
// css-update
|
// css-update
|
||||||
// this is only sent when a css file referenced with <link> is updated
|
// this is only sent when a css file referenced with <link> is updated
|
||||||
let { path, timestamp } = update;
|
let { path, timestamp } = update;
|
||||||
path = path.replace(/\?.*/, '');
|
let searchUrl = cleanUrl(path);
|
||||||
// can't use querySelector with `[href*=]` here since the link may be
|
// can't use querySelector with `[href*=]` here since the link may be
|
||||||
// using relative paths so we need to use link.href to grab the full
|
// using relative paths so we need to use link.href to grab the full
|
||||||
// URL for the include check.
|
// URL for the include check.
|
||||||
const el = [].slice.call(document.querySelectorAll(`link`)).find((e) => e.href.includes(path));
|
const el = [].slice.call(document.querySelectorAll(`link`)).find((e) => {
|
||||||
|
return cleanUrl(e.href).includes(searchUrl)
|
||||||
|
});
|
||||||
if (el) {
|
if (el) {
|
||||||
const newPath = `${base}${path.slice(1)}${path.includes('?') ? '&' : '?'}t=${timestamp}`;
|
const newPath = `${base}${path.slice(1)}${path.includes('?') ? '&' : '?'}t=${timestamp}`;
|
||||||
el.href = new URL(newPath, el.href).href;
|
el.href = new URL(newPath, el.href).href;
|
||||||
|
|
Loading…
Reference in a new issue