Skip to content
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

introduce _app.mdx for better performance and smallest .next/static/chunks size #1448

Merged
merged 18 commits into from Feb 24, 2023

Conversation

dimaMachina
Copy link
Collaborator

@dimaMachina dimaMachina commented Feb 1, 2023

I am pretty sure, this will fix #1131

also, it opens the opportunity to use react context in future refactor of v3 instead of useInternals?

Update

I guess there is some race condition for _app.mdx sometimes next build passe and sometimes not

image

✅ Fixed here #1463

before

 dmytro@MacBook-Pro  ~/Desktop/nextra   main  find examples/blog/.next/static/chunks -ls | awk '{sum += $7} END {print sum}'
435979
 dmytro@MacBook-Pro  ~/Desktop/nextra   main  find examples/docs/.next/static/chunks -ls | awk '{sum += $7} END {print sum}'
980947
 dmytro@MacBook-Pro  ~/Desktop/nextra   main  find examples/swr-site/.next/static/chunks -ls | awk '{sum += $7} END {print sum}'
4060262
 dmytro@MacBook-Pro  ~/Desktop/nextra   main  find docs/.next/static/chunks -ls | awk '{sum += $7} END {print sum}' 
1342697

after

 dmytro@MacBook-Pro  ~/Desktop/nextra   _app  find examples/blog/.next/static/chunks -ls | awk '{sum += $7} END {print sum}'    
429701
 dmytro@MacBook-Pro  ~/Desktop/nextra   _app  find examples/docs/.next/static/chunks -ls | awk '{sum += $7} END {print sum}'
958154
 dmytro@MacBook-Pro  ~/Desktop/nextra   _app  find examples/swr-site/.next/static/chunks -ls | awk '{sum += $7} END {print sum}'
3247164
 dmytro@MacBook-Pro  ~/Desktop/nextra   _app  find docs/.next/static/chunks -ls | awk '{sum += $7} END {print sum}'     
1254104

diff

example-blog example-docs swr-site nextra website
1.45% 2.35% 20.25% 6.6%

@changeset-bot
Copy link

changeset-bot bot commented Feb 1, 2023

🦋 Changeset detected

Latest commit: f15aa61

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
nextra Major
nextra-theme-blog Major
nextra-theme-docs Major
example-blog Patch
example-docs Patch
swr-site Patch
docs Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Feb 1, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated
nextra 🔄 Building (Inspect) Feb 24, 2023 at 2:44PM (UTC)
nextra-theme-docs-dev ❌ Failed (Inspect) Feb 24, 2023 at 2:44PM (UTC)
nextra-v2 ✅ Ready (Inspect) Visit Preview 💬 Add your feedback Feb 24, 2023 at 2:44PM (UTC)

@github-actions
Copy link
Contributor

github-actions bot commented Feb 2, 2023

📦 Next.js Bundle Analysis

This analysis was generated by the next.js bundle analysis action 🤖

⚠️ Global Bundle Size Increased

Page Size (compressed)
global 174.16 KB (🔴 +95.97 KB)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

One Hundred Five Pages Changed Size

