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:
commit
58d1d9e000
13 changed files with 587 additions and 541 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
|
|
1
packages/astro/src/env/runtime-constants.ts
vendored
Normal file
1
packages/astro/src/env/runtime-constants.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
export const ENV_SYMBOL = Symbol.for('astro:env/dev');
|
6
packages/astro/src/env/runtime.ts
vendored
6
packages/astro/src/env/runtime.ts
vendored
|
@ -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;
|
||||
|
|
7
packages/astro/src/env/vite-plugin-env.ts
vendored
7
packages/astro/src/env/vite-plugin-env.ts
vendored
|
@ -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,
|
||||
|
|
|
@ -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>/);
|
||||
});
|
||||
});
|
||||
|
|
12
packages/astro/test/fixtures/container-custom-renderers/src/pages/react-as-page.ts
vendored
Normal file
12
packages/astro/test/fixtures/container-custom-renderers/src/pages/react-as-page.ts
vendored
Normal 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
|
||||
});
|
||||
}
|
|
@ -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};
|
Loading…
Add table
Reference in a new issue