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
5 changes: 5 additions & 0 deletions .github/workflows/e2e-next-faustwp-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,8 @@ jobs:
working-directory: e2e-app
run: |
npm run build
# next build alone doesn't catch errors that only happen when the
# production server renders a page on demand.
- name: Serve and load a page rendered on demand
run: |
bash scripts/smoke-test-example.sh e2e-app
22 changes: 19 additions & 3 deletions docs/reference/with-faust/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The `withFaust` helper function is used to merge your `next.config.js` config wi
To use `withFaust`, create a `next.config.js` file in your project root with the following content:

```js title="next.config.js"
const { withFaust } = require("@faustjs/next");
const { withFaust } = require("@faustwp/core");

/**
* @type {import('next').NextConfig}
Expand All @@ -23,7 +23,7 @@ If you already have a `next.config.js` file, you can use the first argument of `
Take the following example, where we have a custom `next.config.js` handling a rewrite:

```js title="next.config.js"
const { withFaust } = require("@faustjs/next");
const { withFaust } = require("@faustwp/core");

const nextConfig = {
async rewrites() {
Expand All @@ -42,6 +42,22 @@ const nextConfig = {
module.exports = withFaust(nextConfig);
```

## What `withFaust` changes

`withFaust` keeps your config and adds:

- A redirect that sends preview links to the preview page.
- An `x-using: faust` header, and `poweredByHeader: false`.
- `@faustwp/core` and `@faustwp/blocks` in `transpilePackages`, so Next.js bundles them into your pages. Without this, Turbopack production builds return a 500 error ("NextRouter was not mounted") for pages rendered on demand.

If you don't use `withFaust`, add the packages yourself:

```js title="next.config.js"
module.exports = {
transpilePackages: ["@faustwp/core", "@faustwp/blocks"],
};
```

## Additional Options

`withFaust` also accepts a second argument for `withFaustConfig`. `withFaustConfig` represented as a TypeScript interface looks like this:
Expand All @@ -56,7 +72,7 @@ interface WithFaustConfig {
For example, if you want to change the default preview destination from `/preview` to `/previews`, you can do so by passing the following to `withFaust`:

```js title="next.config.js"
const { withFaust } = require("@faustjs/next");
const { withFaust } = require("@faustwp/core");

const nextConfig = {};

Expand Down
15 changes: 15 additions & 0 deletions packages/faustwp-core/src/config/withFaust.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ export interface WithFaustConfig {
previewDestination?: string;
}

/**
* Faust packages to bundle into the app. In production, Turbopack loads
* packages from node_modules outside the app's bundle, so their components
* read a separate copy of Next.js's router context and throw "NextRouter was
* not mounted" on pages rendered on demand. Bundling them keeps one copy.
*/
export const FAUST_TRANSPILE_PACKAGES = ['@faustwp/core', '@faustwp/blocks'];

export async function createRedirects(
nextConfig?: NextConfig,
redirectFn?: NextConfig['redirects'],
Expand Down Expand Up @@ -105,5 +113,12 @@ export function withFaust(
nextConfig.headers = () => addHeaders(nextConfig, existingHeaders);
nextConfig.poweredByHeader = false;

nextConfig.transpilePackages = Array.from(
new Set([
...(nextConfig.transpilePackages ?? []),
...FAUST_TRANSPILE_PACKAGES,
]),
);

return nextConfig;
}
14 changes: 14 additions & 0 deletions packages/faustwp-core/tests/config/withFaust.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,18 @@ describe('withFaust', () => {
]
`);
});

test('it bundles the Faust packages', () => {
expect(withFaust({}).transpilePackages).toEqual([
'@faustwp/core',
'@faustwp/blocks',
]);
});

test('it keeps transpilePackages from the user config', () => {
expect(
withFaust({ transpilePackages: ['my-lib', '@faustwp/core'] })
.transpilePackages,
).toEqual(['my-lib', '@faustwp/core', '@faustwp/blocks']);
});
});
30 changes: 30 additions & 0 deletions scripts/smoke-test-example.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Serve a built example app and check that a page rendered on demand loads.
# `next build` alone doesn't catch errors that only happen when a page is
# rendered by the production server.
#
# Usage: scripts/smoke-test-example.sh <app-dir> [path]
set -euo pipefail

APP_DIR="$1"
PAGE_PATH="${2:-/sample-page}"
PORT="${PORT:-3999}"

cd "$APP_DIR"
npx next start -p "$PORT" >next-start.log 2>&1 &
SERVER_PID=$!
trap 'kill "$SERVER_PID" 2>/dev/null || true' EXIT

for _ in $(seq 1 30); do
curl -s -o /dev/null "http://localhost:$PORT/" && break
sleep 1
done

STATUS=$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:$PORT$PAGE_PATH")
echo "GET $PAGE_PATH -> $STATUS"

if [ "$STATUS" != "200" ]; then
echo "Expected 200. Server log:"
cat next-start.log
exit 1
fi
Loading