1.0.0-beta.21 • Published 12 months ago

global-store v1.0.0-beta.21

Weekly downloads
60
License
MIT
Repository
github
Last release
12 months ago

global-store

NPM version NPM downloads badge-size-es5-url badge-size-esnext-url

Circle CI Travis CI Codecov Coveralls Status

Greenkeeper Visual Studio Code Wallaby.js

global-store provides version stable stores for library.

Who need this

  • library that can be used by other libraries, and
  • library that has state, and/or
  • library that want to protect its state from modification.

Why do you need this

If you use a file level variable to store some states, and your library might be used by other libraries, the state it store would scatter around the memory and you will get inconsistent result:

const registry = {}

export function addComponent(name: string, component: any) {
  registry[name] = component
}

This is because when your library is used by other libraries, they may use different versions. For example:

app
- some-library@1.5
  - your-library@1.0
- your-library@2.0

Since the versions are not compatible, both versions of your library are loaded thus two instance of the registry variable exists.

Solution to this problem is to use some form of global storage such as process.env in NodeJS, and localStorage or global variable in browser.

The problem is that these mechanism are shared by everything else in the application, completely exposed to everyone, and there is no mechanism to consolidate your state when they are populated my each copy of your library.

These are the problems addressed by global-store

API

createStore()

createStore() creates a version stable store.

import { createStore } from 'global-store'

const store = createStore(
  'your-module',
  'unique-string',
  previous => ({ ...previous, prop1: false, prop2: [] as string[] })
)

console.log(store.get().prop1) // false

store.get().prop1 = true
store.get().prop2.push('a')
console.log(store.get()) // { prop1: true, prop2: ['a'] }

createStore(moduleName, key, initializer)

  • moduleName: string: Name of your module. This is typically your npm package name.
  • key: string | symbol: Together with moduleName, key + moduleName forms an unique id to the store. The key should be unique for each store you create. You can use some random string such as UUID. You can also use symbol, but not that you need to use the Symbol.for('key') variant as Symbol() does not work for this purpose.
  • initializer: (previous) => initValue: initializer to initialize the store. Since there may be multiple copies of your library loaded, multiple calls to createStore() may occurs. For the first call, the previous argument will be an empty object. For subsequence calls, it will be the value returned by the previous call. Since there is no way to control the load order, createStore() can be called by a newer version of your libary before an older version of your libary calls it. To property setup your store, you can use a property such as revisions or versions to help this process.

Store#get()

Gets the store value. Also use this to update the store.

import { createStore } from 'global-store'

const store = createStore(
  'your-module',
  'general:300c47d7-b3a8-43ee-9dea-1e05a7b34240',
  p => ({ ...p, a: 1 })
)

store.get().a = 2

console.log(store.get().a) // 2

Store#reset()

Reset the store to its initial value.

This is used mostly in your test, so that the tests would not interferred each other.

createReadonlyStore()

createReadonlyStore() creates a version stable store that prevents modification.

It signature is the same as createStore(). The returned ReadonlyStore has the following additional features:

ReadonlyStore#get()

When the store is created, calling get() would result in error if lock() is not called. This avoids the store to be used accidentially without protection.

Readonly#lock()

Lock the store, making it read only.

Then the store is locked, the following happens:

  • the value is frozen, making each property read only.
  • if the property is an array, it is also frozen, making it unable to add or remove entry.
  • get() is open to be used.
  • reset() results in error.
  • getWritable() results in error.
  • openForTesting() results in error.

lock() takes an optional finalizer argument. It can contains properties matching the property names of the store, where each one is a transform function for that property.

It allows you to process the store before it is locked.

The typical use cases are to validate, clean up, transform, and freeze the values.

import { createReadonlyStore } from 'global-store'

const store = createStore(
  'your-module',
  'general:ea305f50-c48c-4d18-97ef-4c8e8f130446',
  p => ({ ...p, a: 1, b: [], c: {} })
)

store.lock({
  b: values => values.map(v => Object.freeze(v)),
  c: value => Object.freeze(value),
  prev: value => undefined // make the older version property disappear.
})

ReadonlyStore#getWritable()

Before the store is locked, you need a mechanism to access the store and configure it. getWritable() by pass the check and allow you to do that.

Once the store is locked, calling getWritable() results in error.

ReadonlyStore#openForTesting()

During testing, you need a mechanism to allow the get() calls to go through without locking the store. openForTesting() tells the store to turn off all checks so it can be used during test.

Due to its power, you should not have any code calling this method except in your test code.

Installation

npm install global-store
yarn add global-store

Bundling

If your library will be a standalone bundle, make sure to exclude global-store. If not, there will be multiple copies of global-store loaded and will completely defeat the purose.

You also should mark global-store as a peer dependency and tell people who use your library to include global-store as their dependency.

Any application that eventually uses your library should do the same, install global-store as their own dependency.

1.0.0-beta.22

12 months ago

1.0.0-beta.20

2 years ago

1.0.0-beta.21

2 years ago

1.0.0-beta.19

2 years ago

1.0.0-beta.18

3 years ago

1.0.0-beta.17

4 years ago

1.0.0-beta.16

4 years ago

1.0.0-beta.15

4 years ago

1.0.0-beta.14

5 years ago

1.0.0-beta.13

5 years ago

1.0.0-beta.12

5 years ago

1.0.0-beta.11

5 years ago

1.0.0-beta.10

5 years ago

1.0.0-beta.9

5 years ago

1.0.0-beta.8

5 years ago

1.0.0-beta.7

5 years ago

1.0.0-beta.6

5 years ago

1.0.0-beta.5

5 years ago

1.0.0-beta.4

5 years ago

1.0.0-beta.3

5 years ago

1.0.0-beta.2

5 years ago

1.0.0-beta.1

5 years ago

1.0.0-beta.0

5 years ago

0.8.2

5 years ago

0.8.1

5 years ago

0.8.0

5 years ago

0.7.3

6 years ago

0.7.2

7 years ago

0.7.1

7 years ago

0.7.0

7 years ago

0.6.1

7 years ago

0.6.0

7 years ago

0.5.3

7 years ago

0.5.2

7 years ago

0.5.1

7 years ago

0.5.0

7 years ago

0.4.0

7 years ago

0.3.0

7 years ago

0.2.0

7 years ago

0.1.0

7 years ago