Search code examples
angularngrxngrx-storenrwl

How to use ngrx-store-freeze with nx workspace


I am using nx workspaces for my application. I have put all the reducers in the libs section because they are shared between several apps. But when creating the meta-reducer I want to use ngrx-store-freeze for development.

The way that this is recommended is with this line: export const metaReducers: MetaReducer<State>[] = !environment.production ? [storeFreeze] : [];

But how can I know if the app is production when I do not know which environment to import because I do not know which app will be running in the nx workspace, and the ngrx reducers are pure functions so I cannot inject the environment?


Solution

  • Create a function that will create the meta reducers for you. This function accepts a paremeter which indicates if it is for production mode or not.

    export function createMetaReducers(freeze = false): MetaReducer<State>[] {
        return freeze
            ? [storeFreeze] 
            : [];
    }
    

    Like this your library does not care about if you are in production mode and the user of your library can decide instead.

    Update regarding your comment

    I have created a function, but I cannot use this function in my app.module.ts, in the imports section, before I did this: 'StoreModule.forRoot(reducers, { metaReducers }),' Now I have tried using the new function StoreModule.forRoot(reducers, { createMetaReducers(true) }) but get the error: "Argument of type '{ createMetaReducers(: any): any; }' is not assignable to parameter of type 'StoreConfig'." How would you resolve this problem?

    You already resolved your problem but I want to give an explanation on what is going on.

    Typescript and modern ECMA script has some syntax sugar to shorten certain things.

    Let's say you have an object where you want to assign a name:

    const obj: any = { name: 'Tom' }
    

    Now we might not hardcode the name but have it in a variable called name. Then the code looks like this:

    const name: string = 'Tom';
    const obj: any = { name: name };
    

    You can see that the variable is named the same as the field in the object. If that is the case you can simply drop the : name part and write it like this:

    const name: string = 'Tom';
    const obj: any = { name };
    

    This code snippet does the same thing as the one above.

    This is called Object Literal Property Value Shorthand (Please somone correct me if I got that wrong) and you can find more information here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

    Now back to your code. StoreModule.forRoot expects two parameters. The second parameter is a configuration object where you can pass in the meta reducers

    StoreModule.forRoot(reducers, { metaReducers: [] })
    

    So to fix this you have 2 possibilities.

    What you did works fine:

    const metaReducers = createMetaReducers();
    StoreModule.forRoot(reducers, { metaReducers })
    

    Another way to resolve this would be following approach:

    StoreModule.forRoot(reducers, { metaReducers: createMetaReducers() })