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

Reportes sizes don't match reality #96

Closed
PierBover opened this issue Apr 7, 2021 · 11 comments
Closed

Reportes sizes don't match reality #96

PierBover opened this issue Apr 7, 2021 · 11 comments

Comments

@PierBover
Copy link

The reported bundle size is double the size of the actual bundle:

image

image

The file deployed to Netlify with brotli compression weights 7.3kB and not 17.59kB:

image

Here's the stats.html file:

https://gist.github.com/PierBover/05bfd099b7d150e5fadf42e195b8ba34

@btd
Copy link
Owner

btd commented Apr 10, 2021

Hi, thanks for the question. I got such usually at least once a year.

Short answer: yes it is different, stats file will always show bigger numbers by design and rollup functionality provided.

Longer answer

I think first i need to explain treemap/sunburst diagram works.

For each bundle rollup provided set of dependencies that included in bundle. Each of them contains some properties (useful for my purpose only module id and renderendLength). The first problem is exactly in property renderedLength. It is string.length of code after treeshaking. It means that if you file contains only ascii characters it will be accurate byte representation, otherwise not. This is a first place where results shows bigger numbers for individual files. At rollup 2.44 were added functionality to get treeshaked code (i sent this PR) and sooner or later i will fix this to use byte size.

Returning to treemap. After all individual files gathered it starts to compute numbers for top directories until root. Meaning that bundle size shown is a sum of every single file size. This is a second biggest difference from actual size. It is not possible with rollup only to get individual file sizes after whole bundle transformation (read it after for example minification with terser). For this at the beginning we added sourcemap option, which get sizes from sourcemap. But it is still number of characters, but at least after all transformations.

Plugin order is matter also. For sourcemap option it is important to include plugin to be last in plugins array. Without sourcemap it is not that critical, but still you can miss some individual transformations.

The last i think need to add about gzip and brotli size, before rollup 2.44 these numbers where based on real files in your FS, i just read them put through gzip/brotli and show byte size. Now it is using treeshaked code for size estimation.

And at the end of all this mess. It is still OK. You need to understand whole purpose of this plugin. This plugin allows you to visually see biggest/repeated parts of your bundle for further optimizations. This plugin is not representation of your filesystem.

Let me know if you have more questions.

@btd btd closed this as completed Apr 10, 2021
@btd btd pinned this issue Apr 10, 2021
@marcofugaro
Copy link

@btd what about adding an option to hide file sizes?

If as you say

This plugin allows you to visually see biggest/repeated parts of your bundle for further optimizations. This plugin is not representation of your filesystem.

Then I'd like an option to hide file sizes as they are confusing if they don't match.

^ The tooltip would show only the percentage ideally.

@btd
Copy link
Owner

btd commented Apr 14, 2021

That makes sense, i will think about it

@btd
Copy link
Owner

btd commented Apr 15, 2021

I will close this one in favor of #98

@smalllong
Copy link

Still. it is very unintuitive that comments are contributing to the size in visualizer, although they won't contribute to the final minified file, which is misleading. Hope the visualizer can visualize based on output file rather than source file

kodiakhq bot pushed a commit to recipeyak/recipeyak that referenced this issue Aug 1, 2022
Basically:
- Replace web pack setup with vite and upgrade various dependencies and cull unnecessary ones.
- Also remove TSLint. Will replace with typescript-eslint rules eventually.
- Got rid of the hacky landing page static generation.

Various road bumps along the way:

- https://javascript.plainenglish.io/how-to-set-up-path-resolving-in-vite-ad284e0d9eae
- fix sass imports vitejs/vite#5764 (comment)
- Then needed to rewrite the alias for typescript again to match the types
- Replace `process`. With the `import.meta.env` thing
- https://stackoverflow.com/questions/64677212/how-to-configure-proxy-in-vite
- Fix imports for static files from `requires()`
- Had to fix proxying for `/avatar` and `/api` in dev
- Ran into remarkjs/react-markdown#339 (comment)
    - Upgrade markdown react to fix
- Migrate from `react-helmet` to fix some deprecation warnings
- Vite has a different jsx config, so no need to import React
    - microsoft/TypeScript#41882
- Vitest issue:
    - https://github.com/vitest-dev/vitest/blob/57c2367196b3fd978a04fa38ebdac7a5b6ef9b16/packages/vite-node/src/client.ts#L178-L179
- Couldn’t import react-dnd, upgraded
    - react-dnd/react-dnd#3368
- `import { isUndefined } from "util"` didn’t work
- Favicon via https://github.com/darkobits/vite-plugin-favicons to replace web pack equivalent 
- Issue with React router browser history in vitest, it exploded until jsdom was setup
- Question: https://stackoverflow.com/questions/71703933/what-is-the-difference-between-vite-and-vite-preview
- Vitest vscode integration broken :/
    - vitest-dev/vscode#44
- Tried happy-dom but it doesn’t work, lots of issues, supposed to be faster
- Took a while to get MSW in a good place, had to write some stuff so missing endpoint mocks fail the test
    - I think there's room for improvement here in terms of developer experience
    - Test with react testing library and API calls
        - https://www.npmjs.com/package/nock
            - Doesn’t fail test on unknown mock
            - https://stackoverflow.com/questions/69430232/jest-nock-how-to-fail-a-test-if-a-non-mocked-request-is-made
        - MSW
            - Doesn’t fail test on unknown mock
            - mswjs/msw#946
        - Relay’s mockEnvironment
          - couldn't easily find thorough examples
        - Apollo mock provider
            - Doesn’t fail test on unknown mock
