Uri Klar
Uri Klar

Reputation: 3988

Turborepo - node modules not being tree shaken even though not being used

Trying to wrap my head around Turborepo so I might be doing something wrong here.
Here is my current turborepo setup (you can see the full code in this repo)

I have two components in my ui package:

Button - uses styled-components and framer-motion
Loader - uses neither..

Button.tsx

import * as React from "react";
import styled from "styled-components";
import { motion } from "framer-motion";

export const Button = () => {
  return (
    <ButtonContainer
      initial={{ opacity: 0, scale: 0.5 }}
      animate={{ opacity: 1, scale: 1 }}
      transition={{ duration: 0.5 }}
    >
      Boop
    </ButtonContainer>
  );
};

const ButtonContainer = styled(motion.button)``;

Loader.tsx

import * as React from "react";

export const Loader = () => {
  return <div>MyLoader</div>;
};

and this is the package.json for the ui library:

{
 "devDependencies": {
    "@types/react": "^17.0.37",
    "@types/react-dom": "^17.0.11",
    "@types/styled-components": "^5.1.25",
    "eslint": "^7.32.0",
    "eslint-config-custom": "workspace:*",
    "react": "^17.0.2",
    "styled-components": ">=5.3.3",
    "tsconfig": "workspace:*",
    "typescript": "^4.5.2"
  },
  "dependencies": {
    "framer-motion": "^2.9.4"
  }
}

My docs app only imports the Loader component (that uses no libraries).
and the web app only imports the Button component (that uses both styled and framer)

Is it correct to expect the docs app not to include these libraries in it's bundle? Should I define the dependencies in a different way? (Let's assume framer motion will only be used inside the ui library, so I wouldn't want it as a peer dependency)

When I build the apps, their bundle is exactly the same size (IE, their both getting both 3rd party libraries in the bundle?)

Build output:

docs:build: Page                                       Size     First Load JS
docs:build: ┌ ○ /                                      44.3 kB         115 kB
docs:build: └ ○ /404                                   192 B          71.3 kB
docs:build: + First Load JS shared by all              71.2 kB
docs:build:   ├ chunks/framework-18dbf282fc9f86dd.js   42 kB
docs:build:   ├ chunks/main-7adb95b49d154e8e.js        26.9 kB
docs:build:   ├ chunks/pages/_app-5e74c22d5551a606.js  1.37 kB
docs:build:   └ chunks/webpack-49b6f2937c9ce9f4.js     838 B
docs:build:
docs:build: ○  (Static)  automatically rendered as static HTML (uses no initial props)
docs:build:
web:build: Page                                       Size     First Load JS
web:build: ┌ ○ /                                      44.3 kB         115 kB
web:build: └ ○ /404                                   192 B          71.3 kB
web:build: + First Load JS shared by all              71.2 kB
web:build:   ├ chunks/framework-18dbf282fc9f86dd.js   42 kB
web:build:   ├ chunks/main-7adb95b49d154e8e.js        26.9 kB
web:build:   ├ chunks/pages/_app-5e74c22d5551a606.js  1.37 kB
web:build:   └ chunks/webpack-49b6f2937c9ce9f4.js     838 B

PS - I do see that tree shaking works for the components (IE - The Loader component doesn't appear in the web app's bundle, and the Button component doesn't appear in the docs app bundle). But the lib's don't seem to be tree shaking.

Thanks!

Upvotes: 2

Views: 798

Answers (1)

Silencer
Silencer

Reputation: 1618

This is because you have to specifically import components like this:

import { Button } from "ui/Button";
import { Loader } from "ui/Loader";

Something similar is also in their examples on importing from a ui package, you can read more about this here: https://github.com/vercel/turbo/issues/6019 and some other info scattered around the web, this honestly sounds awful and it leads to awful performance...

Upvotes: 0

Related Questions