mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 13:46:16 -08:00
perf(web): provide form-field defaults per component, not at the root (#1928)
* perf(web): provide form-field defaults per component, not at the root app.config.ts provided MAT_FORM_FIELD_DEFAULT_OPTIONS in the root injector. Importing the token kept @angular/material/form-field in main.js, and Material 22.2's form field imports @angular/forms/signals, which would add @angular/forms to startup as well (the reason the Angular 22.2 dependency update exceeds the initial-bytes ratchet). Every form field renders in a lazy chunk, so the outline + dynamic defaults now come from provideFormFieldDefaults() (@iptvnator/ui/components/form-field-defaults) on each component that renders <mat-form-field>. tools/nx/check-form-field-defaults.mjs (ui:form-field-defaults:validate, run in CI) reports a component that renders a form field without the provider, and any use of the token outside the shared provider. The Xtream import form test asserts outlined, dynamically sized fields with no root provider; without the component provider they render as fill. renderer.initialBytes: 1,596,201 -> 1,534,604 bytes (-61,597) on a local production build; the baseline is lowered to the measured value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * perf(web): cite #1928 as the initial-bytes baseline evidence Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(ui): check form-field providers per component on the TypeScript AST The guard matched templates and providers with regular expressions over the whole file: a quoted inline template went unread, one component's provider covered another in the same file, an earlier array-valued provider hid the call, and provideFormFieldDefaults() in app.config or a route passed although it loads Material's form field on startup again. It now reads each @Component decorator's own template and providers array, and reports any provideFormFieldDefaults() call outside one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: 4gray <fourgray@proton.me> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
28 files changed
+500
-11
No files matched your search
@@ -9,7 +9,6 @@ import {
|
||||
OverlayContainer,
|
||||
} from '@angular/cdk/overlay';
|
||||
import { ApplicationConfig, inject, importProvidersFrom } from '@angular/core';
|
||||
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
||||
import { provideAnimations } from '@angular/platform-browser/animations';
|
||||
import { provideRouter, withComponentInputBinding } from '@angular/router';
|
||||
import { provideServiceWorker } from '@angular/service-worker';
|
||||
@@ -162,9 +161,5 @@ export const appConfig: ApplicationConfig = {
|
||||
...provideParentalLockPrompt(),
|
||||
provideParentalLockPlaylistCleanup(),
|
||||
...provideXtreamDataSource(),
|
||||
{
|
||||
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
||||
useValue: { appearance: 'outline', subscriptSizing: 'dynamic' },
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
} from '@iptvnator/shared/interfaces';
|
||||
import { UpdateChannelOption } from './settings.models';
|
||||
import { markSectionForCheckOnFormEvents } from './settings-section-form-render';
|
||||
import { provideFormFieldDefaults } from '@iptvnator/ui/components/form-field-defaults';
|
||||
|
||||
interface SettingsUpdateStatusChip {
|
||||
readonly labelKey: string;
|
||||
@@ -28,6 +29,7 @@ interface SettingsUpdateStatusChip {
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings-about-section',
|
||||
providers: [provideFormFieldDefaults()],
|
||||
imports: [
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
|
||||
@@ -23,9 +23,11 @@ import { EpgSourceStatusComponent } from '@iptvnator/ui/epg';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { EpgViewModeOption } from './settings.models';
|
||||
import { markSectionForCheckOnFormEvents } from './settings-section-form-render';
|
||||
import { provideFormFieldDefaults } from '@iptvnator/ui/components/form-field-defaults';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings-epg-section',
|
||||
providers: [provideFormFieldDefaults()],
|
||||
imports: [
|
||||
EpgSourceStatusComponent,
|
||||
MatButtonModule,
|
||||
|
||||
@@ -20,9 +20,11 @@ import {
|
||||
ThemeOption,
|
||||
} from './settings.models';
|
||||
import { markSectionForCheckOnFormEvents } from './settings-section-form-render';
|
||||
import { provideFormFieldDefaults } from '@iptvnator/ui/components/form-field-defaults';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings-general-section',
|
||||
providers: [provideFormFieldDefaults()],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatFormFieldModule,
|
||||
|
||||
@@ -9,9 +9,11 @@ import {
|
||||
} from '@angular/material/slide-toggle';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ParentalLockRelockMinutes } from '@iptvnator/shared/interfaces';
|
||||
import { provideFormFieldDefaults } from '@iptvnator/ui/components/form-field-defaults';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings-parental-lock-section',
|
||||
providers: [provideFormFieldDefaults()],
|
||||
imports: [
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
|
||||
@@ -22,9 +22,11 @@ import {
|
||||
} from '@iptvnator/shared/interfaces';
|
||||
import { SettingsPlayerOption } from './settings.models';
|
||||
import { markSectionForCheckOnFormEvents } from './settings-section-form-render';
|
||||
import { provideFormFieldDefaults } from '@iptvnator/ui/components/form-field-defaults';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings-playback-section',
|
||||
providers: [provideFormFieldDefaults()],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatButtonModule,
|
||||
|
||||
@@ -15,9 +15,11 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { QRCodeComponent } from 'angularx-qrcode';
|
||||
import { markSectionForCheckOnFormEvents } from './settings-section-form-render';
|
||||
import { provideFormFieldDefaults } from '@iptvnator/ui/components/form-field-defaults';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings-remote-control-section',
|
||||
providers: [provideFormFieldDefaults()],
|
||||
imports: [
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
|
||||
@@ -17,11 +17,13 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TmdbApiService, TmdbCacheService } from '@iptvnator/services';
|
||||
import type { TmdbCacheStats } from '@iptvnator/shared/interfaces';
|
||||
import { markSectionForCheckOnFormEvents } from './settings-section-form-render';
|
||||
import { provideFormFieldDefaults } from '@iptvnator/ui/components/form-field-defaults';
|
||||
|
||||
type TmdbKeyTestState = 'idle' | 'testing' | 'success' | 'error';
|
||||
|
||||
@Component({
|
||||
selector: 'app-settings-tmdb-section',
|
||||
providers: [provideFormFieldDefaults()],
|
||||
imports: [
|
||||
MatButtonModule,
|
||||
MatFormFieldModule,
|
||||
|
||||
@@ -279,8 +279,9 @@ html {
|
||||
|
||||
// ─── Global refined outlined inputs ──────────────────────────────────────────
|
||||
// Applied app-wide AFTER mat.all-component-themes so these overrides win the
|
||||
// cascade. Pairs with MAT_FORM_FIELD_DEFAULT_OPTIONS (outline + dynamic) set
|
||||
// in app.config.ts.
|
||||
// cascade. Pairs with the outline + dynamic MAT_FORM_FIELD_DEFAULT_OPTIONS
|
||||
// that provideFormFieldDefaults() (@iptvnator/ui/components) sets on each
|
||||
// component rendering a form field.
|
||||
$app-refined-input-density: mat.define-theme((
|
||||
density: (scale: -2),
|
||||
));
|
||||
|
||||
Reference in new issue
Block a user