Angular 2: Musing on the potential of Hot Module Replacement and the power of @ngrx/store

If you're just getting started, this link might be helpful: understanding the purpose of HMR.

When it comes to managing and designing large projects, I'm still in the early stages and haven't grown a wise beard yet. So, I'm seeking advice from experienced individuals like yourself.

Exploring the Seed

I've been exploring the Angular 2 seed project and wondering if implementing HMR is a feasible option for developing a large application effectively.

These are just my initial thoughts, and I'm eager to have a discussion with others to make an informed decision. Learning from each other's experiences is crucial :-)

Data Structure Discussion

Considering the example below:

 (component code snippet) 

Utilizing appState allows components to be dynamically reloaded and data injected. However, should we rely on objects like localState within components? Is this practice manageable in large applications?

On the other hand, utilizing localStorage solely for tracking data required by HMR seems like a straightforward approach.

Data Storage and @ngrx/store

In terms of storage, I also utilize @ngrx/store as a Redux implementation where the state serves as the application's localStorage. While this setup sounds promising, integrating @ngrx/store with HMR poses some challenges given that existing connectors may be outdated.

Aligning Angular services with reducers and finding ways to update HMR's state presents further considerations.

While @ngrx/store and HMR are recognized technologies within the Angular community, resources on combining them are limited. Therefore, I seek insights based on practical experiences and potential pitfalls that may not be immediately evident.

Final Thoughts

  • Is HMR deployment-ready for production environments?
  • Is storing substantial information within @ngrx/store advisable?
  • A crucial question: How well do these technologies integrate?

These inquiries echo similar discussions found at this link.

Answer №1

In Summary - HMR is primarily a development tool that helps speed up the process without requiring you to fully understand its inner workings. If issues arise, simply refresh the page. In the long run, it will save you time...

Building Angular apps can be time-consuming due to their size (a few megabytes). HMR is utilized during development to reduce compilation times, allowing you to see changes instantly without delay. It operates by leveraging existing loaders like webpack and systemjs. Most likely, this information isn't new to you (;

I recently developed a personalized HMR solution based on Systemjs (using systemjs-hmr). The fundamental principle involves: notifying the loader of code changes and reloading those changes. Additional adjustments are necessary to ensure your app remains functional...

The core features of my HMR include:

  • reloading modified app code (components, services, pipes...),
  • recreating <app-root>, as depicted here,
  • disposing of the previous app with NgModuleRef.destory(),
  • bootstrapping the new app using:
    platformBrowserDynamic().bootstrapModule(AppModule).then(module => window['__HMR__'] = module)
  • obtaining the initial value of @ngrx/store

This is the script I implemented:

import { Store } from '@ngrx/store';
export function get__HMR__state() {
  let state = {};
  if (window['__HMR__']) {
    const module = window['__HMR__'];
    const store = module.injector.get(Store);
    store.take(1).subscribe(s => state = s);
  }
  return state;
}

@NgModule({
  imports: [
    StoreModule.provideStore(AppReducer, get__HMR__state())
  ]
})

I refrain from storing unnecessary data in my app's AppState (ngrx/store). Input values and attributes should be managed more effectively like this.

The functionality works efficiently; after initiating my custom gulp build workflow at the beginning of the day, I rarely encounter issues thereafter (; An occasional hiccup may occur, especially when adjusting project structure and dependencies, but a quick F5 resolves the problem. Reloading promptly functions well when editing templates and styles, which significantly reduces downtime.

For "project management," I rely on angular-cli, and while using its ng serve feature (powered by webpack), the rebuild time ranges between 3-8 seconds + 2-4 seconds for the reload with each code alteration. Conversely, with Gulp+HMR (implemented on the same cli project), the rebuild time diminishes to 50-400ms + 200-500ms reload. That disparity prompted me to develop a tailored build solution (; Should complications arise, pressing F5 ensures the app runs smoothly within 2-4 seconds.

In conclusion, I highly recommend incorporating HMR for individuals spending several hours per day coding (; While it may not be flawless, no tool is, yet it ultimately saves substantial time in the grand scheme. Nevertheless, do not adjust your app solely to accommodate the tool. Write code as you normally would without HMR. Custom enhancements are possible if additional functionalities are required since, essentially, it's just JavaScript (;

Answer №2

Upon exploring this repository, I found it to be incredibly insightful.

The codebase utilizes Angular 2, HMR, @ngrx/store, and more. Through reviewing the code, I have gained valuable knowledge. The approach of using @ngrx/effects alongside @ngrx/store and HMR is impressively straightforward, especially evident in the app.module.ts. Thanks to AngularClass/hmr-loader, everything is conveniently consolidated here:

hmrOnInit(store) {
    if (!store || !store.rootState) return;

    // restore state by dispatching a SET_ROOT_STATE action
    if (store.rootState) {
      this._store.dispatch({
        type: 'SET_ROOT_STATE',
        payload: store.rootState
      });
    }

    if ('restoreInputValues' in store) { store.restoreInputValues(); }
    this.appRef.tick();
    Object.keys(store).forEach(prop => delete store[prop]);
  }
  hmrOnDestroy(store) {
    const cmpLocation = this.appRef.components.map(cmp => cmp.location.nativeElement);
    this._store.take(1).subscribe(s => store.rootState = s);
    store.disposeOldHosts = createNewHosts(cmpLocation);
    store.restoreInputValues = createInputTransfer();
    removeNgStyles();
  }
  hmrAfterDestroy(store) {
    store.disposeOldHosts();
    delete store.disposeOldHosts;
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Revamping an npm package on GitHub

Currently, I am managing a project that has gained popularity among users and has received contributions from multiple individuals. The next step I want to take is to convert the entire library into TypeScript, but I am unsure of the best approach to ach ...

Utilize puppeteer and web-vitals in NextJS to retrieve the web performance metrics of a website

I'm currently working on a basic tool in NextJS that uses puppeteer to fetch web vitals data from a given URL. However, I'm facing an issue where the results are not being printed out. What could be causing this problem? const browser = await pup ...

Issue: Unable to find solutions for all parameters in (?, ?)

Below is the unit test I've written for my Angular 10 component, which showcases a tree view with interactive features: import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/for ...

Access the CSV file using Office365 Excel via a scripting tool

Objective I want to open a CSV file using Office365's Excel without actually saving the file on the client's machine. Challenge The issue with saving raw data on the client's machine is that it leads to clutter with old Excel files accumu ...

Unexpected Behavior when Passing @Input() Data Between Parent and Child Components in Angular 2 Application

I am currently in the process of abstracting out a tabular-data display to transform it into a child component that can be loaded into different parent components. The main aim behind this transformation is to ensure that the overall application remains "d ...

How can I effectively make properties accessible in my template to facilitate form validation in Angular?

Scenario: I'm facing a situation in my Angular project where I have a LoginFormComponent. This component has a form with two properties: email and password. My goal is to create properties within this component that can be accessed in the template. Th ...

The event triggered by the tinymce editor does not immediately refresh the Angular Component

I am currently working on creating an Angular application using a WordPress instance of TinyMCE. Within the editor, there are non-content-editable elements that trigger a modal window to open when clicked. However, I have encountered an issue where the mo ...

The sequence of execution in React hooks with Typescript

I'm having difficulty implementing a language switching feature. On the home page of my app located at /, it should retrieve a previously set preference from localStorage called 'preferredLanguage'. If no preference is found, it should defau ...

Obtaining a Slick Component Instance with the help of View Child

I am a beginner in angular and I am currently working on implementing a paginated carousel using the ngx-slick plugin. However, I am facing an issue where I need the carousel to start from index 1 instead of 0 when it loads in the template. The ngx-slick p ...

Having trouble with downloading a zipped folder on the client side in an Angular and Node.js (MEAN) application

I am facing an issue with allowing users to download compressed folders from the server. I have successfully compressed the folder, however, when attempting to read the tar file and send it for download on the client side, the file is either corrupted or o ...

Aligning the React Navigation header component's bottom shadow/border width with the bottom tabs border-top width

Currently, I am working on achieving a uniform width for the top border of the React Navigation bottom tabs to match that of the top header. Despite my efforts, I am unable to achieve the exact width and I am uncertain whether it is due to the width or sha ...

Tips and tricks for accessing the state tree within effects in @ngrx/effects 2.x

I am currently in the process of migrating my code from version 1.x to 2.x of @ngrx/effects. Previously, in version 1.x, I was able to access the state tree directly within an effect: constructor(private updates$: StateUpdates<AppState>) {} @E ...

The child component fails to inherit the data types provided by the parent component

I am currently working on setting up a dynamic table that will receive updates from the backend based on actions taken, which is why I need to pass the endpoint and response model. When I try to nest and pass the response type, it seems to get lost in the ...

Tips on switching the default camera with ngx-scanner-qrcode library in Angular

In my current project, I am utilizing the ngx-sanner-qrcode library for QRCode scanning. However, I am interested in changing the default camera from front to back in order to enhance the user experience. I assumed that I could change the default camera b ...

Incorporating npm packages into an Angular2 (v2.0.0-rc.1) application

Struggling with integrating npm libraries into my Angular2 app has been a challenge, especially when trying to include https://github.com/manfredsteyer/angular2-oauth2. Every time I try to import the library, I encounter a 404 error. Even after adding the ...

Can we set a specific length for an array passed in as a prop?

Can we use Typescript to specify the exact length of an array coming from props? Consider the following array of objects: const sampleArray = [ { key: '1', label: 'Label 1', value: 9 }, { key: '2', label: 'Label 2&ap ...

After installing Node.js on a Windows machine, the program 'npm' is not identified as an internal or external command, and cannot be executed as an operable program or batch file

I have been searching for a solution to this problem, but none of the suggestions I found seem to work for me. I am currently using a Windows 10 Laptop where I do not have administrative rights. My goal is to run my Angular + NodeJS application on this ma ...

When using Typescript, I am encountering an issue where declared modules in my declaration file, specifically those with the file

One of the declarations in my ./src/types.d.ts file includes various modules: /// <reference types="@emotion/react/types/css-prop" /> import '@emotion/react'; import { PureComponent, SVGProps } from 'react'; declare mod ...

Retrieve information from two distinct observables from within the resolver function

I'm facing an issue with my services that work on the observable principle. I am trying to fetch the results of 2 services inside a resolver to display on my page. However, the data being displayed on the page is just an empty data object. I even trie ...

Why isn't the class applying the color to the Angular span element?

My Angular application generates text that needs to be dynamically colorized. To achieve this, I inject a span element with a specific class into the text output like so: Some text <span class="failResult">that's emphasized</span> and oth ...