Skip to content

Commit fe86a17

Browse files
authored
Merge branch 'canary' into sam/docs/experimental-https
2 parents 41d4bda + 82682dd commit fe86a17

File tree

35 files changed

+1277
-864
lines changed

35 files changed

+1277
-864
lines changed

docs/02-app/01-building-your-application/05-styling/03-sass.mdx

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,58 @@ npm install --save-dev sass
2424
2525
### Customizing Sass Options
2626

27-
If you want to configure the Sass compiler, use `sassOptions` in `next.config.js`.
27+
If you want to configure your Sass options, use `sassOptions` in `next.config`.
2828

29-
```js filename="next.config.js"
30-
const path = require('path')
29+
```ts filename="next.config.ts" switcher
30+
import type { NextConfig } from 'next'
3131

32-
module.exports = {
32+
const nextConfig: NextConfig = {
3333
sassOptions: {
34-
includePaths: [path.join(__dirname, 'styles')],
34+
additionalData: `$var: red;`,
3535
},
3636
}
37+
38+
export default nextConfig
39+
```
40+
41+
```js filename="next.config.js" switcher
42+
/** @type {import('next').NextConfig} */
43+
44+
const nextConfig = {
45+
sassOptions: {
46+
additionalData: `$var: red;`,
47+
},
48+
}
49+
50+
module.exports = nextConfig
51+
```
52+
53+
#### Implementation
54+
55+
You can use the `implementation` property to specify the Sass implementation to use. By default, Next.js uses the [`sass`](https://www.npmjs.com/package/sass) package.
56+
57+
```ts filename="next.config.ts" switcher
58+
import type { NextConfig } from 'next'
59+
60+
const nextConfig: NextConfig = {
61+
sassOptions: {
62+
implementation: 'sass-embedded',
63+
},
64+
}
65+
66+
export default nextConfig
67+
```
68+
69+
```js filename="next.config.js" switcher
70+
/** @type {import('next').NextConfig} */
71+
72+
const nextConfig = {
73+
sassOptions: {
74+
implementation: 'sass-embedded',
75+
},
76+
}
77+
78+
module.exports = nextConfig
3779
```
3880

3981
### Sass Variables
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
title: sassOptions
3+
description: Configure Sass options.
4+
---
5+
6+
`sassOptions` allow you to configure the Sass compiler.
7+
8+
```ts filename="next.config.ts" switcher
9+
import type { NextConfig } from 'next'
10+
11+
const sassOptions = {
12+
additionalData: `
13+
$var: red;
14+
`,
15+
}
16+
17+
const nextConfig: NextConfig = {
18+
sassOptions: {
19+
...sassOptions,
20+
implementation: 'sass-embedded',
21+
},
22+
}
23+
24+
export default nextConfig
25+
```
26+
27+
```js filename="next.config.js" switcher
28+
/** @type {import('next').NextConfig} */
29+
30+
const sassOptions = {
31+
additionalData: `
32+
$var: red;
33+
`,
34+
}
35+
36+
const nextConfig = {
37+
sassOptions: {
38+
...sassOptions,
39+
implementation: 'sass-embedded',
40+
},
41+
}
42+
43+
module.exports = nextConfig
44+
```
45+
46+
> **Good to know:** `sassOptions` are not typed outside of `implementation` because Next.js does not maintain the other possible properties.

docs/02-app/02-api-reference/05-next-config-js/useLightningcss.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ version: experimental
66

77
Experimental support for using [Lightning CSS](https://lightningcss.dev), a fast CSS bundler and minifier, written in Rust.
88

9-
```ts filename="next.config.ts"
9+
```ts filename="next.config.ts" switcher
1010
import type { NextConfig } from 'next'
1111

1212
const nextConfig: NextConfig = {
@@ -18,7 +18,7 @@ const nextConfig: NextConfig = {
1818
export default nextConfig
1919
```
2020

21-
```js filename="next.config.js"
21+
```js filename="next.config.js" switcher
2222
/** @type {import('next').NextConfig} */
2323
const nextConfig = {
2424
experimental: {

packages/next/src/server/config-schema.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -602,8 +602,13 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
602602
)
603603
)
604604
.optional(),
605-
// saas option is unknown, use z.any() here
606-
sassOptions: z.record(z.string(), z.any()).optional(),
605+
// sassOptions properties are unknown besides implementation, use z.any() here
606+
sassOptions: z
607+
.object({
608+
implementation: z.string().optional(),
609+
})
610+
.catchall(z.any())
611+
.optional(),
607612
serverExternalPackages: z.array(z.string()).optional(),
608613
serverRuntimeConfig: z.record(z.string(), z.any()).optional(),
609614
skipMiddlewareUrlNormalize: z.boolean().optional(),

packages/next/src/server/config-shared.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -770,8 +770,11 @@ export interface NextConfig extends Record<string, any> {
770770
*/
771771
basePath?: string
772772

773-
/** @see [Customizing sass options](https://nextjs.org/docs/basic-features/built-in-css-support#customizing-sass-options) */
774-
sassOptions?: { [key: string]: any }
773+
/** @see [Customizing sass options](https://nextjs.org/docs/app/api-reference/next-config-js/sassOptions) */
774+
sassOptions?: {
775+
implementation?: string
776+
[key: string]: any
777+
}
775778

776779
/**
777780
* Enable browser source map generation during the production build

test/e2e/app-dir/ppr-full/ppr-full.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -458,7 +458,14 @@ describe('ppr-full', () => {
458458

459459
// We expect to get the fallback shell.
460460
$ = await next.render$(pathname)
461-
expect($('[data-layout]').data('layout')).toBe(fallbackID)
461+
462+
// When deployed to Vercel, it will serve a stale version of the dynamic shell
463+
// Whereas with `next start` it will serve the fallback shell
464+
if (isNextDeploy) {
465+
expect($('[data-layout]').data('layout')).toBe(dynamicID)
466+
} else {
467+
expect($('[data-layout]').data('layout')).toBe(fallbackID)
468+
}
462469

463470
// Let's wait for the page to be revalidated.
464471
let revalidatedDynamicID: string

turbopack/crates/turbopack-browser/src/ecmascript/evaluate/chunk.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ impl EcmascriptDevEvaluateChunk {
146146
let runtime_code = turbopack_ecmascript_runtime::get_browser_runtime_code(
147147
environment,
148148
chunking_context.chunk_base_path(),
149+
Value::new(chunking_context.runtime_type()),
149150
Vc::cell(output_root.to_string().into()),
150151
);
151152
code.push_code(&*runtime_code.await?);
@@ -154,6 +155,7 @@ impl EcmascriptDevEvaluateChunk {
154155
let runtime_code = turbopack_ecmascript_runtime::get_browser_runtime_code(
155156
environment,
156157
chunking_context.chunk_base_path(),
158+
Value::new(chunking_context.runtime_type()),
157159
Vc::cell(output_root.to_string().into()),
158160
);
159161
code.push_code(&*runtime_code.await?);

turbopack/crates/turbopack-ecmascript-runtime/js/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
"check": "run-p check:*",
99
"check:nodejs": "tsc -p src/nodejs",
1010
"check:browser-dev-client": "tsc -p src/browser/dev/hmr-client",
11-
"check:browser-dev-runtime-base": "tsc -p src/browser/dev/runtime/base",
12-
"check:browser-dev-runtime-dom": "tsc -p src/browser/dev/runtime/dom",
13-
"check:browser-dev-runtime-edge": "tsc -p src/browser/dev/runtime/edge"
11+
"check:browser-runtime-base": "tsc -p src/browser/runtime/base",
12+
"check:browser-runtime-dom": "tsc -p src/browser/runtime/dom",
13+
"check:browser-runtime-edge": "tsc -p src/browser/runtime/edge"
1414
},
1515
"exports": {
1616
".": "./src/main.js",

turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/dev/hmr-client/hmr-client.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// <reference path="../../../shared/runtime-types.d.ts" />
2-
/// <reference path="../runtime/base/globals.d.ts" />
3-
/// <reference path="../runtime/base/protocol.d.ts" />
4-
/// <reference path="../runtime/base/extensions.d.ts" />
2+
/// <reference path="../../runtime/base/dev-globals.d.ts" />
3+
/// <reference path="../../runtime/base/dev-protocol.d.ts" />
4+
/// <reference path="../../runtime/base/dev-extensions.ts" />
55

66
import {
77
addMessageListener as turboSocketAddMessageListener,
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/// <reference path="./runtime-base.ts" />
2+
/// <reference path="./dummy.ts" />
3+
4+
declare var augmentContext: ((context: unknown) => unknown);
5+
6+
const moduleCache: ModuleCache<Module> = {};
7+
8+
/**
9+
* Gets or instantiates a runtime module.
10+
*/
11+
// @ts-ignore
12+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
13+
function getOrInstantiateRuntimeModule(
14+
moduleId: ModuleId,
15+
chunkPath: ChunkPath,
16+
): Module {
17+
const module = moduleCache[moduleId];
18+
if (module) {
19+
if (module.error) {
20+
throw module.error;
21+
}
22+
return module;
23+
}
24+
25+
return instantiateModule(moduleId, { type: SourceType.Runtime, chunkPath });
26+
}
27+
28+
/**
29+
* Retrieves a module from the cache, or instantiate it if it is not cached.
30+
*/
31+
// Used by the backend
32+
// @ts-ignore
33+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
34+
const getOrInstantiateModuleFromParent: GetOrInstantiateModuleFromParent<Module> = (
35+
id,
36+
sourceModule
37+
) => {
38+
const module = moduleCache[id];
39+
40+
if (module) {
41+
return module;
42+
}
43+
44+
return instantiateModule(id, {
45+
type: SourceType.Parent,
46+
parentId: sourceModule.id,
47+
});
48+
};
49+
50+
function instantiateModule(id: ModuleId, source: SourceInfo): Module {
51+
const moduleFactory = moduleFactories[id];
52+
if (typeof moduleFactory !== "function") {
53+
// This can happen if modules incorrectly handle HMR disposes/updates,
54+
// e.g. when they keep a `setTimeout` around which still executes old code
55+
// and contains e.g. a `require("something")` call.
56+
let instantiationReason;
57+
switch (source.type) {
58+
case SourceType.Runtime:
59+
instantiationReason = `as a runtime entry of chunk ${source.chunkPath}`;
60+
break;
61+
case SourceType.Parent:
62+
instantiationReason = `because it was required from module ${source.parentId}`;
63+
break;
64+
case SourceType.Update:
65+
instantiationReason = "because of an HMR update";
66+
break;
67+
default:
68+
invariant(source, (source) => `Unknown source type: ${source?.type}`);
69+
}
70+
throw new Error(
71+
`Module ${id} was instantiated ${instantiationReason}, but the module factory is not available. It might have been deleted in an HMR update.`
72+
);
73+
}
74+
75+
switch (source.type) {
76+
case SourceType.Runtime:
77+
runtimeModules.add(id);
78+
break;
79+
case SourceType.Parent:
80+
// No need to add this module as a child of the parent module here, this
81+
// has already been taken care of in `getOrInstantiateModuleFromParent`.
82+
break;
83+
case SourceType.Update:
84+
throw new Error('Unexpected')
85+
default:
86+
invariant(source, (source) => `Unknown source type: ${source?.type}`);
87+
}
88+
89+
const module: Module = {
90+
exports: {},
91+
error: undefined,
92+
loaded: false,
93+
id,
94+
namespaceObject: undefined,
95+
};
96+
97+
moduleCache[id] = module;
98+
99+
// NOTE(alexkirsz) This can fail when the module encounters a runtime error.
100+
try {
101+
const sourceInfo: SourceInfo = { type: SourceType.Parent, parentId: id };
102+
103+
const r = commonJsRequire.bind(null, module);
104+
moduleFactory.call(
105+
module.exports,
106+
augmentContext({
107+
a: asyncModule.bind(null, module),
108+
e: module.exports,
109+
r: commonJsRequire.bind(null, module),
110+
t: runtimeRequire,
111+
f: moduleContext,
112+
i: esmImport.bind(null, module),
113+
s: esmExport.bind(null, module, module.exports),
114+
j: dynamicExport.bind(null, module, module.exports),
115+
v: exportValue.bind(null, module),
116+
n: exportNamespace.bind(null, module),
117+
m: module,
118+
c: moduleCache,
119+
M: moduleFactories,
120+
l: loadChunk.bind(null, sourceInfo),
121+
w: loadWebAssembly.bind(null, sourceInfo),
122+
u: loadWebAssemblyModule.bind(null, sourceInfo),
123+
g: globalThis,
124+
P: resolveAbsolutePath,
125+
U: relativeURL,
126+
R: createResolvePathFromModule(r),
127+
b: getWorkerBlobURL,
128+
__dirname: typeof module.id === "string" ? module.id.replace(/(^|\/)\/+$/, "") : module.id
129+
})
130+
);
131+
} catch (error) {
132+
module.error = error as any;
133+
throw error;
134+
}
135+
136+
module.loaded = true;
137+
if (module.namespaceObject && module.exports !== module.namespaceObject) {
138+
// in case of a circular dependency: cjs1 -> esm2 -> cjs1
139+
interopEsm(module.exports, module.namespaceObject);
140+
}
141+
142+
return module;
143+
}
144+

0 commit comments

Comments
 (0)