Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ci] release #103

Merged
merged 1 commit into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 0 additions & 69 deletions .changeset/ten-cougars-pretend.md

This file was deleted.

70 changes: 70 additions & 0 deletions packages/netlify/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,75 @@
# @astrojs/netlify

## 4.0.0

### Major Changes

- [#84](https://github.com/withastro/adapters/pull/84) [`ca64544`](https://github.com/withastro/adapters/commit/ca645447402316963bcc1181292baea58b8e3bff) Thanks [@Skn0tt](https://github.com/Skn0tt)! - # Netlify Adapter v4 simplifies static + SSR deployments

This update is a complete overhaul of the Netlify adapter.
It simplifies the user-facing config, and resolves a number of bugs along the way.

Here's what changes:

## Netlify Context is automatically available via Locals

In v3, you could use `netlify-edge-middleware.ts` to inject data from the Netlify context into your Astro locals.
In v4, this file is no longer needed because the Netlify context is automatically made available via `Astro.locals.netlify.context`.
You can use this context to access information about the user (like geolocation or IP address), your Netlify site (like deploy ID) or the request (like its request ID or the CDN region it's served from).

**Action Required:**
Remove the `netlify-edge-middleware.ts` or `netlify-edge-middleware.js` file.
In your codebase, change all usage of locals injected through that file to use `Astro.locals.netlify.context` instead.

### Image CDN

v4 of this adapter integrates your Astro site with Netlify [Image CDN](https://docs.netlify.com/image-cdn/overview/).
This allows transforming images on-the-fly without impacting build times.
It's implemented using an [Astro Image Service](https://docs.astro.build/en/reference/image-service-reference/), and enabled by default.

## Replacement for On-Demand Builders

On-Demand Builders (ODB) allows SSR-Rendered pages to be cached using a Time to Live (TTL) strategy.
While the Netlify platform continues to support existing pages with ODBs, we now recommend using the much more powerful
[Fine-Grained Cache Control](https://www.netlify.com/blog/swr-and-fine-grained-cache-control) going forward.

In v3, you could deploy your SSR-Rendered Astro pages to ODBs by enabling the `builders` config option,
and then specifying the TTL on a per-page basis.
In v4, a new `cacheOnDemandPages` option replaces this config option. Take a look at the README to learn more about this.

**Action Required:**
Replace the `builders` config option with `cacheOnDemandPages`.

```diff lang="ts"
// astro.config.mjs
export default defineConfig({
// ...
adapter: netlify({
- builders: true
+ cacheOnDemandPages: true
}),
});
```

## `functionPerRoute` was removed

In v3, the `functionPerRoute` option allowed the SSR routes to be split up into multiple Netlify Functions.
This reduced the bundle sizes of each individual function, with the intention of speeding up code parsing, and therefore the time of cold starts.
In practice, this benefit is often nullified by the increase in number of cold starts - more handlers means fewer requests per handler, means more cold starts.

In v4, support for this deployment mode was removed.

**Action Required:**
Remove the `functionPerRoute` field from your config.

## `binaryMediaTypes` was removed

`binaryMediaTypes` was a workaround required for some Astro endpoints, because v3 deployed those as "old" Netlify Functions (now referred to as ["Lambda Compatibility Mode"](https://docs.netlify.com/functions/lambda-compatibility)).
v4 uses the new [Netlify Functions 2.0](https://www.netlify.com/blog/introducing-netlify-functions-2-0/), which simply doesn't need this workaround anymore - so we're removing it 🎉

**Action Required:**
Remove the `binaryMediaTypes` field from your config.

## 3.1.1

### Patch Changes
Expand Down
11 changes: 6 additions & 5 deletions packages/netlify/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ netlify deploy

The [Netlify Blog post on Astro](https://www.netlify.com/blog/how-to-deploy-astro/) and the [Netlify Docs](https://docs.netlify.com/integrations/frameworks/astro/) provide more information on how to use this integration to deploy to Netlify.


### Accessing edge context from your site

Netlify Edge Functions provide a [context object](https://docs.netlify.com/edge-functions/api/#netlify-specific-context-object) that includes metadata about the request such as a user’s IP, geolocation data, and cookies.
Expand All @@ -79,8 +78,11 @@ This can be accessed through the `Astro.locals.netlify.context` object:

```astro
---
const { geo: { city } } = Astro.locals.netlify.context
const {
geo: { city },
} = Astro.locals.netlify.context;
---

<h1>Hello there, friendly visitor from {city}!</h1>
```

Expand Down Expand Up @@ -164,20 +166,19 @@ Enabling the `cacheOnDemandPages` option in the adapter will cache all server-re
export default defineConfig({
output: 'server',
adapter: netlify({
cacheOnDemandPages: true
cacheOnDemandPages: true,
}),
});
```

This can be changed on a per-page basis by adding caching headers to your response:


```astro
---
// src/pages/index.astro
import Layout from '../components/Layout.astro';

Astro.response.headers.set('CDN-Cache-Control', "public, max-age=45, must-revalidate")
Astro.response.headers.set('CDN-Cache-Control', 'public, max-age=45, must-revalidate');
---

<Layout title="Astro on Netlify">
Expand Down
2 changes: 1 addition & 1 deletion packages/netlify/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@astrojs/netlify",
"description": "Deploy your site to Netlify",
"version": "3.1.1",
"version": "4.0.0",
"type": "module",
"types": "./dist/index.d.ts",
"author": "withastro",
Expand Down
10 changes: 6 additions & 4 deletions packages/netlify/src/functions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import netlifyIntegration, { type NetlifyIntegrationConfig } from "./index.js"
import netlifyIntegration, { type NetlifyIntegrationConfig } from './index.js';

export default function functionsIntegration(config: NetlifyIntegrationConfig) {
console.warn("The @astrojs/netlify/functions import is deprecated and will be removed in a future release. Please use @astrojs/netlify instead.")
return netlifyIntegration(config)
}
console.warn(
'The @astrojs/netlify/functions import is deprecated and will be removed in a future release. Please use @astrojs/netlify instead.'
);
return netlifyIntegration(config);
}
2 changes: 1 addition & 1 deletion packages/netlify/src/image-service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ExternalImageService, ImageMetadata } from 'astro';
import { baseService } from 'astro/assets';
import { AstroError } from 'astro/errors';
import { baseService } from 'astro/assets'

const SUPPORTED_FORMATS = ['avif', 'jpg', 'png', 'webp'];
const QUALITY_NAMES: Record<string, number> = { low: 25, mid: 50, high: 90, max: 100 };
Expand Down
10 changes: 5 additions & 5 deletions packages/netlify/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import type { AstroConfig, AstroIntegration, RouteData } from 'astro';
import { writeFile, mkdir, appendFile, rm } from 'fs/promises';
import type { IncomingMessage } from 'http';
import { fileURLToPath } from 'url';
import { build } from 'esbuild';
import { createRedirectsFromAstroRoutes } from '@astrojs/underscore-redirects';
import { version as packageVersion } from '../package.json';
import type { Context } from '@netlify/functions';
import type { AstroConfig, AstroIntegration, RouteData } from 'astro';
import { AstroError } from 'astro/errors';
import type { IncomingMessage } from 'http';
import { build } from 'esbuild';
import { appendFile, mkdir, rm, writeFile } from 'fs/promises';
import { version as packageVersion } from '../package.json';

export interface NetlifyLocals {
netlify: {
Expand Down
10 changes: 6 additions & 4 deletions packages/netlify/src/static.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import netlifyIntegration from "./index.js"
import netlifyIntegration from './index.js';

export default function staticIntegration() {
console.warn("The @astrojs/netlify/static import is deprecated and will be removed in a future release. Please use @astrojs/netlify instead.")
return netlifyIntegration()
}
console.warn(
'The @astrojs/netlify/static import is deprecated and will be removed in a future release. Please use @astrojs/netlify instead.'
);
return netlifyIntegration();
}
2 changes: 1 addition & 1 deletion packages/netlify/src/types.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
declare module "*.json";
declare module '*.json';
9 changes: 6 additions & 3 deletions packages/netlify/test/functions/cookies.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { loadFixture } from '@astrojs/test-utils';
import { expect } from 'chai';
import { loadFixture } from "@astrojs/test-utils"

describe('Cookies', () => {
let fixture;
Expand All @@ -15,9 +15,12 @@ describe('Cookies', () => {
import.meta.url
);
const { default: handler } = await import(entryURL);
const resp = await handler(new Request('http://example.com/login', { method: "POST", body: '{}' }), {})
const resp = await handler(
new Request('http://example.com/login', { method: 'POST', body: '{}' }),
{}
);
expect(resp.status).to.equal(301);
expect(resp.headers.get("location")).to.equal('/');
expect(resp.headers.get('location')).to.equal('/');
expect(resp.headers.getSetCookie()).to.eql(['foo=foo; HttpOnly', 'bar=bar; HttpOnly']);
});
});
42 changes: 22 additions & 20 deletions packages/netlify/test/functions/edge-middleware.test.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,47 @@
import { loadFixture } from '@astrojs/test-utils';
import { expect } from 'chai';
import { loadFixture } from "@astrojs/test-utils"

describe('Middleware', () => {
const root = new URL('./fixtures/middleware/', import.meta.url)
const root = new URL('./fixtures/middleware/', import.meta.url);

describe("edgeMiddleware: false", () => {
let fixture
describe('edgeMiddleware: false', () => {
let fixture;
before(async () => {
process.env.EDGE_MIDDLEWARE = 'false';
fixture = await loadFixture({ root });
await fixture.build();
})
});

it('emits no edge function', async () => {
expect(fixture.pathExists('../.netlify/edge-functions/middleware/middleware.mjs')).to.be.false
expect(fixture.pathExists('../.netlify/edge-functions/middleware/middleware.mjs')).to.be
.false;
});

it('applies middleware to static files at build-time', async () => {
// prerendered page has middleware applied at build time
const prerenderedPage = await fixture.readFile('prerender/index.html')
expect(prerenderedPage).to.contain("<title>Middleware</title>")
const prerenderedPage = await fixture.readFile('prerender/index.html');
expect(prerenderedPage).to.contain('<title>Middleware</title>');
});
})

});

describe("edgeMiddleware: true", () => {
let fixture
describe('edgeMiddleware: true', () => {
let fixture;
before(async () => {
process.env.EDGE_MIDDLEWARE = 'true';
fixture = await loadFixture({ root });
await fixture.build();
})
});

it('emits an edge function', async () => {
const contents = await fixture.readFile('../.netlify/edge-functions/middleware/middleware.mjs')
const contents = await fixture.readFile(
'../.netlify/edge-functions/middleware/middleware.mjs'
);
expect(contents.includes('"Hello world"')).to.be.false;
})
});

it('does not apply middleware during prerendering', async () => {
const prerenderedPage = await fixture.readFile('prerender/index.html')
expect(prerenderedPage).to.contain("<title></title>")
})
})
const prerenderedPage = await fixture.readFile('prerender/index.html');
expect(prerenderedPage).to.contain('<title></title>');
});
});
});
10 changes: 2 additions & 8 deletions packages/netlify/test/functions/redirects.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { loadFixture } from '@astrojs/test-utils';
import { expect } from 'chai';
import { loadFixture } from "@astrojs/test-utils"

describe('SSR - Redirects', () => {
let fixture;
Expand All @@ -12,13 +12,7 @@ describe('SSR - Redirects', () => {
it('Creates a redirects file', async () => {
let redirects = await fixture.readFile('./_redirects');
let parts = redirects.split(/\s+/);
expect(parts).to.deep.equal([
'',
'/other',
'/',
'301',
'',
]);
expect(parts).to.deep.equal(['', '/other', '/', '301', '']);
expect(redirects).to.matchSnapshot();
});

Expand Down
4 changes: 2 additions & 2 deletions packages/netlify/test/static/redirects.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { loadFixture } from '@astrojs/test-utils';
import { expect } from 'chai';
import { loadFixture } from "@astrojs/test-utils"

describe('SSG - Redirects', () => {
let fixture;
Expand All @@ -26,7 +26,7 @@ describe('SSG - Redirects', () => {
'/blog/*',
'/team/articles/*/index.html',
'301',

'',
]);
});
Expand Down