astro 3.0.9 → 3.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,7 +19,9 @@ const { fallback = 'animate' } = Astro.props as Props;
19
19
  };
20
20
  type Events = 'astro:page-load' | 'astro:after-swap';
21
21
 
22
- const persistState = (state: State) => history.replaceState(state, '');
22
+ // only update history entries that are managed by us
23
+ // leave other entries alone and do not accidently add state.
24
+ const persistState = (state: State) => history.state && history.replaceState(state, '');
23
25
  const supportsViewTransitions = !!document.startViewTransition;
24
26
  const transitionEnabledOnThisPage = () =>
25
27
  !!document.querySelector('[name="astro-view-transitions-enabled"]');
@@ -32,11 +34,13 @@ const { fallback = 'animate' } = Astro.props as Props;
32
34
  // can use that to determine popstate if going forward or back.
33
35
  let currentHistoryIndex = 0;
34
36
  if (history.state) {
35
- // we reloaded a page with history state (e.g. back button or browser reload)
37
+ // we reloaded a page with history state
38
+ // (e.g. history navigation from non-transition page or browser reload)
36
39
  currentHistoryIndex = history.state.index;
37
40
  scrollTo({ left: 0, top: history.state.scrollY });
41
+ } else if (transitionEnabledOnThisPage()) {
42
+ history.replaceState({ index: currentHistoryIndex, scrollY }, '');
38
43
  }
39
-
40
44
  const throttle = (cb: (...args: any[]) => any, delay: number) => {
41
45
  let wait = false;
42
46
  // During the waiting time additional events are lost.
@@ -102,20 +106,14 @@ const { fallback = 'animate' } = Astro.props as Props;
102
106
 
103
107
  function isInfinite(animation: Animation) {
104
108
  const effect = animation.effect;
105
- if(
106
- !effect ||
107
- !(effect instanceof KeyframeEffect) ||
108
- !effect.target
109
- ) return false;
110
- const style = window.getComputedStyle(effect.target, effect.pseudoElement);
111
- return style.animationIterationCount === "infinite";
112
- }
109
+ if (!effect || !(effect instanceof KeyframeEffect) || !effect.target) return false;
110
+ const style = window.getComputedStyle(effect.target, effect.pseudoElement);
111
+ return style.animationIterationCount === 'infinite';
112
+ }
113
113
 
114
114
  const parser = new DOMParser();
115
115
 
116
- async function updateDOM(html: string, state?: State, fallback?: Fallback) {
117
- const doc = parser.parseFromString(html, 'text/html');
118
-
116
+ async function updateDOM(doc: Document, loc: URL, state?: State, fallback?: Fallback) {
119
117
  // Check for a head element that should persist, either because it has the data
120
118
  // attribute or is a link el.
121
119
  const persistedHeadElement = (el: Element): Element | null => {
@@ -193,19 +191,17 @@ const { fallback = 'animate' } = Astro.props as Props;
193
191
  // Chromium based browsers (Chrome, Edge, Opera, ...)
194
192
  scrollTo({ left: 0, top: 0, behavior: 'instant' });
195
193
 
196
- if (state?.scrollY === 0 && location.hash) {
197
- const id = decodeURIComponent(location.hash.slice(1));
194
+ let initialScrollY = 0;
195
+ if (!state && loc.hash) {
196
+ const id = decodeURIComponent(loc.hash.slice(1));
198
197
  const elem = document.getElementById(id);
199
198
  // prefer scrollIntoView() over scrollTo() because it takes scroll-padding into account
200
- if (elem) {
201
- state.scrollY = elem.offsetTop;
202
- persistState(state); // first guess, later updated by scroll handler
203
- elem.scrollIntoView(); // for Firefox, this should better be {behavior: 'instant'}
204
- }
199
+ elem && (initialScrollY = elem.offsetTop) && elem.scrollIntoView();
205
200
  } else if (state && state.scrollY !== 0) {
206
201
  scrollTo(0, state.scrollY); // usings default scrollBehavior
207
202
  }
208
-
203
+ !state &&
204
+ history.pushState({ index: ++currentHistoryIndex, scrollY: initialScrollY }, '', loc.href);
209
205
  triggerEvent('astro:after-swap');
210
206
  };
211
207
 
@@ -236,8 +232,10 @@ const { fallback = 'animate' } = Astro.props as Props;
236
232
  // Trigger the animations
237
233
  const currentAnimations = document.getAnimations();
238
234
  document.documentElement.dataset.astroTransitionFallback = 'old';
239
- const newAnimations = document.getAnimations().filter(a => !currentAnimations.includes(a) && !isInfinite(a));
240
- const finished = Promise.all(newAnimations.map(a => a.finished));
235
+ const newAnimations = document
236
+ .getAnimations()
237
+ .filter((a) => !currentAnimations.includes(a) && !isInfinite(a));
238
+ const finished = Promise.all(newAnimations.map((a) => a.finished));
241
239
  const fallbackSwap = () => {
242
240
  swap();
243
241
  document.documentElement.dataset.astroTransitionFallback = 'new';
@@ -249,19 +247,26 @@ const { fallback = 'animate' } = Astro.props as Props;
249
247
  }
250
248
  }
251
249
 
252
- async function navigate(dir: Direction, href: string, state?: State) {
250
+ async function navigate(dir: Direction, loc: URL, state?: State) {
253
251
  let finished: Promise<void>;
252
+ const href = loc.href;
254
253
  const { html, ok } = await getHTML(href);
255
254
  // If there is a problem fetching the new page, just do an MPA navigation to it.
256
255
  if (!ok) {
257
256
  location.href = href;
258
257
  return;
259
258
  }
259
+ const doc = parser.parseFromString(html, 'text/html');
260
+ if (!doc.querySelector('[name="astro-view-transitions-enabled"]')) {
261
+ location.href = href;
262
+ return;
263
+ }
264
+
260
265
  document.documentElement.dataset.astroTransition = dir;
261
266
  if (supportsViewTransitions) {
262
- finished = document.startViewTransition(() => updateDOM(html, state)).finished;
267
+ finished = document.startViewTransition(() => updateDOM(doc, loc, state)).finished;
263
268
  } else {
264
- finished = updateDOM(html, state, getFallback());
269
+ finished = updateDOM(doc, loc, state, getFallback());
265
270
  }
266
271
  try {
267
272
  await finished;
@@ -313,11 +318,11 @@ const { fallback = 'animate' } = Astro.props as Props;
313
318
  ev.shiftKey || // new window
314
319
  ev.defaultPrevented ||
315
320
  !transitionEnabledOnThisPage()
316
- )
321
+ ) {
317
322
  // No page transitions in these cases,
318
323
  // Let the browser standard action handle this
319
324
  return;
320
-
325
+ }
321
326
  // We do not need to handle same page links because there are no page transitions
322
327
  // Same page means same path and same query params (but different hash)
323
328
  if (location.pathname === link.pathname && location.search === link.search) {
@@ -343,10 +348,8 @@ const { fallback = 'animate' } = Astro.props as Props;
343
348
 
344
349
  // these are the cases we will handle: same origin, different page
345
350
  ev.preventDefault();
346
- navigate('forward', link.href, { index: ++currentHistoryIndex, scrollY: 0 });
347
- const newState: State = { index: currentHistoryIndex, scrollY };
348
- persistState({ index: currentHistoryIndex - 1, scrollY });
349
- history.pushState(newState, '', link.href);
351
+ persistState({ index: currentHistoryIndex, scrollY });
352
+ navigate('forward', new URL(link.href));
350
353
  });
351
354
 
352
355
  addEventListener('popstate', (ev) => {
@@ -354,7 +357,7 @@ const { fallback = 'animate' } = Astro.props as Props;
354
357
  // The current page doesn't haven't View Transitions,
355
358
  // respect that with a full page reload
356
359
  // -- but only for transition managed by us (ev.state is set)
357
- history.scrollRestoration && (history.scrollRestoration = "manual")
360
+ history.scrollRestoration && (history.scrollRestoration = 'manual');
358
361
  location.reload();
359
362
  return;
360
363
  }
@@ -365,7 +368,7 @@ const { fallback = 'animate' } = Astro.props as Props;
365
368
  // The browser will handle navigation fine without our help
366
369
  if (ev.state === null) {
367
370
  if (history.scrollRestoration) {
368
- history.scrollRestoration = "auto";
371
+ history.scrollRestoration = 'auto';
369
372
  }
370
373
  return;
371
374
  }
@@ -373,14 +376,14 @@ const { fallback = 'animate' } = Astro.props as Props;
373
376
  // With the default "auto", the browser will jump to the old scroll position
374
377
  // before the ViewTransition is complete.
375
378
  if (history.scrollRestoration) {
376
- history.scrollRestoration = "manual";
379
+ history.scrollRestoration = 'manual';
377
380
  }
378
381
 
379
- const state: State | undefined = history.state;
380
- const nextIndex = state?.index ?? currentHistoryIndex + 1;
382
+ const state: State = history.state;
383
+ const nextIndex = state.index;
381
384
  const direction: Direction = nextIndex > currentHistoryIndex ? 'forward' : 'back';
382
- navigate(direction, location.href, state);
383
385
  currentHistoryIndex = nextIndex;
386
+ navigate(direction, new URL(location.href), state);
384
387
  });
385
388
 
386
389
  ['mouseenter', 'touchstart', 'focus'].forEach((evName) => {
@@ -404,13 +407,10 @@ const { fallback = 'animate' } = Astro.props as Props;
404
407
  addEventListener('load', onPageLoad);
405
408
  // There's not a good way to record scroll position before a back button.
406
409
  // So the way we do it is by listening to scrollend if supported, and if not continuously record the scroll position.
407
- const updateState = () => {
408
- // only update history entries that are managed by us
409
- // leave other entries alone and do not accidently add state.
410
- if (history.state) {
411
- persistState({ ...history.state, scrollY });
412
- }
413
- }
410
+ const updateState = () => {
411
+ persistState({ ...history.state, scrollY });
412
+ };
413
+
414
414
  if ('onscrollend' in window) addEventListener('scrollend', updateState);
415
415
  else addEventListener('scroll', throttle(updateState, 300));
416
416
  }
@@ -6,10 +6,11 @@ import {
6
6
  prependForwardSlash,
7
7
  removeQueryString
8
8
  } from "../core/path.js";
9
- import { VIRTUAL_MODULE_ID, VIRTUAL_SERVICE_ID } from "./consts.js";
9
+ import { VALID_INPUT_FORMATS, VIRTUAL_MODULE_ID, VIRTUAL_SERVICE_ID } from "./consts.js";
10
10
  import { emitESMImage } from "./utils/emitAsset.js";
11
11
  import { hashTransform, propsToFilename } from "./utils/transformToPath.js";
12
12
  const resolvedVirtualModuleId = "\0" + VIRTUAL_MODULE_ID;
13
+ const assetRegex = new RegExp(`.(${VALID_INPUT_FORMATS.join("|")})$`, "i");
13
14
  function assets({
14
15
  settings,
15
16
  mode
@@ -99,7 +100,7 @@ function assets({
99
100
  if (id !== removeQueryString(id)) {
100
101
  return;
101
102
  }
102
- if (/\.(jpeg|jpg|png|tiff|webp|gif|svg)$/.test(id)) {
103
+ if (assetRegex.test(id)) {
103
104
  const meta = await emitESMImage(id, this.meta.watchMode, this.emitFile);
104
105
  return `export default ${JSON.stringify(meta)}`;
105
106
  }
@@ -2,7 +2,7 @@ import whichPm from "which-pm";
2
2
  import * as msg from "../../core/messages.js";
3
3
  import { telemetry } from "../../events/index.js";
4
4
  async function notify() {
5
- const packageManager = (await whichPm(process.cwd())).name ?? "npm";
5
+ const packageManager = (await whichPm(process.cwd()))?.name ?? "npm";
6
6
  await telemetry.notify(() => {
7
7
  console.log(msg.telemetryNotice(packageManager) + "\n");
8
8
  return true;
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "3.0.9";
1
+ const ASTRO_VERSION = "3.0.11";
2
2
  const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
3
3
  ".markdown",
4
4
  ".mdown",
@@ -20,7 +20,7 @@ async function dev(inlineConfig) {
20
20
  base: restart.container.settings.config.base
21
21
  })
22
22
  );
23
- const currentVersion = "3.0.9";
23
+ const currentVersion = "3.0.11";
24
24
  if (currentVersion.includes("-")) {
25
25
  logger.warn(null, msg.prerelease({ currentVersion }));
26
26
  }
@@ -50,7 +50,7 @@ function serverStart({
50
50
  base,
51
51
  isRestart = false
52
52
  }) {
53
- const version = "3.0.9";
53
+ const version = "3.0.11";
54
54
  const localPrefix = `${dim("\u2503")} Local `;
55
55
  const networkPrefix = `${dim("\u2503")} Network `;
56
56
  const emptyPrefix = " ".repeat(11);
@@ -235,7 +235,7 @@ function printHelp({
235
235
  message.push(
236
236
  linebreak(),
237
237
  ` ${bgGreen(black(` ${commandName} `))} ${green(
238
- `v${"3.0.9"}`
238
+ `v${"3.0.11"}`
239
239
  )} ${headline}`
240
240
  );
241
241
  }
@@ -16,6 +16,8 @@ async function renderChild(destination, child) {
16
16
  });
17
17
  });
18
18
  for (const childRender of childRenders) {
19
+ if (!childRender)
20
+ continue;
19
21
  await childRender.renderToFinalDestination(destination);
20
22
  }
21
23
  } else if (typeof child === "function") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "3.0.9",
3
+ "version": "3.0.11",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -159,7 +159,7 @@
159
159
  "yargs-parser": "^21.1.1",
160
160
  "zod": "3.21.1",
161
161
  "@astrojs/internal-helpers": "0.2.0",
162
- "@astrojs/markdown-remark": "3.0.0",
162
+ "@astrojs/markdown-remark": "3.1.0",
163
163
  "@astrojs/telemetry": "3.0.1"
164
164
  },
165
165
  "optionalDependencies": {