Skip to content
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## UNRELEASED

### Adds

* Add support for `prependMain` and `appendMain` in the `aposData` object, allowing for custom HTML to be injected into the `<main>` sections of the layout.
* Add `portMapping` option.

## 1.5.2 (2025-09-09)

### Fixes
Expand Down
73 changes: 42 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ When you use this module, you will have **two** projects:
1. An Astro project. This is where you write your templates and frontend code.

2. An Apostrophe project. This is where you define your page types, widget types
and other content types with their schemas and other customizations.
and other content types with their schemas and other customizations.

This kind of dual-project CMS integration is typical for Astro.

Expand All @@ -48,7 +48,7 @@ To get you started quickly, we recommend one of our official Astro starter kits:
* [apostrophecms/starter-kit-astro-apollo](https://github.com/apostrophecms/starter-kit-astro-apollo) is a full-fledged project with a blog, a design system and other nice touches.
* [apostrophecms/starter-kit-astro-apollo-pro](https://github.com/apostrophecms/starter-kit-astro-apollo-pro) is great for those who expect to use our [Pro features](https://apostrophecms.com/pro) right away, but keep in mind you can add those modules to any project later.

> 💡 These combined Astro + Apostrophe projects are best launched by forking the repository, not using our CLI. Follow the links to see how to fork these projects and get started on your own.
> 💡 These combined Astro + Apostrophe projects are best launched by forking the repository, not using our CLI. Follow the links to see how to fork these projects and get started on your own.

You can also adapt your own existing ApostropheCMS project as explained below.

Expand All @@ -67,7 +67,7 @@ module into your Astro project. Install this module in your
```shell
cd my-astro-project
npm install @apostrophecms/apostrophe-astro
```
```

*Astro 3.x and 4.x are both supported.*

Expand Down Expand Up @@ -141,14 +141,21 @@ at runtime with the `APOS_HOST` environment variable.

During development it defaults automatically to: `http://localhost:3000`

You can use `*` as value to allow all host. Should be used in conjunction with `portMapping` below.

### `widgetsMapping` (mandatory)

The file in your project that contains the mapping between Apostrophe widget types and your Astro components (see below).
The file in your project that contains the mapping between Apostrophe widget types and your Astro components (see below).

### `templatesMapping` (mandatory)

The file in your project that contains the mapping between Apostrophe templates and your Astro templates (see below).

### `portMapping` (optional)

An array containing the mapping between the origin port and the target port.
Setting `[ 4321, 3000 ]` means calls from `http://localhost:4321` will be forwarded to `http://localhost:3000`.

### `viewTransitionWorkaround` (optional)

If set to `true`, Apostrophe will refresh its admin UI JavaScript on
Expand Down Expand Up @@ -225,8 +232,8 @@ the standard name for this template in ApostropheCMS.
The integration comes with two additional special template names that can be mapped to Astro templates.
You should not add a module name to these special names:

- `apos-fetch-error`: served when Apostrophe generates a 500-class error. The integration will set Astro's response status to 500.
- `apos-no-template`: served when there is no mapping corresponding to the Apostrophe page type for this page.
* `apos-fetch-error`: served when Apostrophe generates a 500-class error. The integration will set Astro's response status to 500.
* `apos-no-template`: served when there is no mapping corresponding to the Apostrophe page type for this page.

See below for an example Astro template for the `@apostrophe-cms/home-page` type. But first,
let's look at widgets.
Expand Down Expand Up @@ -310,13 +317,13 @@ Thanks to the `aposPageFetch` call, the `aposData` object will then contain all
the information normally provided by `data` in an ApostropheCMS Nunjucks template.
This includes, but is not limited to:

- `page`: the page document for the current URL, if any
- `piece`: the piece document when on a "show page" for a piece page type
- `pieces`: an array of pieces when on an "index page" for a piece page type
- `user`: information about the currently logged-in user
- `global`: the ApostropheCMS global document e.g. global settings, editable global
* `page`: the page document for the current URL, if any
* `piece`: the piece document when on a "show page" for a piece page type
* `pieces`: an array of pieces when on an "index page" for a piece page type
* `user`: information about the currently logged-in user
* `global`: the ApostropheCMS global document e.g. global settings, editable global
headers and footers, etc.
- `query`: the `req.query` object, giving access to query parameters in the URL.
* `query`: the `req.query` object, giving access to query parameters in the URL.

Any other data that your custom Apostrophe code attaches to `req.data` is also
available here.
Expand All @@ -332,21 +339,21 @@ integration to leverage the global layout.
To override any aspect of the global layout, take advantage of the following Astro slots,
which are closely related to what ApostropheCMS offers in Nunjucks:

- `startHead`: slot in the very beginning of the `<head>`
- `standardHead`: slot in the middle of `<head>`, just after `<title>`
- `extraHead`: still in the HTML `<head>`, at the very end
- `startBody`: at the very beginning of the `<body>` - this is not part of the refresh zone in edit mode
- `beforeMain`: at the very beginning of the main body zone - part of the refresh zone in edit mode
- `main`: the inner part of the main body zone - part of the refresh zone in edit mode
- `afterMain`: at the very end of the main body zone - part of the refresh zone in edit mode
- `endBody`: at the very end of the `<body>` - this is not part of the refresh zone in edit mode
* `startHead`: slot in the very beginning of the `<head>`
* `standardHead`: slot in the middle of `<head>`, just after `<title>`
* `extraHead`: still in the HTML `<head>`, at the very end
* `startBody`: at the very beginning of the `<body>` - this is not part of the refresh zone in edit mode
* `beforeMain`: at the very beginning of the main body zone - part of the refresh zone in edit mode
* `main`: the inner part of the main body zone - part of the refresh zone in edit mode
* `afterMain`: at the very end of the main body zone - part of the refresh zone in edit mode
* `endBody`: at the very end of the `<body>` - this is not part of the refresh zone in edit mode

In addition, the `AposLayout` component expects four props:

- `aposData`: the data fetched from Apostrophe
- `title`: this will go in the `<title>` HTML tag
- `lang` which will be set in the `<html>` `lang` attribute
- `bodyClass`: this will be added in the `class` attribute of the `<body>` element
* `aposData`: the data fetched from Apostrophe
* `title`: this will go in the `<title>` HTML tag
* `lang` which will be set in the `<html>` `lang` attribute
* `bodyClass`: this will be added in the `class` attribute of the `<body>` element

This layout component will automatically manage the switch between support for
the editing UI if a user is logged in and a simpler "Run Layout" for all other
Expand Down Expand Up @@ -453,7 +460,7 @@ the [attachment field format](https://v3.docs.apostrophecms.org/reference/api/fi

Nothing! Well, almost.

* Your project must be using Apostrophe 3.x.
* Your project must be using Apostrophe 4.x.
* You'll need to `npm update` your project to the latest version of `apostrophe`.
* You'll need to set the `APOS_EXTERNAL_FRONT_KEY` environment variable to a secret
value of your choosing when running Apostrphe.
Expand Down Expand Up @@ -493,6 +500,7 @@ to Apostrophe. Therefore any additional extensions you have added such as
Apostrophe's hCaptcha and TOTP modules will work as expected.

## Redirections

When Apostrophe sends a response as a redirection, you will receive a specially
formatted `aposData` object containing `redirect: true`, a `url` property for the url
to redirect to, and a `status` for the redirection HTTP status code. This is handled
Expand All @@ -507,19 +515,22 @@ if (aposData.redirect) {
```

## 404 Not Found

Much like the redirect case, when Apostrophe determines that the page was not
found, `aposData.notFound` will be set to true. The example `[...slug].astro`
file provided above includes logic to set Astro's status code to 404 in this
situation.

## Reserved routes
As this integration proxies certain Apostrophe endpoints, there are some routes that are taken by those endpoints:
- `/apos-frontend/[...slug]` for serving Apostrophe assets
- `/uploads/[...slug]` for serving Apostrophe uploaded assets
- `/api/v1/[...slug]` and `/[locale]/api/v1/[...slug]` for Apostrophe API endpoints
- `/login` and `/[locale]/login` for the login page

As all Apostrophe API endpoints are proxied, you can expose new api routes as usual in your Apostrophe modules, and be able to request them through your Astro application.
As this integration proxies certain Apostrophe endpoints, there are some routes that are taken by those endpoints:

* `/apos-frontend/[...slug]` for serving Apostrophe assets
* `/uploads/[...slug]` for serving Apostrophe uploaded assets
* `/api/v1/[...slug]` and `/[locale]/api/v1/[...slug]` for Apostrophe API endpoints
* `/login` and `/[locale]/login` for the login page

As all Apostrophe API endpoints are proxied, you can expose new api routes as usual in your Apostrophe modules, and be able to request them through your Astro application.
Those proxies are forwarding all of the original request headers, such as cookies, so that Apostrophe login works normally.

## What about widget players?
Expand Down
2 changes: 2 additions & 0 deletions components/layouts/AposEditLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ if (aposData.bundleMarkup) {

<div data-apos-refreshable>
<slot name="beforeMain" />
<Fragment set:html={aposData.prependMain} is:inline />
<slot name="main" />
<Fragment set:html={aposData.appendMain} is:inline />
<slot name="afterMain" />
</div>

Expand Down
2 changes: 2 additions & 0 deletions components/layouts/AposRunLayout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ const { title, bodyClass, aposData } = Astro.props;
<Fragment set:html={aposData.prependBody} is:inline />
<slot name="startBody" />
<slot name="beforeMain" />
<Fragment set:html={aposData.prependMain} is:inline />
<slot name="main" />
<Fragment set:html={aposData.appendMain} is:inline />
<slot name="afterMain" />
<Fragment set:html={aposData.appendBody} is:inline />
<slot name="endBody" />
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export default function apostropheIntegration(options) {
),
vitePluginApostropheConfig(
options.aposHost,
options.portMapping,
options.forwardHeaders,
options.viewTransitionWorkaround,
options.includeResponseHeaders,
Expand Down
10 changes: 9 additions & 1 deletion lib/aposResponse.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,16 @@ export default async function aposResponse(req) {
try {
// Prepare URL for the backend request
const url = new URL(req.url);

const [ portSource, portTarget ] = config.portMapping;
if (portSource && portTarget) {
url.port = url.port.replace(portSource, portTarget);
}

const aposHost = process.env.APOS_HOST || config.aposHost;
const aposUrl = new URL(url.pathname, aposHost);
const aposUrl = (aposHost === '*')
? new URL(url.pathname, url)
: new URL(url.pathname, aposHost);
aposUrl.search = url.search;

// Prepare headers, excluding any specified in config
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion vite/vite-plugin-apostrophe-config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export function vitePluginApostropheConfig(
aposHost,
portMapping = [],
forwardHeaders = null,
viewTransitionWorkaround,
includeResponseHeaders = null,
Expand All @@ -23,6 +24,9 @@ export function vitePluginApostropheConfig(
return `
export default {
aposHost: "${aposHost}"
${aposHost === '*' ? `,
portMapping: ${JSON.stringify(portMapping)}` : '[]'
}
${headersToInclude ? `,
includeResponseHeaders: ${JSON.stringify(headersToInclude)}` : ''
}
Expand All @@ -37,4 +41,4 @@ export function vitePluginApostropheConfig(
}
},
};
};
};