mui-toolpad icon indicating copy to clipboard operation
mui-toolpad copied to clipboard

Decrease bundle size

Open WangLarry opened this issue 3 years ago • 8 comments

Duplicates

  • [X] I have searched the existing issues

Latest version

  • [X] I have tested the latest version

Summary 💡

I use @next/bundle-analyzer to analyze toolpad-app. It show there are two huge packages: monaco-editor and @mui/icons-material.

截屏2022-09-15 19 19 08 截屏2022-09-15 19 20 11

Examples 🌈

No response

Motivation 🔦

No response

WangLarry avatar Sep 15 '22 11:09 WangLarry

  • monaco-editor is needed for the code editors. It's big because it contains a language server. It's in its own chunk and loaded asynchronously as a worker. I don't see a problem here.
  • @mui/icons-material is also in its own chunk and lazy loaded on the deployed application but only if the user uses icons in custom scripts.

Janpot avatar Sep 15 '22 12:09 Janpot

info  - Collecting page data  
Route (pages)                                Size     First Load JS
┌ λ /                                        1.16 kB         195 kB
├   /_app                                    0 B             119 kB
├ λ /_toolpad/[[...index]]                   330 kB         1.53 MB
├ λ /404                                     199 B           120 kB
├ λ /api/data/[appId]/[version]/[queryId]    0 B             119 kB
├ λ /api/dataSources/[dataSource]/[...path]  0 B             119 kB
├ λ /api/health-check                        0 B             119 kB
├ λ /api/rpc                                 0 B             119 kB
├ λ /app-canvas/[[...path]]                  2.92 kB         1.2 MB
├ λ /app/[appId]/[version]/[[...path]]       358 B           1.2 MB
└ λ /deploy/[appId]/[[...path]]              353 B           1.2 MB
+ First Load JS shared by all                119 kB
  ├ chunks/framework-2422bd4d7ba12811.js     45.9 kB
  ├ chunks/main-5b7e023216b20801.js          35 kB
  ├ chunks/pages/_app-5b8c0ac2d0c62fea.js    32 kB
  └ chunks/webpack-f2ca0da3ac4cec04.js       6.56 kB

ƒ Middleware                                 20.5 kB

WangLarry avatar Sep 15 '22 12:09 WangLarry

http://localhost:3000/deploy/cl7q3tf6a0005px8cz8jbuij0/pages 截屏2022-09-15 23 04 39

截屏2022-09-15 23 02 21

WangLarry avatar Sep 15 '22 15:09 WangLarry

@WangLarry Are there any specific problems you'd like to point out?

Janpot avatar Sep 15 '22 18:09 Janpot

235 request, too many. Can optimize load @mui/material/* module, using the method of dealing @mui/icons-material

I have tested,it will decrease request times to 95

Are you understand? Sorry my bad english

WangLarry avatar Sep 15 '22 18:09 WangLarry

Can optimize load @mui/material/* module, using the method of dealing @mui/icons-material

I'm not sure that would work well with imports like:

import Button, { buttonClasses } from "@mui/material/Button";

Janpot avatar Sep 15 '22 19:09 Janpot

@Janpot


const muiMaterialExports = new Map<string, ExportMapValue>([
  ['@mui/material', import('@mui/material')],
  // ['@mui/material/Accordion', import('@mui/material/Accordion')],
  // ['@mui/material/CssBaseline', import('@mui/material/CssBaseline')],
  // ['@mui/material/List', import('@mui/material/List')],
  // ['@mui/material/Snackbar', import('@mui/material/Snackbar')],
  // ['@mui/material/ToggleButtonGroup', import('@mui/material/ToggleButtonGroup')],
  // ['@mui/material/AccordionActions', import('@mui/material/AccordionActions')],
  // ['@mui/material/Dialog', import('@mui/material/Dialog')],
  // ['@mui/material/ListItem', import('@mui/material/ListItem')],
  // ['@mui/material/SnackbarContent', import('@mui/material/SnackbarContent')],
  // ['@mui/material/Toolbar', import('@mui/material/Toolbar')],
  // ['@mui/material/AccordionDetails', import('@mui/material/AccordionDetails')],
  // ['@mui/material/DialogActions', import('@mui/material/DialogActions')],
  // ['@mui/material/ListItemAvatar', import('@mui/material/ListItemAvatar')],
  // ['@mui/material/SpeedDial', import('@mui/material/SpeedDial')],

....

      const compMatch = /^@mui\/material\/(.*)$/.exec(moduleId);
      if (compMatch) {
        const compName = compMatch[1];
        const compModule = modules.get('@mui/material');
        const compClasses = `${uncapitalize(compName)}Classes`;
        esModule = {
          default: (compModule as any)[compName],
          [compClasses]: (compModule as any)[compClasses],
        };
      }

截屏2022-09-16 09 48 02

WangLarry avatar Sep 16 '22 01:09 WangLarry

@WangLarry The point was that it requires us to hardcode the exports of each of those modules imported, which will be a maintenance burden as we'll have to keep it up to date as @mui/material evolves. So I don't feel like we should go that way. If the problem is the bundle splitting, we could organize the imports in a way that would create a single chunk for all library code:

// ./loadModule.ts

// ...
    const muiExports = await import('./muiExports')
// ...
import muiMaterialDefault, * as muiMaterial from '@mui/material';
import muiMaterialAccordionDefault, * as muiMaterialAccordion from '@mui/material/Accordion';
// ...

function esm(defaultExport: any, namedExports: any) {
  return { ...namedExports, default: defaultExport, __esModule: true };
}

export default new Map([
  ['@mui/material', esm(muiMaterial, muiMaterialDefault)],
  ['@mui/material/Accordion', esm(muiMaterialAccordionDefault, muiMaterialAccordion)],
  // ...
]);

It's still not great as it still imports all library code, even when unused, but it will use less requests. It also hacks esm support on top of commonjs which will for sure run into edge cases at some point. In the future we could look into either a pure ESM runtime that only loads used components, or a serverside compilation step for deployed applications.

Janpot avatar Oct 04 '22 10:10 Janpot

Closing this issue as we have replaced the runtime with vite and are now compiling only the libraries that are being used. See https://github.com/mui/mui-toolpad/pull/1881

Janpot avatar Jun 12 '23 13:06 Janpot