Skip to content

Commit

Permalink
experimental: css inlining
Browse files Browse the repository at this point in the history
  • Loading branch information
gaojude committed Nov 1, 2024
1 parent a44a0d9 commit 7bac059
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 8 deletions.
1 change: 1 addition & 0 deletions packages/next/src/export/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ async function exportAppImpl(
expireTime: nextConfig.expireTime,
after: nextConfig.experimental.after ?? false,
dynamicIO: nextConfig.experimental.dynamicIO ?? false,
inlineCss: nextConfig.experimental.inlineCss ?? false,
},
reactMaxHeadersLength: nextConfig.reactMaxHeadersLength,
}
Expand Down
35 changes: 27 additions & 8 deletions packages/next/src/server/app-render/get-layer-assets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import type { AppRenderContext } from './app-render'
import { getAssetQueryString } from './get-asset-query-string'
import { encodeURIPath } from '../../shared/lib/encode-uri-path'
import type { PreloadCallbacks } from './types'
import path from 'path'
import { readFileSync } from 'fs'

export function getLayerAssets({
ctx,
Expand Down Expand Up @@ -74,6 +76,15 @@ export function getLayerAssets({

const styles = styleTags
? styleTags.map((href, index) => {
// `Precedence` is an opt-in signal for React to handle resource
// loading and deduplication, etc. It's also used as the key to sort
// resources so they will be injected in the correct order.
// During HMR, it's critical to use different `precedence` values
// for different stylesheets, so their order will be kept.
// https://github.com/facebook/react/pull/25060
const precedence =
process.env.NODE_ENV === 'development' ? 'next_' + href : 'next'

// In dev, Safari and Firefox will cache the resource during HMR:
// - https://github.com/vercel/next.js/issues/5860
// - https://bugs.webkit.org/show_bug.cgi?id=187726
Expand All @@ -84,14 +95,22 @@ export function getLayerAssets({
href
)}${getAssetQueryString(ctx, true)}`

// `Precedence` is an opt-in signal for React to handle resource
// loading and deduplication, etc. It's also used as the key to sort
// resources so they will be injected in the correct order.
// During HMR, it's critical to use different `precedence` values
// for different stylesheets, so their order will be kept.
// https://github.com/facebook/react/pull/25060
const precedence =
process.env.NODE_ENV === 'development' ? 'next_' + href : 'next'
if (ctx.renderOpts.experimental.inlineCss) {
return (
<style
key={index}
dangerouslySetInnerHTML={{
__html: String(
readFileSync(path.join(ctx.renderOpts.distDir ?? '', href))
),
}}
nonce={ctx.nonce}
// @ts-ignore
precedence={precedence}
data-href={href}
/>
)
}

preloadCallbacks.push(() => {
ctx.componentMod.preloadStyle(
Expand Down
2 changes: 2 additions & 0 deletions packages/next/src/server/app-render/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export type ServerOnInstrumentationRequestError = (
) => void | Promise<void>

export interface RenderOptsPartial {
distDir?: string
previewProps: __ApiPreviewProps | undefined
err?: Error | null
dev?: boolean
Expand Down Expand Up @@ -182,6 +183,7 @@ export interface RenderOptsPartial {
clientTraceMetadata: string[] | undefined
after: boolean
dynamicIO: boolean
inlineCss: boolean
}
postponed?: string
/**
Expand Down
2 changes: 2 additions & 0 deletions packages/next/src/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ export default abstract class Server<
clientTraceMetadata: this.nextConfig.experimental.clientTraceMetadata,
after: this.nextConfig.experimental.after ?? false,
dynamicIO: this.nextConfig.experimental.dynamicIO ?? false,
inlineCss: this.nextConfig.experimental.inlineCss ?? false,
},
onInstrumentationRequestError:
this.instrumentationOnRequestError.bind(this),
Expand Down Expand Up @@ -2493,6 +2494,7 @@ export default abstract class Server<
onAfterTaskError: undefined,
// only available in dev
setAppIsrStatus: (this as any).setAppIsrStatus,
distDir: this.distDir,
}

if (isDebugStaticShell || isDebugDynamicAccesses) {
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 @@ -291,6 +291,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
disableOptimizedLoading: z.boolean().optional(),
disablePostcssPresetEnv: z.boolean().optional(),
dynamicIO: z.boolean().optional(),
inlineCss: z.boolean().optional(),
esmExternals: z.union([z.boolean(), z.literal('loose')]).optional(),
serverActions: z
.object({
Expand Down
5 changes: 5 additions & 0 deletions packages/next/src/server/config-shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,11 @@ export interface ExperimentalConfig {
* unless explicitly cached.
*/
dynamicIO?: boolean

/**
* Render <style> tags inline in the HTML for imported CSS assets.
*/
inlineCss?: boolean
}

export type ExportPathMap = {
Expand Down

0 comments on commit 7bac059

Please sign in to comment.