Merge branch 'main' into main

This commit is contained in:
Chris 2023-09-06 14:30:22 +02:00 committed by GitHub
commit 09de89b6fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 359 additions and 62 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixed a case where dynamic imports tried to preload inlined stylesheets.

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes remote assets caching logic to not use expired assets

View file

@ -0,0 +1,5 @@
---
'@astrojs/svelte': patch
---
Removed vite warnings.

View file

@ -0,0 +1,6 @@
---
'create-astro': patch
'astro': patch
---
Support detecting Bun when logging messages with package manager information.

View file

@ -0,0 +1,5 @@
---
'@astrojs/vercel': patch
---
Fix serverless function naming conflicts for routes with identical filenames but different directory structures

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix markdown page HMR

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix scroll position when navigating back from page w/o ViewTransitions

View file

@ -13,7 +13,10 @@ module.exports = {
rules: { rules: {
// These off/configured-differently-by-default rules fit well for us // These off/configured-differently-by-default rules fit well for us
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }], '@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
'@typescript-eslint/no-unused-vars': ['error', { ignoreRestSiblings: true }], '@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_', ignoreRestSiblings: true },
],
'no-only-tests/no-only-tests': 'error', 'no-only-tests/no-only-tests': 'error',
'@typescript-eslint/no-shadow': ['error'], '@typescript-eslint/no-shadow': ['error'],
'no-console': 'warn', 'no-console': 'warn',

View file

@ -30,9 +30,11 @@ const { fallback = 'animate' } = Astro.props as Props;
// The History API does not tell you if navigation is forward or back, so // The History API does not tell you if navigation is forward or back, so
// you can figure it using an index. On pushState the index is incremented so you // you can figure it using an index. On pushState the index is incremented so you
// can use that to determine popstate if going forward or back. // can use that to determine popstate if going forward or back.
let currentHistoryIndex = history.state?.index || 0; let currentHistoryIndex = 0;
if (!history.state && transitionEnabledOnThisPage()) { if (history.state) {
persistState({ index: currentHistoryIndex, scrollY: 0 }); // we reloaded a page with history state (e.g. back button or browser reload)
currentHistoryIndex = history.state.index;
scrollTo({ left: 0, top: history.state.scrollY });
} }
const throttle = (cb: (...args: any[]) => any, delay: number) => { const throttle = (cb: (...args: any[]) => any, delay: number) => {
@ -352,6 +354,7 @@ const { fallback = 'animate' } = Astro.props as Props;
// The current page doesn't haven't View Transitions, // The current page doesn't haven't View Transitions,
// respect that with a full page reload // respect that with a full page reload
// -- but only for transition managed by us (ev.state is set) // -- but only for transition managed by us (ev.state is set)
history.scrollRestoration && (history.scrollRestoration = "manual")
location.reload(); location.reload();
return; return;
} }

View file

@ -32,6 +32,8 @@ import Layout from '../components/Layout.astro';
<div><a id="click-one-again" href="/one">go to 1</a></div> <div><a id="click-one-again" href="/one">go to 1</a></div>
<div><a id="click-scroll-up" href="#longpage">go back up</a></div> <div><a id="click-scroll-up" href="#longpage">go back up</a></div>
<div><a id="click-external" href="/three">leave ViewTransitions</a></div>
Morbi tristique senectus et netus et. Neque aliquam vestibulum morbi blandit cursus risus. Pharetra pharetra massa massa ultricies mi quis. Sit amet aliquam id diam maecenas ultricies mi eget mauris. Ultrices mi tempus imperdiet nulla malesuada. At consectetur lorem donec massa sapien faucibus et molestie. Non sodales neque sodales ut etiam. Eget nunc lobortis mattis aliquam faucibus purus in massa tempor. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus. Pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum. Diam vulputate ut pharetra sit. Felis donec et odio pellentesque diam. Mollis aliquam ut porttitor leo. Vitae nunc sed velit dignissim sodales. Facilisis mauris sit amet massa vitae tortor condimentum lacinia quis. Morbi tristique senectus et netus et. Neque aliquam vestibulum morbi blandit cursus risus. Pharetra pharetra massa massa ultricies mi quis. Sit amet aliquam id diam maecenas ultricies mi eget mauris. Ultrices mi tempus imperdiet nulla malesuada. At consectetur lorem donec massa sapien faucibus et molestie. Non sodales neque sodales ut etiam. Eget nunc lobortis mattis aliquam faucibus purus in massa tempor. Viverra suspendisse potenti nullam ac tortor vitae purus faucibus. Pellentesque eu tincidunt tortor aliquam nulla facilisi cras fermentum. Diam vulputate ut pharetra sit. Felis donec et odio pellentesque diam. Mollis aliquam ut porttitor leo. Vitae nunc sed velit dignissim sodales. Facilisis mauris sit amet massa vitae tortor condimentum lacinia quis.
Aliquet enim tortor at auctor urna nunc id cursus. Bibendum at varius vel pharetra vel turpis nunc eget. Mattis molestie a iaculis at erat. Vel turpis nunc eget lorem dolor sed viverra ipsum nunc. Aliquam malesuada bibendum arcu vitae elementum curabitur vitae nunc sed. Nunc congue nisi vitae suscipit. Donec massa sapien faucibus et molestie ac. Nec feugiat nisl pretium fusce. At imperdiet dui accumsan sit amet nulla facilisi. Sed viverra tellus in hac. Aliquet enim tortor at auctor urna nunc id cursus. Bibendum at varius vel pharetra vel turpis nunc eget. Mattis molestie a iaculis at erat. Vel turpis nunc eget lorem dolor sed viverra ipsum nunc. Aliquam malesuada bibendum arcu vitae elementum curabitur vitae nunc sed. Nunc congue nisi vitae suscipit. Donec massa sapien faucibus et molestie ac. Nec feugiat nisl pretium fusce. At imperdiet dui accumsan sit amet nulla facilisi. Sed viverra tellus in hac.

