Skip to content

Commit

Permalink
Merge branch 'main' into slots-base
Browse files Browse the repository at this point in the history
* main:
  [Next.js] Better Vercel deployment (#6441)
  Replace all `yarn` appearences with `pnpm` (#6433)
  Add deprecation notices to the Upgrade guide (#6426)
  Clean up #6422 (#6443)
  Rename page title from Frontend to Volto UI (#6438)
  URL-Management control panel: Add missing translations (#6436)
  Fix broken links (#6440)
  Fix broken links (#6439)
  Used resource title instead of resource type in page title. (#6402)
  • Loading branch information
sneridagh committed Oct 26, 2024
2 parents 3bb80e9 + f576c13 commit 4fa8e43
Show file tree
Hide file tree
Showing 48 changed files with 774 additions and 246 deletions.
95 changes: 63 additions & 32 deletions apps/nextjs/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Plone on Next.js

This is a proof of concept of a [Next.js](https://nextjs.org) app, using the app router and the `@plone/client` and `@plone/components` library. This is intended to serve as both a playground for the development of both packages and as demo of Plone using Next.js.
This is a proof of concept of a [Next.js](https://nextjs.org) app, using the app router and the `@plone/client` and `@plone/components` library.
This is intended to serve as both a playground for the development of both packages and as a demo of Plone using Next.js.

> [!WARNING]
> This package or app is experimental.
Expand All @@ -9,7 +10,7 @@ This is a proof of concept of a [Next.js](https://nextjs.org) app, using the app
## Development

To start, from the root of the monorepo:
To start, from the root of the monorepo, issue the following commands in a shell session.

```shell
pnpm install
Expand All @@ -25,65 +26,93 @@ make backend-docker-start

## Deployment at Vercel


We introduce an environment variable `API_SERVER_URL`.
You need to create this environment variable in the Vercel deployment's control panel, specifying the URL where your backend API server is deployed, and the route where the API is located, as shown.
For deploying your app at Vercel, you need to create the environment variable `API_SERVER_URL` in Vercel's deployment control panel, specifying the URL where your backend API server is deployed, and the route where the API is located, as shown.

```shell
API_SERVER_URL=https://my-server-DNS-name.tld/api
```

For production deployments, you will need to force the deployment URL, otherwise you will have issues with CORS.
To do so, set another environment variable for the production URL, `NEXT_PRODUCTION_URL`.
This URL needs to be scheme-less, without `http` or `https`, and consist only of the domain name:

```shell
NEXT_PRODUCTION_URL=my-nextjs-production-DNS-name.tld
```

### Application rewrite configuragtion

To avoid issues with CORS and maintain the server counterpart private, our Next.js app should have a rewrite, configured as follows:
To avoid issues with CORS and maintain the server counterpart private, your Next.js app should have a rewrite, configured as follows:

```jsx
const nextConfig = {
// Rewrite to the backend to avoid CORS
async rewrites() {
const apiServerURL =
process.env.API_SERVER_URL ||
'http://localhost:8080/Plone/%2B%2Bapi%2B%2B';
let apiServerURL, vhmRewriteRule;
if (
process.env.API_SERVER_URL &&
(process.env.NEXT_PRODUCTION_URL || process.env.NEXT_PUBLIC_VERCEL_URL)
) {
// We are in Vercel
apiServerURL = process.env.API_SERVER_URL;
vhmRewriteRule = `/VirtualHostBase/https/${
process.env.NEXT_PRODUCTION_URL
? // We are in the production deployment
process.env.NEXT_PRODUCTION_URL
: // We are in the preview deployment
process.env.NEXT_PUBLIC_VERCEL_URL
}%3A443/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot`;
} else if (process.env.API_SERVER_URL) {
// We are in development
apiServerURL = process.env.API_SERVER_URL;
vhmRewriteRule =
'/VirtualHostBase/http/localhost%3A3000/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot';
} else {
// We are in development and the API_SERVER_URL is not set, so we use a local backend
apiServerURL = 'http://localhost:8080';
vhmRewriteRule =
'/VirtualHostBase/http/localhost%3A3000/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot';
}

return [
{
source: '/\\+\\+api\\+\\+/:slug*',
destination:
`${apiServerURL}/VirtualHostBase/https/${process.env.NEXT_PUBLIC_VERCEL_URL}%3A443/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot/:slug*`,
`${apiServerURL}${vhmRewriteRule}/:slug*`,
},
];
},
};
```

Plone Client uses the `++api++` prefix as default, so we should create a redirect in our app pointing to the API server, but using Plone's traditional virtual host management configuration.
Plone Client uses the `++api++` prefix as default, so you should create a redirect in your app pointing to the API server, but using Plone's traditional virtual host management configuration.

Next.js rewrites are picky on the `destination` field, because its rewrite library does not support URLs with regular expression operators.
Therefore, we can't use the usual `++api++` route for the rewrite.
This will allow us to infer the current server URL—even in deployed branches and pull requests—without touching the rewrite rules.
We will fallback to configure a `api` route in our reverse proxy of choice.
Next.js rewrites are picky with the `destination` field, because its rewrite library does not support URLs with regular expression operators.
Therefore, you can't use the usual `++api++` route for the rewrite.
This will allow you to infer the current server URL—even in deployed branches and pull requests—without touching the rewrite rules.
You will fallback to configure a `api` route in your reverse proxy of choice.

### Plone backend

You have to deploy the Plone backend elsewhere, since Vercel is serverless oriented.
We need to set up the rewrite rule in Next.js's `rewrite` feature as shown in the previous section.
You need to set up the rewrite rule in Next.js's `rewrite` feature as shown in the previous section.

We will fallback to configure an `api` route in our reverse proxy of choice.
You will fallback to configure an `api` route in your reverse proxy of choice.

For example, if we use `traefik`:
For example, if you use `traefik`:

```yaml
## VHM rewrite /api/ (Plone Next.js)
- "traefik.http.middlewares.mw-backend-vhm-api.replacepathregex.regex=^/api($$|/.*)"
## We remove the incoming /api and just use the path
- "traefik.http.middlewares.mw-backend-vhm-api.replacepathregex.replacement=$$1"

## /api router
- traefik.http.routers.rt-backend-api.rule=Host(`my_server_DNS_name`) && PathPrefix(`/api`)
- traefik.http.routers.rt-backend-api.entrypoints=https
- traefik.http.routers.rt-backend-api.tls=true
- traefik.http.routers.rt-backend-api.service=svc-backend
- traefik.http.routers.rt-backend-api.middlewares=gzip,mw-backend-vhm-api
## VHM rewrite /api/ (Plone Next.js)
- "traefik.http.middlewares.mw-backend-vhm-api.replacepathregex.regex=^/api($$|/.*)"
## We remove the incoming /api and just use the path
- "traefik.http.middlewares.mw-backend-vhm-api.replacepathregex.replacement=$$1"

## /api router
- traefik.http.routers.rt-backend-api.rule=Host(`my_server_DNS_name`) && PathPrefix(`/api`)
- traefik.http.routers.rt-backend-api.entrypoints=https
- traefik.http.routers.rt-backend-api.tls=true
- traefik.http.routers.rt-backend-api.service=svc-backend
- traefik.http.routers.rt-backend-api.middlewares=gzip,mw-backend-vhm-api
```
## About this app
Expand All @@ -100,16 +129,18 @@ pnpm dev

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
You can start editing the page by modifying `app/page.tsx`.
The page auto-updates as you edit the file.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and its API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/).
Your feedback and contributions are welcome!

## Deploy on Vercel

Expand Down
27 changes: 18 additions & 9 deletions apps/nextjs/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import path from 'path';
// import path from 'path';

/** @type {import('next').NextConfig} */
const nextConfig = {
Expand All @@ -21,17 +21,26 @@ const nextConfig = {
// Rewrite to the backend to avoid CORS
async rewrites() {
let apiServerURL, vhmRewriteRule;
if (process.env.API_SERVER_URL) {
apiServerURL = process.env.API_SERVER_URL;
vhmRewriteRule = `/VirtualHostBase/https/${process.env.NEXT_PUBLIC_VERCEL_URL}%3A443/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot`;
} else if (
if (
process.env.API_SERVER_URL &&
!process.env.NEXT_PUBLIC_VERCEL_URL
(process.env.NEXT_PRODUCTION_URL || process.env.NEXT_PUBLIC_VERCEL_URL)
) {
throw new Error(
'API_SERVER_URL set and NEXT_PUBLIC_VERCEL_URL not present.',
);
// We are in Vercel
apiServerURL = process.env.API_SERVER_URL;
vhmRewriteRule = `/VirtualHostBase/https/${
process.env.NEXT_PRODUCTION_URL
? // We are in the production deployment
process.env.NEXT_PRODUCTION_URL
: // We are in the preview deployment
process.env.NEXT_PUBLIC_VERCEL_URL
}%3A443/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot`;
} else if (process.env.API_SERVER_URL) {
// We are in development
apiServerURL = process.env.API_SERVER_URL;
vhmRewriteRule =
'/VirtualHostBase/http/localhost%3A3000/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot';
} else {
// We are in development and the API_SERVER_URL is not set, so we use a local backend
apiServerURL = 'http://localhost:8080';
vhmRewriteRule =
'/VirtualHostBase/http/localhost%3A3000/Plone/%2B%2Bapi%2B%2B/VirtualHostRoot';
Expand Down
21 changes: 16 additions & 5 deletions apps/nextjs/src/app/config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,26 @@
import config from '@plone/registry';
import type { ConfigType } from '@plone/registry';
import { slate } from '@plone/blocks';
import { blocksConfig } from '@plone/blocks';

const settings = {
apiPath: process.env.NEXT_PUBLIC_VERCEL_URL
? // Vercel does not prepend the schema to the NEXT_PUBLIC_VERCEL_URL automatic env var
`https://${process.env.NEXT_PUBLIC_VERCEL_URL}`
: 'http://localhost:3000',
const settings: Partial<ConfigType['settings']> = {
slate,
};

if (process.env.NEXT_PUBLIC_VERCEL_URL) {
// This app is at Vercel
if (process.env.NEXT_PRODUCTION_URL) {
// This app is in a production deployment, so set the apiPath to the production URL
settings.apiPath = process.env.NEXT_PRODUCTION_URL;
} else {
// This app is in a preview deployment, so set the apiPath to the Vercel URL
settings.apiPath = `https://${process.env.NEXT_PUBLIC_VERCEL_URL}`;
}
} else {
// This app is in development, so set the apiPath to localhost
settings.apiPath = 'http://localhost:3000/';
}

// @ts-expect-error Improve typings
config.set('settings', settings);

Expand Down
6 changes: 3 additions & 3 deletions docs/source/addons/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ Your add-on has a `locales` folder with a `.pot` file.
└── volto.po
```

1. Run `yarn i18n` in the context of your add-on.
1. Run `pnpm i18n` in the context of your add-on.
1. Go to each `.po` file in your `locales` folder, and write the translations for each translation literal.

In the context of your project, run `yarn i18n` to merge the add-on translations with the ones of your project.
In the context of your project, run `pnpm i18n` to merge the add-on translations with the ones of your project.


## Override translations

If you have multiple add-ons installed in your project, the translations are loaded in the order your add-ons are listed in `package.json`.
If two add-ons provide different translations for the same message, then the last defined add-on wins.

When running `yarn i18n` in the context of your project, the project's own locales are processed last and can override translations from any add-on.
When running `pnpm i18n` in the context of your project, the project's own locales are processed last and can override translations from any add-on.
2 changes: 1 addition & 1 deletion docs/source/addons/theme.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ or add a key in your `package.json` project:
or via a `THEME` variable:

```shell
THEME='volto-my-theme' yarn start
THEME='volto-my-theme' pnpm start
```

2. Create a directory `src/theme` in your add-on, then add this file `theme.config`, replacing `<name_of_your_theme>` with your add-on name:
Expand Down
6 changes: 3 additions & 3 deletions docs/source/backend/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ Block transformers
Search and indexing integration
: By providing the right adapters, you can extract searchable text from blocks.

Client Reducer Content Transforms
Client reducer content transforms
: These transforms run in the client when the response from the backend is received.
These are useful when you need to modify on the fly the response from the backend, in case you need to make an amendment of the backend data, like a data migration of any kind.
These are useful when you need to modify the response from the backend on-the-fly for amending the backend data, such as a data migration of any kind.
You can register a utility that mutates the response at your convenience.

```ts
Expand All @@ -50,7 +50,7 @@ Client Reducer Content Transforms
});
```

The `type` of the utility needs to be `transform` and the dependencies set to `{reducer: 'content'}`.
The `type` of the utility needs to be `transform`, and the `dependencies` set to `{reducer: 'content'}`.

## Proxied backend routes

Expand Down
4 changes: 3 additions & 1 deletion docs/source/client/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ These functions can be used in other use cases like command line helpers, script
To install the Javascript Plone client run the following command:

```shell
yarn add @plone/client
pnpm add @plone/client
```

or use your package manager of choice.

## `ploneClient` entry point

The main artifact that the client provides is the `ploneClient` entry point.
Expand Down
Loading

0 comments on commit 4fa8e43

Please sign in to comment.