components icon indicating copy to clipboard operation
components copied to clipboard

Significant Slowdown in M3 Runtime Compilation

Open flipcasa opened this issue 2 months ago • 7 comments

Is this a regression?

  • [ ] Yes, this behavior used to work in the previous version

The previous version in which this bug was not present was

No response

Description

Building our NX monorepo, particularly when utilizing M3 material components at runtime, is experiencing noticeable delays. This slowdown in compilation time is impacting our development efficiency.

Without M3, the compilation process takes approximately 2 seconds. However, with M3 integrated, the compilation time extends to 40 seconds or more.

Reproduction

StackBlitz link: Steps to reproduce: 1. 2.

Expected Behavior

.

Actual Behavior

.

Environment

  • Angular: v18.0.0-rc.0
  • CDK/Material: v18.0.0-rc.0
  • Browser(s): chrome
  • Operating System (e.g. Windows, macOS, Ubuntu): mac

flipcasa avatar Apr 26 '24 16:04 flipcasa

I believe that Nx uses some sort of build caching. Do you see these slowdowns consistently or only on the initial build? Also what changes did you make to enable M3? We export all the APIs through the same _index.scss so I would expect the build graph to look identical no matter what version of Material you're using.

crisbeto avatar May 06 '24 18:05 crisbeto

@crisbeto slowdown is consistent

@use '@angular/material' as mat;
@use 'sass:map';

mat.$theme-legacy-inspection-api-compatibility: false;

// Create a theme with the specified color type and density.
@function create-theme($type: light, $density: 0, $primary: mat.$blue-palette, $tertiary: mat.$violet-palette) {
  @return mat.define-theme(
    (
      color: (
        theme-type: $type,
        primary: $primary,
        tertiary: $tertiary
      ),
      density: (
        scale: $density
      ),
      typography: (
        brand-family: 'Be Vietnam Pro',
        plain-family: 'sans-serif',
        // regular-weight: 400,
        // medium-weight: 500,
        // bold-weight: 700
      )
    )
  );
}

// Define the default (light) theme.
$light-theme: create-theme(
  $type: light
);

// Create our dark theme.
$dark-theme: create-theme(
  $type: dark
);

// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat.core();

// Include the default theme styles.
html {
  @include mat.all-component-themes($light-theme);
}
@include mat.typography-hierarchy($light-theme);

.dark-theme {
  // Include the dark theme color styles.
  @include mat.all-component-colors($dark-theme);
}

// Create classes for all density scales which are supported by all MDC-based components.
// The classes are applied conditionally based on the selected density in the dev-app layout
// component.
$density-scales: (0, -1, -2, -3, -4);
@each $scale in $density-scales {
  .density-#{$scale} {
    $density-theme: create-theme(
      $density: $scale
    );
    @include mat.all-component-densities($density-theme);
  }
}

.default {
  $light-theme: create-theme(
    $type: light,
    $primary: mat.$azure-palette,
    $tertiary: mat.$blue-palette
  );

  // Create our dark theme.
  $dark-theme: create-theme(
    $type: dark,
    $primary: mat.$azure-palette,
    $tertiary: mat.$blue-palette
  );

  // Theme Config
  @include mat.all-component-colors($light-theme);

  &.dark-theme {
    @include mat.all-component-colors($dark-theme);
  }

  // Enable backwards-compatibility CSS for color="..." API & typography hierarchy.
  &.back-compat {
    @include mat.color-variants-backwards-compatibility($light-theme);
    @include mat.typography-hierarchy($light-theme, $back-compat: true);

    &.dark-theme {
      @include mat.color-variants-backwards-compatibility($dark-theme);
    }
  }
}

Nx 18, 19 Angular 18 rc 0 even with experimental 17 package

before m3 and after m3 build times and runtimes doubled up

flipcasa avatar May 06 '24 23:05 flipcasa

Can you also post what your theme looked like for M2?

crisbeto avatar May 07 '24 03:05 crisbeto

I've sent out #29009 which seems to cut the compilation time at least in half for M3.

crisbeto avatar May 07 '24 10:05 crisbeto

Can you also post what your theme looked like for M2?

Im adding my entire m3 and m2 styles @crisbeto

M3

@use '@angular/material' as mat;
@use 'sass:map';

mat.$theme-legacy-inspection-api-compatibility: false;

// Create a theme with the specified color type and density.
@function create-theme($type: light, $density: 0, $primary: mat.$blue-palette, $tertiary: mat.$violet-palette) {
  @return mat.define-theme(
    (
      color: (
        theme-type: $type,
        primary: $primary,
        tertiary: $tertiary
      ),
      density: (
        scale: $density
      ),
      typography: (
        brand-family: 'Be Vietnam Pro',
        plain-family: 'sans-serif',
        // regular-weight: 400,
        // medium-weight: 500,
        // bold-weight: 700
      )
    )
  );
}

// Define the default (light) theme.
$light-theme: create-theme(
  $type: light
);

// Create our dark theme.
$dark-theme: create-theme(
  $type: dark
);

// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// **Be sure that you only ever include this mixin once!**
@include mat.core();

// Include the default theme styles.
html {
  @include mat.all-component-themes($light-theme);
}
@include mat.typography-hierarchy($light-theme);

.dark-theme {
  // Include the dark theme color styles.
  @include mat.all-component-colors($dark-theme);
}

// Create classes for all density scales which are supported by all MDC-based components.
// The classes are applied conditionally based on the selected density in the dev-app layout
// component.
$density-scales: (0, -1, -2, -3, -4);
@each $scale in $density-scales {
  .density-#{$scale} {
    $density-theme: create-theme(
      $density: $scale
    );
    @include mat.all-component-densities($density-theme);
  }
}

.theme-default {
  $light-theme: create-theme(
    $type: light,
    $primary: mat.$azure-palette,
    $tertiary: mat.$blue-palette
  );

  // Create our dark theme.
  $dark-theme: create-theme(
    $type: dark,
    $primary: mat.$azure-palette,
    $tertiary: mat.$blue-palette
  );

  // Theme Config
  @include mat.all-component-colors($light-theme);

  &.dark-theme {
    @include mat.all-component-colors($dark-theme);
  }

  // Enable backwards-compatibility CSS for color="..." API & typography hierarchy.
  &.back-compat {
    @include mat.color-variants-backwards-compatibility($light-theme);
    @include mat.typography-hierarchy($light-theme, $back-compat: true);

    &.dark-theme {
      @include mat.color-variants-backwards-compatibility($dark-theme);
    }
  }
}

.theme-rose {
  // Define the default (light) theme.
  $light-theme: create-theme(
    $type: light,
    $primary: mat.$rose-palette,
    $tertiary: mat.$red-palette
  );

  // Create our dark theme.
  $dark-theme: create-theme(
    $type: dark,
    $primary: mat.$rose-palette,
    $tertiary: mat.$red-palette
  );

  // Theme Config
  @include mat.all-component-colors($light-theme);

  &.dark-theme {
    @include mat.all-component-colors($dark-theme);
  }

  // Enable backwards-compatibility CSS for color="..." API & typography hierarchy.
  &.back-compat {
    @include mat.color-variants-backwards-compatibility($light-theme);
    @include mat.typography-hierarchy($light-theme, $back-compat: true);

    &.dark-theme {
      @include mat.color-variants-backwards-compatibility($dark-theme);
    }
  }
}

.theme-cyan {
  // Define the default (light) theme.
  $light-theme: create-theme(
    $type: light,
    $primary: mat.$cyan-palette,
    $tertiary: mat.$orange-palette
  );

  // Create our dark theme.
  $dark-theme: create-theme(
    $type: dark,
    $primary: mat.$cyan-palette,
    $tertiary: mat.$orange-palette
  );

  // Theme Config
  @include mat.all-component-colors($light-theme);

  &.dark-theme {
    @include mat.all-component-colors($dark-theme);
  }

  // Enable backwards-compatibility CSS for color="..." API & typography hierarchy.
  &.back-compat {
    @include mat.color-variants-backwards-compatibility($light-theme);
    @include mat.typography-hierarchy($light-theme, $back-compat: true);

    &.dark-theme {
      @include mat.color-variants-backwards-compatibility($dark-theme);
    }
  }
}

.theme-magenta {
  // Define the default (light) theme.
  $light-theme: create-theme(
    $type: light,
    $primary: mat.$magenta-palette,
    $tertiary: mat.$violet-palette
  );

  // Create our dark theme.
  $dark-theme: create-theme(
    $type: dark,
    $primary: mat.$magenta-palette,
    $tertiary: mat.$violet-palette
  );

  // Theme Config
  @include mat.all-component-colors($light-theme);

  &.dark-theme {
    @include mat.all-component-colors($dark-theme);
  }

  // Enable backwards-compatibility CSS for color="..." API & typography hierarchy.
  &.back-compat {
    @include mat.color-variants-backwards-compatibility($light-theme);
    @include mat.typography-hierarchy($light-theme, $back-compat: true);

    &.dark-theme {
      @include mat.color-variants-backwards-compatibility($dark-theme);
    }
  }
}

M2

@use '@angular/material' as mat;

mat.$theme-ignore-duplication-warnings: true;

// Light Theme Text
$dark-text: #000000;
$dark-primary-text: rgba($dark-text, 0.87);
$dark-accent-text: rgba($dark-primary-text, 0.54);

// Dark Theme text
$light-text: #ffffff;
$light-primary-text: $light-text;
$light-accent-text: rgba($light-primary-text, 0.7);

@include mat.core();

.theme-core {
  // Compute font config
  // @include mat.core($fontConfig);
  $mat-primary: (
    main: #115df6,
    lighter: #f0f5fe,
    darker: #0a41f2,
    200: #115df6,
    // For slide toggle,
    contrast:
      (
        main: $light-primary-text,
        lighter: $dark-primary-text,
        darker: $light-primary-text
      )
  );
  $theme-primary: mat.define-palette($mat-primary, main, lighter, darker);
  $mat-accent: (
    main: #042a76,
    lighter: #dbe7fe,
    darker: #021959,
    200: #042a76,
    // For slide toggle,
    contrast:
      (
        main: $light-primary-text,
        lighter: $dark-primary-text,
        darker: $light-primary-text
      )
  );
  $theme-accent: mat.define-palette($mat-accent, main, lighter, darker);
  $mat-warn: (
    main: #d17823,
    lighter: #f8dbd8,
    darker: #c05b15,
    200: #d17823,
    // For slide toggle,
    contrast:
      (
        main: $dark-primary-text,
        lighter: $dark-primary-text,
        darker: $light-primary-text
      )
  );
  $theme-warn: mat.define-palette($mat-warn, main, lighter, darker);

  --primary-color: #115df6;
  --primary-lighter-color: #f0f5fe;
  --primary-darker-color: #0a41f2;
  --text-primary-color: #{$light-primary-text};
  --text-primary-lighter-color: #{$dark-primary-text};
  --text-primary-darker-color: #{$light-primary-text};

  --accent-color: #042a76;
  --accent-lighter-color: #dbe7fe;
  --accent-darker-color: #021959;
  // --text-accent-color: #{$light-accent-text};
  // --text-accent-lighter-color: #{$dark-accent-text};
  // --text-accent-darker-color: #{$light-accent-text};

  --warn-color: #d17823;
  --warn-lighter-color: #f8dbd8;
  --warn-darker-color: #c05b15;
  --text-warn-color: #{$dark-primary-text};
  --text-warn-lighter-color: #{$dark-primary-text};
  --text-warn-darker-color: #{$light-primary-text};

  // Theme Config
  $typography: mat.define-typography-config(
    $font-family: 'Be Vietnam Pro',
    $headline-1: mat.define-typography-level(112px, 112px, 300, $letter-spacing: -0.0134em),
    $headline-2: mat.define-typography-level(56px, 56px, 400, $letter-spacing: -0.0089em),
    $headline-3: mat.define-typography-level(45px, 48px, 400, $letter-spacing: 0em),
    $headline-4: mat.define-typography-level(34px, 40px, 400, $letter-spacing: 0.0074em),
    $headline-5: mat.define-typography-level(24px, 32px, 400, $letter-spacing: 0em),
    $headline-6: mat.define-typography-level(20px, 32px, 500, $letter-spacing: 0.0075em),
    $subtitle-1: mat.define-typography-level(16px, 28px, 400, $letter-spacing: 0.0094em),
    $subtitle-2: mat.define-typography-level(15px, 24px, 500, $letter-spacing: 0.0067em),
    $body-2: mat.define-typography-level(14px, 24px, 500, $letter-spacing: 0.0179em),
    $body-1: mat.define-typography-level(14px, 20px, 400, $letter-spacing: 0.0179em),
    $button: mat.define-typography-level(14px, 14px, 500, $letter-spacing: 0.0893em),
    $caption: mat.define-typography-level(12px, 20px, 400, $letter-spacing: 0.0333em)
  );

  $theme: mat.define-light-theme(
    (
      color: (
        primary: $theme-primary,
        accent: $theme-accent,
        warn: $theme-warn
      ),
      typography: $typography,
      density: 0
    )
  );
  $altTheme: mat.define-dark-theme(
    (
      color: (
        primary: $theme-primary,
        accent: $theme-accent,
        warn: $theme-warn
      ),
      typography: $typography,
      density: 0
    )
  );

  @include mat.all-component-themes($theme);

  &.dark-theme {
    @include mat.all-component-colors($altTheme);
  }
}

