Compare commits

...

17 commits

Author SHA1 Message Date
Martin Trapp
068e618cb9 Fix head swap for persisted client:only components (dev mode) 2023-10-04 18:06:32 +02:00
Bjorn Lu
85cc8daff8 Remove unused CSS output files when inlined (#8743) 2023-10-04 18:06:32 +02:00
bluwy
9ed7da1e3b [ci] format 2023-10-04 18:06:32 +02:00
Arsh
d50aaea36d chore: remove undici polyfill (#8729) 2023-10-04 18:06:32 +02:00
bluwy
05833ab44e [ci] format 2023-10-04 18:06:32 +02:00
Chris
6bba4efb3f Fixes: Shiki syntax highlighting adds is:raw attribute to the HTML output (#8715)
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
2023-10-04 18:06:32 +02:00
Kobe Ruado
a3ebad84a8 Fix markdown rehype plugin example (#8733) 2023-10-04 18:06:31 +02:00
natemoo-re
4e2c65c27c [ci] format 2023-10-04 18:06:31 +02:00
Nate Moore
9c7cd7c9f6 Improve astro info compatability (#8730)
* Improve `astro info` compatability

* Update packages/astro/src/cli/info/index.ts

Co-authored-by: Arsh <69170106+lilnasy@users.noreply.github.com>

* chore: add changeset

* feat(info): add copy to clipboard support on Unix machines with xclip installed

---------

Co-authored-by: Arsh <69170106+lilnasy@users.noreply.github.com>
2023-10-04 18:06:31 +02:00
Florian Lefebvre
49cbbf8d23 feat: expose partytown types (close #8723) (#8740) 2023-10-04 18:06:31 +02:00
Emanuele Stoppa
8eed6cc7ac feat: add provenance to packages (#8737) 2023-10-04 18:06:31 +02:00
Bjorn Lu
cb62f02ea1 Fix tsconfig.json update causing the server to crash (#8736) 2023-10-04 18:06:31 +02:00
Genteure
d125095d09 fix: typo in error deprecation message (#8708)
Co-authored-by: Alexander Niebuhr <alexander@nbhr.io>
2023-10-04 18:06:31 +02:00
Martin Trapp
365adee6f6
Merge branch 'main' into mt/client-only 2023-10-02 18:18:26 +02:00
Martin Trapp
20c1b3b0d0 Fix view transitions with client:only components 2023-10-02 18:02:41 +02:00
Martin Trapp
84d1f05964 Fix view transitions with client:only components 2023-10-02 17:16:00 +02:00
Martin Trapp
363f80011b Fix view transitions with client:only components 2023-10-02 16:41:23 +02:00
50 changed files with 350 additions and 171 deletions

View file

@ -0,0 +1,5 @@
---
'@astrojs/markdown-remark': patch
---
Remove `is:raw` from remark Shiki plugin

View file

@ -0,0 +1,25 @@
---
'@astrojs/cloudflare': patch
'@astrojs/partytown': patch
'@astrojs/alpinejs': patch
'@astrojs/prefetch': patch
'@astrojs/tailwind': patch
'@astrojs/markdoc': patch
'@astrojs/sitemap': patch
'@astrojs/underscore-redirects': patch
'@astrojs/preact': patch
'@astrojs/svelte': patch
'@astrojs/vercel': patch
'@astrojs/react': patch
'@astrojs/solid-js': patch
'@astrojs/node': patch
'@astrojs/lit': patch
'@astrojs/mdx': patch
'@astrojs/vue': patch
'@astrojs/internal-helpers': patch
'@astrojs/markdown-remark': patch
'@astrojs/telemetry': patch
'astro': patch
---
Add provenance statement when publishing the library from CI

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix view transitions with client:only components

View file

@ -0,0 +1,5 @@
---
'@astrojs/telemetry': patch
---
Removed an unnecessary dependency.

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix `tsconfig.json` update causing the server to crash

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Remove unused CSS output files when inlined

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Node-based adapters now create less server-side javascript

View file

@ -0,0 +1,5 @@
---
'@astrojs/partytown': patch
---
Expose types for TypeScript users

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Improve `astro info` copy to clipboard compatability

View file

@ -3,7 +3,6 @@
// ISOMORPHIC FILE: NO TOP-LEVEL IMPORT/REQUIRE() ALLOWED
// This file has to run as both ESM and CJS on older Node.js versions
// Needed for Stackblitz: https://github.com/stackblitz/webcontainer-core/issues/281
const CI_INSTRUCTIONS = {
NETLIFY: 'https://docs.netlify.com/configure-builds/manage-dependencies/#node-js-and-javascript',
@ -16,15 +15,11 @@ const CI_INSTRUCTIONS = {
const engines = '>=18.14.1';
const skipSemverCheckIfAbove = 19;
// HACK (2023-08-18) Stackblitz does not support Node 18 yet, so we'll fake Node 16 support for some time until it's supported
// TODO: Remove when Node 18 is supported on Stackblitz
const isStackblitz = process.env.SHELL === '/bin/jsh' && process.versions.webcontainer != null;
/** `astro *` */
async function main() {
const version = process.versions.node;
// Fast-path for higher Node.js versions
if (!isStackblitz && (parseInt(version) || 0) <= skipSemverCheckIfAbove) {
if ((parseInt(version) || 0) <= skipSemverCheckIfAbove) {
try {
const semver = await import('semver');
if (!semver.satisfies(version, engines)) {

View file

@ -3,6 +3,7 @@ import Layout from '../components/Layout.astro';
import Island from '../components/Island';
---
<Layout>
<p id="page-one">Page 1</p>
<a id="click-two" href="/client-only-two">go to page 2</a>
<div transition:persist="island">
<Island client:only count={5}>message here</Island>

View file

@ -4,6 +4,7 @@ import Island from '../components/Island';
---
<Layout>
<p id="page-two">Page 2</p>
<a id="click-one" href="/client-only-one">go to page 1</a>
<div transition:persist="island">
<Island client:only count={5}>message here</Island>
</div>

View file

@ -649,9 +649,14 @@ test.describe('View Transitions', () => {
});
test('client:only styles are retained on transition', async ({ page, astro }) => {
const loads = [];
page.addListener('load', async (p) => {
loads.push(p);
});
const totalExpectedStyles = 7;
// Go to page 1
// Go to page 1 (normal load)
await page.goto(astro.resolveUrl('/client-only-one'));
let msg = page.locator('.counter-message');
await expect(msg).toHaveText('message here');
@ -659,13 +664,24 @@ test.describe('View Transitions', () => {
let styles = await page.locator('style').all();
expect(styles.length).toEqual(totalExpectedStyles);
// Transition to page 2 (will do a full load)
await page.click('#click-two');
let pageTwo = page.locator('#page-two');
await expect(pageTwo, 'should have content').toHaveText('Page 2');
// Transition to page 1 (will do a full load)
await page.click('#click-one');
let pageOne = page.locator('#page-one');
await expect(pageOne, 'should have content').toHaveText('Page 1');
// Transition to page 1 (real transition, no full load)
await page.click('#click-two');
styles = await page.locator('style').all();
expect(styles.length).toEqual(totalExpectedStyles, 'style count has not changed');
expect(loads.length, 'There should only be 1 page load').toEqual(3);
});
test('Horizontal scroll position restored on back button', async ({ page, astro }) => {

View file

@ -168,7 +168,6 @@
"string-width": "^6.1.0",
"strip-ansi": "^7.1.0",
"tsconfig-resolver": "^3.0.1",
"undici": "^5.23.0",
"unist-util-visit": "^4.1.2",
"vfile": "^5.3.7",
"vite": "^4.4.9",
@ -226,5 +225,8 @@
"engines": {
"node": ">=18.14.1",
"npm": ">=6.14.0"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -1168,10 +1168,10 @@ export interface AstroUserConfig {
* Pass [rehype plugins](https://github.com/remarkjs/remark-rehype) to customize how your Markdown's output HTML is processed. You can import and apply the plugin function (recommended), or pass the plugin name as a string.
*
* ```js
* import rehypeMinifyHtml from 'rehype-minify';
* import { rehypeAccessibleEmojis } from 'rehype-accessible-emojis';
* {
* markdown: {
* rehypePlugins: [rehypeMinifyHtml]
* rehypePlugins: [rehypeAccessibleEmojis]
* }
* }
* ```

View file

@ -41,10 +41,22 @@ export async function printInfo({ flags }: InfoOptions) {
await copyToClipboard(output.trim());
}
const SUPPORTED_SYSTEM = new Set(['darwin', 'win32']);
async function copyToClipboard(text: string) {
const system = platform();
if (!SUPPORTED_SYSTEM.has(system)) return;
let command = '';
if (system === 'darwin') {
command = 'pbcopy';
} else if (system === 'win32') {
command = 'clip';
} else {
// Unix: check if `xclip` is installed
const output = execSync('which xclip', { encoding: 'utf8' });
if (output[0] !== '/') {
// Did not find a path for xclip, bail out!
return;
}
command = 'xclip -sel clipboard -l 1';
}
console.log();
const { shouldCopy } = await prompts({
@ -54,11 +66,11 @@ async function copyToClipboard(text: string) {
initial: true,
});
if (!shouldCopy) return;
const command = system === 'darwin' ? 'pbcopy' : 'clip';
try {
execSync(`echo ${JSON.stringify(text.trim())} | ${command}`, {
execSync(command, {
input: text.trim(),
encoding: 'utf8',
stdio: 'ignore',
});
} catch (e) {
console.error(

View file

@ -148,9 +148,15 @@ export const _internal = {
hasContentFlag(modUrl, DATA_FLAG) ||
Boolean(getContentRendererByViteId(modUrl, settings))
) {
const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
if (mod) {
viteServer.moduleGraph.invalidateModule(mod);
try {
const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
if (mod) {
viteServer.moduleGraph.invalidateModule(mod);
}
} catch (e: any) {
// The server may be closed due to a restart caused by this file change
if (e.code === 'ERR_CLOSED_SERVER') break;
throw e;
}
}
}

View file

@ -200,7 +200,7 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
const inlineConfig = settings.config.build.inlineStylesheets;
const { assetsInlineLimit = 4096 } = settings.config.vite?.build ?? {};
Object.entries(bundle).forEach(([_, stylesheet]) => {
Object.entries(bundle).forEach(([id, stylesheet]) => {
if (
stylesheet.type !== 'asset' ||
stylesheet.name?.endsWith('.css') !== true ||
@ -224,10 +224,15 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
: { type: 'external', src: stylesheet.fileName };
const pages = Array.from(eachPageData(internals));
let sheetAddedToPage = false;
pages.forEach((pageData) => {
const orderingInfo = pagesToCss[pageData.moduleSpecifier]?.[stylesheet.fileName];
if (orderingInfo !== undefined) return pageData.styles.push({ ...orderingInfo, sheet });
if (orderingInfo !== undefined) {
pageData.styles.push({ ...orderingInfo, sheet });
sheetAddedToPage = true;
return;
}
const propagatedPaths = pagesToPropagatedCss[pageData.moduleSpecifier];
if (propagatedPaths === undefined) return;
@ -243,8 +248,21 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
pageData.propagatedStyles.set(pageInfoId, new Set()).get(pageInfoId)!;
propagatedStyles.add(sheet);
sheetAddedToPage = true;
});
});
if (toBeInlined && sheetAddedToPage) {
// CSS is already added to all used pages, we can delete it from the bundle
// and make sure no chunks reference it via `importedCss` (for Vite preloading)
// to avoid duplicate CSS.
delete bundle[id];
for (const chunk of Object.values(bundle)) {
if (chunk.type === 'chunk') {
chunk.viteMetadata?.importedCss?.delete(id);
}
}
}
});
},
};

View file

@ -39,7 +39,6 @@ export function createAPIContext({
props,
adapterName,
}: CreateAPIContext): APIContext {
initResponseWithEncoding();
const context = {
cookies: new AstroCookies(request),
request,
@ -92,44 +91,28 @@ export function createAPIContext({
type ResponseParameters = ConstructorParameters<typeof Response>;
export let ResponseWithEncoding: ReturnType<typeof initResponseWithEncoding>;
// TODO Remove this after StackBlitz supports Node 18.
let initResponseWithEncoding = () => {
class LocalResponseWithEncoding extends Response {
constructor(
body: ResponseParameters[0],
init: ResponseParameters[1],
encoding?: BufferEncoding
) {
// If a body string is given, try to encode it to preserve the behaviour as simple objects.
// We don't do the full handling as simple objects so users can control how headers are set instead.
if (typeof body === 'string') {
// In NodeJS, we can use Buffer.from which supports all BufferEncoding
if (typeof Buffer !== 'undefined' && Buffer.from) {
body = Buffer.from(body, encoding);
}
// In non-NodeJS, use the web-standard TextEncoder for utf-8 strings
else if (encoding == null || encoding === 'utf8' || encoding === 'utf-8') {
body = encoder.encode(body);
}
export class ResponseWithEncoding extends Response {
constructor(body: ResponseParameters[0], init: ResponseParameters[1], encoding?: BufferEncoding) {
// If a body string is given, try to encode it to preserve the behaviour as simple objects.
// We don't do the full handling as simple objects so users can control how headers are set instead.
if (typeof body === 'string') {
// In NodeJS, we can use Buffer.from which supports all BufferEncoding
if (typeof Buffer !== 'undefined' && Buffer.from) {
body = Buffer.from(body, encoding);
}
super(body, init);
if (encoding) {
this.headers.set('X-Astro-Encoding', encoding);
// In non-NodeJS, use the web-standard TextEncoder for utf-8 strings
else if (encoding == null || encoding === 'utf8' || encoding === 'utf-8') {
body = encoder.encode(body);
}
}
super(body, init);
if (encoding) {
this.headers.set('X-Astro-Encoding', encoding);
}
}
// Set the module scoped variable.
ResponseWithEncoding = LocalResponseWithEncoding;
// Turn this into a noop.
initResponseWithEncoding = (() => {}) as any;
return LocalResponseWithEncoding;
};
}
export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>(
mod: EndpointHandler,

View file

@ -1158,7 +1158,7 @@ export const ContentSchemaContainsSlugError = {
/**
* @docs
* @message A collection queried via `getCollection()` does not exist.
* @deprecated Collections that do not exist no longer result in an error. A warning is omitted instead.
* @deprecated Collections that do not exist no longer result in an error. A warning is given instead.
* @description
* When querying a collection, ensure a collection directory with the requested name exists under `src/content/`.
*/

View file

@ -1,19 +1,52 @@
import { EventEmitter } from 'node:events';
import path from 'node:path';
import type * as vite from 'vite';
import type { ModuleLoader, ModuleLoaderEventEmitter } from './loader.js';
export function createViteLoader(viteServer: vite.ViteDevServer): ModuleLoader {
const events = new EventEmitter() as ModuleLoaderEventEmitter;
viteServer.watcher.on('add', (...args) => events.emit('file-add', args));
viteServer.watcher.on('unlink', (...args) => events.emit('file-unlink', args));
viteServer.watcher.on('change', (...args) => events.emit('file-change', args));
let isTsconfigUpdated = false;
function isTsconfigUpdate(filePath: string) {
const result = path.basename(filePath) === 'tsconfig.json';
if (result) isTsconfigUpdated = true;
return result;
}
wrapMethod(viteServer.ws, 'send', (msg) => {
// Skip event emit on tsconfig change as Vite restarts the server, and we don't
// want to trigger unnecessary work that will be invalidated shortly.
viteServer.watcher.on('add', (...args) => {
if (!isTsconfigUpdate(args[0])) {
events.emit('file-add', args);
}
});
viteServer.watcher.on('unlink', (...args) => {
if (!isTsconfigUpdate(args[0])) {
events.emit('file-unlink', args);
}
});
viteServer.watcher.on('change', (...args) => {
if (!isTsconfigUpdate(args[0])) {
events.emit('file-change', args);
}
});
const _wsSend = viteServer.ws.send;
viteServer.ws.send = function (...args: any) {
// If the tsconfig changed, Vite will trigger a reload as it invalidates the module.
// However in Astro, the whole server is restarted when the tsconfig changes. If we
// do a restart and reload at the same time, the browser will refetch and the server
// is not ready yet, causing a blank page. Here we block that reload from happening.
if (isTsconfigUpdated) {
isTsconfigUpdated = false;
return;
}
const msg = args[0] as vite.HMRPayload;
if (msg?.type === 'error') {
events.emit('hmr-error', msg);
}
});
_wsSend.apply(this, args);
};
return {
import(src) {
@ -56,11 +89,3 @@ export function createViteLoader(viteServer: vite.ViteDevServer): ModuleLoader {
events,
};
}
function wrapMethod(object: any, method: string, newFn: (...args: any[]) => void) {
const orig = object[method];
object[method] = function (...args: any[]) {
newFn.apply(this, args);
return orig.apply(this, args);
};
}

View file

@ -1,63 +1,7 @@
import buffer from 'node:buffer';
import crypto from 'node:crypto';
import {
ByteLengthQueuingStrategy,
CountQueuingStrategy,
ReadableByteStreamController,
ReadableStream,
ReadableStreamBYOBReader,
ReadableStreamBYOBRequest,
ReadableStreamDefaultController,
ReadableStreamDefaultReader,
TransformStream,
WritableStream,
WritableStreamDefaultController,
WritableStreamDefaultWriter,
} from 'node:stream/web';
import { File, FormData, Headers, Request, Response, fetch } from 'undici';
// NOTE: This file does not intend to polyfill everything that exists, its main goal is to make life easier
// for users deploying to runtime that do support these features. In the future, we hope for this file to disappear.
// HACK (2023-08-18) Stackblitz does not support Node 18 yet, so we'll fake Node 16 support for some time until it's supported
// TODO: Remove when Node 18 is supported on Stackblitz. File should get imported from `node:buffer` instead of `undici` once this is removed
const isStackblitz = process.env.SHELL === '/bin/jsh' && process.versions.webcontainer != null;
export function apply() {
if (isStackblitz) {
const neededPolyfills = {
ByteLengthQueuingStrategy,
CountQueuingStrategy,
ReadableByteStreamController,
ReadableStream,
ReadableStreamBYOBReader,
ReadableStreamBYOBRequest,
ReadableStreamDefaultController,
ReadableStreamDefaultReader,
TransformStream,
WritableStream,
WritableStreamDefaultController,
WritableStreamDefaultWriter,
File,
FormData,
Headers,
Request,
Response,
fetch,
};
for (let polyfillName of Object.keys(neededPolyfills)) {
if (Object.hasOwnProperty.call(globalThis, polyfillName)) continue;
// Add polyfill to globalThis
Object.defineProperty(globalThis, polyfillName, {
configurable: true,
enumerable: true,
writable: true,
value: neededPolyfills[polyfillName as keyof typeof neededPolyfills],
});
}
}
// Remove when Node 18 is dropped for Node 20
if (!globalThis.crypto) {
Object.defineProperty(globalThis, 'crypto', {
@ -68,7 +12,7 @@ export function apply() {
// Remove when Node 18 is dropped for Node 20
if (!globalThis.File) {
Object.defineProperty(globalThis, 'File', {
value: File,
value: buffer.File,
});
}
}

View file

@ -10,6 +10,15 @@ type State = {
};
type Events = 'astro:page-load' | 'astro:after-swap';
let viteDevIds: { static: Record<string, string[]>; dynamic: Record<string, string[]> };
if (import.meta.env.DEV) {
// viteDevIds on a page
viteDevIds = JSON.parse(
sessionStorage.getItem('astro:viteDevIds') || '{"static":{},"dynamic":{}}'
);
}
const page = (url: { origin: string; pathname: string }) => url.origin + url.pathname;
// only update history entries that are managed by us
// leave other entries alone and do not accidently add state.
const persistState = (state: State) => history.state && history.replaceState(state, '');
@ -44,8 +53,10 @@ const PERSIST_ATTR = 'data-astro-transition-persist';
const parser = new DOMParser();
// explained at its usage
let noopEl: HTMLDivElement;
let reloadEl: HTMLDivElement;
if (import.meta.env.DEV) {
noopEl = document.createElement('div');
reloadEl = document.createElement('div');
}
// The History API does not tell you if navigation is forward or back, so
@ -198,20 +209,40 @@ async function updateDOM(
const href = el.getAttribute('href');
return newDocument.head.querySelector(`link[rel=stylesheet][href="${href}"]`);
}
// What follows is a fix for an issue (#8472) with missing client:only styles after transition.
// That problem exists only in dev mode where styles are injected into the page by Vite.
// Returning a noop element ensures that the styles are not removed from the old document.
// Guarding the code below with the dev mode check
// allows tree shaking to remove this code in production.
if (import.meta.env.DEV) {
if (el.tagName === 'STYLE' && el.dataset.viteDevId) {
const devId = el.dataset.viteDevId;
// If this same style tag exists, remove it from the new page
return (
newDocument.querySelector(`style[data-vite-dev-id="${devId}"]`) ||
// Otherwise, keep it anyways. This is client:only styles.
noopEl
);
const viteDevId = el.getAttribute('data-vite-dev-id');
if (!viteDevId) {
return null;
}
const newDevEl = newDocument.head.querySelector(`[data-vite-dev-id="${viteDevId}"]`);
if (newDevEl) {
return newDevEl;
}
// What follows is a fix for an issue (#8472) with missing client:only styles after transition.
// That problem exists only in dev mode where styles are injected into the page by Vite.
// Returning a noop element ensures that the styles are not removed from the old document.
// Guarding the code below with the dev mode check
// allows tree shaking to remove this code in production.
if (
document.querySelector(
`[${PERSIST_ATTR}] astro-island[client="only"], astro-island[client="only"][${PERSIST_ATTR}]`
)
) {
const here = page(toLocation);
const dynamicViteDevIds = viteDevIds.dynamic[here];
if (!dynamicViteDevIds) {
console.info(`
${toLocation.pathname}
Development mode only: This page uses view transitions with persisted client:only Astro islands.
On the first transition to this page, Astro did a full page reload to capture the dynamic effects of the client only code.
`);
location.href = toLocation.href;
return reloadEl;
}
if (dynamicViteDevIds?.includes(viteDevId)) {
return noopEl;
}
}
}
return null;
@ -249,12 +280,16 @@ async function updateDOM(
// Swap head
for (const el of Array.from(document.head.children)) {
const newEl = persistedHeadElement(el as HTMLElement);
if (newEl === reloadEl) {
return;
}
// If the element exists in the document already, remove it
// from the new document and leave the current node alone
if (newEl) {
newEl.remove();
} else {
// Otherwise remove the element in the head. It doesn't exist in the new page.
// Otherwise remove the element from the head.
// It doesn't exist in the new page or will be re-inserted after this loop
el.remove();
}
}
@ -336,6 +371,20 @@ async function transition(
options: Options,
popState?: State
) {
if (import.meta.env.DEV) {
const thisPageStaticViteDevIds = viteDevIds.static[page(location)];
if (thisPageStaticViteDevIds) {
const allViteDevIds = new Set<string>();
document.head
.querySelectorAll('[data-vite-dev-id]')
.forEach((el) => allViteDevIds.add(el.getAttribute('data-vite-dev-id')!));
viteDevIds.dynamic[page(location)] = [...allViteDevIds].filter(
(x) => !thisPageStaticViteDevIds.includes(x)
);
sessionStorage.setItem('astro:viteDevIds', JSON.stringify(viteDevIds, null, 2));
}
}
let finished: Promise<void>;
const href = toLocation.href;
const response = await fetchHTML(href);
@ -360,6 +409,14 @@ async function transition(
location.href = href;
return;
}
if (import.meta.env.DEV) {
const staticViteDevIds = new Set<string>();
newDocument.querySelectorAll('head > [data-vite-dev-id]').forEach((el) => {
staticViteDevIds.add(el.getAttribute('data-vite-dev-id')!);
});
viteDevIds.static[page(toLocation)] = [...staticViteDevIds];
sessionStorage.setItem('astro:viteDevIds', JSON.stringify(viteDevIds, null, 2));
}
if (!popState) {
// save the current scroll position before we change the DOM and transition to the new page

View file

@ -170,7 +170,7 @@ export async function loadFixture(inlineConfig) {
try {
return await fetch(resolvedUrl, init);
} catch (err) {
// undici throws a vague error when it fails, so we log the url here to easily debug it
// node fetch throws a vague error when it fails, so we log the url here to easily debug it
if (err.message?.includes('fetch failed')) {
console.error(`[astro test] failed to fetch ${resolvedUrl}`);
console.error(err);

View file

@ -39,5 +39,8 @@
"devDependencies": {
"astro": "workspace:*",
"astro-scripts": "workspace:*"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -58,5 +58,8 @@
"cheerio": "1.0.0-rc.12",
"mocha": "^10.2.0",
"wrangler": "^3.5.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -59,5 +59,8 @@
"peerDependencies": {
"@webcomponents/template-shadowroot": "^0.2.1",
"lit": "^2.7.0"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -94,5 +94,8 @@
},
"engines": {
"node": ">=18.14.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -79,5 +79,8 @@
},
"engines": {
"node": ">=18.14.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -49,7 +49,9 @@
"cheerio": "1.0.0-rc.12",
"express": "^4.18.2",
"mocha": "^10.2.0",
"node-mocks-http": "^1.13.0",
"undici": "^5.23.0"
"node-mocks-http": "^1.13.0"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -8,15 +8,12 @@ import type { OutgoingHttpHeaders } from 'node:http';
* @returns NodeJS OutgoingHttpHeaders object with multiple set-cookie handled as an array of values
*/
export const createOutgoingHttpHeaders = (
webHeaders: Headers | undefined | null
headers: Headers | undefined | null
): OutgoingHttpHeaders | undefined => {
if (!webHeaders) {
if (!headers) {
return undefined;
}
// re-type to access Header.getSetCookie()
const headers = webHeaders as HeadersWithGetSetCookie;
// at this point, a multi-value'd set-cookie header is invalid (it was concatenated as a single CSV, which is not valid for set-cookie)
const nodeHeaders: OutgoingHttpHeaders = Object.fromEntries(headers.entries());
@ -26,7 +23,8 @@ export const createOutgoingHttpHeaders = (
// if there is > 1 set-cookie header, we have to fix it to be an array of values
if (headers.has('set-cookie')) {
const cookieHeaders = headers.getSetCookie();
// @ts-expect-error
const cookieHeaders = headers.getSetCookie() as string[];
if (cookieHeaders.length > 1) {
// the Headers.entries() API already normalized all header names to lower case so we can safely index this as 'set-cookie'
nodeHeaders['set-cookie'] = cookieHeaders;
@ -35,8 +33,3 @@ export const createOutgoingHttpHeaders = (
return nodeHeaders;
};
interface HeadersWithGetSetCookie extends Headers {
// the @astrojs/webapi polyfill makes this available (as of undici@5.19.0), but tsc doesn't pick it up on the built-in Headers type from DOM lib
getSetCookie(): string[];
}

View file

@ -38,5 +38,8 @@
"devDependencies": {
"astro": "workspace:*",
"astro-scripts": "workspace:*"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -9,7 +9,7 @@ import { fileURLToPath } from 'node:url';
import sirv from './sirv.js';
const resolve = createRequire(import.meta.url).resolve;
type PartytownOptions = {
export type PartytownOptions = {
config?: PartytownConfig;
};

View file

@ -52,5 +52,8 @@
},
"engines": {
"node": ">=18.14.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -40,5 +40,8 @@
},
"dependencies": {
"throttles": "^1.0.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -67,5 +67,8 @@
},
"engines": {
"node": ">=18.14.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -43,5 +43,8 @@
"chai": "^4.3.7",
"mocha": "^10.2.0",
"xml2js": "0.6.2"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -47,5 +47,8 @@
},
"engines": {
"node": ">=18.14.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -53,5 +53,8 @@
},
"engines": {
"node": ">=18.14.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -45,5 +45,8 @@
"peerDependencies": {
"astro": "workspace:^3.2.2",
"tailwindcss": "^3.0.24"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -72,5 +72,8 @@
"chai-jest-snapshot": "^2.0.0",
"cheerio": "1.0.0-rc.12",
"mocha": "^10.2.0"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -61,5 +61,8 @@
},
"engines": {
"node": ">=18.14.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -37,5 +37,8 @@
"keywords": [
"astro",
"astro-component"
]
],
"publishConfig": {
"provenance": true
}
}

View file

@ -57,5 +57,8 @@
"chai": "^4.3.7",
"mdast-util-mdx-expression": "^1.3.2",
"mocha": "^10.2.0"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -76,8 +76,8 @@ export function remarkShiki({
// It would become this before hitting our regexes:
// &lt;span class=&quot;line&quot;
// Replace "shiki" class naming with "astro" and add "is:raw".
html = html.replace(/<pre class="(.*?)shiki(.*?)"/, `<pre is:raw class="$1astro-code$2"`);
// Replace "shiki" class naming with "astro".
html = html.replace(/<pre class="(.*?)shiki(.*?)"/, `<pre class="$1astro-code$2"`);
// Add "user-select: none;" for "+"/"-" diff symbols
if (node.lang === 'diff') {
html = html.replace(

View file

@ -0,0 +1,12 @@
import { createMarkdownProcessor } from '../dist/index.js';
import chai from 'chai';
describe('shiki syntax highlighting', async () => {
const processor = await createMarkdownProcessor();
it('does not add is:raw to the output', async () => {
const { code } = await processor.render('```\ntest\n```');
chai.expect(code).not.to.contain('is:raw');
});
});

View file

@ -35,7 +35,6 @@
"dset": "^3.1.2",
"is-docker": "^3.0.0",
"is-wsl": "^3.0.0",
"undici": "^5.23.0",
"which-pm-runs": "^1.1.0"
},
"devDependencies": {
@ -49,5 +48,8 @@
},
"engines": {
"node": ">=18.14.1"
},
"publishConfig": {
"provenance": true
}
}

View file

@ -1,5 +1,4 @@
const ASTRO_TELEMETRY_ENDPOINT = `https://telemetry.astro.build/api/v1/record`;
import { fetch } from 'undici';
export function post(body: Record<string, any>): Promise<any> {
return fetch(ASTRO_TELEMETRY_ENDPOINT, {

View file

@ -38,5 +38,8 @@
"keywords": [
"astro",
"astro-component"
]
],
"publishConfig": {
"provenance": true
}
}

View file

@ -628,9 +628,6 @@ importers:
tsconfig-resolver:
specifier: ^3.0.1
version: 3.0.1
undici:
specifier: ^5.23.0
version: 5.23.0
unist-util-visit:
specifier: ^4.1.2
version: 4.1.2
@ -4307,9 +4304,6 @@ importers:
node-mocks-http:
specifier: ^1.13.0
version: 1.13.0
undici:
specifier: ^5.23.0
version: 5.23.0
packages/integrations/node/test/fixtures/api-route:
dependencies:
@ -5005,9 +4999,6 @@ importers:
is-wsl:
specifier: ^3.0.0
version: 3.0.0
undici:
specifier: ^5.23.0
version: 5.23.0
which-pm-runs:
specifier: ^1.1.0
version: 1.1.0
@ -17276,6 +17267,7 @@ packages:
engines: {node: '>=14.0'}
dependencies:
busboy: 1.6.0
dev: true
/unherit@3.0.1:
resolution: {integrity: sha512-akOOQ/Yln8a2sgcLj4U0Jmx0R5jpIg2IUyRrWOzmEbjBtGzBdHtSeFKgoEcoH4KYIG/Pb8GQ/BwtYm0GCq1Sqg==}