The following pages changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load % of Budget (350 KB)
/404 7.01 KB 181.17 KB 51.76% (🟢 -27.08%)
/500 7 KB 181.16 KB 51.76% (🟢 -27.08%)
/about/a-page.en-US 6.97 KB 181.13 KB 51.75% (🟢 -27.09%)
/about/acknowledgement.en-US 6.96 KB 181.12 KB 51.75% (🟢 -27.09%)
/about/team.en-US 7.01 KB 181.17 KB 51.76% (🟢 -27.08%)
/blog.en-US 7.58 KB 181.74 KB 51.93% (🟢 -27.07%)
/blog/swr-v1.en-US 12.46 KB 186.61 KB 53.32% (🟢 -27.03%)
/blog/swr-v1.ru 14.13 KB 188.29 KB 53.80% (🟢 -26.97%)
/docs/404-500.en-US 7.85 KB 182 KB 52.00% (🟢 -27.08%)
/docs/advanced.en-US 7.34 KB 181.49 KB 51.86% (🟢 -27.08%)
/docs/advanced/cache.en-US 19.12 KB 193.28 KB 55.22% (🟢 -27.15%)
/docs/advanced/cache.ru 20.36 KB 194.52 KB 55.58% (🟢 -27.11%)
/docs/advanced/code-highlighting.en-US 7.8 KB 181.96 KB 51.99% (🟢 -27.08%)
/docs/advanced/dynamic-markdown-import.en-US 8.56 KB 182.72 KB 52.21% (🟢 -27.08%)
/docs/advanced/file-name.with.DOTS.en-US 7.01 KB 181.17 KB 51.76% (🟢 -27.08%)
/docs/advanced/file-name.with.DOTS.es-ES 7.03 KB 181.18 KB 51.77% (🟢 -26.99%)
/docs/advanced/file-name.with.DOTS.ru 7.08 KB 181.23 KB 51.78% (🟢 -27.06%)
/docs/advanced/images.en-US 7.25 KB 181.41 KB 51.83% (🟢 -27.08%)
/docs/advanced/markdown-import.en-US 11.3 KB 185.46 KB 52.99% (🟢 -27.08%)
/docs/advanced/more/loooooooooooooooooooong-title.en-US 7.06 KB 181.22 KB 51.78% (🟢 -27.08%)
/docs/advanced/more/tree/one.en-US 7.02 KB 181.18 KB 51.76% (🟢 -27.08%)
/docs/advanced/more/tree/three.en-US 6.97 KB 181.12 KB 51.75% (🟢 -27.09%)
/docs/advanced/more/tree/two.en-US 7.02 KB 181.18 KB 51.76% (🟢 -27.08%)
/docs/advanced/performance.en-US 9.29 KB 183.44 KB 52.41% (🟢 -27.08%)
/docs/advanced/performance.es-ES 9.46 KB 183.62 KB 52.46% (🟢 -26.98%)
/docs/advanced/performance.ru 10.1 KB 184.25 KB 52.64% (🟢 -27.02%)
/docs/advanced/react-native.en-US 8.87 KB 183.02 KB 52.29% (🟢 -27.07%)
/docs/advanced/react-native.ru 9.44 KB 183.6 KB 52.46% (🟢 -27.03%)
/docs/advanced/scrollbar-x.en-US 7.99 KB 182.14 KB 52.04% (🟢 -27.09%)
/docs/arguments.en-US 8.08 KB 182.24 KB 52.07% (🟢 -27.08%)
/docs/arguments.es-ES 8.15 KB 182.31 KB 52.09% (🟢 -26.99%)
/docs/arguments.ru 8.41 KB 182.56 KB 52.16% (🟢 -27.04%)
/docs/callout.en-US 7.13 KB 181.29 KB 51.80% (🟢 -27.08%)
/docs/change-log.en-US 7.33 KB 181.49 KB 51.85% (🟢 -27.07%)
/docs/change-log.es-ES 12.78 KB 186.94 KB 53.41% (🟢 -26.97%)
/docs/change-log.ru 12.89 KB 187.05 KB 53.44% (🟢 -27.04%)
/docs/code-block-without-language.en-US 7.16 KB 181.32 KB 51.81% (🟢 -27.08%)
/docs/conditional-fetching.en-US 7.95 KB 182.11 KB 52.03% (🟢 -27.09%)
/docs/conditional-fetching.es-ES 8.01 KB 182.16 KB 52.05% (🟢 -26.99%)
/docs/conditional-fetching.ru 8.24 KB 182.39 KB 52.11% (🟢 -27.03%)
/docs/data-fetching.en-US 8.35 KB 182.5 KB 52.14% (🟢 -27.06%)
/docs/data-fetching.es-ES 8.4 KB 182.55 KB 52.16% (🟢 -26.97%)
/docs/data-fetching.ru 8.7 KB 182.86 KB 52.24% (🟢 -27.01%)
/docs/error-handling.en-US 9.16 KB 183.32 KB 52.38% (🟢 -27.08%)
/docs/error-handling.es-ES 9.31 KB 183.46 KB 52.42% (🟢 -26.99%)
/docs/error-handling.ru 9.88 KB 184.03 KB 52.58% (🟢 -27.03%)
/docs/getting-started.en-US 14.16 KB 188.31 KB 53.80% (🟢 -27.10%)
/docs/getting-started.es-ES 14.18 KB 188.33 KB 53.81% (🟢 -27.00%)
/docs/getting-started.ru 14.81 KB 188.96 KB 53.99% (🟢 -27.05%)
/docs/global-configuration.en-US 8.24 KB 182.4 KB 52.11% (🟢 -27.08%)
/docs/global-configuration.es-ES 8.3 KB 182.45 KB 52.13% (🟢 -26.99%)
/docs/global-configuration.ru 8.6 KB 182.76 KB 52.22% (🟢 -27.04%)
/docs/middleware.en-US 9.84 KB 184 KB 52.57% (🟢 -27.13%)
/docs/middleware.ru 10.65 KB 184.8 KB 52.80% (🟢 -27.08%)
/docs/mutation.en-US 9.73 KB 183.88 KB 52.54% (🟢 -27.12%)
/docs/mutation.es-ES 9.81 KB 183.96 KB 52.56% (🟢 -27.02%)
/docs/mutation.ru 10.49 KB 184.65 KB 52.76% (🟢 -27.07%)
/docs/options.en-US 8.78 KB 182.93 KB 52.27% (🟢 -27.07%)
/docs/options.es-ES 8.93 KB 183.09 KB 52.31% (🟢 -26.96%)
/docs/options.ru 9.53 KB 183.68 KB 52.48% (🟢 -27.00%)
/docs/pagination.en-US 19.16 KB 193.31 KB 55.23% (🟢 -27.14%)
/docs/pagination.es-ES 19.51 KB 193.67 KB 55.33% (🟢 -27.04%)
/docs/pagination.ru 20.4 KB 194.56 KB 55.59% (🟢 -27.10%)
/docs/prefetching.en-US 8.41 KB 182.56 KB 52.16% (🟢 -27.06%)
/docs/prefetching.es-ES 8.49 KB 182.65 KB 52.19% (🟢 -26.97%)
/docs/prefetching.ru 8.91 KB 183.06 KB 52.30% (🟢 -27.01%)
/docs/raw-layout.en-US 7.69 KB 181.84 KB 51.95% (🟢 -27.07%)
/docs/revalidation.en-US 13.44 KB 187.6 KB 53.60% (🟢 -27.06%)
/docs/revalidation.es-ES 13.58 KB 187.74 KB 53.64% (🟢 -26.96%)
/docs/revalidation.ru 14.17 KB 188.33 KB 53.81% (🟢 -27.01%)
/docs/suspense.en-US 8.45 KB 182.6 KB 52.17% (🟢 -27.07%)
/docs/suspense.es-ES 8.5 KB 182.66 KB 52.19% (🟢 -26.98%)
/docs/suspense.ru 8.86 KB 183.02 KB 52.29% (🟢 -27.02%)
/docs/typescript.en-US 8.73 KB 182.89 KB 52.25% (🟢 -27.10%)
/docs/understanding.en-US 14.54 KB 188.69 KB 53.91% (🟢 -27.07%)
/docs/understanding.es-ES 14.53 KB 188.69 KB 53.91% (🟢 -26.97%)
/docs/understanding.ru 14.53 KB 188.69 KB 53.91% (🟢 -27.06%)
/docs/with-nextjs.en-US 8.53 KB 182.68 KB 52.19% (🟢 -27.07%)
/docs/with-nextjs.es-ES 8.66 KB 182.81 KB 52.23% (🟢 -26.97%)
/docs/with-nextjs.ru 9.04 KB 183.2 KB 52.34% (🟢 -27.02%)
/docs/wrap-toc-items.en-US 7.79 KB 181.94 KB 51.98% (🟢 -27.08%)
/docs/wrap-toc-items.es-ES 7.78 KB 181.94 KB 51.98% (🟢 -26.99%)
/docs/wrap-toc-items.ru 7.78 KB 181.94 KB 51.98% (🟢 -27.08%)
/examples/auth.en-US 7.24 KB 181.4 KB 51.83% (🟢 -27.07%)
/examples/auth.es-ES 7.25 KB 181.4 KB 51.83% (🟢 -26.97%)
/examples/auth.ru 7.28 KB 181.43 KB 51.84% (🟢 -27.05%)
/examples/basic.en-US 7.24 KB 181.4 KB 51.83% (🟢 -27.07%)
/examples/basic.es-ES 7.24 KB 181.4 KB 51.83% (🟢 -26.97%)
/examples/basic.ru 7.29 KB 181.44 KB 51.84% (🟢 -27.05%)
/examples/error-handling.en-US 7.25 KB 181.41 KB 51.83% (🟢 -27.07%)
/examples/error-handling.es-ES 7.25 KB 181.41 KB 51.83% (🟢 -26.97%)
/examples/error-handling.ru 7.28 KB 181.44 KB 51.84% (🟢 -27.05%)
/examples/full.en-US 7.23 KB 181.38 KB 51.82% (🟢 -27.07%)
/examples/infinite-loading.en-US 7.26 KB 181.42 KB 51.83% (🟢 -27.07%)
/examples/infinite-loading.es-ES 7.26 KB 181.42 KB 51.83% (🟢 -26.97%)
/examples/infinite-loading.ru 7.31 KB 181.46 KB 51.85% (🟢 -27.05%)
/examples/ssr.en-US 7.25 KB 181.41 KB 51.83% (🟢 -27.07%)
/examples/ssr.ru 7.25 KB 181.4 KB 51.83% (🟢 -27.06%)
/index.en-US 10.99 KB 185.14 KB 52.90% (🟢 -27.08%)
/index.es-ES 10.77 KB 184.92 KB 52.84% (🟢 -26.99%)
/index.ru 11.16 KB 185.31 KB 52.95% (🟢 -27.05%)
/remote/[slug] 6.94 KB 181.1 KB 51.74% (🟢 -27.09%)
/remote/graphql-eslint/[[...slug]] 6.99 KB 181.15 KB 51.76% (🟢 -27.09%)
/remote/graphql-yoga/[[...slug]] 7.01 KB 181.17 KB 51.76% (🟢 -27.08%)
/test.en-US 7.21 KB 181.37 KB 51.82% (🟢 -27.08%)
Details

