diff --git a/docs/01-app/03-api-reference/05-config/01-next-config-js/sassOptions.mdx b/docs/01-app/03-api-reference/05-config/01-next-config-js/sassOptions.mdx index 8c510fb6c625ff..138c7d08b5f520 100644 --- a/docs/01-app/03-api-reference/05-config/01-next-config-js/sassOptions.mdx +++ b/docs/01-app/03-api-reference/05-config/01-next-config-js/sassOptions.mdx @@ -43,4 +43,7 @@ const nextConfig = { module.exports = nextConfig ``` -> **Good to know:** `sassOptions` are not typed outside of `implementation` because Next.js does not maintain the other possible properties. +> **Good to know:** +> +> - `sassOptions` are not typed outside of `implementation` because Next.js does not maintain the other possible properties. +> - The `functions` property for defining custom Sass functions is only supported with webpack. When using Turbopack, custom Sass functions are not available because Turbopack's Rust-based architecture cannot directly execute JavaScript functions passed through this option. diff --git a/docs/01-app/03-api-reference/08-turbopack.mdx b/docs/01-app/03-api-reference/08-turbopack.mdx index 2b47fb0b11297e..dab526faffeebf 100644 --- a/docs/01-app/03-api-reference/08-turbopack.mdx +++ b/docs/01-app/03-api-reference/08-turbopack.mdx @@ -72,16 +72,16 @@ Turbopack in Next.js has **zero-configuration** for the common use cases. Below ### CSS and styling -| Feature | Status | Notes | -| ------------------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Global CSS** | **Supported** | Import `.css` files directly in your application. | -| **CSS Modules** | **Supported** | `.module.css` files work natively (Lightning CSS). | -| **CSS Nesting** | **Supported** | Lightning CSS supports [modern CSS nesting](https://lightningcss.dev/). | -| **@import syntax** | **Supported** | Combine multiple CSS files. | -| **PostCSS** | **Supported** | Automatically processes `postcss.config.js` in a Node.js worker pool. Useful for Tailwind, Autoprefixer, etc. | -| **Sass / SCSS** | **Supported** (Next.js) | For Next.js, Sass is supported out of the box. In the future, Turbopack standalone usage will likely require a loader config. | -| **Less** | Planned via plugins | Not yet supported by default. Will likely require a loader config once custom loaders are stable. | -| **Lightning CSS** | **In Use** | Handles CSS transformations. Some low-usage CSS Modules features (like `:local/:global` as standalone pseudo-classes) are not yet supported. [See below for more details.](#unsupported-and-unplanned-features) | +| Feature | Status | Notes | +| ------------------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Global CSS** | **Supported** | Import `.css` files directly in your application. | +| **CSS Modules** | **Supported** | `.module.css` files work natively (Lightning CSS). | +| **CSS Nesting** | **Supported** | Lightning CSS supports [modern CSS nesting](https://lightningcss.dev/). | +| **@import syntax** | **Supported** | Combine multiple CSS files. | +| **PostCSS** | **Supported** | Automatically processes `postcss.config.js` in a Node.js worker pool. Useful for Tailwind, Autoprefixer, etc. | +| **Sass / SCSS** | **Supported** (Next.js) | For Next.js, Sass is supported out of the box. Custom Sass functions (`sassOptions.functions`) are not supported because Turbopack's Rust-based architecture cannot directly execute JavaScript functions, unlike webpack's Node.js environment. Use webpack if you need this feature. In the future, Turbopack standalone usage will likely require a loader config. | +| **Less** | Planned via plugins | Not yet supported by default. Will likely require a loader config once custom loaders are stable. | +| **Lightning CSS** | **In Use** | Handles CSS transformations. Some low-usage CSS Modules features (like `:local/:global` as standalone pseudo-classes) are not yet supported. [See below for more details.](#unsupported-and-unplanned-features) | ### Assets @@ -175,6 +175,8 @@ Some features are not yet implemented or not planned: - `:import` and `:export` ICSS rules. - `composes` in `.module.css` composing a `.css` file. In webpack this would treat the `.css` file as a CSS Module, with Turbopack the `.css` file will always be global. This means that if you want to use `composes` in a CSS Module, you need to change the `.css` file to a `.module.css` file. - `@import` in CSS Modules importing `.css` as a CSS Module. In webpack this would treat the `.css` file as a CSS Module, with Turbopack the `.css` file will always be global. This means that if you want to use `@import` in a CSS Module, you need to change the `.css` file to a `.module.css` file. +- **`sassOptions.functions`** + Custom Sass functions defined in `sassOptions.functions` are not supported. This feature allows defining JavaScript functions that can be called from Sass code during compilation. Turbopack's Rust-based architecture cannot directly execute JavaScript functions passed through `sassOptions.functions`, unlike webpack's Node.js-based sass-loader which runs entirely in JavaScript. If you're using custom Sass functions, you'll need to use webpack instead of Turbopack. - **`webpack()` configuration** in `next.config.js` Turbopack replaces webpack, so `webpack()` configs are not recognized. Use the [`turbopack` config](/docs/app/api-reference/config/next-config-js/turbopack) instead. - **Yarn PnP** diff --git a/packages/next/errors.json b/packages/next/errors.json index 19f2a0b300dcaf..0d1aed0ca08a47 100644 --- a/packages/next/errors.json +++ b/packages/next/errors.json @@ -890,5 +890,6 @@ "889": "Unknown \\`cacheLife()\\` profile \"%s\" is not configured in next.config.js\\nmodule.exports = {\n cacheLife: {\n \"%s\": ...\\n }\n}", "890": "Received an underlying cookies object that does not match either `cookies` or `mutableCookies`", "891": "Failed to read build paths file \"%s\": %s", - "892": "Failed to resolve glob pattern \"%s\": %s" + "892": "Failed to resolve glob pattern \"%s\": %s", + "893": "The \"sassOptions.functions\" option is not supported when using Turbopack. Custom Sass functions are only available with webpack. Please remove the \"functions\" property from your sassOptions in %s." } diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index 5a5d36755b416d..0fbf30bc9dba83 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -378,6 +378,19 @@ function assignDefaultsAndValidate( ) } + // Validate sassOptions.functions is not used with Turbopack + if ( + process.env.TURBOPACK && + result.sassOptions && + 'functions' in result.sassOptions + ) { + throw new Error( + `The "sassOptions.functions" option is not supported when using Turbopack. ` + + `Custom Sass functions are only available with webpack. ` + + `Please remove the "functions" property from your sassOptions in ${configFileName}.` + ) + } + if (isStableBuild()) { // Prevents usage of certain experimental features outside of canary if (result.experimental?.turbopackFileSystemCacheForBuild) { diff --git a/test/unit/isolated/config.test.ts b/test/unit/isolated/config.test.ts index 1fdf060c32860a..7fdc7a28504724 100644 --- a/test/unit/isolated/config.test.ts +++ b/test/unit/isolated/config.test.ts @@ -102,6 +102,60 @@ describe('config', () => { ) }) + it('Should throw an error when sassOptions.functions is used with Turbopack', async () => { + const originalTurbopack = process.env.TURBOPACK + process.env.TURBOPACK = '1' + + try { + await expect(async () => { + // Use a unique directory to avoid cache conflicts + await loadConfig(PHASE_DEVELOPMENT_SERVER, '-turbopack-test', { + customConfig: { + sassOptions: { + functions: { + 'get($keys)': function (keys) { + return 'test' + }, + }, + }, + }, + }) + }).rejects.toThrow( + /The "sassOptions\.functions" option is not supported when using Turbopack/ + ) + } finally { + if (originalTurbopack === undefined) { + delete process.env.TURBOPACK + } else { + process.env.TURBOPACK = originalTurbopack + } + } + }) + + it('Should allow sassOptions.functions when not using Turbopack', async () => { + const originalTurbopack = process.env.TURBOPACK + delete process.env.TURBOPACK + + try { + const config = await loadConfig(PHASE_DEVELOPMENT_SERVER, '', { + customConfig: { + sassOptions: { + functions: { + 'get($keys)': function (keys) { + return 'test' + }, + }, + }, + }, + }) + expect((config as any).sassOptions.functions).toBeDefined() + } finally { + if (originalTurbopack !== undefined) { + process.env.TURBOPACK = originalTurbopack + } + } + }) + it('Should not throw an error when two versions of next.config.js are present', async () => { const config = await loadConfig( PHASE_DEVELOPMENT_SERVER,