View file

@ -502,3 +502,24 @@ test.describe('View Transitions', () => {
await downloadPromise; await downloadPromise;
}); });
}); });
test('Scroll position is restored on back navigation from page w/o ViewTransitions', async ({
page,
astro,
}) => {
// Go to middle of long page
await page.goto(astro.resolveUrl('/long-page#click-external'));
let locator = page.locator('#click-external');
await expect(locator).toBeInViewport();
// Go to a page that has not enabled ViewTransistions
await page.click('#click-external');
locator = page.locator('#three');
await expect(locator).toHaveText('Page 3');
// Scroll back to long page
await page.goBack();
locator = page.locator('#click-external');
await expect(locator).toBeInViewport();
});

View file

@ -156,7 +156,7 @@
"ora": "^7.0.1", "ora": "^7.0.1",
"p-limit": "^4.0.0", "p-limit": "^4.0.0",
"path-to-regexp": "^6.2.1", "path-to-regexp": "^6.2.1",
"preferred-pm": "^3.0.3", "preferred-pm": "^3.1.2",
"prompts": "^2.4.2", "prompts": "^2.4.2",
"rehype": "^12.0.1", "rehype": "^12.0.1",
"resolve": "^1.22.4", "resolve": "^1.22.4",
@ -172,7 +172,7 @@
"vfile": "^5.3.7", "vfile": "^5.3.7",
"vite": "^4.4.9", "vite": "^4.4.9",
"vitefu": "^0.2.4", "vitefu": "^0.2.4",
"which-pm": "^2.0.0", "which-pm": "^2.1.1",
"yargs-parser": "^21.1.1", "yargs-parser": "^21.1.1",
"zod": "3.21.1" "zod": "3.21.1"
}, },

View file

