Skip to content

Commit

Permalink
Allow disabling runtime JS in production for certain pages (#11949)
Browse files Browse the repository at this point in the history
This allows a page to be fully static (no runtime JavaScript) on a per-page basis.

The initial implementation does not disable JS in development mode as we need to figure out a way to inject CSS from CSS imports / CSS modules without executing the component JS. This restriction is somewhat similar to https://www.gatsbyjs.org/packages/gatsby-plugin-no-javascript/. All things considered that plugin only has a usage of 600 downloads per week though, hence why I've made this option unstable/experimental initially as I'd like to see adoption patterns for it first.

Having a built-in way to do this makes sense however as the people that do want to adopt this pattern are overriding Next.js internals currently and that'll break between versions.

Related issue: #5054 - Not adding `fixes` right now as this implementation needs more work. If anyone wants to work on this feel free to reach out on https://twitter.com/timneutkens
  • Loading branch information
timneutkens authored Apr 17, 2020
1 parent 22e3c69 commit 2fa26a2
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 24 deletions.
1 change: 1 addition & 0 deletions packages/next/next-server/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ export type DocumentProps = DocumentInitialProps & {
htmlProps: any
bodyTags: any[]
headTags: any[]
unstable_runtimeJS?: false
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/next/next-server/server/render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export type RenderOptsPartial = {
params?: ParsedUrlQuery
previewProps: __ApiPreviewProps
basePath: string
unstable_runtimeJS?: false
}

export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial
Expand Down Expand Up @@ -200,6 +201,7 @@ function renderDocument(
customServer,
gip,
appGip,
unstable_runtimeJS,
}: RenderOpts & {
props: any
docProps: DocumentInitialProps
Expand Down Expand Up @@ -268,6 +270,7 @@ function renderDocument(
htmlProps,
bodyTags,
headTags,
unstable_runtimeJS,
...docProps,
})}
</AmpStateContext.Provider>
Expand Down Expand Up @@ -772,6 +775,11 @@ export async function renderToHTML(

let html = renderDocument(Document, {
...renderOpts,
// Only enabled in production as development mode has features relying on HMR (style injection for example)
unstable_runtimeJS:
process.env.NODE_ENV === 'production'
? pageConfig.unstable_runtimeJS
: undefined,
dangerousAsPath: router.asPath,
ampState,
props,
Expand Down
54 changes: 30 additions & 24 deletions packages/next/pages/_document.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,9 @@ export class Head extends Component<
__NEXT_DATA__,
dangerousAsPath,
headTags,
unstable_runtimeJS,
} = this.context._documentProps
const disableRuntimeJS = unstable_runtimeJS === false
const { _devOnlyInvalidateCacheQueryString } = this.context
const { page, buildId } = __NEXT_DATA__

Expand Down Expand Up @@ -490,7 +492,7 @@ export class Head extends Component<
/>
)}
{this.getCssLinks()}
{page !== '/_error' && (
{!disableRuntimeJS && page !== '/_error' && (
<link
rel="preload"
href={
Expand All @@ -507,21 +509,23 @@ export class Head extends Component<
crossOrigin={this.props.crossOrigin || process.crossOrigin}
/>
)}
<link
rel="preload"
href={
assetPrefix +
getOptionalModernScriptVariant(
encodeURI(`/_next/static/${buildId}/pages/_app.js`)
) +
_devOnlyInvalidateCacheQueryString
}
as="script"
nonce={this.props.nonce}
crossOrigin={this.props.crossOrigin || process.crossOrigin}
/>
{this.getPreloadDynamicChunks()}
{this.getPreloadMainLinks()}
{!disableRuntimeJS && (
<link
rel="preload"
href={
assetPrefix +
getOptionalModernScriptVariant(
encodeURI(`/_next/static/${buildId}/pages/_app.js`)
) +
_devOnlyInvalidateCacheQueryString
}
as="script"
nonce={this.props.nonce}
crossOrigin={this.props.crossOrigin || process.crossOrigin}
/>
)}
{!disableRuntimeJS && this.getPreloadDynamicChunks()}
{!disableRuntimeJS && this.getPreloadMainLinks()}
{this.context._documentProps.isDevelopment &&
this.context._documentProps.hasCssMode && (
// this element is used to mount development styles so the
Expand All @@ -532,7 +536,7 @@ export class Head extends Component<
{styles || null}
</>
)}
{this.getFidPolyfill()}
{!disableRuntimeJS && this.getFidPolyfill()}
{React.createElement(React.Fragment, {}, ...(headTags || []))}
</head>
)
Expand Down Expand Up @@ -669,7 +673,9 @@ export class NextScript extends Component<OriginProps> {
devFiles,
__NEXT_DATA__,
bodyTags,
unstable_runtimeJS,
} = this.context._documentProps
const disableRuntimeJS = unstable_runtimeJS === false

const { _devOnlyInvalidateCacheQueryString } = this.context

Expand Down Expand Up @@ -790,7 +796,7 @@ export class NextScript extends Component<OriginProps> {

return (
<>
{devFiles
{!disableRuntimeJS && devFiles
? devFiles.map(
(file: string) =>
!file.match(/\.js\.map/) && (
Expand Down Expand Up @@ -818,7 +824,7 @@ export class NextScript extends Component<OriginProps> {
}}
/>
)}
{process.env.__NEXT_MODERN_BUILD ? (
{process.env.__NEXT_MODERN_BUILD && !disableRuntimeJS ? (
<script
nonce={this.props.nonce}
crossOrigin={this.props.crossOrigin || process.crossOrigin}
Expand All @@ -828,11 +834,11 @@ export class NextScript extends Component<OriginProps> {
}}
/>
) : null}
{this.getPolyfillScripts()}
{page !== '/_error' && pageScript}
{appScript}
{staticMarkup ? null : this.getDynamicChunks()}
{staticMarkup ? null : this.getScripts()}
{!disableRuntimeJS && this.getPolyfillScripts()}
{!disableRuntimeJS && page !== '/_error' && pageScript}
{!disableRuntimeJS && appScript}
{disableRuntimeJS || staticMarkup ? null : this.getDynamicChunks()}
{disableRuntimeJS || staticMarkup ? null : this.getScripts()}
{React.createElement(React.Fragment, {}, ...(bodyTags || []))}
</>
)
Expand Down
1 change: 1 addition & 0 deletions packages/next/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export type PageConfig = {
bodyParser?: { sizeLimit?: number | string } | false
}
env?: Array<string>
unstable_runtimeJS?: false
}

export {
Expand Down
6 changes: 6 additions & 0 deletions test/integration/disable-js/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
onDemandEntries: {
// Make sure entries are not getting disposed.
maxInactiveAge: 1000 * 60 * 60,
},
}
5 changes: 5 additions & 0 deletions test/integration/disable-js/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const config = {
unstable_runtimeJS: false,
}

export default () => <h1>Hello World!</h1>

0 comments on commit 2fa26a2

Please sign in to comment.