summaryrefslogtreecommitdiff
path: root/packages/integrations/node
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/node')
-rw-r--r--packages/integrations/node/CHANGELOG.md12
-rw-r--r--packages/integrations/node/README.md10
-rw-r--r--packages/integrations/node/src/http-server.ts16
-rw-r--r--packages/integrations/node/src/index.ts3
-rw-r--r--packages/integrations/node/src/preview.ts3
-rw-r--r--packages/integrations/node/src/server.ts1
-rw-r--r--packages/integrations/node/src/standalone.ts1
-rw-r--r--packages/integrations/node/src/types.ts1
-rw-r--r--packages/integrations/node/test/assets.test.js43
-rw-r--r--packages/integrations/node/test/fixtures/image/src/assets/file.txt1
-rw-r--r--packages/integrations/node/test/fixtures/image/src/pages/text-file.astro14
11 files changed, 103 insertions, 2 deletions
diff --git a/packages/integrations/node/CHANGELOG.md b/packages/integrations/node/CHANGELOG.md
index 732122ecf..e4cf76b85 100644
--- a/packages/integrations/node/CHANGELOG.md
+++ b/packages/integrations/node/CHANGELOG.md
@@ -13,6 +13,18 @@
- Updated dependencies [[`abf601233`](https://github.com/withastro/astro/commit/abf601233f8188d118a8cb063c777478d8d9f1a3), [`6201bbe96`](https://github.com/withastro/astro/commit/6201bbe96c2a083fb201e4a43a9bd88499821a3e), [`cdabf6ef0`](https://github.com/withastro/astro/commit/cdabf6ef02be7220fd2b6bdcef924ceca089381e), [`1c48ed286`](https://github.com/withastro/astro/commit/1c48ed286538ab9e354eca4e4dcd7c6385c96721), [`37697a2c5`](https://github.com/withastro/astro/commit/37697a2c5511572dc29c0a4ea46f90c2f62be8e6), [`bd0c2e9ae`](https://github.com/withastro/astro/commit/bd0c2e9ae3389a9d3085050c1e8134ae98dff299), [`0fe3a7ed5`](https://github.com/withastro/astro/commit/0fe3a7ed5d7bb1a9fce1623e84ba14104b51223c), [`710be505c`](https://github.com/withastro/astro/commit/710be505c9ddf416e77a75343d8cae9c497d72c6), [`153a5abb9`](https://github.com/withastro/astro/commit/153a5abb905042ac68b712514dc9ec387d3e6b17)]:
- astro@4.0.0-beta.0
+## 6.1.0
+
+### Minor Changes
+
+- [#9125](https://github.com/withastro/astro/pull/9125) [`8f1d50957`](https://github.com/withastro/astro/commit/8f1d509574f5ee5d77816a13d89ce452dce403ff) Thanks [@matthewp](https://github.com/matthewp)! - Automatically sets immutable cache headers for assets served from the `/_astro` directory.
+
+## 6.1.0
+
+### Minor Changes
+
+- [#9125](https://github.com/withastro/astro/pull/9125) [`8f1d50957`](https://github.com/withastro/astro/commit/8f1d509574f5ee5d77816a13d89ce452dce403ff) Thanks [@matthewp](https://github.com/matthewp)! - Automatically sets immutable cache headers for assets served from the `/_astro` directory.
+
## 6.0.4
### Patch Changes
diff --git a/packages/integrations/node/README.md b/packages/integrations/node/README.md
index 5753a59bc..af11405c0 100644
--- a/packages/integrations/node/README.md
+++ b/packages/integrations/node/README.md
@@ -190,6 +190,16 @@ In the case of multiple run-time variables, store them in a seperate file (e.g.
export $(cat .env.runtime) && astro build
```
+#### Assets
+
+In standalone mode, assets in your `dist/client/` folder are served via the standalone server. You might be deploying these assets to a CDN, in which case the server will never actually be serving them. But in some cases, such as intranet sites, it's fine to serve static assets directly from the application server.
+
+Assets in the `dist/client/_astro/` folder are the ones that Astro has built. These assets are all named with a hash and therefore can be given long cache headers. Internally the adapter adds this header for these assets:
+
+```
+Cache-Control: public, max-age=31536000, immutable
+```
+
## Troubleshooting
### SyntaxError: Named export 'compile' not found
diff --git a/packages/integrations/node/src/http-server.ts b/packages/integrations/node/src/http-server.ts
index 2f2339cdf..904937601 100644
--- a/packages/integrations/node/src/http-server.ts
+++ b/packages/integrations/node/src/http-server.ts
@@ -10,6 +10,7 @@ interface CreateServerOptions {
port: number;
host: string | undefined;
removeBase: (pathname: string) => string;
+ assets: string;
}
function parsePathname(pathname: string, host: string | undefined, port: number) {
@@ -22,9 +23,16 @@ function parsePathname(pathname: string, host: string | undefined, port: number)
}
export function createServer(
- { client, port, host, removeBase }: CreateServerOptions,
+ { client, port, host, removeBase, assets }: CreateServerOptions,
handler: http.RequestListener
) {
+ // The `base` is removed before passed to this function, so we don't
+ // need to check for it here.
+ const assetsPrefix = `/${assets}/`;
+ function isImmutableAsset(pathname: string) {
+ return pathname.startsWith(assetsPrefix);
+ }
+
const listener: http.RequestListener = (req, res) => {
if (req.url) {
let pathname: string | undefined = removeBase(req.url);
@@ -54,6 +62,12 @@ export function createServer(
// File not found, forward to the SSR handler
handler(req, res);
});
+ stream.on('headers', (_res: http.ServerResponse<http.IncomingMessage>) => {
+ if (isImmutableAsset(encodedURI)) {
+ // Taken from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#immutable
+ _res.setHeader('Cache-Control', 'public, max-age=31536000, immutable');
+ }
+ });
stream.on('directory', () => {
// On directory find, redirect to the trailing slash
let location: string;
diff --git a/packages/integrations/node/src/index.ts b/packages/integrations/node/src/index.ts
index 1f3707949..bac5c25ef 100644
--- a/packages/integrations/node/src/index.ts
+++ b/packages/integrations/node/src/index.ts
@@ -6,7 +6,7 @@ export function getAdapter(options: Options): AstroAdapter {
name: '@astrojs/node',
serverEntrypoint: '@astrojs/node/server.js',
previewEntrypoint: '@astrojs/node/preview.js',
- exports: ['handler', 'startServer'],
+ exports: ['handler', 'startServer', 'options'],
args: options,
supportedAstroFeatures: {
hybridOutput: 'stable',
@@ -49,6 +49,7 @@ export default function createIntegration(userOptions: UserOptions): AstroIntegr
server: config.build.server?.toString(),
host: config.server.host,
port: config.server.port,
+ assets: config.build.assets,
};
setAdapter(getAdapter(_options));
diff --git a/packages/integrations/node/src/preview.ts b/packages/integrations/node/src/preview.ts
index 70ed54698..89baa1897 100644
--- a/packages/integrations/node/src/preview.ts
+++ b/packages/integrations/node/src/preview.ts
@@ -17,11 +17,13 @@ const preview: CreatePreviewServer = async function ({
type ServerModule = ReturnType<typeof createExports>;
type MaybeServerModule = Partial<ServerModule>;
let ssrHandler: ServerModule['handler'];
+ let options: ServerModule['options'];
try {
process.env.ASTRO_NODE_AUTOSTART = 'disabled';
const ssrModule: MaybeServerModule = await import(serverEntrypoint.toString());
if (typeof ssrModule.handler === 'function') {
ssrHandler = ssrModule.handler;
+ options = ssrModule.options!;
} else {
throw new AstroError(
`The server entrypoint doesn't have a handler. Are you sure this is the right file?`
@@ -59,6 +61,7 @@ const preview: CreatePreviewServer = async function ({
port,
host,
removeBase,
+ assets: options.assets,
},
handler
);
diff --git a/packages/integrations/node/src/server.ts b/packages/integrations/node/src/server.ts
index 90bf8c44c..88bcd7d62 100644
--- a/packages/integrations/node/src/server.ts
+++ b/packages/integrations/node/src/server.ts
@@ -8,6 +8,7 @@ applyPolyfills();
export function createExports(manifest: SSRManifest, options: Options) {
const app = new NodeApp(manifest);
return {
+ options: options,
handler: middleware(app, options.mode),
startServer: () => startServer(app, options),
};
diff --git a/packages/integrations/node/src/standalone.ts b/packages/integrations/node/src/standalone.ts
index abe40ff5c..e167e8ab6 100644
--- a/packages/integrations/node/src/standalone.ts
+++ b/packages/integrations/node/src/standalone.ts
@@ -52,6 +52,7 @@ export default function startServer(app: NodeApp, options: Options) {
port,
host,
removeBase: app.removeBase.bind(app),
+ assets: options.assets,
},
handler
);
diff --git a/packages/integrations/node/src/types.ts b/packages/integrations/node/src/types.ts
index 85f4f4fbc..1917d8cf3 100644
--- a/packages/integrations/node/src/types.ts
+++ b/packages/integrations/node/src/types.ts
@@ -15,6 +15,7 @@ export interface Options extends UserOptions {
port: number;
server: string;
client: string;
+ assets: string;
}
export type RequestHandlerParams = [
diff --git a/packages/integrations/node/test/assets.test.js b/packages/integrations/node/test/assets.test.js
new file mode 100644
index 000000000..9e44ab31d
--- /dev/null
+++ b/packages/integrations/node/test/assets.test.js
@@ -0,0 +1,43 @@
+import { expect } from 'chai';
+import nodejs from '../dist/index.js';
+import { loadFixture } from './test-utils.js';
+import * as cheerio from 'cheerio';
+
+describe('Assets', () => {
+ /** @type {import('./test-utils').Fixture} */
+ let fixture;
+ let devPreview;
+
+ before(async () => {
+ fixture = await loadFixture({
+ root: './fixtures/image/',
+ output: 'server',
+ adapter: nodejs({ mode: 'standalone' }),
+ vite: {
+ build: {
+ assetsInlineLimit: 0,
+ },
+ },
+ });
+ await fixture.build();
+ devPreview = await fixture.preview();
+ });
+
+ after(async () => {
+ await devPreview.stop();
+ });
+
+ it('Assets within the _astro folder should be given immutable headers', async () => {
+ let response = await fixture.fetch('/text-file');
+ let cacheControl = response.headers.get('cache-control');
+ expect(cacheControl).to.equal(null);
+ const html = await response.text();
+ const $ = cheerio.load(html);
+
+ // Fetch the asset
+ const fileURL = $('a').attr('href');
+ response = await fixture.fetch(fileURL);
+ cacheControl = response.headers.get('cache-control');
+ expect(cacheControl).to.equal('public, max-age=31536000, immutable');
+ });
+});
diff --git a/packages/integrations/node/test/fixtures/image/src/assets/file.txt b/packages/integrations/node/test/fixtures/image/src/assets/file.txt
new file mode 100644
index 000000000..e9ea42a12
--- /dev/null
+++ b/packages/integrations/node/test/fixtures/image/src/assets/file.txt
@@ -0,0 +1 @@
+this is a text file
diff --git a/packages/integrations/node/test/fixtures/image/src/pages/text-file.astro b/packages/integrations/node/test/fixtures/image/src/pages/text-file.astro
new file mode 100644
index 000000000..893250360
--- /dev/null
+++ b/packages/integrations/node/test/fixtures/image/src/pages/text-file.astro
@@ -0,0 +1,14 @@
+---
+import txt from '../assets/file.txt?url';
+---
+<html>
+ <head>
+ <title>Testing</title>
+ </head>
+ <body>
+ <h1>Testing</h1>
+ <main>
+ <a href={txt} download>Download text file</a>
+ </main>
+ </body>
+</html>