@ -75,7 +75,7 @@ export async function generateImage(
const JSONData = JSON.parse(readFileSync(cachedFileURL, 'utf-8')) as RemoteCacheEntry; const JSONData = JSON.parse(readFileSync(cachedFileURL, 'utf-8')) as RemoteCacheEntry;
// If the cache entry is not expired, use it // If the cache entry is not expired, use it
if (JSONData.expires < Date.now()) { if (JSONData.expires > Date.now()) {
await fs.promises.writeFile(finalFileURL, Buffer.from(JSONData.data, 'base64')); await fs.promises.writeFile(finalFileURL, Buffer.from(JSONData.data, 'base64'));
return { return {

View file

@ -620,6 +620,8 @@ async function getInstallIntegrationsCommand({
return { pm: 'yarn', command: 'add', flags: [], dependencies }; return { pm: 'yarn', command: 'add', flags: [], dependencies };
case 'pnpm': case 'pnpm':
return { pm: 'pnpm', command: 'add', flags: [], dependencies }; return { pm: 'pnpm', command: 'add', flags: [], dependencies };
case 'bun':
return { pm: 'bun', command: 'add', flags: [], dependencies };
default: default:
return null; return null;
} }

View file

@ -67,6 +67,8 @@ function getInstallCommand(packages: string[], packageManager: string) {
return { pm: 'yarn', command: 'add', flags: [], dependencies: packages }; return { pm: 'yarn', command: 'add', flags: [], dependencies: packages };
case 'pnpm': case 'pnpm':
return { pm: 'pnpm', command: 'add', flags: [], dependencies: packages }; return { pm: 'pnpm', command: 'add', flags: [], dependencies: packages };
case 'bun':
return { pm: 'bun', command: 'add', flags: [], dependencies: packages };
default: default:
return null; return null;
} }

View file

@ -1,4 +1,5 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import whichPm from 'which-pm';
import type yargs from 'yargs-parser'; import type yargs from 'yargs-parser';
import * as msg from '../../core/messages.js'; import * as msg from '../../core/messages.js';
import { telemetry } from '../../events/index.js'; import { telemetry } from '../../events/index.js';
@ -8,8 +9,9 @@ interface TelemetryOptions {
} }
export async function notify() { export async function notify() {
const packageManager = (await whichPm(process.cwd())).name ?? 'npm';
await telemetry.notify(() => { await telemetry.notify(() => {
console.log(msg.telemetryNotice() + '\n'); console.log(msg.telemetryNotice(packageManager) + '\n');
return true; return true;
}); });
} }

View file

@ -121,8 +121,6 @@ export class App {
} }
return pathname; return pathname;
} }
// Disable no-unused-vars to avoid breaking signature change
// eslint-disable-next-line @typescript-eslint/no-unused-vars
match(request: Request, _opts: MatchOptions = {}): RouteData | undefined { match(request: Request, _opts: MatchOptions = {}): RouteData | undefined {
const url = new URL(request.url); const url = new URL(request.url);
// ignore requests matching public assets // ignore requests matching public assets

View file

@ -200,7 +200,7 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
const inlineConfig = settings.config.build.inlineStylesheets; const inlineConfig = settings.config.build.inlineStylesheets;
const { assetsInlineLimit = 4096 } = settings.config.vite?.build ?? {}; const { assetsInlineLimit = 4096 } = settings.config.vite?.build ?? {};
Object.entries(bundle).forEach(([id, stylesheet]) => { Object.entries(bundle).forEach(([_, stylesheet]) => {
if ( if (
stylesheet.type !== 'asset' || stylesheet.type !== 'asset' ||
stylesheet.name?.endsWith('.css') !== true || stylesheet.name?.endsWith('.css') !== true ||
@ -217,8 +217,6 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
? false ? false
: assetSize <= assetsInlineLimit; : assetSize <= assetsInlineLimit;
if (toBeInlined) delete bundle[id];
// there should be a single js object for each stylesheet, // there should be a single js object for each stylesheet,
// allowing the single reference to be shared and checked for duplicates // allowing the single reference to be shared and checked for duplicates
const sheet: StylesheetAsset = toBeInlined const sheet: StylesheetAsset = toBeInlined

View file

@ -105,10 +105,10 @@ export function serverStart({
.join('\n'); .join('\n');
} }
export function telemetryNotice() { export function telemetryNotice(packageManager = 'npm') {
const headline = `${cyan('◆')} Astro collects completely anonymous usage data.`; const headline = `${cyan('◆')} Astro collects completely anonymous usage data.`;
const why = dim(' This optional program helps shape our roadmap.'); const why = dim(' This optional program helps shape our roadmap.');
const disable = dim(' Run `npm run astro telemetry disable` to opt-out.'); const disable = dim(` Run \`${packageManager} run astro telemetry disable\` to opt-out.`);
const details = ` Details: ${underline('https://astro.build/telemetry')}`; const details = ` Details: ${underline('https://astro.build/telemetry')}`;
return [headline, why, disable, details].map((v) => ' ' + v).join('\n'); return [headline, why, disable, details].map((v) => ' ' + v).join('\n');
} }

View file

@ -107,7 +107,7 @@ export default function markdown({ settings, logger }: AstroPluginOptions): Plug
} }
const code = escapeViteEnvReferences(` const code = escapeViteEnvReferences(`
import { unescapeHTML, spreadAttributes, createComponent, render, renderComponent } from ${JSON.stringify( import { unescapeHTML, spreadAttributes, createComponent, render, renderComponent, maybeRenderHead } from ${JSON.stringify(
astroServerRuntimeModulePath astroServerRuntimeModulePath
)}; )};
import { AstroError, AstroErrorData } from ${JSON.stringify(astroErrorModulePath)}; import { AstroError, AstroErrorData } from ${JSON.stringify(astroErrorModulePath)};
@ -180,10 +180,9 @@ export default function markdown({ settings, logger }: AstroPluginOptions): Plug
}, { }, {
'default': () => render\`\${unescapeHTML(html)}\` 'default': () => render\`\${unescapeHTML(html)}\`
})}\`;` })}\`;`
: `render\`\${unescapeHTML(html)}\`;` : `render\`\${maybeRenderHead(result)}\${unescapeHTML(html)}\`;`
} }
}); });
Content[Symbol.for('astro.needsHeadRendering')] = ${layout ? 'false' : 'true'};
export default Content; export default Content;
`); `);

