Skip to content

Commit

Permalink
Merge branch 'canary' into sam/docs/experimental-https
Browse files Browse the repository at this point in the history
  • Loading branch information
samcx authored Sep 26, 2024
2 parents 41d4bda + 82682dd commit fe86a17
Show file tree
Hide file tree
Showing 35 changed files with 1,277 additions and 864 deletions.
52 changes: 47 additions & 5 deletions docs/02-app/01-building-your-application/05-styling/03-sass.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,58 @@ npm install --save-dev sass
### Customizing Sass Options

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

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

module.exports = {
const nextConfig: NextConfig = {
sassOptions: {
includePaths: [path.join(__dirname, 'styles')],
additionalData: `$var: red;`,
},
}

export default nextConfig
```

```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */

const nextConfig = {
sassOptions: {
additionalData: `$var: red;`,
},
}

module.exports = nextConfig
```

#### Implementation

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.

```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
sassOptions: {
implementation: 'sass-embedded',
},
}

export default nextConfig
```

```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */

const nextConfig = {
sassOptions: {
implementation: 'sass-embedded',
},
}

module.exports = nextConfig
```

### Sass Variables
Expand Down
46 changes: 46 additions & 0 deletions docs/02-app/02-api-reference/05-next-config-js/sassOptions.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: sassOptions
description: Configure Sass options.
---

`sassOptions` allow you to configure the Sass compiler.

```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'

const sassOptions = {
additionalData: `
$var: red;
`,
}

const nextConfig: NextConfig = {
sassOptions: {
...sassOptions,
implementation: 'sass-embedded',
},
}

export default nextConfig
```

```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */

const sassOptions = {
additionalData: `
$var: red;
`,
}

const nextConfig = {
sassOptions: {
...sassOptions,
implementation: 'sass-embedded',
},
}

module.exports = nextConfig
```

> **Good to know:** `sassOptions` are not typed outside of `implementation` because Next.js does not maintain the other possible properties.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ version: experimental

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

```ts filename="next.config.ts"
```ts filename="next.config.ts" switcher
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
Expand All @@ -18,7 +18,7 @@ const nextConfig: NextConfig = {
export default nextConfig
```

