Skip to content

Commit

Permalink
Merge branch 'main' into overhauladdonssection
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)
  • Loading branch information
sneridagh committed Oct 26, 2024
2 parents a016e79 + f576c13 commit 6e467a3
Show file tree
Hide file tree
Showing 25 changed files with 301 additions and 216 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/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
38 changes: 19 additions & 19 deletions docs/source/configuration/environmentvariables.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ All configurable environment variables work at runtime, not only at build time.
You could, for example, build your Volto application, then start it in production with the `RAZZLE_API_PATH` environment variable.

```shell
yarn build && RAZZLE_API_PATH=https://plone.org yarn start:prod
pnpm build && RAZZLE_API_PATH=https://plone.org pnpm start:prod
```

This brings you a lot of power since you don't have to rebuild on every configuration change.
Expand All @@ -40,7 +40,7 @@ You can also generate builds on your continuous integration, then deploy them an
However, if you are not able to upgrade the packages `plone.restapi` (8.12.1 or greater) and `plone.rest` (2.0.0a1 or greater) in the backend, you can adjust your web server configuration and use the `RAZZLE_LEGACY_TRAVERSE` flag.
```shell
RAZZLE_LEGACY_TRAVERSE=true yarn start:prod
RAZZLE_LEGACY_TRAVERSE=true pnpm start:prod
```
`VOLTO_ROBOTSTXT`
Expand All @@ -50,7 +50,7 @@ You can also generate builds on your continuous integration, then deploy them an
```shell
VOLTO_ROBOTSTXT="User-agent: *
Disallow: /" yarn start
Disallow: /" pnpm start
```
```{note}
Expand All @@ -67,19 +67,19 @@ You can also generate builds on your continuous integration, then deploy them an
It helps you identify problems with a customization that does not work as you expect.
```shell
DEBUG=volto:shadowing yarn start
DEBUG=volto:shadowing pnpm start
```
`i18n` enables the log of missing internationalization messages in the console.
```shell
DEBUG=volto:i18n yarn start
DEBUG=volto:i18n pnpm start
```
`*` enables logging everywhere it exists in Volto.
```shell
DEBUG=volto:* yarn start
DEBUG=volto:* pnpm start
```
`DEBUG_ADDONS_LOADER`
Expand Down Expand Up @@ -107,34 +107,34 @@ You can also generate builds on your continuous integration, then deploy them an
`ADDONS` can be used to temporarily add an add-on to your build for testing purposes.
```shell
yarn add volto-slate
ADDONS=volto-slate:asDefault yarn start
pnpm add @kitconcept/volto-light-theme
ADDONS=@kitconcept/volto-light-theme pnpm start
```
`ADDONS` can also be used to temporarily enable a feature or a set of customizations.
```shell
# given a folder './packages/coresandbox', like in vanilla Volto
ADDONS=coresandbox:multilingualFixture yarn start
ADDONS=coresandbox:multilingualFixture pnpm start
```
If you need to specify several add-ons, separate them with a semicolon (`;`):
```shell
ADDONS="test-addon;test-addon2" yarn start
ADDONS="test-addon;test-addon2" pnpm start
```
You can specify profiles for installation:
```shell
ADDONS="test-addon:profile1;test-addon2:profile2" yarn start
ADDONS="test-addon:profile1;test-addon2:profile2" pnpm start
```
The following code snippets demonstrate how to configure add-ons.
First in `package.json`:
```json
"addons": [
"@kitconcept/volto-blocks-grid"
Expand All @@ -152,8 +152,8 @@ You can also generate builds on your continuous integration, then deploy them an
And finally using `ADDONS`:
```shell
yarn add volto-slate
ADDONS=volto-slate:asDefault yarn start
pnpm add volto-slate
ADDONS=volto-slate:asDefault pnpm start
```
As a result, your app will load the add-ons in the following order:
Expand All @@ -165,14 +165,14 @@ You can also generate builds on your continuous integration, then deploy them an
```{important}
The `ADDONS` key is a Volto specific configuration.
Simply setting `ADDONS` doesn't download the JavaScript package.
This has to be covered another way, by either installing the add-on package (with `yarn add`), or loading it as a development package with `mrs-developer`.
This has to be covered another way, by either installing the add-on package (with `pnpm add`), or loading it as a development package with `mrs-developer`.
```
`BUILD_DIR`
This is a runtime-only environment variable that directs the build to run Volto from a specific location, other than the default folder `build`.
```shell
yarn
pnpm install
BUILD_DIR=dist node dist/server.js
```
Expand All @@ -182,7 +182,7 @@ You can also generate builds on your continuous integration, then deploy them an
It can be relative to the current project or absolute.
```shell
VOLTOCONFIG=../../volto.config.js yarn start
VOLTOCONFIG=../../volto.config.js pnpm start
```
````

Expand Down
Loading

0 comments on commit 6e467a3

Please sign in to comment.