0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-01-27 22:19:04 -05:00

Merge branch 'main' into next

This commit is contained in:
Emanuele Stoppa 2024-10-17 15:08:42 +01:00
commit 58d1d9e000
13 changed files with 587 additions and 541 deletions

View file

@ -5,6 +5,7 @@ on:
push:
branches:
- main
- next
merge_group:
pull_request:
paths-ignore:
@ -209,6 +210,11 @@ jobs:
repository: withastro/docs
ref: 5.0.0-beta
path: smoke/docs
# For a commit event on the `next` branch (`ref_name`), use the `5.0.0-beta` branch.
# For a pull_request event merging into the `next` branch (`base_ref`), use the `5.0.0-beta` branch.
# NOTE: For a pull_request event, the `ref_name` is something like `<pr-number>/merge` than the branch name.
# NOTE: Perhaps docs repo should use a consistent `next` branch in the future.
ref: ${{ (github.ref_name == 'next' || github.base_ref == 'next') && '5.0.0-beta' || 'main' }}
- name: Install dependencies
run: pnpm install --no-frozen-lockfile

View file

@ -15,7 +15,7 @@
],
"scripts": {},
"devDependencies": {
"astro": "^5.0.0-beta.5"
"astro": "^5.0.0-beta.6"
},
"peerDependencies": {
"astro": "^4.0.0 || ^5.0.0"

View file

@ -25,12 +25,11 @@
"test:match": "cd packages/astro && pnpm run test:match",
"test:unit": "cd packages/astro && pnpm run test:unit",
"test:types": "cd packages/astro && pnpm run test:types",
"test:unit:match": "cd packages/astro && pnpm run test:unit:match",
"test:smoke": "pnpm test:smoke:example && pnpm test:smoke:docs",
"test:smoke:example": "turbo run build --concurrency=100% --filter=\"@example/*\"",
"test:smoke:docs": "turbo run build --filter=docs",
"test:check-examples": "node ./scripts/smoke/check.js",
"test:vite-ci": "cd packages/astro && pnpm run test:node",
"test:vite-ci": "cd packages/astro && pnpm run test:unit && pnpm run test:integration",
"test:e2e": "cd packages/astro && pnpm playwright install chromium firefox && pnpm run test:e2e",
"test:e2e:match": "cd packages/astro && pnpm playwright install chromium firefox && pnpm run test:e2e:match",
"test:e2e:hosts": "turbo run test:hosted",
@ -80,9 +79,6 @@
"astro",
"vite"
]
},
"patchedDependencies": {
"fs-fixture@2.4.0": "patches/fs-fixture@2.4.0.patch"
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@ import {
} from './types.js';
import { isESMImportedImage, isRemoteImage, resolveSrc } from './utils/imageKind.js';
import { inferRemoteSize } from './utils/remoteProbe.js';
import {isRemotePath} from "@astrojs/internal-helpers/path";
export async function getConfiguredImageService(): Promise<ImageService> {
if (!globalThis?.astroAsset?.imageService) {
@ -65,7 +66,11 @@ export async function getImage(
};
// Infer size for remote images if inferSize is true
if (options.inferSize && isRemoteImage(resolvedOptions.src)) {
if (
options.inferSize &&
isRemoteImage(resolvedOptions.src) &&
isRemotePath(resolvedOptions.src)
) {
const result = await inferRemoteSize(resolvedOptions.src); // Directly probe the image URL
resolvedOptions.width ??= result.width;
resolvedOptions.height ??= result.height;

View file

@ -97,6 +97,14 @@ export type ContainerRenderOptions = {
* ```
*/
props?: Props;
/**
* When `false`, it forces to render the component as it was a full-fledged page.
*
* By default, the container API render components as [partials](https://docs.astro.build/en/basics/astro-pages/#page-partials).
*
*/
partial?: boolean;
};
export type AddServerRenderer =
@ -499,6 +507,7 @@ export class experimental_AstroContainer {
request,
pathname: url.pathname,
locals: options?.locals ?? {},
partial: options?.partial ?? true,
});
if (options.params) {
renderContext.params = options.params;

View file

@ -48,6 +48,7 @@ export class RenderContext {
public params = getParams(routeData, pathname),
protected url = new URL(request.url),
public props: Props = {},
public partial: undefined | boolean = undefined,
) {}
/**
@ -68,9 +69,10 @@ export class RenderContext {
routeData,
status = 200,
props,
partial = undefined,
}: Pick<RenderContext, 'pathname' | 'pipeline' | 'request' | 'routeData'> &
Partial<
Pick<RenderContext, 'locals' | 'middleware' | 'status' | 'props'>
Pick<RenderContext, 'locals' | 'middleware' | 'status' | 'props' | 'partial'>
>): Promise<RenderContext> {
const pipelineMiddleware = await pipeline.getMiddleware();
return new RenderContext(
@ -85,6 +87,7 @@ export class RenderContext {
undefined,
undefined,
props,
partial,
);
}
@ -304,7 +307,7 @@ export class RenderContext {
const componentMetadata =
(await pipeline.componentMetadata(routeData)) ?? manifest.componentMetadata;
const headers = new Headers({ 'Content-Type': 'text/html' });
const partial = Boolean(mod.partial);
const partial = typeof this.partial === 'boolean' ? this.partial : Boolean(mod.partial);
const response = {
status,
statusText: 'OK',

View file

@ -0,0 +1 @@
export const ENV_SYMBOL = Symbol.for('astro:env/dev');

View file

@ -1,12 +1,16 @@
import { AstroError, AstroErrorData } from '../core/errors/index.js';
import { invalidVariablesToError } from './errors.js';
import { ENV_SYMBOL } from './runtime-constants.js';
import type { ValidationResultInvalid } from './validators.js';
export { validateEnvVariable, getEnvFieldType } from './validators.js';
export type GetEnv = (key: string) => string | undefined;
type OnSetGetEnv = (reset: boolean) => void;
let _getEnv: GetEnv = (key) => process.env[key];
let _getEnv: GetEnv = (key) => {
const env = (globalThis as any)[ENV_SYMBOL] ?? {};
return env[key];
};
export function setGetEnv(fn: GetEnv, reset = false) {
_getEnv = fn;

View file

@ -9,6 +9,7 @@ import {
VIRTUAL_MODULES_IDS_VALUES,
} from './constants.js';
import { type InvalidVariable, invalidVariablesToError } from './errors.js';
import { ENV_SYMBOL } from './runtime-constants.js';
import type { EnvSchema } from './schema.js';
import { getEnvFieldType, validateEnvVariable } from './validators.js';
@ -32,11 +33,7 @@ export function astroEnv({ settings, mode, sync }: AstroEnvPluginParams): Plugin
fileURLToPath(settings.config.root),
'',
);
for (const [key, value] of Object.entries(loadedEnv)) {
if (value !== undefined) {
process.env[key] = value;
}
}
(globalThis as any)[ENV_SYMBOL] = loadedEnv;
const validatedVariables = validatePublicVariables({
schema,

View file

@ -252,6 +252,16 @@ describe('Container with renderers', () => {
const html = await response.text();
assert.match(html, /I am a react button/);
assert.doesNotMatch(html, /<!DOCTYPE html>/);
});
it('the endpoint should return the HTML of the React component, with DOCTYPE when rendered when partial is off', async () => {
const request = new Request('https://example.com/react-as-page');
const response = await app.render(request);
const html = await response.text();
assert.match(html, /I am a react button/);
assert.match(html, /<!DOCTYPE html>/);
});
it('the endpoint should return the HTML of the Vue component', async () => {
@ -260,6 +270,7 @@ describe('Container with renderers', () => {
const html = await response.text();
assert.match(html, /I am a vue button/);
assert.doesNotMatch(html, /<!DOCTYPE html>/);
});
it('Should render a component with directives', async () => {
@ -269,5 +280,6 @@ describe('Container with renderers', () => {
assert.match(html, /Button not rendered/);
assert.match(html, /I am a react button/);
assert.doesNotMatch(html, /<!DOCTYPE html>/);
});
});

View file

@ -0,0 +1,12 @@
import type {APIRoute} from "astro";
import { experimental_AstroContainer } from "astro/container";
import renderer from '@astrojs/react/server.js';
import Component from "../components/button.jsx"
export const GET: APIRoute = async (ctx) => {
const container = await experimental_AstroContainer.create();
container.addServerRenderer({ renderer });
return await container.renderToResponse(Component, {
partial: false
});
}

View file

@ -1,24 +0,0 @@
diff --git a/dist/index.d.mts b/dist/index.d.mts
index be5b88e034211892ba079c3c5c5c6f5d5f767cd4..55dcc0e99c66719d5fa68d4713b02c1919deae19 100644
--- a/dist/index.d.mts
+++ b/dist/index.d.mts
@@ -61,6 +61,10 @@ type Api = ApiBase & {
type FileTree = {
[path: string]: string | FileTree | ((api: Api) => string | Symlink);
};
-declare const createFixture: (source?: string | FileTree) => Promise<FsFixture>;
+type CreateFixtureOptions = {
+ // An absolute path to a different directory than `os.tmpdir()`
+ tempDir?: string
+}
+declare const createFixture: (source?: string | FileTree, opts?: CreateFixtureOptions) => Promise<FsFixture>;
-export { type FileTree, FsFixture, createFixture };
+export { type FileTree, FsFixture, CreateFixtureOptions, createFixture };
diff --git a/dist/index.mjs b/dist/index.mjs
index cd6cab3beebf3f38fe4f1e2a9c58aff2b87258f7..ad24d852a357fd582f9e83ac20cb73bfbcb9bfc0 100755
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -1 +1 @@
-import s from"fs/promises";import o from"path";import y from"fs";import m from"os";typeof Symbol.asyncDispose!="symbol"&&Object.defineProperty(Symbol,"asyncDispose",{configurable:!1,enumerable:!1,writable:!1,value:Symbol.for("asyncDispose")});class w{path;constructor(t){this.path=t}getPath(...t){return o.join(this.path,...t)}exists(t=""){return s.access(this.getPath(t)).then(()=>!0,()=>!1)}rm(t=""){return s.rm(this.getPath(t),{recursive:!0,force:!0})}writeFile(t,r){return s.writeFile(this.getPath(t),r)}writeJson(t,r){return this.writeFile(t,JSON.stringify(r,null,2))}readFile(t,r){return s.readFile(this.getPath(t),r)}async[Symbol.asyncDispose](){await this.rm()}}const g=y.realpathSync(m.tmpdir()),b=`fs-fixture-${Date.now()}`;let l=0;const P=()=>(l+=1,l);class h{target;type;path;constructor(t,r){this.target=t,this.type=r}}const u=(i,t,r)=>{const e=[];for(const n in i){if(!Object.hasOwn(i,n))continue;const c=o.join(t,n);let a=i[n];if(typeof a=="function"){const f=Object.assign(Object.create(r),{filePath:c}),p=a(f);if(p instanceof h){p.path=c,e.push(p);continue}else a=p}typeof a=="string"?e.push({path:c,content:a}):e.push(...u(a,c,r))}return e},d=async i=>{const t=o.join(g,`${b}-${P()}/`);if(await s.mkdir(t,{recursive:!0}),i){if(typeof i=="string")await s.cp(i,t,{recursive:!0});else if(typeof i=="object"){const r={fixturePath:t,getPath:(...e)=>o.join(t,...e),symlink:(e,n)=>new h(e,n)};await Promise.all(u(i,t,r).map(async e=>{await s.mkdir(o.dirname(e.path),{recursive:!0}),e instanceof h?await s.symlink(e.target,e.path,e.type):await s.writeFile(e.path,e.content)}))}}return new w(t)};export{d as createFixture};
+import s from"fs/promises";import o from"path";import y from"fs";import m from"os";typeof Symbol.asyncDispose!="symbol"&&Object.defineProperty(Symbol,"asyncDispose",{configurable:!1,enumerable:!1,writable:!1,value:Symbol.for("asyncDispose")});class w{path;constructor(t){this.path=t}getPath(...t){return o.join(this.path,...t)}exists(t=""){return s.access(this.getPath(t)).then(()=>!0,()=>!1)}rm(t=""){return s.rm(this.getPath(t),{recursive:!0,force:!0})}writeFile(t,r){return s.writeFile(this.getPath(t),r)}writeJson(t,r){return this.writeFile(t,JSON.stringify(r,null,2))}readFile(t,r){return s.readFile(this.getPath(t),r)}async[Symbol.asyncDispose](){await this.rm()}}const g=y.realpathSync(m.tmpdir()),b=`fs-fixture-${Date.now()}`;let l=0;const P=()=>(l+=1,l);class h{target;type;path;constructor(t,r){this.target=t,this.type=r}}const u=(i,t,r)=>{const e=[];for(const n in i){if(!Object.hasOwn(i,n))continue;const c=o.join(t,n);let a=i[n];if(typeof a=="function"){const f=Object.assign(Object.create(r),{filePath:c}),p=a(f);if(p instanceof h){p.path=c,e.push(p);continue}else a=p}typeof a=="string"?e.push({path:c,content:a}):e.push(...u(a,c,r))}return e},d=async (i, opts)=>{const t=o.join(opts?.tempDir ?? g,`${b}-${P()}/`);if(await s.mkdir(t,{recursive:!0}),i){if(typeof i=="string")await s.cp(i,t,{recursive:!0});else if(typeof i=="object"){const r={fixturePath:t,getPath:(...e)=>o.join(t,...e),symlink:(e,n)=>new h(e,n)};await Promise.all(u(i,t,r).map(async e=>{await s.mkdir(o.dirname(e.path),{recursive:!0}),e instanceof h?await s.symlink(e.target,e.path,e.type):await s.writeFile(e.path,e.content)}))}}return new w(t)};export{d as createFixture};