Skip to content

Commit

Permalink
Merge branch 'main' into patch-images
Browse files Browse the repository at this point in the history
  • Loading branch information
Rishi Raj Jain authored Apr 16, 2024
2 parents 465f6a9 + a92e263 commit 7060fbd
Show file tree
Hide file tree
Showing 23 changed files with 416 additions and 79 deletions.
5 changes: 5 additions & 0 deletions .changeset/afraid-laws-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"astro": patch
---

Correctly sets `build.assets` directory during `vite` config setup
5 changes: 5 additions & 0 deletions .changeset/eight-hotels-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"astro": patch
---

Disables streaming when rendering site with `output: "static"`
5 changes: 5 additions & 0 deletions .changeset/famous-seals-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@astrojs/sitemap": patch
---

Improves performance when generating the sitemap data
3 changes: 2 additions & 1 deletion packages/astro/src/core/build/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export class BuildPipeline extends Pipeline {
return assetLink;
}
const serverLike = isServerLikeOutput(config);
const streaming = true;
// We can skip streaming in SSG for performance as writing as strings are faster
const streaming = serverLike;
super(
options.logger,
manifest,
Expand Down
1 change: 1 addition & 0 deletions packages/astro/src/core/create-vite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ export async function createVite(
noExternal: [...ALWAYS_NOEXTERNAL, ...astroPkgsConfig.ssr.noExternal],
external: [...(mode === 'dev' ? ONLY_DEV_EXTERNAL : []), ...astroPkgsConfig.ssr.external],
},
build: { assetsDir: settings.config.build.assets },
};