.theme-dev {
  // Compute font config
  // @include mat.core($fontConfig);
  $mat-primary: (
    main: #b71c1c,
    lighter: #e9bbbb,
    darker: #9f1111,
    200: #b71c1c,
    // For slide toggle,
    contrast:
      (
        main: $light-primary-text,
        lighter: $dark-primary-text,
        darker: $light-primary-text
      )
  );
  $theme-primary: mat.define-palette($mat-primary, main, lighter, darker);
  $mat-accent: (
    main: #797979,
    lighter: #d7d7d7,
    darker: #5c5c5c,
    200: #797979,
    // For slide toggle,
    contrast:
      (
        main: $light-primary-text,
        lighter: $dark-primary-text,
        darker: $light-primary-text
      )
  );
  $theme-accent: mat.define-palette($mat-accent, main, lighter, darker);
  $mat-warn: (
    main: #ff0000,
    lighter: #ffb3b3,
    darker: #ff0000,
    200: #ff0000,
    // For slide toggle,
    contrast:
      (
        main: $dark-primary-text,
        lighter: $dark-primary-text,
        darker: $light-primary-text
      )
  );
  $theme-warn: mat.define-palette($mat-warn, main, lighter, darker);

  --primary-color: #b71c1c;
  --primary-lighter-color: #e9bbbb;
  --primary-darker-color: #9f1111;
  --text-primary-color: #{$light-primary-text};
  --text-primary-lighter-color: #{$dark-primary-text};
  --text-primary-darker-color: #{$light-primary-text};

  --accent-color: #797979;
  --accent-lighter-color: #d7d7d7;
  --accent-darker-color: #5c5c5c;
  // --text-accent-color: #{$light-accent-text};
  // --text-accent-lighter-color: #{$dark-accent-text};
  // --text-accent-darker-color: #{$light-accent-text};

  --warn-color: #ff0000;
  --warn-lighter-color: #ffb3b3;
  --warn-darker-color: #ff0000;
  --text-warn-color: #{$light-primary-text};
  --text-warn-lighter-color: #{$dark-primary-text};
  --text-warn-darker-color: #{$light-primary-text};

  // Theme Config
  $typography: mat.define-typography-config(
    $font-family: 'Be Vietnam Pro',
    $headline-1: mat.define-typography-level(112px, 112px, 300, $letter-spacing: -0.0134em),
    $headline-2: mat.define-typography-level(56px, 56px, 400, $letter-spacing: -0.0089em),
    $headline-3: mat.define-typography-level(45px, 48px, 400, $letter-spacing: 0em),
    $headline-4: mat.define-typography-level(34px, 40px, 400, $letter-spacing: 0.0074em),
    $headline-5: mat.define-typography-level(24px, 32px, 400, $letter-spacing: 0em),
    $headline-6: mat.define-typography-level(20px, 32px, 500, $letter-spacing: 0.0075em),
    $subtitle-1: mat.define-typography-level(16px, 28px, 400, $letter-spacing: 0.0094em),
    $subtitle-2: mat.define-typography-level(15px, 24px, 500, $letter-spacing: 0.0067em),
    $body-2: mat.define-typography-level(14px, 24px, 500, $letter-spacing: 0.0179em),
    $body-1: mat.define-typography-level(14px, 20px, 400, $letter-spacing: 0.0179em),
    $button: mat.define-typography-level(14px, 14px, 500, $letter-spacing: 0.0893em),
    $caption: mat.define-typography-level(12px, 20px, 400, $letter-spacing: 0.0333em)
  );

  $theme: mat.define-light-theme(
    (
      color: (
        primary: $theme-primary,
        accent: $theme-accent,
        warn: $theme-warn
      ),
      typography: $typography,
      density: 0
    )
  );
  $altTheme: mat.define-dark-theme(
    (
      color: (
        primary: $theme-primary,
        accent: $theme-accent,
        warn: $theme-warn
      ),
      typography: $typography,
      density: 0
    )
  );

  @include mat.all-component-themes($theme);

  &.dark-theme {
    @include mat.all-component-colors($altTheme);
  }
}

flipcasa avatar May 07 '24 13:05 flipcasa

@crisbeto i just tested with 18 rc1 its better now it reduced to 20s but its still a lot

with m3 its 20s with m2 its 7s

with all the esbuild and latest stack should be always faster compared to older versions seems like its other way around

everytime you compile the app it feels like running a java application it takes forever

flipcasa avatar May 09 '24 18:05 flipcasa

I agree that the timing still isn't ideal, I just wasn't able to find more ways in which to cut it down. Sass doesn't have APIs to profile the speed of the various function calls so it's lots of trial and error.

crisbeto avatar May 10 '24 02:05 crisbeto