Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Tree Shake] Next.js emit unused code into the main bundle #35900

Closed
1 task done
SukkaW opened this issue Apr 5, 2022 · 0 comments
Closed
1 task done

[Tree Shake] Next.js emit unused code into the main bundle #35900

SukkaW opened this issue Apr 5, 2022 · 0 comments
Labels
bug Issue was opened via the bug report template.

Comments

@SukkaW
Copy link
Contributor

SukkaW commented Apr 5, 2022

Verify canary release

  • I verified that the issue exists in Next.js canary release

Provide environment information

Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 21.4.0: Mon Feb 21 20:34:37 PST 2022; root:xnu-8020.101.4~2/RELEASE_X86_64
Binaries:
  Node: 16.14.0
  npm: 8.5.1
  Yarn: 1.22.18
  pnpm: 6.32.4
Relevant packages:
  next: 12.1.5-canary.1
  react: 18.0.0
  react-dom: 18.0.0

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

next build / export

Describe the Bug

I notice the main bundle emitted by next build is a bit heavy, so I use @next/bundle-analyzer to analyze my bundle:

image

And there are many features I don't use at all that are included in the bundle:

next/dist/shared/amp.js

I don't use the AMP feature at all. So I take a look at the source code. shared/lib/amp.ts has 2 named export, useAmp and isInAmpMode:

export function isInAmpMode({
ampFirst = false,
hybrid = false,
hasQuery = false,
} = {}): boolean {
return ampFirst || (hybrid && hasQuery)
}
export function useAmp(): boolean {
// Don't assign the context value to a variable to save bytes
return isInAmpMode(React.useContext(AmpStateContext))
}

isInAmpMode is then imported by shared/lib/head.tsx:

import { isInAmpMode } from './amp'

I do use next/head component, so it is very reasonable that isInAmpMode is included in my bundle. However, useAmp is also included in the final bundle:

image

next/dist/client/script.js

I don't use next/script component at all. And the scriptLoader property of the __NEXT_DATA__ is also an empty array:

image

So I take a look at the source code again. client/script.tsx has a default export and a named export initScriptLoader:

export function initScriptLoader(scriptLoaderItems: ScriptProps[]) {
scriptLoaderItems.forEach(handleClientScriptLoad)
}

...which is then imported by client/index.tsx:

if (initialData.scriptLoader) {
const { initScriptLoader } = require('./script')
initScriptLoader(initialData.scriptLoader)
}

However, the entire next/dist/client/script.js is still included in the final main bundle:

image

As you can see there are keywords like text/partydown, afterInteractive and lazyOnLoad.

next/dist/client/streaming/vitals.js

I do use reportWebVitals named export on my custom _app, but I don't use unstable_useWebVitalsReport. So once again, I take a look at the source code of next.js.

There are tons of named export at client/streaming/vitals.ts:

export const webVitalsCallbacks = new Set<ReportWebVitalsCallback>()

export function getBufferedVitalsMetrics() {
return metrics
}

export function trackWebVitalMetric(metric: NextWebVitalsMetric) {
metrics.push(metric)
webVitalsCallbacks.forEach((callback) => callback(metric))
}

export function useWebVitalsReport(callback: ReportWebVitalsCallback) {

flushBufferedVitalsMetrics and trackWebVitalMetric are imported by client/index.tsx:

import {
flushBufferedVitalsMetrics,
trackWebVitalMetric,
} from './streaming/vitals'

... which is used by <Root /> component:

React.useEffect(() => {
measureWebVitals(onPerfEntry)
flushBufferedVitalsMetrics()
}, [])

... and hydrate function:

trackWebVitalMetric(webVitals)

However, useWebVitalsReport is also included in my final bundle:

image

next/dist/client/streaming/refresh.js

I am pretty sure I don't use useRefreshRoot at all. And Next.js itself doesn't uses useRefreshRoot either. However, it is still included in the final bundle:

image

Expected Behavior

All those unused codes I mentioned above should not be included in the final main bundle.

To Reproduce

I introduce @next/bundle-analyzer into another bare bone Next.js reproduction (the one I used in #35286), and all those unused codes are included in the main bundle:

image

@SukkaW SukkaW added the bug Issue was opened via the bug report template. label Apr 5, 2022
@SukkaW SukkaW changed the title Next.js emit unused code into the main bundle [Tree Shake] Next.js emit unused code into the main bundle Apr 5, 2022
@vercel vercel locked and limited conversation to collaborators Apr 5, 2022
@balazsorban44 balazsorban44 converted this issue into discussion #35907 Apr 5, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
bug Issue was opened via the bug report template.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant