Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add turbo.define option #71802

Open
wants to merge 2 commits into
base: canary
Choose a base branch
from
Open
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
19 changes: 19 additions & 0 deletions docs/02-app/02-api-reference/05-next-config-js/turbo.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ The following options are available for the `turbo` configuration:
| `useSwcCss` | Use `swc_css` instead of `lightningcss` for Turbopack |
| `treeshaking` | Enable tree shaking for the turbopack dev server and build. |
| `memoryLimit` | A target memory limit for turbo, in bytes. |
| `define` | Replace variables in your code during the build. |

### Supported loaders

Expand Down Expand Up @@ -168,6 +169,24 @@ module.exports = {
}
```

### Replacing variables during build

The `define` option allows you to statically replace variables in your code at build-time.
The option takes an object as key-value pairs, where the keys are the variables that should be replaced with the corresponding values.

Use the `define` field in `next.config.js`:

```js filename="next.config.js"
module.exports = {
experimental: {
turbo: {
MY_STRING_VARIABLE: JSON.stringify('my-string'),
MY_NUMBER_VARIABLE: '42',
},
},
}
```

## Version History

| Version | Changes |
Expand Down
11 changes: 11 additions & 0 deletions packages/next/src/build/webpack/plugins/define-env-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,17 @@ export function getDefineEnv({
}
: undefined),
}

const userDefines = isTurbopack ? config.experimental.turbo?.define : {}
for (const key in userDefines) {
if (defineEnv.hasOwnProperty(key)) {
throw new Error(
`The \`turbo.define\` option is configured to replace the \`${key}\` variable. This variable is either part of a Next.js built-in or is already configured via the \`env\` option.`
)
}
defineEnv[key] = userDefines[key]
}

const serializedDefineEnv = serializeDefineEnv(defineEnv)

if (!dev && Boolean(config.experimental.flyingShuttle)) {
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
.optional(),
memoryLimit: z.number().optional(),
moduleIdStrategy: z.enum(['named', 'deterministic']).optional(),
define: z.record(z.string(), z.string()).optional(),
})
.optional(),
optimizePackageImports: z.array(z.string()).optional(),
Expand Down
6 changes: 6 additions & 0 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ export interface ExperimentalTurboOptions {
* directory can be resolved by turbopack.
*/
root?: string

/**
* Replaces variables in your code during compile time. Each key will be
* replaced with the respective values.
*/
define?: Record<string, string>
}

export interface WebpackConfigContext {
Expand Down
9 changes: 9 additions & 0 deletions test/e2e/define/app/client-component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client'

declare const MY_MAGIC_VARIABLE: string

export function ClientValue() {
return (
<>{typeof MY_MAGIC_VARIABLE === 'string' ? MY_MAGIC_VARIABLE : 'not set'}</>
)
}
7 changes: 7 additions & 0 deletions test/e2e/define/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Root({ children }: { children: React.ReactNode }) {
return (
<html>
<body>{children}</body>
</html>
)
}
17 changes: 17 additions & 0 deletions test/e2e/define/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ClientValue } from './client-component'

declare const MY_MAGIC_VARIABLE: string

export default function Page() {
return (
<ul>
<li>
Server value:{' '}
{typeof MY_MAGIC_VARIABLE === 'string' ? MY_MAGIC_VARIABLE : 'not set'}
</li>
<li>
Client value: <ClientValue />
</li>
</ul>
)
}
21 changes: 21 additions & 0 deletions test/e2e/define/define.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { nextTestSetup } from 'e2e-utils'

describe('define', () => {
const { next } = nextTestSetup({
files: __dirname,
})

it('should render the magic variable on server side', async () => {
const res = await next.fetch('/')
const html = (await res.text()).replaceAll(/<!-- -->/g, '')
expect(html).toContain('Server value: foobar')
expect(html).toContain('Client value: foobar')
})

it('should render the magic variable on client side', async () => {
const browser = await next.browser('/')
const text = await browser.elementByCss('body').text()
expect(text).toContain('Server value: foobar')
expect(text).toContain('Client value: foobar')
})
})
9 changes: 9 additions & 0 deletions test/e2e/define/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
experimental: {
turbo: {
define: {
MY_MAGIC_VARIABLE: JSON.stringify('foobar'),
},
},
},
}
Loading