Skip to content

Commit

Permalink
Merge pull request #6 from mayank1513/use-storage-event
Browse files Browse the repository at this point in the history
Use-storage-event
  • Loading branch information
mayank1513 authored Dec 2, 2023
2 parents 5a67184 + 7c0052e commit afe30a1
Show file tree
Hide file tree
Showing 14 changed files with 89 additions and 43 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,6 @@ jobs:
run: pnpm build && pnpm publish-package
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }}

TOKEN: ${{ secrets.GITHUB_TOKEN }}
OWNER: ${{ github.event.repository.owner.login }}
REPO: ${{ github.event.repository.name }}
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
token: ${{ secrets.CODECOV_TOKEN }}
flags: fork-me
- uses: paambaati/[email protected]
continue-on-error: true
env:
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
with:
Expand Down
7 changes: 7 additions & 0 deletions examples/nextjs/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# nextjs-example

## 1.0.3

### Patch Changes

- Updated dependencies
- [email protected]

## 1.0.2

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion examples/nextjs/app/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ export const useMyStore = create<MyStoreType>()(
set(state => ({ ...state, _count }));
},
}),
{ name: "example", exclude: ["_count"] },
{ name: "example", exclude: ["_count"], storage: "cookies" },
),
);
8 changes: 4 additions & 4 deletions examples/nextjs/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nextjs-example",
"version": "1.0.2",
"version": "1.0.3",
"private": true,
"scripts": {
"dev": "next dev --port 3001",
Expand All @@ -13,12 +13,12 @@
"persist-and-sync": "workspace:*",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"zustand": "^4.4.6"
"zustand": "^4.4.7"
},
"devDependencies": {
"@next/eslint-plugin-next": "^14.0.3",
"@types/node": "^20.9.4",
"@types/react": "^18.2.38",
"@types/node": "^20.10.2",
"@types/react": "^18.2.41",
"@types/react-dom": "^18.2.17",
"eslint-config-custom": "workspace:*",
"tsconfig": "workspace:*",
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,md,css,scss}\""
},
"devDependencies": {
"@changesets/cli": "^2.26.2",
"eslint": "^8.54.0",
"@changesets/cli": "^2.27.1",
"eslint": "^8.55.0",
"prettier": "^3.1.0",
"tsconfig": "workspace:*",
"turbo": "^1.10.16"
Expand Down
6 changes: 6 additions & 0 deletions packages/persist-and-sync/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# persist-and-sync

## 1.1.1

### Patch Changes

- Updated internal sync mechanism

## 1.1.0

### Minor Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/persist-and-sync/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { act, cleanup, renderHook } from "@testing-library/react";

import { afterEach, describe, test } from "vitest";
import { useMyStore } from "./store";
import { useCookieStore, useMyStore } from "./store";

describe.concurrent("Setting state", () => {
afterEach(cleanup);
Expand All @@ -11,7 +11,7 @@ describe.concurrent("Setting state", () => {
});

test("test setting state", async ({ expect }) => {
const { result } = renderHook(() => useMyStore());
const { result } = renderHook(() => useCookieStore());
act(() => result.current.setCount(5));
expect(result.current.count).toBe(5);
expect(localStorage.getItem("example")).toBe('{"count":5}');
Expand Down
16 changes: 14 additions & 2 deletions packages/persist-and-sync/__tests__/store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { create } from "../vitest-setup";
import { create } from "../vitest.setup";
import { persistNSync } from "../src";

type MyStoreType = {
Expand All @@ -16,6 +16,18 @@ export const useMyStore = create<MyStoreType>(
setCount: count => set(state => ({ ...state, count })),
set_Count: _count => set(state => ({ ...state, _count })),
}),
{ name: "example", regExpToIgnore: /^_/ },
{ name: "example", exclude: [/^_/] },
),
);

export const useCookieStore = create<MyStoreType>(
persistNSync(
set => ({
count: 0,
_count: 0 /** skipped as it matches the regexp provided */,
setCount: count => set(state => ({ ...state, count })),
set_Count: _count => set(state => ({ ...state, _count })),
}),
{ name: "example", include: [/count/], exclude: [/^_/], storage: "cookies" },
),
);
38 changes: 34 additions & 4 deletions packages/persist-and-sync/createPackageJSON.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,42 @@
const fs = require("fs");
const path = require("path");
const packageJson = require(path.resolve(__dirname, "package.json"));
if (process.env.TOKEN) {
const { Octokit } = require("octokit");
// Octokit.js
// https://github.com/octokit/core.js#readme
const octokit = new Octokit({
auth: process.env.TOKEN,
});

const { devDependencies, scripts, ...newPackageJSON } = packageJson;
newPackageJSON.main = packageJson.main.split("/")[1];
newPackageJSON.types = packageJson.types.split("/")[1];
const octoOptions = {
owner: process.env.OWNER,
repo: process.env.REPO,
headers: {
"X-GitHub-Api-Version": "2022-11-28",
},
};
const tagName = `v${packageJson.version}`;
const name = `Release ${tagName}`;
/** Create a release */
octokit.request("POST /repos/{owner}/{repo}/releases", {
...octoOptions,
tag_name: tagName,
target_commitish: "main",
name,
draft: false,
prerelease: false,
generate_release_notes: true,
headers: {
"X-GitHub-Api-Version": "2022-11-28",
},
});
}
delete packageJson.scripts;
packageJson.main = packageJson.main.split("/")[1];
packageJson.types = packageJson.types.split("/")[1];

fs.writeFileSync(
path.resolve(__dirname, "dist", "package.json"),
JSON.stringify(newPackageJSON, null, 2),
JSON.stringify(packageJson, null, 2),
);
9 changes: 5 additions & 4 deletions packages/persist-and-sync/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "persist-and-sync",
"author": "Mayank Kumar Chaudhari <https://mayank-chaudhari.vercel.app>",
"version": "1.1.0",
"version": "1.1.1",
"description": "Zustand middleware to easily persist and sync Zustand state between tabs and windows",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand All @@ -26,13 +26,14 @@
},
"devDependencies": {
"@testing-library/react": "^14.1.2",
"@types/node": "^20.9.4",
"@types/node": "^20.10.2",
"@vitejs/plugin-react": "^4.2.0",
"@vitest/coverage-v8": "^0.34.6",
"jsdom": "^22.1.0",
"jsdom": "^23.0.1",
"octokit": "^3.1.2",
"typescript": "^5.3.2",
"vitest": "^0.34.6",
"zustand": "^4.4.6"
"zustand": "^4.4.7"
},
"peerDependencies": {
"zustand": "^3 || ^4"
Expand Down
31 changes: 9 additions & 22 deletions packages/persist-and-sync/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function getItem(options: PersistNSyncOptionsType) {
function setItem(options: PersistNSyncOptionsType, value: string) {
const { storage } = options;
if (storage === "cookies") {
document.cookie = `${options.name}=${value}; max-age=31536000`;
document.cookie = `${options.name}=${value}; max-age=31536000; SameSite=Strict;`;
}
if (storage === "sessionStorage") sessionStorage.setItem(options.name, value);
else localStorage.setItem(options.name, value);
Expand All @@ -48,27 +48,23 @@ export const persistNSync: PersistNSyncType = (stateCreator, options) => (set, g
/** timeout 0 is enough. timeout 100 is added to avoid server and client render content mismatch error */
if (savedState) setTimeout(() => set({ ...get(), ...JSON.parse(savedState) }), 100);

const channel = globalThis.BroadcastChannel ? new BroadcastChannel(name) : undefined;

const set_: typeof set = (newStateOrPartialOrFunction, replace) => {
const prevState = get() as { [k: string]: any };
set(newStateOrPartialOrFunction, replace);
const newState = get() as { [k: string]: any };
saveAndSync({ newState, prevState, channel, options });
saveAndSync({ newState, options });
};

if (channel) {
channel.onmessage = e => {
set({ ...get(), ...e.data });
};
}
window.addEventListener("storage", e => {
if (e.key === name) {
const newState = JSON.parse(e.newValue || "{}");
set({ ...get(), ...newState });
}
});
return stateCreator(set_, get, store);
};

interface SaveAndSyncProps {
newState: { [k: string]: any };
prevState: { [k: string]: any };
channel?: BroadcastChannel;
options: PersistNSyncOptionsType;
}

Expand Down Expand Up @@ -107,21 +103,12 @@ const getKeysToPersistAndSyncMemoised = (() => {
};
})();

function saveAndSync({ newState, prevState, channel, options }: SaveAndSyncProps) {
function saveAndSync({ newState, options }: SaveAndSyncProps) {
const keysToPersistAndSync = getKeysToPersistAndSyncMemoised(Object.keys(newState), options);

if (keysToPersistAndSync.length === 0) return;

const stateToStore: { [k: string]: any } = {};
keysToPersistAndSync.forEach(key => (stateToStore[key] = newState[key]));
setItem(options, JSON.stringify(stateToStore));

if (!channel) return;
const stateUpdates: { [k: string]: any } = {};
keysToPersistAndSync.forEach(key => {
if (newState[key] !== prevState[key]) stateUpdates[key] = newState[key];
});
if (Object.keys(stateUpdates).length) {
channel?.postMessage(stateUpdates);
}
}
2 changes: 1 addition & 1 deletion packages/persist-and-sync/vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export default defineConfig({
test: {
environment: "jsdom",
globals: true,
setupFiles: ["vitest-setup.ts"],
setupFiles: ["vitest.setup.ts"],
coverage: {
reporter: ["text", "json", "clover", "html"],
},
Expand Down
File renamed without changes.

0 comments on commit afe30a1

Please sign in to comment.