```js filename="next.config.js"
```js filename="next.config.js" switcher
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
Expand Down
9 changes: 7 additions & 2 deletions packages/next/src/server/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,8 +602,13 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
)
)
.optional(),
// saas option is unknown, use z.any() here
sassOptions: z.record(z.string(), z.any()).optional(),
// sassOptions properties are unknown besides implementation, use z.any() here
sassOptions: z
.object({
implementation: z.string().optional(),
})
.catchall(z.any())
.optional(),
serverExternalPackages: z.array(z.string()).optional(),
serverRuntimeConfig: z.record(z.string(), z.any()).optional(),
skipMiddlewareUrlNormalize: z.boolean().optional(),
Expand Down
7 changes: 5 additions & 2 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -770,8 +770,11 @@ export interface NextConfig extends Record<string, any> {
*/
basePath?: string

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

/**
* Enable browser source map generation during the production build
Expand Down
9 changes: 8 additions & 1 deletion test/e2e/app-dir/ppr-full/ppr-full.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,14 @@ describe('ppr-full', () => {

// We expect to get the fallback shell.
$ = await next.render$(pathname)
expect($('[data-layout]').data('layout')).toBe(fallbackID)

// When deployed to Vercel, it will serve a stale version of the dynamic shell
// Whereas with `next start` it will serve the fallback shell
if (isNextDeploy) {
expect($('[data-layout]').data('layout')).toBe(dynamicID)
} else {
expect($('[data-layout]').data('layout')).toBe(fallbackID)
}

// Let's wait for the page to be revalidated.
let revalidatedDynamicID: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ impl EcmascriptDevEvaluateChunk {
let runtime_code = turbopack_ecmascript_runtime::get_browser_runtime_code(
environment,
chunking_context.chunk_base_path(),
Value::new(chunking_context.runtime_type()),
Vc::cell(output_root.to_string().into()),
);
code.push_code(&*runtime_code.await?);
Expand All @@ -154,6 +155,7 @@ impl EcmascriptDevEvaluateChunk {
let runtime_code = turbopack_ecmascript_runtime::get_browser_runtime_code(
environment,
chunking_context.chunk_base_path(),
Value::new(chunking_context.runtime_type()),
Vc::cell(output_root.to_string().into()),
);
code.push_code(&*runtime_code.await?);
Expand Down
6 changes: 3 additions & 3 deletions turbopack/crates/turbopack-ecmascript-runtime/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
"check": "run-p check:*",
"check:nodejs": "tsc -p src/nodejs",
"check:browser-dev-client": "tsc -p src/browser/dev/hmr-client",
"check:browser-dev-runtime-base": "tsc -p src/browser/dev/runtime/base",
"check:browser-dev-runtime-dom": "tsc -p src/browser/dev/runtime/dom",
"check:browser-dev-runtime-edge": "tsc -p src/browser/dev/runtime/edge"
"check:browser-runtime-base": "tsc -p src/browser/runtime/base",
"check:browser-runtime-dom": "tsc -p src/browser/runtime/dom",
"check:browser-runtime-edge": "tsc -p src/browser/runtime/edge"
},
"exports": {
".": "./src/main.js",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/// <reference path="../../../shared/runtime-types.d.ts" />
/// <reference path="../runtime/base/globals.d.ts" />
/// <reference path="../runtime/base/protocol.d.ts" />
/// <reference path="../runtime/base/extensions.d.ts" />
/// <reference path="../../runtime/base/dev-globals.d.ts" />
/// <reference path="../../runtime/base/dev-protocol.d.ts" />
/// <reference path="../../runtime/base/dev-extensions.ts" />

import {
addMessageListener as turboSocketAddMessageListener,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/// <reference path="./runtime-base.ts" />
/// <reference path="./dummy.ts" />

declare var augmentContext: ((context: unknown) => unknown);

const moduleCache: ModuleCache<Module> = {};

/**
* Gets or instantiates a runtime module.
*/
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function getOrInstantiateRuntimeModule(
moduleId: ModuleId,
chunkPath: ChunkPath,
): Module {
const module = moduleCache[moduleId];
if (module) {
if (module.error) {
throw module.error;
}
return module;
}

return instantiateModule(moduleId, { type: SourceType.Runtime, chunkPath });
}

/**
* Retrieves a module from the cache, or instantiate it if it is not cached.
*/
// Used by the backend
// @ts-ignore
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const getOrInstantiateModuleFromParent: GetOrInstantiateModuleFromParent<Module> = (
id,
sourceModule
) => {
const module = moduleCache[id];

if (module) {
return module;
}

return instantiateModule(id, {
type: SourceType.Parent,
parentId: sourceModule.id,
});
};

function instantiateModule(id: ModuleId, source: SourceInfo): Module {
const moduleFactory = moduleFactories[id];
if (typeof moduleFactory !== "function") {
// This can happen if modules incorrectly handle HMR disposes/updates,
// e.g. when they keep a `setTimeout` around which still executes old code
// and contains e.g. a `require("something")` call.
let instantiationReason;
switch (source.type) {
case SourceType.Runtime:
instantiationReason = `as a runtime entry of chunk ${source.chunkPath}`;
break;
case SourceType.Parent:
instantiationReason = `because it was required from module ${source.parentId}`;
break;
case SourceType.Update:
instantiationReason = "because of an HMR update";
break;
default:
invariant(source, (source) => `Unknown source type: ${source?.type}`);
}
throw new Error(
`Module ${id} was instantiated ${instantiationReason}, but the module factory is not available. It might have been deleted in an HMR update.`
);
}

switch (source.type) {
case SourceType.Runtime:
runtimeModules.add(id);
break;
case SourceType.Parent:
// No need to add this module as a child of the parent module here, this
// has already been taken care of in `getOrInstantiateModuleFromParent`.
break;
case SourceType.Update:
throw new Error('Unexpected')
default:
invariant(source, (source) => `Unknown source type: ${source?.type}`);
}

const module: Module = {
exports: {},
error: undefined,
loaded: false,
id,
namespaceObject: undefined,
};

moduleCache[id] = module;

// NOTE(alexkirsz) This can fail when the module encounters a runtime error.
try {
const sourceInfo: SourceInfo = { type: SourceType.Parent, parentId: id };

const r = commonJsRequire.bind(null, module);
moduleFactory.call(
module.exports,
augmentContext({
a: asyncModule.bind(null, module),
e: module.exports,
r: commonJsRequire.bind(null, module),
t: runtimeRequire,
f: moduleContext,
i: esmImport.bind(null, module),
s: esmExport.bind(null, module, module.exports),
j: dynamicExport.bind(null, module, module.exports),
v: exportValue.bind(null, module),
n: exportNamespace.bind(null, module),
m: module,
c: moduleCache,
M: moduleFactories,
l: loadChunk.bind(null, sourceInfo),
w: loadWebAssembly.bind(null, sourceInfo),
u: loadWebAssemblyModule.bind(null, sourceInfo),
g: globalThis,
P: resolveAbsolutePath,
U: relativeURL,
R: createResolvePathFromModule(r),
b: getWorkerBlobURL,
__dirname: typeof module.id === "string" ? module.id.replace(/(^|\/)\/+$/, "") : module.id
})
);
} catch (error) {
module.error = error as any;
throw error;
}

module.loaded = true;
if (module.namespaceObject && module.exports !== module.namespaceObject) {
// in case of a circular dependency: cjs1 -> esm2 -> cjs1
interopEsm(module.exports, module.namespaceObject);
}

return module;
}

Loading

0 comments on commit fe86a17

Please sign in to comment.