View file

@ -49,5 +49,10 @@ describe('Pages', () => {
expect($('#testing').length).to.be.greaterThan(0); expect($('#testing').length).to.be.greaterThan(0);
}); });
it('should have Vite client in dev', async () => {
const html = await fixture.fetch('/').then((res) => res.text());
expect(html).to.include('/@vite/client', 'Markdown page does not have Vite client for HMR');
});
}); });
}); });

View file

@ -0,0 +1,36 @@
import { expect } from 'chai';
import { loadFixture } from './test-utils.js';
const cssAssetReferenceRegExp = /_astro\/[A-Za-z0-9\-]+\.[a0-9a-f]{8}\.css/g;
describe("When Vite's preloadModule polyfill is used", async () => {
let fixture;
before(async () => {
fixture = await loadFixture({
root: './fixtures/css-dangling-references/',
});
await fixture.build();
});
it('there are no references to deleted CSS chunks', async () => {
const fileNames = await fixture.readdir('/_astro/');
const filePaths = fileNames.map((filename) => '_astro/' + filename);
const expectations = filePaths
.filter((filePath) => filePath.endsWith('js'))
.map(async (filePath) => {
const contents = await fixture.readFile(filePath);
const cssReferences = contents.match(cssAssetReferenceRegExp);
if (cssReferences === null) return;
expect(filePaths).to.contain.members(
cssReferences,
filePath + ' contains a reference to a deleted css asset: ' + cssReferences
);
});
await Promise.all(expectations);
});
});

View file

@ -0,0 +1,8 @@
import { defineConfig } from 'astro/config';
import svelte from '@astrojs/svelte';
// https://astro.build/config
export default defineConfig({
integrations: [svelte()],
});

View file

@ -0,0 +1,11 @@
{
"name": "@test/css-dangling-references",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*",
"@astrojs/svelte": "workspace:*",
"svelte": "4"
}
}

View file

@ -0,0 +1,6 @@
<style>
h1 {
background-color: gold;
}
</style>
<h1>This sentence should have a gold background.</h1>

View file

@ -0,0 +1,6 @@
<style>
p {
background-color: lavender;
}
</style>
<p>This sentence should have a lavender background color.</p>

View file

