Skipping larger chunks while running "Npm run build"
Asked Answered
L

6

26

Facing this problem while trying to run "npm run build"

(!) Some chunks are larger than 500 KiB after minification. Consider:
- Using dynamic import() to code-split the application
- Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/guide/en/#outputmanualchunks
- Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
Leavenworth answered 20/9, 2021 at 20:55 Comment(1)
So did you try any of those three things? Without a minimal reproducible example there's not much else to say.Reactant
G
60

If you don't want to increase the chunkSizeWarningLimit and focus more on solving the actual size issue, Try this solution:

export default defineConfig({
....
build: {
        rollupOptions: {
            output:{
                manualChunks(id) {
                    if (id.includes('node_modules')) {
                        return id.toString().split('node_modules/')[1].split('/')[0].toString();
                    }
                }
            }
        }
    }
});
Goer answered 10/10, 2022 at 18:15 Comment(2)
Can you please elaborate on what this does?Alenealenson
node_modules is mostly the main reason for the large chunk problem, With this you're telling Vite to treat the used modules separately. To understand better what it does, try to compare the logs from the build command with and without this change.Goer
L
14

EDIT: This is a work around and only hides warnings

Add command in vite.config.js

build: {
    chunkSizeWarningLimit: 1600,
  },

full code

// https://vitejs.dev/config/
export default defineConfig({
  base: "/Stakepool-Frontend/",
  plugins: [vue()],
  resolve: {
    alias: {
      "~": path.resolve(__dirname, "node_modules"),
      "@": path.resolve(__dirname, "src"),
    },
  },
  build: {
    chunkSizeWarningLimit: 1600,
  },
});
Leavenworth answered 20/9, 2021 at 23:54 Comment(4)
so this only increases the size limit and does not actually address the size issue?Cymbal
I don't think this should be the accepted answer as it only increases the size limit warning.Ineducable
This is a work around you are not actually solve the issueInhabitancy
@Ineducable which answer works best for you. MohKoma's answer?Leavenworth
E
7

While these solutions may seem valid I am not really satisfied with the details provided:

The answer given by Haseeb essentially hides the warning and may lead to more confusion.

MohKomas answer is on the right track but doesn't explain the whys.

I was facing the same issue while working on a Svelte project which relies heavily on the Apache ECharts library (which is quite big when importing it as a whole package). The key was to just import the parts needed and make use of the tree-shakeable interface of the library. Doing this shaved off over 500KiB from the built application.

Epaulet answered 18/10, 2022 at 9:6 Comment(0)
L
3

This is solution for Nuxt3

file: nuxt.confin.ts

export default {
  ...
  vite: {
    build: {
      rollupOptions: {
        output: {
          manualChunks(id: any) {
            if (id.includes("node_modules")) {
              return id.toString().split("node_modules/")[1].split("/")[0].toString();
            }
          },
        },
      },
    },
  },
}

