Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possibility to exclude withDevTools in production mode when ngrx-toolkit is installed under dependencies #53

Closed
koempf opened this issue May 31, 2024 · 13 comments

Comments

@koempf
Copy link

koempf commented May 31, 2024

No description provided.

@REVenkatesan
Copy link

Is there any possibility to exclude withDevtools in production mode...

@marcindz88
Copy link
Contributor

marcindz88 commented Sep 14, 2024

Hi there, I have a solution for this although it is a bit hacky:
Assuming you have setup environment files you can do the following:

environment.ts:

import { withDevtools } from '@angular-architects/ngrx-toolkit';

export const environment = {
   storeDevToolsFeature: withDevtools
}

environment.prod.ts

export const environment = {
   storeDevToolsFeature: ((_: string) => store => store) as (name: string) => SignalStoreFeature
}

If you have a type defined for your environment, you can use the type and skip above type assertion:

{
  storeDevToolsFeature: (name: string) => SignalStoreFeature
}

Then all you need to do is replace withDevTools everywhere in your app with environment.storeDevToolsFeature
e.g.:

export const SomeStore = signalStore(
  withState({strings: [] as string[] }),
  environment.storeDevToolsFeature('some')
);

Make sure you have file replacements in angular.json prod configuration:

"fileReplacements": [
  {
    "replace": "src/environments/environment.ts",
    "with": "src/environments/environment.prod.ts"
  }
]

As a result, when running the prod version of ng serve or build this file will be replaced and not compiled at all, which will disable and tree-shake the whole withDevTools feature 😀

@rainerhahnekamp
Copy link
Collaborator

We could use isDevMode (https://angular.dev/api/core/isDevMode) instead of accessing the environment files. As far as I understand, that's the standard way on how to do it.

withDevtools could become a wrapper function which first checks if the user wants to disable it during prod mode and could then return an empty Feature.

@marcindz88 would you have time to implement that and provide a PR?

@marcindz88
Copy link
Contributor

@rainerhahnekamp I thought about adding isDevMode but this leads to the withDevTools code to be included in the production bundle, unless there is some method to mark it for exclusion that I don't know.

@marcindz88
Copy link
Contributor

Hmm, I may be wrong about that, I will check if it is tree shaken by default and if yes, I will provide a PR

@REVenkatesan
Copy link

i have tried as you post @marcindz88 but i got the below error while importing environment file of production
export const environment = {
storeDevToolsFeature: (_: string) => (store: any) => store
};
Spread types may only be created from object types.ts(2698)
Property 'discountList' comes from an index signature, so it must be accessed with ['discountList'].ts(4111)
(() => unknown) & {
[SIGNAL]: unknown;
} & Function

@REVenkatesan
Copy link

i have tried withdevtools @rainerhahnekamp it will not works for me

@marcindz88
Copy link
Contributor

marcindz88 commented Sep 14, 2024

@rainerhahnekamp Hmm, I have this (and more) in my prod bundle when using isDevMode:

function fo() {
  $(() => {
    if (!Vt) return;
    let t = Oe(),
      e = {};
    for (let i in t) {
      let s = t[i];
      e[i] = s();
    }
    let o = Array.from(ie),
      n = o.length ? o.join(', ') : 'Store Update';
    (ie = new Set()), Vt.send({ type: n }, e);
  });
}

function mo(t, e) {
  if (typeof t == 'object' && t && e in t) return t[e];
}

function ho(t) {
  let [e] = Object.getOwnPropertySymbols(t);
  if (!e) throw new Error('Cannot find State Signal');
  return mo(t, e);
}

var Vt;

function Ue(t) {
  return e => {
    if (Bt(E(nt))) return e;
    let n = window.__REDUX_DEVTOOLS_EXTENSION__;
    if (!n) return e;
    Vt || (Vt = n.connect({ name: 'NgRx Signal Store' }));
    let i = ho(e);
    return Oe.update(s => g(r({}, s), { [t]: i })), je || (fo(), (je = !0)), e;
  };
}

@marcindz88
Copy link
Contributor

@REVenkatesan if you don't type your environment which I would encourage you to do, to reduce the probability of having different Environment types, you probably need to add a type assertion as (name: string) => SignalStoreFeature (I have edited the example above).
Your build crashes because of the (store:any) type

@rainerhahnekamp
Copy link
Collaborator

@REVenkatesan we will find a solution for the typing issue you reported. Once @marcindz88 says it is tree shaken, it will be added to the next release.

@marcindz88
Copy link
Contributor

@rainerhahnekamp I think this is related to this issue: angular/angular#51175.
Anyway, it is not a lot of code so we could ignore this issue until angular provides some solution. Nevertheless, the environment-based approach does remove the code from the bundle.

@rainerhahnekamp
Copy link
Collaborator

@marcindz88, I see two use cases for this feature:

  1. Hiding state mutation from end users
  2. Optimizing the bundle size

I'd say isDevMode is meant for use case 1, and I would favor that. Since use case 2 requires a little bit more work from the end user, I would explain how to do it in the docs.

@rainerhahnekamp
Copy link
Collaborator

@koempf has just been merged. it is part of the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants