In the previous blog post I was talking about how I've set up my project and about creating login and create account pages. Now it's time to move into main part of the application and also to start thinking a bit about project structure!
Day 8 - Home view
Day 8 was quite simple. It was Sunday, so I had more time to code and I spent it on creating the layout for the home view for my application. And here is the effect!
For the most part is was going pretty smoothly. I just ran into one problem, I spent way too much time trying to solve (and eventually giving up...) Namely, trying to change the fill color of SVGs... I still have no idea, why is it not working... If you have some suggestions, I'd be glad to hear!
The icon here also should change the color on hover as the text does...
Days 9-10 - Project structure
On days 9 to 10 it was time to start thinking about project structure! I wasn't coding too much these days, but some conceptual work is needed sometimes as well! First my idea was to split an app into modules - the old fashioned way 😉
But then I learned that I've had this misconception about standalone components, that they are mostly good as a substitute for shared module. It turns out, it is actually recommended to build whole applications using them nowadays! So that's what I decided to do! But first... what the hell are standalone components?
Standalone components
Standalone components are a relatively new feature introduced in Angular 15. They offer a simplified way of building applications, because they are not a part of any module, and also, when used in another standalone components, they don't need to be imported! You can use them just like that! But they can also be imported into a module, so you can slowly transition into this new style without having to refactor the whole application.
So what are the advantages of standalone components? The main one is that you don't introduce unnecessary dependencies, by importing whole modules, when you only need bunch of components from them, which in turn reduces the bundle size, thus making your application run faster!
So how do I make an standalone component? It's very easy! You just add standalone: true
to it's declaration :) Also you need to import into a component all the components that you are using in it. So now the declaration looks like this:
@Component({
selector: 'app-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss'],
standalone: true,
imports: [ToggleButtonsComponent],
})
export class NavbarComponent {
Migrating an application to standalone components
So do I have to go through the whole application now, and manually change the declarations of all components? No! There is a tool for that!
You just need to tun this command thrice: ng generate @angular/core:standalone
Wait.. why thrice? Is it some kind of weird spell? No, it's because the migration is split into parts, and each time you need to select another option :) These are the options, you get when you run this command:
Step 1: Convert all components, directives and pipes to standalone
This step is doing something similar to what I have shown in the code block above. It turns all the components into standalone versions and adds necessary imports to them!
Step 2: Remove unnecessary NgModule classes
This step did nothing when I ran this in my application. That's because I only have AppModule
which is my root
module, and AppRoutingModule
which is my main routing module. But if I had any other modules in my app, they should in theory be removed. But this step often doesn't remove all the modules, and some manual work may still be needed.
Step 3: Bootstrap the application using standalone APIs
This step removes the root
module of your application and instead invokes bootstrapApplication
function in your main.ts
. That function is responsible for bootstrapping your routing, singleton services etc. It looks like this:
bootstrapApplication(AppComponent, {
providers: [
importProvidersFrom(BrowserModule, AppRoutingModule, ReactiveFormsModule, AngularSvgIconModule.forRoot()),
provideHttpClient(withInterceptorsFromDi())
]
})
.catch(err => console.error(err));
??? Profit?
Not yet in my case! One pesky module is still standing strong! And it is routing module.
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
})
export class AppRoutingModule {}
Let's just get rid of it, export routes, and rename the file to something like routes.ts
. So the content of this file looks something like this now:
export const routes: Routes = [
{ path: '', redirectTo: '/sign-in', pathMatch: 'full' },
{
path: 'sign-in',
title: 'Sign in',
component: LoginComponent,
pathMatch: 'full',
},
{
path: 'sign-up',
title: 'Sign up',
component: SignUpComponent,
pathMatch: 'full',
},
{
path: 'dashboard',
title: 'Dashboard',
component: DashboardComponent,
pathMatch: 'full',
canActivate: [authGuard],
},
];
Now we can change the way we provide it in our bootstapApplication
function:
bootstrapApplication(AppComponent, {
providers: [
importProvidersFrom(BrowserModule, ReactiveFormsModule, AngularSvgIconModule.forRoot()),
provideHttpClient(withInterceptorsFromDi()),
provideRouter(routes)
]
})
And that's it! The application is working fine, and we don't have a single module in it! Well, instead of the ones from Angular and external libraries 😉
Conclusion
For the past two days I haven't done much coding, but I still learned a lot. And now I can play more with this new style of application and play around with concepts like lazy loading
. In the following days I'll probably get back to coding to cool off a bit, but I still have some concepts like this to explore, so from time to time I will be sharing these effects of my exploration. Until next time!
Top comments (0)