
Versatile Angular Style brings Modern Dev Tools to Angular

๐ use standalone components only. ๐ use the inject()
function only. ๐บ use inline template only. ๐จ use inline styles only. ๐จ do not use Sass or Tailwind features that need preprocessing in the inline styles.
๐ Dev Tools Evolve & Proliferate
โฉ esbuild & โก๏ธ Vite
๐ค ... but what about Angular support?
{
// Nx
"executor": "@angular-devkit/build-angular:browser-esbuild",
// Angular CLI
"builder": "@angular-devkit/build-angular:browser-esbuild",
}
๐ฆ mind the Rustaceans !
๐ด๐ผ Wait or Act ๐ช
๐ช JIT is the Golden Ticket
๐ Use inline template
& styles
template
styles
templateUrl
styleUrls
template
styles
@Component({
...
template: `<h1>Hello!</h1>`,
styles: [
`
:host {
background: purple;
color: white;
}
`
]
})
class GreetingsComponent {}
๐ Avoid Style Preprocessors
@apply
index.html
main.ts
๐ Use inject()
instead of Traditional DI
inject()
@Component(...)
class GreetingsComponent {
constructor(greetings: GreetingsService) {}
}
GreetingsService
design:paramtypes
emitDecoratorMetadata
emitDecoratorMetadata
Prefer inject()
to @Inject()
inject()
@Inject()
@Inject()
@Component(...)
class GreetingsComponent {
constructor(@Inject(GreetingsService) greetings: GreetingsService) {}
}
@Inject()
๐ @Inject()
is not type-safe, and makes DI error-prone, ๐ฎ Parameter Decorators are not future-proof as they are not part of the ECMAScript Decorator Proposal .
The best alternative is the inject()
function.
inject()
inject()
inject()
TestBed
inject()
it doesn't need any TypeScript metadata, it is type-safe and provides powerful type-inference (cf. example below ) , and it doesn't require us to implement constructors.
const GREETINGS_TOKEN = new InjectionToken<GreetingsService>('GREETINGS');
@Component(...)
class GreetingsComponent {
greetings = inject(GreetingsService); // GreetingsService
greetingsWithToken = inject(GREETINGS_TOKEN); // GreetingsService
greetingsOptional = inject(GreetingsService, {optional: true}); // GreetingsService | null
}
๐ค Maybe @Inject()
should be deprecated in favor of the inject()
function... ๐ฃ
๐ Use Standalone Components
mount()
In other words, Standalone Components are more aligned with how other frameworks and libraries are integrated with modern dev tools.
๐คน Demo
๐ ฐ๏ธ Angular CLI build โก๏ธ Vite โ Vitest ๐ฆ Jest + SWC ๐ญ ... and why not give a try to Playwright Component Testing?
โก๏ธ Vite
style
// vite.config.ts
import { defineConfig } from 'vite';
export default defineConfig({
root: 'src',
resolve: {
conditions: ['style'],
},
});
โ
Vitest
zoneless & fine
change detection should only concern components & directives, so we don't have to worry about zones when testing services for example; we will generally prefer testing components & directives with Cypress Component Testing or Playwright Component Testing; if we are looking for performance and testing components and directives using a browserless option (Jest or Vitest), then we will probably prefer shallow tests (generally 5 to 10x faster) so we will have to trigger change detection manually in the tests, thus no need for zone.js; ... or we might be using a wrapper like @testing-library/angular
that will trigger change detection when necessary.
TestBed
zone.js
NoopZone
Zone
NgNoopZone
NgZone
Excluding the NoopZone
, it takes around 20 lines of configuration and no extra plugin or transformer to run Angular tests using Vitest.
// vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'jsdom',
setupFiles: ['src/test-setup.ts']
},
});
// test-setup.ts
import './app/testing/noop-zone';
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing';
import { getTestBed } from '@angular/core/testing';
getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting()
);
๐ฆ Jest + SWC
@swc/jest
// jest.config.ts
module.exports = {
setupFilesAfterEnv: ["<rootDir>/src/test-setup.ts"],
testEnvironment: "jsdom",
transform: {
"^.+\\.m?(t|j)sx?$": ["@swc/jest"],
},
/* We could get rid of this if we switch to ESM. */
transformIgnorePatterns: ["/node_modules/(?!(@angular/)"],
};
๐ญ Playwright Component Testing
๐ค What about adding Angular support to some dev tool where all other frameworks/libs support is still experimental too?
You can try Playwright Component Testing support for Angular right now !
๐ข Progressive Migration to Versatile Angular Style
ษตษตdirectiveInject()
inject()