@ -0,0 +1,15 @@
<script>
export let path
const allAppModules = import.meta.glob('./*.svelte')
const AppModule = Object.entries(allAppModules).find(
([key]) => key.includes(path)
)[1]
</script>
{#await AppModule() then Mod}
<Mod.default />
{/await}

View file

@ -0,0 +1,4 @@
---
import Wrapper from "../components/Wrapper.svelte"
---
<Wrapper path="1" client:load/>

View file

@ -0,0 +1,5 @@
---
import Wrapper from "../components/Wrapper.svelte"
---
<Wrapper path="2" client:load/>

View file

@ -1,5 +1,5 @@
{ {
"name": "@test/css-inline-stylesheets-always", "name": "@test/css-inline-stylesheets",
"version": "0.0.0", "version": "0.0.0",
"private": true, "private": true,
"dependencies": { "dependencies": {

View file

@ -9,7 +9,7 @@ export interface Context {
help: boolean; help: boolean;
prompt: typeof prompt; prompt: typeof prompt;
cwd: string; cwd: string;
pkgManager: string; packageManager: string;
username: string; username: string;
version: string; version: string;
skipHouston: boolean; skipHouston: boolean;
@ -51,7 +51,7 @@ export async function getContext(argv: string[]): Promise<Context> {
{ argv, permissive: true } { argv, permissive: true }
); );
const pkgManager = detectPackageManager()?.name ?? 'npm'; const packageManager = detectPackageManager()?.name ?? 'npm';
const [username, version] = await Promise.all([getName(), getVersion()]); const [username, version] = await Promise.all([getName(), getVersion()]);
let cwd = flags['_'][0]; let cwd = flags['_'][0];
let { let {
@ -85,7 +85,7 @@ export async function getContext(argv: string[]): Promise<Context> {
const context: Context = { const context: Context = {
help, help,
prompt, prompt,
pkgManager, packageManager,
username, username,
version, version,
skipHouston, skipHouston,

View file

@ -6,7 +6,7 @@ import { shell } from '../shell.js';
import type { Context } from './context'; import type { Context } from './context';
export async function dependencies( export async function dependencies(
ctx: Pick<Context, 'install' | 'yes' | 'prompt' | 'pkgManager' | 'cwd' | 'dryRun'> ctx: Pick<Context, 'install' | 'yes' | 'prompt' | 'packageManager' | 'cwd' | 'dryRun'>
) { ) {
let deps = ctx.install ?? ctx.yes; let deps = ctx.install ?? ctx.yes;
if (deps === undefined) { if (deps === undefined) {
@ -25,15 +25,15 @@ export async function dependencies(
await info('--dry-run', `Skipping dependency installation`); await info('--dry-run', `Skipping dependency installation`);
} else if (deps) { } else if (deps) {
await spinner({ await spinner({
start: `Installing dependencies with ${ctx.pkgManager}...`, start: `Installing dependencies with ${ctx.packageManager}...`,
end: 'Dependencies installed', end: 'Dependencies installed',
while: () => { while: () => {
return install({ pkgManager: ctx.pkgManager, cwd: ctx.cwd }).catch((e) => { return install({ packageManager: ctx.packageManager, cwd: ctx.cwd }).catch((e) => {
error('error', e); error('error', e);
error( error(
'error', 'error',
`Dependencies failed to install, please run ${color.bold( `Dependencies failed to install, please run ${color.bold(
ctx.pkgManager + ' install' ctx.packageManager + ' install'
)} to install them manually after setup.` )} to install them manually after setup.`
); );
}); });
@ -47,9 +47,9 @@ export async function dependencies(
} }
} }
async function install({ pkgManager, cwd }: { pkgManager: string; cwd: string }) { async function install({ packageManager, cwd }: { packageManager: string; cwd: string }) {
if (pkgManager === 'yarn') await ensureYarnLock({ cwd }); if (packageManager === 'yarn') await ensureYarnLock({ cwd });
return shell(pkgManager, ['install'], { cwd, timeout: 90_000, stdio: 'ignore' }); return shell(packageManager, ['install'], { cwd, timeout: 90_000, stdio: 'ignore' });
} }
async function ensureYarnLock({ cwd }: { cwd: string }) { async function ensureYarnLock({ cwd }: { cwd: string }) {

View file

@ -3,14 +3,17 @@ import type { Context } from './context';
import { nextSteps, say } from '../messages.js'; import { nextSteps, say } from '../messages.js';
export async function next(ctx: Pick<Context, 'cwd' | 'pkgManager' | 'skipHouston'>) { export async function next(ctx: Pick<Context, 'cwd' | 'packageManager' | 'skipHouston'>) {
let projectDir = path.relative(process.cwd(), ctx.cwd); let projectDir = path.relative(process.cwd(), ctx.cwd);
const devCmd =
ctx.pkgManager === 'npm' const commandMap: { [key: string]: string } = {
? 'npm run dev' npm: 'npm run dev',
: ctx.pkgManager === 'bun' bun: 'bun run dev',
? 'bun run dev' yarn: 'yarn dev',
: `${ctx.pkgManager} dev`; pnpm: 'pnpm dev',
};
const devCmd = commandMap[ctx.packageManager as keyof typeof commandMap] || 'npm run dev';
await nextSteps({ projectDir, devCmd }); await nextSteps({ projectDir, devCmd });
if (!ctx.skipHouston) { if (!ctx.skipHouston) {

View file

@ -10,7 +10,7 @@ describe('dependencies', () => {
const context = { const context = {
cwd: '', cwd: '',
yes: true, yes: true,
pkgManager: 'npm', packageManager: 'npm',
dryRun: true, dryRun: true,
prompt: () => ({ deps: true }), prompt: () => ({ deps: true }),
}; };
@ -21,7 +21,7 @@ describe('dependencies', () => {
it('prompt yes', async () => { it('prompt yes', async () => {
const context = { const context = {
cwd: '', cwd: '',
pkgManager: 'npm', packageManager: 'npm',
dryRun: true, dryRun: true,
prompt: () => ({ deps: true }), prompt: () => ({ deps: true }),
install: undefined, install: undefined,
@ -34,7 +34,7 @@ describe('dependencies', () => {
it('prompt no', async () => { it('prompt no', async () => {
const context = { const context = {
cwd: '', cwd: '',
pkgManager: 'npm', packageManager: 'npm',
dryRun: true, dryRun: true,
prompt: () => ({ deps: false }), prompt: () => ({ deps: false }),
install: undefined, install: undefined,
@ -48,7 +48,7 @@ describe('dependencies', () => {
const context = { const context = {
cwd: '', cwd: '',
install: true, install: true,
pkgManager: 'npm', packageManager: 'npm',
dryRun: true, dryRun: true,
prompt: () => ({ deps: false }), prompt: () => ({ deps: false }),
}; };
@ -61,7 +61,7 @@ describe('dependencies', () => {
const context = { const context = {
cwd: '', cwd: '',
install: false, install: false,
pkgManager: 'npm', packageManager: 'npm',
dryRun: true, dryRun: true,
prompt: () => ({ deps: false }), prompt: () => ({ deps: false }),
}; };

View file

@ -7,14 +7,14 @@ describe('next steps', () => {
const fixture = setup(); const fixture = setup();
it('no arguments', async () => { it('no arguments', async () => {
await next({ skipHouston: false, cwd: './it/fixtures/not-empty', pkgManager: 'npm' }); await next({ skipHouston: false, cwd: './it/fixtures/not-empty', packageManager: 'npm' });
expect(fixture.hasMessage('Liftoff confirmed.')).to.be.true; expect(fixture.hasMessage('Liftoff confirmed.')).to.be.true;
expect(fixture.hasMessage('npm run dev')).to.be.true; expect(fixture.hasMessage('npm run dev')).to.be.true;
expect(fixture.hasMessage('Good luck out there, astronaut!')).to.be.true; expect(fixture.hasMessage('Good luck out there, astronaut!')).to.be.true;
}); });
it('--skip-houston', async () => { it('--skip-houston', async () => {
await next({ skipHouston: true, cwd: './it/fixtures/not-empty', pkgManager: 'npm' }); await next({ skipHouston: true, cwd: './it/fixtures/not-empty', packageManager: 'npm' });
expect(fixture.hasMessage('Good luck out there, astronaut!')).to.be.false; expect(fixture.hasMessage('Good luck out there, astronaut!')).to.be.false;
}); });
}); });

View file

@ -8,14 +8,18 @@ describe('Basic app', () => {
/** @type {import('./test-utils').WranglerCLI} */ /** @type {import('./test-utils').WranglerCLI} */
let cli; let cli;
before(async () => { before(async function () {
fixture = await loadFixture({ fixture = await loadFixture({
root: './fixtures/basics/', root: './fixtures/basics/',
}); });
await fixture.build(); await fixture.build();
cli = await runCLI('./fixtures/basics/', { silent: true, port: 8789 }); cli = await runCLI('./fixtures/basics/', { silent: true, port: 8789 });
await cli.ready; await cli.ready.catch((e) => {
console.log(e);
// if fail to start, skip for now as it's very flaky
this.skip();
});
}); });
after(async () => { after(async () => {

View file

@ -9,7 +9,7 @@ describe('Cf metadata and caches', () => {
/** @type {import('./test-utils').WranglerCLI} */ /** @type {import('./test-utils').WranglerCLI} */
let cli; let cli;
before(async () => { before(async function () {
fixture = await loadFixture({ fixture = await loadFixture({
root: './fixtures/cf/', root: './fixtures/cf/',
output: 'server', output: 'server',
@ -17,8 +17,12 @@ describe('Cf metadata and caches', () => {
}); });
await fixture.build(); await fixture.build();
cli = await runCLI('./fixtures/cf/', { silent: false, port: 8788 }); cli = await runCLI('./fixtures/cf/', { silent: true, port: 8786 });
await cli.ready; await cli.ready.catch((e) => {
console.log(e);
// if fail to start, skip for now as it's very flaky
this.skip();
});
}); });
after(async () => { after(async () => {
@ -26,7 +30,7 @@ describe('Cf metadata and caches', () => {
}); });
it('Load cf and caches API', async () => { it('Load cf and caches API', async () => {
let res = await fetch(`http://127.0.0.1:8788/`); let res = await fetch(`http://127.0.0.1:8786/`);
expect(res.status).to.equal(200); expect(res.status).to.equal(200);
let html = await res.text(); let html = await res.text();
let $ = cheerio.load(html); let $ = cheerio.load(html);

View file

@ -9,7 +9,7 @@ describe('Runtime Locals', () => {
/** @type {import('./test-utils.js').WranglerCLI} */ /** @type {import('./test-utils.js').WranglerCLI} */
let cli; let cli;
before(async () => { before(async function () {
fixture = await loadFixture({ fixture = await loadFixture({
root: './fixtures/runtime/', root: './fixtures/runtime/',
output: 'server', output: 'server',
@ -18,7 +18,11 @@ describe('Runtime Locals', () => {
await fixture.build(); await fixture.build();
cli = await runCLI('./fixtures/runtime/', { silent: true, port: 8793 }); cli = await runCLI('./fixtures/runtime/', { silent: true, port: 8793 });
await cli.ready; await cli.ready.catch((e) => {
console.log(e);
// if fail to start, skip for now as it's very flaky
this.skip();
});
}); });
after(async () => { after(async () => {

View file

@ -8,14 +8,18 @@ describe('With SolidJS', () => {
/** @type {import('./test-utils').WranglerCLI} */ /** @type {import('./test-utils').WranglerCLI} */
let cli; let cli;
before(async () => { before(async function () {
fixture = await loadFixture({ fixture = await loadFixture({
root: './fixtures/with-solid-js/', root: './fixtures/with-solid-js/',
}); });
await fixture.build(); await fixture.build();
cli = await runCLI('./fixtures/with-solid-js/', { silent: true, port: 8790 }); cli = await runCLI('./fixtures/with-solid-js/', { silent: true, port: 8790 });
await cli.ready; await cli.ready.catch((e) => {
console.log(e);
// if fail to start, skip for now as it's very flaky
this.skip();
});
}); });
after(async () => { after(async () => {

View file

@ -17,7 +17,8 @@ async function svelteConfigHasPreprocess(root: URL) {
for (const file of svelteConfigFiles) { for (const file of svelteConfigFiles) {
const filePath = fileURLToPath(new URL(file, root)); const filePath = fileURLToPath(new URL(file, root));
try { try {
const config = (await import(filePath)).default; // Suppress warnings by vite: "The above dynamic import cannot be analyzed by Vite."
const config = (await import(/* @vite-ignore */ filePath)).default;
return !!config.preprocess; return !!config.preprocess;
} catch {} } catch {}
} }

View file

@ -243,8 +243,18 @@ You can set functionPerRoute: false to prevent surpassing the limit.`
// Multiple entrypoint support // Multiple entrypoint support
if (_entryPoints.size) { if (_entryPoints.size) {
const getRouteFuncName = (route: RouteData) => route.component.replace('src/pages/', '');
const getFallbackFuncName = (entryFile: URL) =>
basename(entryFile.toString())
.replace('entry.', '')
.replace(/\.mjs$/, '');
for (const [route, entryFile] of _entryPoints) { for (const [route, entryFile] of _entryPoints) {
const func = basename(entryFile.toString()).replace(/\.mjs$/, ''); const func = route.component.startsWith('src/pages/')
? getRouteFuncName(route)
: getFallbackFuncName(entryFile);
await createFunctionFolder(func, entryFile, filesToInclude, logger); await createFunctionFolder(func, entryFile, filesToInclude, logger);
routeDefinitions.push({ routeDefinitions.push({
src: route.pattern.source, src: route.pattern.source,

View file

@ -0,0 +1,10 @@
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
adapter: vercel({
// Pass some value to make sure it doesn't error out
includeFiles: ['included.js'],
}),
output: 'server'
});

View file

@ -0,0 +1 @@
'works'

View file

@ -0,0 +1,9 @@
{
"name": "@test/astro-vercel-serverless-with-dynamic-routes",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/vercel": "workspace:*",
"astro": "workspace:*"
}
}

View file

@ -0,0 +1,12 @@
---
export const prerender = false;
---
<html>
<head>
<title>testing {Astro.params.id}</title>
</head>
<body>
<h1>testing {Astro.params.id}</h1>
</body>
</html>

View file

@ -0,0 +1,7 @@
export const prerender = false;
export async function GET({ params }) {
return Response.json({
id: params.id
});
}

View file

@ -0,0 +1,12 @@
---
export const prerender = import.meta.env.PRERENDER;
---
<html>
<head>
<title>testing</title>
</head>
<body>
<h1>testing</h1>
</body>
</html>

View file

@ -0,0 +1,25 @@
import { expect } from 'chai';
import { loadFixture } from './test-utils.js';
describe('Serverless with dynamic routes', () => {
/** @type {import('./test-utils.js').Fixture} */
let fixture;
before(async () => {
process.env.PRERENDER = true;
fixture = await loadFixture({
root: './fixtures/serverless-with-dynamic-routes/',
output: 'hybrid',
});
await fixture.build();
});
it('build successful', async () => {
expect(await fixture.readFile('../.vercel/output/static/index.html')).to.be.ok;
expect(
await fixture.readFile('../.vercel/output/functions/[id]/index.astro.func/.vc-config.json')
).to.be.ok;
expect(await fixture.readFile('../.vercel/output/functions/api/[id].js.func/.vc-config.json'))
.to.be.ok;
});
});

View file

@ -594,8 +594,8 @@ importers:
specifier: ^6.2.1 specifier: ^6.2.1
version: 6.2.1 version: 6.2.1
preferred-pm: preferred-pm:
specifier: ^3.0.3 specifier: ^3.1.2
version: 3.0.3 version: 3.1.2
prompts: prompts:
specifier: ^2.4.2 specifier: ^2.4.2
version: 2.4.2 version: 2.4.2
@ -642,8 +642,8 @@ importers:
specifier: ^0.2.4 specifier: ^0.2.4
version: 0.2.4(vite@4.4.9) version: 0.2.4(vite@4.4.9)
which-pm: which-pm:
specifier: ^2.0.0 specifier: ^2.1.1
version: 2.0.0 version: 2.1.1
yargs-parser: yargs-parser:
specifier: ^21.1.1 specifier: ^21.1.1
version: 21.1.1 version: 21.1.1
@ -2437,6 +2437,18 @@ importers:
packages/astro/test/fixtures/css-assets/packages/font-awesome: {} packages/astro/test/fixtures/css-assets/packages/font-awesome: {}
packages/astro/test/fixtures/css-dangling-references:
dependencies:
'@astrojs/svelte':
specifier: workspace:*
version: link:../../../../integrations/svelte
astro:
specifier: workspace:*
version: link:../../..
svelte:
specifier: '4'
version: 4.2.0
packages/astro/test/fixtures/css-import-as-inline: packages/astro/test/fixtures/css-import-as-inline:
dependencies: dependencies:
astro: astro:
@ -4800,6 +4812,15 @@ importers:
specifier: workspace:* specifier: workspace:*
version: link:../../../../../astro version: link:../../../../../astro
packages/integrations/vercel/test/fixtures/serverless-with-dynamic-routes:
dependencies:
'@astrojs/vercel':
specifier: workspace:*
version: link:../../..
astro:
specifier: workspace:*
version: link:../../../../../astro
packages/integrations/vercel/test/fixtures/static-assets: packages/integrations/vercel/test/fixtures/static-assets:
dependencies: dependencies:
'@astrojs/vercel': '@astrojs/vercel':
@ -6831,7 +6852,7 @@ packages:
meow: 6.1.1 meow: 6.1.1
outdent: 0.5.0 outdent: 0.5.0
p-limit: 2.3.0 p-limit: 2.3.0
preferred-pm: 3.0.3 preferred-pm: 3.1.2
resolve-from: 5.0.0 resolve-from: 5.0.0
semver: 7.5.4 semver: 7.5.4
spawndamnit: 2.0.0 spawndamnit: 2.0.0
@ -15181,8 +15202,8 @@ packages:
tar-fs: 2.1.1 tar-fs: 2.1.1
tunnel-agent: 0.6.0 tunnel-agent: 0.6.0
/preferred-pm@3.0.3: /preferred-pm@3.1.2:
resolution: {integrity: sha512-+wZgbxNES/KlJs9q40F/1sfOd/j7f1O9JaHcW5Dsn3aUUOZg3L2bjpVUcKV2jvtElYfoTuQiNeMfQJ4kwUAhCQ==} resolution: {integrity: sha512-nk7dKrcW8hfCZ4H6klWcdRknBOXWzNQByJ0oJyX97BOupsYD+FzLS4hflgEu/uPUEHZCuRfMxzCBsuWd7OzT8Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
dependencies: dependencies:
find-up: 5.0.0 find-up: 5.0.0
@ -17875,6 +17896,14 @@ packages:
load-yaml-file: 0.2.0 load-yaml-file: 0.2.0
path-exists: 4.0.0 path-exists: 4.0.0
/which-pm@2.1.1:
resolution: {integrity: sha512-xzzxNw2wMaoCWXiGE8IJ9wuPMU+EYhFksjHxrRT8kMT5SnocBPRg69YAMtyV4D12fP582RA+k3P8H9J5EMdIxQ==}
engines: {node: '>=8.15'}
dependencies:
load-yaml-file: 0.2.0
path-exists: 4.0.0
dev: false
/which-typed-array@1.1.11: /which-typed-array@1.1.11:
resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==} resolution: {integrity: sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}