it`s work nice

Losse answered 9/10, 2023 at 2:17 Comment(0)
I
2

The problem isn't Vite; it's a package on your application that is likely causing the issue.

I was running a Remix application and found it strange that one of my JS files was 914KB in size!

I pinpointed my problem by running vite-bundle-visualizer. It showed me that highlight.js, a package I'm using to highlight code, was bundling itself, contributing to the gigantic file size.

enter image description here

The highlight is the highlight.js package contributing to the overall bundle size

To do the same, navigate to your project's root directory (where the vite.config.ts file is):

Run:

 npx vite-bundle-visualizer

And see which packages Vite includes.

In my case, a direct import of the core library of highlight.js fixed my issue:

import hljs from "highlight.js/lib/core";

Afterwards: enter image description here

Note:

Not all packages you can import {} via destruct, like date-fns (V1 or V2), support tree shaking (You need to use the /ESM suffix for that). So check that you are correctly importing them. If not, try to create a combination of:

  1. Lazy loading
  2. Suspense
  3. Intersection Observer
  4. Dynamic Imports
  5. Move tricky packages to a single file and destruct its import.

I know this is a Vue.js answer, but I wanted to share my React code so anyone can adapt it:

Example: (Actual production code) Generic component that pulls from:

  1. Local SVG files
  2. Local png files
  3. react-icons different libraries.

This is a generic component in which I centralize all of my icons in a single place and then call them via a map key.

Problem: It imported all the destructed icons even though I only requested one.

Solution 1: I wrapped everything with a Suspense and a lazy import.

This allowed each icon to be solicited only when needed.

Problem 2: The problem is that dynamic imports won't destruct the code correctly.

Solution 2: We create another file that exports the destructed icon and import the file.

I also sprinkle some IntersectionObserver even further to delay the import.

Bringing everything together (simplified):

const iconMap = {
  copy: () =>
    import("./icon-exports/AiOutlineCopy").then((module) => ({
      default: module.AiOutlineCopy,
    })),
// Other icons omitted
  awsLambda: () =>
    import("./icon-exports/AwsLambda").then((module) => ({
      default: module.AwsLambda,
    })),
};

export type ColorVariant = "white" | "dark" | "red";
export const colorMap: Record<ColorVariant, string> = {
  white: "#fff",
  dark: "#1e2329",
  red: "#e33122",
};

export type IconType = keyof typeof iconMap;

export type IconProps = {
  icon: IconType;
  color?: ColorVariant;
  stroke?: ColorVariant;
  fill?: ColorVariant;
  size?: number;
  width?: string;
  height?: string;
  customColor?: string;
  className?: string;
};

export const Icon: React.FC<IconProps> = (props) => {
  const { icon, color, stroke, customColor, size = 24, ...otherProps } = props;
  const [loaded, setLoaded] = useState(false);
  const { isIntersecting, setRef } = useIntersectionObserver({
    root: null,
    rootMargin: "0px",
    threshold: 0.1,
  });

  useEffect(() => {
    if (isIntersecting) {
      setLoaded(true);
    }
  }, [isIntersecting]);

  const Element = loaded ? lazy(iconMap[icon]) : null;
  const width = `${size}px`;
  const height = `${size}px`;

  const colors = {
    stroke: stroke ? colorMap[stroke] : undefined,
    color: customColor ? customColor : color ? colorMap[color] : undefined,
  };

  return (
    <div ref={setRef} style={{ width, height }}>
      {loaded && Element ? (
        <Suspense fallback={<div style={{ width, height }} />}>
          <Element size={size} {...otherProps} {...colors} />
        </Suspense>
      ) : (
        <div style={{ width, height }} />
      )}
    </div>
  );
};

Intersection Observer Hook:

import { useEffect, useState } from "react";

export const useIntersectionObserver = (options: IntersectionObserverInit) => {
  const [isIntersecting, setIsIntersecting] = useState(false);
  const [ref, setRef] = useState<HTMLElement | null>(null);

  useEffect(() => {
    if (!ref) return;

    const observer = new IntersectionObserver(([entry]) => {
      if (entry.isIntersecting) {
        setIsIntersecting(true);
        observer.disconnect();
      }
    }, options);

    observer.observe(ref);

    return () => observer.disconnect();
  }, [ref, options]);

  return { isIntersecting, setRef };
};

Then, in ./icon-exports/AwsLambda.tsx, you'd have:

export { AwsLambda } from "../../../../assets/generated/icons";

Creating this indirection will allow Vite to import only the AwsLambda into its own JS file and render it only when needed.

Investment answered 17/6 at 11:40 Comment(0)
C
-7

The following worked for me on Vite:

import { defineConfig } from "vite"
‌ 
export default defineConfig({
    build: {
        chunkSizeWarningLimit: 100000000
    },
})
Calliope answered 20/2, 2023 at 4:47 Comment(2)
The warning is there for a reason. Setting it to some ridiculous high value defeats the purpose of it.Lifton
If you don't care about the warning, you can use this solution, but not recommended. Better to just have the warning if you're not going to address it.Pell

© 2022 - 2024 — McMap. All rights reserved.