next-universal-storage v1.0.0
import withUniversalStorage, { UniversalStorage } from "next-universal-storage";
const universalDataKeys = ["REQUEST_ID", "ACCEPT_LANGUAGE"] as const;
const serverDataKeys = ["REQUEST_HEADERS"] as const;
const universalStorage = new UniversalStorage(universalDataKeys, serverDataKeys);
// /pages/_app.tsx
export default withUniversalStorage(universalStorage)(Application);
// /pages/about.tsx
const Page = (props: { requestId: string }) => <p>Your request ID is {props.requestId}</p>;
Page.getInitialProps = () => ({
requestId: universalStorage.getFromUniversal("REQUEST_ID"),
});
Table of Contents
- Table of Contents
- Features
- Storage Types
- Quick Start
- API
UniversalStorage.constructor
UniversalStorage.prototype.universalDataKeys
UniversalStorage.prototype.serverDataKeys
UniversalStorage.prototype.setToUniversal
UniversalStorage.prototype.getFromUniversal
UniversalStorage.prototype.setToServer
UniversalStorage.prototype.getFromUniversal
- HOC (default exported value)
- Redux (Flux) vs next-universal-storage
- Contributing to next-universal-storage
- License
Features
FEATURES | WHAT YOU CAN DO |
---|---|
⚛️ Designed for Next.js | All you need is using HOC for _app.jsx |
🔄 Sharing data between a server and client | You don't need write if anywhere to handle data |
🌴 Available anywhere | You can get and set data outside React components |
🎩 Type Safe | You can use with TypeScript |
Storage Types
next-universal-storage provides two storages. They are can store values by keys like KVS.
Universal Storage
Universal Storage is available on a server-side and client-side and it shares data between them. This is an interface and using Server Storage or Cookie Store inside.
On a client-side
When your code is running on a client-side, Universal Storage uses Cookie Store in web browsers. If a code sets a data, this storage
writes Cookie Store using document.cookie =
API. If a code gets a data, this storage gets data from Cookie Store using
document.cookie
API and converts to an object, then returns a value.
On a server-side
When your code is running on a server-side, firstly Universal Storage saves Cookie
field of a request object via ctx.req.header.cookie
in getInitialProps
to Server Storage. If a code sets a data, this storage writes the data to Server Storage directly. If a code
gets a data, this storage attempts to get data from Server Storage. On failure, this gets Cookie
field value from Server
Storage and converts to an object, then returns it.
Before the server returns a response, finally all data in Universal Storage are serialized and added to Set-Cookie
fields of
response headers. Web browsers which get the header fields will save them to Cookie Store automatically.
Encoding and decoding strategies
"https://www.example.com" --[SET]--> "https%3A%2F%2Fwww.example.com" --[GET]--> "https://www.example.com"
Because Universal Storage uses Cookie Store, all data in the storage are always encoded using encodeURIComponent
. If your code
gets data from the storage, this decodes using decodeURIComponent
, so you can set a value which includes symbols and non-ASCII
characters.
Serializing
Cookie is not simple KVS and it can configured some access limitations for security. When next-universal-storage converts pure objects to strings, it serializes them to follow RFC 6265.
next-universal-storage uses cookie package to serialize securely. Default options are the following.
OPTION | VALUE |
---|---|
path | "/" |
secure | true |
expires | Ten years from a timing to set values ( Date object) |
sameSite | "lax" |
Also you can specify more detailed options by giving it to the third argument of a constructor. If you omit some of the above options, next-universal-storage merges the default options and your options and sets them.
const universalStorage = new UniversalStorage(
universalDataKeys,
serverDataKeys,
{
universalStorageCookieOptions: { secure: environment !== "development", sameSite: "strict" },
},
);
Server Storage
Server Storage is available on only a server-side and it doesn't share data between a server-side and client-side.
Server Storage saves data to the global object global
in Node.js, so you can save all value types. If your code writes data for
the first time, Server Storage adds _NEXT_UNIVERSAL_STORAGE
property to the global object. All data through Server Storage API
are stored in the property as pure objects.
In order to prevent remaining data between requests, next-universal-storage clears all data in Server Storage at an early stages
in getInitialProps
.
Quick Start
Requirements
- npm or Yarn
- Node.js 10.0.0 or higher
- Next.js 9.0.0 or higher
Installation
$ npm install next-universal-storage
If you are using Yarn, use the following command.
$ yarn add next-universal-storage
Setup
Firstly import UniversalStorage
class and create a new instance object. You have to pass keys of data for Universal Storage
and Server Storage to a constructor.
import { UniversalStorage } from "next-universal-storage";
const universalDataKeys = ["REQUEST_ID", "ACCEPT_LANGUAGE"] as const;
const serverDataKeys = ["REQUEST_HEADERS"] as const;
export const universalStorage = new UniversalStorage(universalDataKeys, serverDataKeys);
Then, import a HOC from a default exported in _app.jsx
(or _app.tsx
). Give the instance object you created to the first
argument and give an application component for Next.js to a returned function.
import App from "next/app";
import withUniversalStorage from "next-universal-storage";
class Application extends App {
...
}
export default withUniversalStorage(universalStorage)(Application);
The setup is done.
API
UniversalStorage.constructor
import { UniversalStorage } from "next-universal-storage";
const universalStorage = new UniversalStorage(
["foo", "bar"],
["baz"],
{
universalStorageCookieOptions: { secure: false },
},
);
This creates a new instance object of UnviersalCookie
class.
universalDataKeys: string[]
- Required.
- A list of keys used in the universal storage.
serverDataKeys: string[]
- Required.
- A list of keys used in the server storage.
options
- Optional, a default value is
{}
universalStorageCookieOptions: CookieSerializeOptions
- Options to serialize keys and values when a server sets
Set-Cookie
response header field. - For more detail: https://github.com/jshttp/cookie#options-1
- Options to serialize keys and values when a server sets
- Optional, a default value is
UniversalStorage.prototype.universalDataKeys
const universalStorage = new UniversalStorage(["foo", "bar"], ["baz"]);
universalStorage.universalDataKeys; // ["foo", "bar"]
This returns keys for Universal Storage. The keys are a value you gives to the first argument of a constructor.
UniversalStorage.prototype.serverDataKeys
const universalStorage = new UniversalStorage(["foo", "bar"], ["baz"]);
universalStorage.serverDataKeys; // ["baz"]
This returns keys for Server Storage. The keys are a value you gives to the second argument of a constructor.
UniversalStorage.prototype.setToUniversal
const universalStorage = new UniversalStorage(["foo", "bar"], ["baz"]);
universalStorage.setToUniversal("bar", "123456");
This sets Universal Storage to a value.
key: string
- Required.
- You have to give a key listed in
UniversalStorage.prototype.universalDataKeys
, otherwise setting is ignored.
value: string
- Required.
UniversalStorage.prototype.getFromUniversal
const universalStorage = new UniversalStorage(["foo", "bar"], ["baz"]);
universalStorage.getFromUniversal("bar");
This gets a string value from Universal Storage.
key: string
- Required.
- You have to give a key listed in
UniversalStorage.prototype.universalDataKeys
, otherwiseundefined
is always returned. - If a data could not be found, this returns
undefined
.
UniversalStorage.prototype.setToServer
const universalStorage = new UniversalStorage(["foo", "bar"], ["baz"]);
universalStorage.setToServer("baz", "123456"); // string
This sets Server Storage to a value.
key: string
- Required.
- You have to give a key listed in
UniversalStorage.prototype.serverDataKeys
, otherwise setting is ignored.
value: any
- Required.
UniversalStorage.prototype.getFromUniversal
const universalStorage = new UniversalStorage(["foo", "bar"], ["baz"]);
universalStorage.getFromUniversal<boolean>("bar"); // boolean | undefined
This gets a value from Universal Storage. In TypeScript files, you can specify a returned type via Generic Types.
key: string
- Required.
- You have to give a key listed in
UniversalStorage.prototype.serverDataKeys
, otherwiseundefined
is always returned. - If a data could not be found, this returns
undefined
.
HOC (default exported value)
import withUniversalStorage from "next-universal-storage";
// If you use CommonJS...
const withUniversalStorage = require("next-universal-storage");
withUniversalStorage(universalStorage)(Application);
This prepares to use storages and returns a new React component. Use in _app.jsx
(or _app.tsx
) and give an application component
for Next.js to an argument of a returned function.
universalStorage: UniversalStorage
- Required.
- Returns a funciton.
nextApplicationComponent: Next.App
(the first argument of a returned function)- Required.
- Returns a new React component for Next.js.
Redux (Flux) vs next-universal-storage
First of all, I recommend to use next-universal-storage hardly. This is for developers who want to set and get data outside React components. If you want to refer data in any components, you should use state management architectures such as Redux and Flux, and others.
next-universal-storage is useful when you want to share data between a client-side and server-side such as a unique request ID and language settings.
Contributing to next-universal-storage
Bug reports and pull requests are welcome on GitHub at https://github.com/jagaapple/next-universal-storage. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
Please read Contributing Guidelines before development and contributing.
License
The library is available as open source under the terms of the MIT License.
Copyright 2020 Jaga Apple. All rights reserved.
4 years ago