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

transpilePackages doesn't tree-shake barrel export in turborepo #55943

Open
1 task done
raphaelbadia opened this issue Sep 25, 2023 · 11 comments
Open
1 task done

transpilePackages doesn't tree-shake barrel export in turborepo #55943

raphaelbadia opened this issue Sep 25, 2023 · 11 comments
Labels
bug Issue was opened via the bug report template. SWC Related to minification/transpilation in Next.js.

Comments

@raphaelbadia
Copy link
Contributor

Link to the code that reproduces this issue

https://github.com/raphaelbadia/barrel-exports-transpile-module-not-treeshaking

To Reproduce

  1. clone the repository and run yarn build in the root repository

Current vs. Expected behavior

Following the steps from the previous section, I expected the build output to be very light for the / (home page), something like : λ / 137 B 79.4 kB.

However I instead saw : λ / 13.7 kB 92.9 kB

Three tabs opened, in the client.html one, I clicked the left drawer, chose app/page as the chunk to explore and saw packages that aren't used: CleanShot 2023-09-25 at 11 05 52@2x

Verify canary release

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

Provide environment information

yarn run v1.22.19
$ /Users/raphael/code/billiv/turbotranspilepkg/node_modules/.bin/next info

Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 22.3.0: Mon Jan 30 20:39:46 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6020
Binaries:
  Node: 18.16.0
  npm: 9.5.1
  Yarn: 1.22.19
  pnpm: 8.6.8
Relevant Packages:
  next: 13.5.3-canary.3
  eslint-config-next: N/A
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 4.9.5
Next.js Config:
  output: N/A


✨  Done in 2.67s.

Which area(s) are affected? (Select all that apply)

SWC transpilation

Additional context

I was trying to understand why my website is so heavy, and decided to create a new project from scratch. I realised that the problem appears as soon as I add a library to the UI package.

@raphaelbadia raphaelbadia added the bug Issue was opened via the bug report template. label Sep 25, 2023
@github-actions github-actions bot added the SWC Related to minification/transpilation in Next.js. label Sep 25, 2023
@boar-is
Copy link
Contributor

boar-is commented Oct 2, 2023

Same here. Moreover, it doesn't tree shake even with "ordinary-non-barrel" exports.

// lib/client.tsx
'use client'
export function ClientComponent() {...}
// lib/server.tsx
export function ServerComponent() {...}
// lib/index.tsx
export { ClientComponent } from './client'
export { ServerComponent } from './server'

Then, in the app:

// app/page.tsx
import { ServerComponent } from "./lib";

export default function Page() {
  return <ServerComponent />;
}

ClientComponent was not tree-shaked and still in the bundle.

@yasssuz
Copy link

yasssuz commented Oct 23, 2023

@mehulkar could we get some input from the Next.js team on this? Looks like it's a pretty big issue, making some internal libs completely unusable.

Thanks in advance 😄

@ealexhaywood
Copy link

I can confirm this issue still exists on Next v13.5.5

@7iomka

This comment has been minimized.

@mrjasonroy
Copy link

this exists on 14.01 as well

@ealexhaywood
Copy link

ealexhaywood commented Nov 7, 2023

Although I believe I've seen @shuding recommending against it for now on Twitter, I've had success using the experimental optimizePackageImports for my turborepo packages for Next 13.5.7 and later

/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: ["ui"],
  experimental: {
    optimizePackageImports: ["ui"]
  }
}

module.exports = nextConfig

If your ui package imports any other package with a lot of modules, you might also need to put them in optimizePackageImports

The number of modules for some pages decreased by over 10k for us

@7iomka
Copy link
Contributor

7iomka commented Nov 7, 2023

Although I believe I've seen @shuding recommending against it for now on Twitter, I've had success using the experimental optimizePackageImports for my turborepo packages for Next 13.5.7 and later

/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: ["ui"],
  experimental: {
    optimizePackageImports: ["ui"]
  }
}

module.exports = nextConfig

If your ui package imports any other package with a lot of modules, you might also need to put them in optimizePackageImports

The number of modules for some pages decreased by over 10k for us

optimizePackageImports not make sense for babel users because it require swc :(

@mrjasonroy
Copy link

Although I believe I've seen @shuding recommending against it for now on Twitter, I've had success using the experimental optimizePackageImports for my turborepo packages for Next 13.5.7 and later

/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: ["ui"],
  experimental: {
    optimizePackageImports: ["ui"]
  }
}

module.exports = nextConfig

If your ui package imports any other package with a lot of modules, you might also need to put them in optimizePackageImports

The number of modules for some pages decreased by over 10k for us

This partially worked for me but I ended up having some components that still imported server specific functions. I ended up going this (long) route I found on the turborepo discord server. Server components header, main-layout and footer are packaged then properly separated. I could referenced the "src" folder directly rather than creating an exports but I had a lot of other code nested in that folder and this approach just seemed cleaner.

{
  "name" : "@acme/chat-ui",

  "exports": {
    "./configs": "./exports/configs.tsx",
    "./utils": "./exports/utils.ts",
    "./hooks": "./exports/hooks.tsx",
    "./context": "./exports/context.tsx",
    "./chat": "./exports/chat.tsx",
    "./sidebar": "./exports/sidebar.tsx",
    "./header": "./exports/header.tsx",
    "./main-layout": "./exports/main-layout.tsx",
    "./footer": "./exports/footer.tsx"
  },
  "typesVersions": {
    "*": {
      "*": [
        "exports/*"
      ]
    }
  }

Used like this:

import { Chat } from '@acme/chat-ui/chat'

@lluiscab
Copy link

We're facing what could very well be the same issue on next 14.2.6 with turbo enabled. experimental.optimizePackageImports and transpilePackages don't seem to change anything. Our index page size is currently 3.77MB (4.79MB first load) and that's just wrong.

During development, no matter if turbo is enabled or not, the next-server process can reach usage of 4GB of ram just compiling he index page. We attribute this to Next loading (very inefficiently) our entire library into memory. Some of our developers have been impacted really heard due to this issue.

We've spent the entire day removing all our barrel exports, updating imports and testing but we can't seem to fix this problem any way.

We'd really appreciate some input as to how we're supposed to debug these issues and how to reduce the 4gb memory usage while in development.

@JulianKingman
Copy link

If you have something like a UI library with many, many components, what do you replace barrel files with? How do you organize exports? I feel like I'm missing something obvious.

@raphaelbadia
Copy link
Contributor Author

You do it the ugly way, like that... 🥲
Screenshot 2024-09-09 at 17 15 42

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template. SWC Related to minification/transpilation in Next.js.
Projects
None yet
Development

No branches or pull requests

8 participants