Skip to content

Commit

Permalink
fix(storage-plugin): require only getItem and setItem on engines (#…
Browse files Browse the repository at this point in the history
…2036)

This commit updates the signature of the `StorageEngine` interface
and removes unnecessary properties that are not being used by the storage
plugin. The properties `length`, `removeItem`, and `clear` have been removed.
This change makes it easier to maintain storage engines that implement the
interface because only the necessary properties will be required. It is important
to note that this change is not considered a breaking change since properties are
being removed rather than added.
  • Loading branch information
arturovt authored Jul 18, 2023
1 parent 68ac7b5 commit a9bb1d9
Show file tree
Hide file tree
Showing 6 changed files with 34 additions and 30 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ $ npm install @ngxs/store@dev
### To become next patch version

- Fix: Storage Plugin - Access local and session storages globals only in browser [#2034](https://github.com/ngxs/store/pull/2034)
- Fix: Storage Plugin - Require only `getItem` and `setItem` on engines [#2036](https://github.com/ngxs/store/pull/2036)
- Performance: Tree-shake selectors validation errors [#2020](https://github.com/ngxs/store/pull/2020)

# 3.8.1 2023-05-16
Expand Down
27 changes: 8 additions & 19 deletions docs/plugins/storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,9 @@ You can even combine state classes and strings:
export class AppModule {}
```

This is very handy to avoid persisting runtime-only states that shouldn't be saved to any storage.
This is very useful for avoiding the persistence of runtime-only states that should not be saved to any storage.

This is also possible to provide storage engines per individual key. Suppose we want to persist `NovelsState` into the local storage and `DetectivesState` into the session storage. The `key` signature will look as follows:
It is also possible to provide storage engines for individual keys. For example, if we want to persist `NovelsState` in the local storage and `DetectivesState` in the session storage, the signature for the key will appear as follows:

```ts
import { LOCAL_STORAGE_ENGINE, SESSION_STORAGE_ENGINE } from '@ngxs/storage-plugin';
Expand All @@ -163,7 +163,7 @@ import { LOCAL_STORAGE_ENGINE, SESSION_STORAGE_ENGINE } from '@ngxs/storage-plug
export class AppModule {}
```

`LOCAL_STORAGE_ENGINE` and `SESSION_STORAGE_ENGINE` are injection tokens that resolve to `localStorage` and `sessionStorage`. They shouldn't be used in apps with server-side rendering because it will throw an exception that those symbols are not defined on the global scope. Instead, we should provide a custom storage engine. The `engine` property may also refer to classes that implement the `StorageEngine` interface:
`LOCAL_STORAGE_ENGINE` and `SESSION_STORAGE_ENGINE` are injection tokens that resolve to `localStorage` and `sessionStorage`, respectively. These tokens should not be used in apps with server-side rendering as it will throw an exception stating that these symbols are not defined in the global scope. Instead, it is recommended to provide a custom storage engine. The `engine` property can also refer to classes that implement the `StorageEngine` interface:

```ts
import { StorageEngine } from '@ngxs/storage-plugin';
Expand Down Expand Up @@ -205,29 +205,18 @@ export class AppModule {}

### Custom Storage Engine

You can add your own storage engine by implementing the `StorageEngine` interface.
You can add your own storage engine by implementing the `StorageEngine` interface:

```ts
import { NgxsStoragePluginModule, StorageEngine, STORAGE_ENGINE } from '@ngxs/storage-plugin';

@Injectable()
export class MyStorageEngine implements StorageEngine {
get length(): number {
// Your logic here
}

getItem(key: string): any {
// Your logic here
}

setItem(key: string, val: any): void {
// Your logic here
}

removeItem(key: string): void {
// Your logic here
}

clear(): void {
setItem(key: string, value: any): void {
// Your logic here
}
}
Expand All @@ -248,8 +237,8 @@ export class MyModule {}

You can define your own logic before or after the state get serialized or deserialized.

- beforeSerialize: Use this option to alter the state before it gets serialized.
- afterSerialize: Use this option to alter the state after it gets deserialized. For instance, you can use it to instantiate a concrete class.
- `beforeSerialize`: Use this option to alter the state before it gets serialized.
- `afterSerialize`: Use this option to alter the state after it gets deserialized. For instance, you can use it to instantiate a concrete class.

```ts
@NgModule({
Expand Down
11 changes: 8 additions & 3 deletions packages/storage-plugin/src/internals/final-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@ export interface FinalNgxsStoragePluginOptions extends NgxsStoragePluginOptions
}[];
}

export const FINAL_NGXS_STORAGE_PLUGIN_OPTIONS = new InjectionToken<
FinalNgxsStoragePluginOptions
>('FINAL_NGXS_STORAGE_PLUGIN_OPTIONS');
declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode === 'undefined' || ngDevMode;

export const FINAL_NGXS_STORAGE_PLUGIN_OPTIONS =
new InjectionToken<FinalNgxsStoragePluginOptions>(
NG_DEV_MODE ? 'FINAL_NGXS_STORAGE_PLUGIN_OPTIONS' : ''
);

export function createFinalStoragePluginOptions(
injector: Injector,
Expand Down
6 changes: 5 additions & 1 deletion packages/storage-plugin/src/storage.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import {
FINAL_NGXS_STORAGE_PLUGIN_OPTIONS
} from './internals/final-options';

export const USER_OPTIONS = new InjectionToken('USER_OPTIONS');
declare const ngDevMode: boolean;

const NG_DEV_MODE = typeof ngDevMode === 'undefined' || ngDevMode;

export const USER_OPTIONS = new InjectionToken(NG_DEV_MODE ? 'USER_OPTIONS' : '');

@NgModule()
export class NgxsStoragePluginModule {
Expand Down
17 changes: 11 additions & 6 deletions packages/storage-plugin/src/symbols.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,19 @@ export interface NgxsStoragePluginOptions {
afterDeserialize?(obj: any, key: string): any;
}

export const NGXS_STORAGE_PLUGIN_OPTIONS = new InjectionToken('NGXS_STORAGE_PLUGIN_OPTIONS');
declare const ngDevMode: boolean;

export const STORAGE_ENGINE = new InjectionToken<StorageEngine>('STORAGE_ENGINE');
const NG_DEV_MODE = typeof ngDevMode === 'undefined' || ngDevMode;

export const NGXS_STORAGE_PLUGIN_OPTIONS = new InjectionToken(
NG_DEV_MODE ? 'NGXS_STORAGE_PLUGIN_OPTIONS' : ''
);

export const STORAGE_ENGINE = new InjectionToken<StorageEngine>(
NG_DEV_MODE ? 'STORAGE_ENGINE' : ''
);

export interface StorageEngine {
readonly length: number;
getItem(key: string): any;
setItem(key: string, val: any): void;
removeItem(key: string): void;
clear(): void;
setItem(key: string, value: any): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('Storage engine per individual key (https://github.com/ngxs/store/issue
},
{
key: 'encrypted',
engine: <any>EncryptedStorageEngine
engine: EncryptedStorageEngine
}
]
})
Expand Down

0 comments on commit a9bb1d9

Please sign in to comment.