Only the gzipped size is provided here based on an expert tip.

First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

The "Budget %" column shows what percentage of your performance budget the First Load total takes up. For example, if your budget was 100kb, and a given page's first load size was 10kb, it would be 10% of your budget. You can also see how much this has increased or decreased compared to the base branch of your PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this. If you see "+/- <0.01%" it means that there was a change in bundle size, but it is a trivial enough amount that it can be ignored.

Copy link
Collaborator

@promer94 promer94 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea we only need to inject pageMap once !
I am also doing some exterimental about this optimization.

Concerns

_app.js is a important entry for next.js. Developers used to do a lot of customizations around this file.

  • Analytics
import type { AppProps } from 'next/app';
import { Analytics } from '@vercel/analytics/react';

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <Analytics />
    </>
  );
}

export default MyApp;
  • Auth
import { SessionProvider } from "next-auth/react"
export default function App({
  Component,
  pageProps: { session, ...pageProps },
}) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}

It seems hard to do the same customization in app.mdx ?

Possible Alternatives

Maybe we could build

  • a webpack plugin used to create a virtual file which contains the pageMaps and other meta data
  • a special loader just for _app.js so it could import the virtual file

@dimaMachina
Copy link
Collaborator Author

dimaMachina commented Feb 2, 2023

_app.js is a important entry for next.js. Developers used to do a lot of customizations around this file.

totally agree

the first concern can be already done

<>
<MDXContent />
<Component {...pageProps} />
</>

// _app.mdx
import { Analytics } from '@vercel/analytics/react'

<Analytics />

for the second one need to think about how to have possibility to wrap everything with user provider

dynamicMetaModules: typeof window === 'undefined' ? [${dynamicMetaModules}] : []
})

export { default } from 'nextra/layout'`
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think nextra/layout we can move directly to nextra/setup-page to have less file size, but in another PR

Comment on lines 275 to 276
${themeConfigImport}
${katexCssImport}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these imports we can inject also in _app.mdx to yet reduce bundle size, but in another PR ;)

@dimaMachina
Copy link
Collaborator Author

dimaMachina commented Feb 2, 2023

@promer94 for the second concern, we could do it

// _app.mdx
import { SessionProvider } from "next-auth/react"
export default function App({
  Component,
  pageProps: { session, ...pageProps },
}) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}

But we should do not do .replace('export default MDXContent;', '') and remove below

return function App({ Component, pageProps }: AppProps): ReactElement {
return (
<>
<MDXContent />
<Component {...pageProps} />
</>
)
}

@promer94
Copy link
Collaborator

promer94 commented Feb 3, 2023

// _app.mdx
import { SessionProvider } from "next-auth/react"
export default function App({
  Component,
  pageProps: { session, ...pageProps },
}) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}

This is ok but not ideal. Since user will lost almost all the code intellisense and autocomplete in mdx.

I know mdx.experimentalLanguageServer: could help to improve this but it is still in its early stage.

@dimaMachina
Copy link
Collaborator Author

// _app.mdx
import { SessionProvider } from "next-auth/react"
export default function App({
  Component,
  pageProps: { session, ...pageProps },
}) {
  return (
    <SessionProvider session={session}>
      <Component {...pageProps} />
    </SessionProvider>
  )
}

This is ok but not ideal. Since user will lost almost all the code intellisense and autocomplete in mdx.

I know mdx.experimentalLanguageServer: could help to improve this but it is still in its early stage.

you can also write your code in typescript and import in _app.mdx

// _app.mdx
export { default } from '../../myUnderscoreAppWrittenInTs'

@dimaMachina dimaMachina changed the title introduce _app.{md,mdx} for better perfomance, smallest bundle size introduce _app.mdx for better performance and smallest .next/static/chunks size Feb 3, 2023
* reduce `.next/static/chunks` for 40%

* autocreate _app.mdx

* remove unneded spaces

* polish

* add tests for getDynamicMeta

* tests

* more tests

* fix getDynamicData

* Apply suggestions from code review
@danez
Copy link
Contributor

danez commented Mar 4, 2023

In all fairness, this should have been a breaking change. It made my website not build for some time and took me a while to figure out that I had to run a build locally to create_app.mdx and commit it.

@dimaMachina
Copy link
Collaborator Author

@danez Can you please open a separate issue for this? It's hard to properly track this in the comments of an already merged PR.

Repository owner locked as resolved and limited conversation to collaborators Mar 5, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Large number of pages causing build error with high memory usage
3 participants