// If the user provides a custom assets prefix, make sure assets handled by Vite
Expand Down
4 changes: 4 additions & 0 deletions packages/astro/src/runtime/server/render/astro/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export async function renderToString(
let str = '';
let renderedFirstPageChunk = false;

if (isPage) {
await bufferHeadContent(result);
}

const destination: RenderDestination = {
write(chunk) {
// Automatic doctype insertion for pages
Expand Down
36 changes: 36 additions & 0 deletions packages/astro/test/astro-assets-dir.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import assert from 'node:assert/strict';
import { before, describe, it } from 'node:test';
import { loadFixture } from './test-utils.js';

describe('assets dir takes the URL path inside the output directory', () => {
/** @type {URL} */
let checkDir;
before(async () => {
const fixture = await loadFixture({
root: './fixtures/astro-assets-dir/',
build: {
assets: 'custom_dir_1',
},
integrations: [
{
name: '@astrojs/dir',
hooks: {
'astro:build:done': ({ dir }) => {
checkDir = dir;
},
},
},
],
});
await fixture.build();
});
it('generates the assets directory as per build.assets configuration', async () => {
const removeTrailingSlash = (str) => str.replace(/\/$/, '');
assert.equal(
removeTrailingSlash(new URL('./custom_dir_1', checkDir).toString()),
removeTrailingSlash(
new URL('./fixtures/astro-assets-dir/dist/custom_dir_1', import.meta.url).toString()
)
);
});
});
6 changes: 1 addition & 5 deletions packages/astro/test/content-collections-render.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ import * as assert from 'node:assert/strict';
import { after, before, describe, it } from 'node:test';
import * as cheerio from 'cheerio';
import testAdapter from './test-adapter.js';
import { isWindows, loadFixture } from './test-utils.js';

if (!isWindows) {
describe();
}
import { loadFixture } from './test-utils.js';

describe('Content Collections - render()', () => {
describe('Build - SSG', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import react from '@astrojs/react';
import { defineConfig } from 'astro/config';

// https://astro.build/config
export default defineConfig({
integrations: [react()],
});
11 changes: 11 additions & 0 deletions packages/astro/test/fixtures/astro-assets-dir/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "@test/astro-assets-dir",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/react": "workspace:*",
"astro": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, { useState } from 'react';

export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<div>Count: {count}</div>
<button type="button" onClick={() => setCount(count+1)}>Increment</button>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
title: My Post
cover: ../../assets/penguin1.jpg
---

Hello world
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { defineCollection, z } from "astro:content";

const blogCollection = defineCollection({
schema: ({image}) => z.object({
title: z.string(),
cover: image(),
}),
});

export const collections = {
blog: blogCollection,
};
16 changes: 16 additions & 0 deletions packages/astro/test/fixtures/astro-assets-dir/src/pages/blog.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
import { Image } from "astro:assets";
import { getCollection } from "astro:content";
const allBlogPosts = await getCollection("blog");
---

{
allBlogPosts.map((post) => (
<div>
<Image src={post.data.cover} alt="cover" width="100" height="100" />
<h2>
<a href={"/blog/" + post.slug}>{post.data.title}</a>
</h2>
</div>
))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
import { Image } from 'astro:assets'
import p1Image from '../assets/penguin1.jpg';
import Counter from '../components/Counter.jsx';
---

<html lang="en">
<head>
<title>Assets Prefix</title>
</head>
<body>
<h1>I am red</h1>
<img id="image-asset" src={p1Image.src} width={p1Image.width} height={p1Image.height} alt="penguin" />
<Image src={p1Image} alt="penguin" />
<Counter client:load />
<p id="assets-prefix-env">{typeof import.meta.env.ASSETS_PREFIX === 'string' ? import.meta.env.ASSETS_PREFIX : JSON.stringify(import.meta.env.ASSETS_PREFIX)}</p>
<style>
h1 {
color: red;
}
</style>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Assets Prefix

Relative image has assetsPrefix

![Relative image](../assets/penguin1.jpg)

![non-UTF-8 file name image](../assets/ペンギン.jpg)
94 changes: 60 additions & 34 deletions packages/integrations/sitemap/src/generate-sitemap.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,77 @@
import type { EnumChangefreq } from 'sitemap';
import type { SitemapItem, SitemapOptions } from './index.js';
import { parseUrl } from './utils/parse-url.js';
import { parseI18nUrl } from './utils/parse-i18n-url.js';

/** Construct sitemap.xml given a set of URLs */
export function generateSitemap(pages: string[], finalSiteUrl: string, opts: SitemapOptions) {
const { changefreq, priority, lastmod: lastmodSrc, i18n } = opts!;
export function generateSitemap(pages: string[], finalSiteUrl: string, opts?: SitemapOptions) {
const { changefreq, priority, lastmod: lastmodSrc, i18n } = opts ?? {};
// TODO: find way to respect <link rel="canonical"> URLs here
const urls = [...pages];
urls.sort((a, b) => a.localeCompare(b, 'en', { numeric: true })); // sort alphabetically so sitemap is same each time

const lastmod = lastmodSrc?.toISOString();

const { locales, defaultLocale } = i18n || {};
const localeCodes = Object.keys(locales || {});
// Parse URLs for i18n matching later
const { defaultLocale, locales } = i18n ?? {};
let getI18nLinks: GetI18nLinks | undefined;
if (defaultLocale && locales) {
getI18nLinks = createGetI18nLinks(urls, defaultLocale, locales, finalSiteUrl);
}

const getPath = (url: string) => {
const result = parseUrl(url, i18n?.defaultLocale || '', localeCodes, finalSiteUrl);
return result?.path;
};
const getLocale = (url: string) => {
const result = parseUrl(url, i18n?.defaultLocale || '', localeCodes, finalSiteUrl);
return result?.locale;
};
const urlData: SitemapItem[] = urls.map((url, i) => ({
url,
links: getI18nLinks?.(i),
lastmod,
priority,
changefreq: changefreq as EnumChangefreq,
}));

return urlData;
}

type GetI18nLinks = (urlIndex: number) => SitemapItem['links'] | undefined;

function createGetI18nLinks(
urls: string[],
defaultLocale: string,
locales: Record<string, string>,
finalSiteUrl: string
): GetI18nLinks {
// `parsedI18nUrls` will have the same length as `urls`, matching correspondingly
const parsedI18nUrls = urls.map((url) => parseI18nUrl(url, defaultLocale, locales, finalSiteUrl));
// Cache as multiple i18n URLs with the same path will have the same links
const i18nPathToLinksCache = new Map<string, SitemapItem['links']>();

const urlData: SitemapItem[] = urls.map((url) => {
let links;
if (defaultLocale && locales) {
const currentPath = getPath(url);
if (currentPath) {
const filtered = urls.filter((subUrl) => getPath(subUrl) === currentPath);
if (filtered.length > 1) {
links = filtered.map((subUrl) => ({
url: subUrl,
lang: locales[getLocale(subUrl)!],
}));
}
return (urlIndex) => {
const i18nUrl = parsedI18nUrls[urlIndex];
if (!i18nUrl) {
return undefined;
}

const cached = i18nPathToLinksCache.get(i18nUrl.path);
if (cached) {
return cached;
}

// Find all URLs with the same path (without the locale part), e.g. /en/foo and /es/foo
const links: NonNullable<SitemapItem['links']> = [];
for (let i = 0; i < parsedI18nUrls.length; i++) {
const parsed = parsedI18nUrls[i];
if (parsed?.path === i18nUrl.path) {
links.push({
url: urls[i],
lang: locales[parsed.locale],
});
}
}

return {
url,
links,
lastmod,
priority,
changefreq: changefreq as EnumChangefreq,
};
});
// If 0 or 1 (which is itself), return undefined to not create any links.
// We also don't need to cache this as we know there's no other URLs that would've match this.
if (links.length <= 1) {
return undefined;
}

return urlData;
i18nPathToLinksCache.set(i18nUrl.path, links);
return links;
};
}
42 changes: 42 additions & 0 deletions packages/integrations/sitemap/src/utils/parse-i18n-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
interface ParsedI18nUrl {
locale: string;
path: string;
}

// NOTE: The parameters have been schema-validated with Zod
export function parseI18nUrl(
url: string,
defaultLocale: string,
locales: Record<string, string>,
base: string
): ParsedI18nUrl | undefined {
if (!url.startsWith(base)) {
return undefined;
}

let s = url.slice(base.length);

// Handle root URL
if (!s || s === '/') {
return { locale: defaultLocale, path: '/' };
}

if (s[0] !== '/') {
s = '/' + s;
}

// Get locale from path, e.g.
// "/en-US/" -> "en-US"
// "/en-US/foo" -> "en-US"
const locale = s.split('/')[1];
if (locale in locales) {
// "/en-US/foo" -> "/foo"
let path = s.slice(1 + locale.length);
if (!path) {
path = '/';
}
return { locale, path };
}

return { locale: defaultLocale, path: s };
}
39 changes: 0 additions & 39 deletions packages/integrations/sitemap/src/utils/parse-url.ts

This file was deleted.

Loading

0 comments on commit 7060fbd

Please sign in to comment.