- Added a visualize plugin similar to a web pack analyzer thing, but it’s slightly off with the numbers it gives for sizes:
    - btd/rollup-plugin-visualizer#96
- TODO:
    - ESLINT rules, replace what tslint provided, eslint-cake anyone?
        - https://typescript-eslint.io/rules/no-floating-promises/
        - And more!!!
    - Replace lodash with lodash-es
        - Or maybe: https://github.com/onebay/vite-plugin-imp
        - Although lodash-es seems cleaner
    - SSR  for landing page?
@btd
Copy link
Owner

btd commented Sep 26, 2022

@smalllong you can try to use sourcemap option, it will use generated from code sourcemap. But still it is not 100% accurate (but close).

@dzegarra
Copy link

dzegarra commented Apr 27, 2023

In my case, not even using sourcemap I get a close approximation of the sizes.
Actual file size: 93Kb
Reported by visualizer: 194Kb

I'm working on a simple proof-of-concept with Vite, preact (no TS), preact/hooks, and @mui/material.

But the visualizer gives me an idea of the proportion each lib takes. The percentages are very useful. Thanks @btd .

image

@btd
Copy link
Owner

btd commented Apr 27, 2023

@dzegarra can you share repro example? I am curious how such big difference could appear even with source map enabled

@SCWR
Copy link

SCWR commented Aug 17, 2023

@btd Hello Thank you for your efforts. I have encountered an issue. I am using the latest version, and it seems that the report is displaying an incorrect file size without tree shaking. Could you please let me know if this is a problem with my settings or something else?

npm create vite
# react + ts
cd test
npm i
// APP.ts
import { useState, useEffect } from 'react';
import reactLogo from './assets/react.svg';
import viteLogo from '/vite.svg';
// import * as _ from 'lodash-es';
// import _ from 'lodash-es';
import {
  isEmpty,
  isEqual,
  debounce,
  sortBy,
  defaultsDeep,
  chunk,
  size,
  throttle,
  get,
  differenceWith,
  unionWith,
  isNil,
  keyBy,
  flatMap,
  isNumber,
  cloneDeep,
  last,
  isString,
  maxBy,
  set,
  random,
} from 'lodash-es';
import './App.css';

function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    // _.isEmpty([]);
    // _.isEqual(1, 2);
    isEmpty([]);
    isEqual(1, 2);
    debounce(() => {}, 250, { maxWait: 1000 });
    throttle(() => {}, 250, { trailing: false });
    const users = [
      { user: 'fred', age: 48 },
      { user: 'barney', age: 36 },
      { user: 'fred', age: 40 },
      { user: 'barney', age: 34 },
    ];

    sortBy(users, [
      function (o) {
        return o.user;
      },
    ]);
    defaultsDeep({ a: { b: 2 } }, { a: { b: 1, c: 3 } });
    chunk(['a', 'b', 'c', 'd'], 2);
    size({ a: 1, b: 2 });
    const object = { a: [{ b: { c: 3 } }] };
    get(object, 'a[0].b.c');
    set(object, 'a[0].b.c', 4);
    differenceWith(
      [
        { x: 1, y: 2 },
        { x: 2, y: 1 },
      ],
      [{ x: 1, y: 2 }],
      isEqual
    );
    unionWith(
      [
        { x: 1, y: 2 },
        { x: 2, y: 1 },
      ],
      [{ x: 1, y: 2 }],
      isEqual
    );
  }, []);
  isNil('');
  keyBy(
    [
      { dir: 'left', code: 97 },
      { dir: 'right', code: 100 },
    ],
    'dir'
  );
  flatMap([1, 2], n => [n, n]);
  isNumber(1);
  cloneDeep({});
  last([1, 2, 3]), isString(1);
  maxBy([{ n: 1 }, { n: 2 }], 'n');
  random(false);
  return (
    <>
      <div>
        <a href="https://vitejs.dev" target="_blank">
          <img src={viteLogo} className="logo" alt="Vite logo" />
        </a>
        <a href="https://react.dev" target="_blank">
          <img src={reactLogo} className="logo react" alt="React logo" />
        </a>
      </div>
      <h1>Vite + React</h1>
      <div className="card">
        <button onClick={() => setCount(count => count + 1)}>count is {count}</button>
        <p>
          Edit <code>src/App.tsx</code> and save to test HMR
        </p>
      </div>
      <p className="read-the-docs">Click on the Vite and React logos to learn more</p>
    </>
  );
}

export default App;
//vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { visualizer } from 'rollup-plugin-visualizer';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  build: {
    sourcemap: true,
    rollupOptions: {
      plugins: [
        visualizer({
          open: true,
          template: 'treemap',
          gzipSize: true,
          brotliSize: true,
          // sourcemap: true,
        }),
      ],
      output: {
        manualChunks: {
          'react-vendor': ['react', 'react-dom'],
          lodash: ['lodash-es'],
        },
      },
    },
  },
});

image
image

@btd
Copy link
Owner

btd commented Nov 30, 2023

@SCWR thanks for example and sorry for long response, i accidentally disabled emails in notifications. I will try to take a look.
Just to be clear this issue possible only about sourcemap option. When it is not enabled plugin report only what rollup report to plugin.

@btd btd reopened this Nov 30, 2023
@btd
Copy link
Owner

btd commented Dec 9, 2023

Add fix for sourcemap to 5.11.0

@btd btd closed this as completed Dec 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants