Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hydration fix #523

Merged
merged 20 commits into from
Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,16 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- uses: actions/setup-node@v1
- uses: actions/setup-node@v3
with:
node-version: '16.x'
registry-url: 'https://registry.npmjs.org'

- id: yarn-cache-dir-path
run: echo "::set-output name=dir::$(yarn cache dir)"
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT

- uses: actions/cache@v2
- uses: actions/cache@v3
with:
path: |
${{ steps.yarn-cache-dir-path.outputs.dir }}
Expand All @@ -42,6 +41,15 @@ jobs:
env:
CI: true

# FIXME Coverage report

- uses: actions/upload-artifact@v3
if: failure()
with:
path: |
packages/*/test-results
packages/*/coverage

- run: echo "TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV

- run: yarn publish:release ${TAG} --yes
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ lib
node_modules
npm-debug*
out
test-results
types
lerna-debug.log

Expand Down
2 changes: 1 addition & 1 deletion .lintstagedrc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"*.{js,jsx,ts,tsx}": ["yarn eslint", "git add"],
"*.{js,jsx,ts,tsx}": ["yarn lint", "git add"],
"*.{js,jsx,ts,tsx,css,scss,sass,less,md,yml,json}": ["yarn prettier", "git add"]
}
986 changes: 342 additions & 644 deletions README.md

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,19 @@
"test:quick": "lerna run test:quick --stream --concurrency=1",
"publish:release": "lerna publish --tag-version-prefix=\"\" --force-publish=* --no-push --no-git-tag-version",
"prettier": "prettier --write --ignore-path=.eslintignore --loglevel=warn",
"eslint": "eslint --cache --cache-location node_modules/.cache/eslint --fix",
"lint": "eslint --cache --cache-location .eslint/cache --fix",
"lint:all": "yarn eslint . && yarn prettier .",
"lint": "eslint --cache --cache-location node_modules/.cache/eslint --fix",
"lint:all": "yarn lint . && yarn prettier .",
"lint:staged": "lint-staged --debug"
},
"devDependencies": {
"eslint": "8.29.0",
"eslint": "8.33.0",
"eslint-config-ringcentral-typescript": "7.0.3",
"husky": "7.0.4",
"lerna": "4.0.0",
"lint-staged": "11.1.2",
"prettier": "2.5.1",
"rimraf": "3.0.2",
"typescript": "4.5.2"
"prettier": "2.8.3",
"rimraf": "4.1.2",
"typescript": "4.5.5"
},
"workspaces": [
"packages/*"
Expand All @@ -43,6 +42,7 @@
"license": "MIT",
"packageManager": "yarn@3.0.2",
"resolutions": {
"@types/react": "17.0.37"
"@types/react": "18.0.27",
"typescript": "4.5.5"
}
}
13 changes: 13 additions & 0 deletions packages/configs/playwright.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
/** @type {import('@playwright/test').PlaywrightTestConfig} */
module.exports = {
use: {
trace: process.env.CI ? 'retain-on-failure' : 'off',
video: 'retain-on-failure',
screenshot: 'on',
},
outputDir: process.cwd() + '/test-results/out',
reporter: [
['html', {outputFolder: process.cwd() + '/test-results/html', open: 'never'}],
['list'],
['junit', {outputFile: process.cwd() + '/test-results/junit.xml'}],
['json', {outputFile: process.cwd() + '/test-results/results.json'}],
],
webServer: {
command: 'yarn start',
port: 3000,
Expand Down
1 change: 0 additions & 1 deletion packages/demo-page/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
Expand Down
5 changes: 5 additions & 0 deletions packages/demo-page/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import('next').NextConfig} */
module.exports = {
// transpilePackages: ['next-redux-wrapper'], // @see https://nextjs.org/docs/advanced-features/compiler#module-transpilation
swcMinify: true,
};
16 changes: 8 additions & 8 deletions packages/demo-page/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@
"dependencies": {
"jsondiffpatch": "0.4.1",
"next-redux-wrapper": "*",
"react": "17.0.2",
"react-dom": "17.0.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-redux": "7.2.6",
"redux": "4.1.2",
"redux-logger": "3.0.6"
},
"devDependencies": {
"@playwright/test": "1.17.1",
"@types/react": "17.0.37",
"@types/react-dom": "17.0.11",
"@playwright/test": "1.30.0",
"@types/react": "18.0.27",
"@types/react-dom": "18.0.10",
"@types/react-redux": "7.1.20",
"@types/redux-logger": "3.0.9",
"next": "12.0.4",
"next": "13.1.6",
"next-redux-wrapper-configs": "*",
"playwright": "1.17.1",
"playwright": "1.30.0",
"rimraf": "3.0.2",
"typescript": "4.5.2"
"typescript": "4.9.5"
},
"author": "Kirill Konshin",
"repository": {
Expand Down
14 changes: 0 additions & 14 deletions packages/demo-page/src/components/reducer.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,11 @@
import {AnyAction} from 'redux';
import {HYDRATE} from 'next-redux-wrapper';
import {diff} from 'jsondiffpatch';

export interface State {
page: string;
}

const reducer = (state: State = {page: 'init'}, action: AnyAction) => {
switch (action.type) {
case HYDRATE:
const stateDiff = diff(state, action.payload) as any;
const wasBumpedOnClient = stateDiff?.page?.[0]?.endsWith('X');
console.log('HYDRATE action handler', {
stateDiff,
wasBumpedOnClient,
});
return {
...state,
...action.payload,
page: wasBumpedOnClient ? state.page : action.payload.page,
};
case 'PAGE':
return {...state, page: action.payload};
case 'BUMP':
Expand Down
6 changes: 3 additions & 3 deletions packages/demo-page/src/components/store.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {createStore, applyMiddleware, Store} from 'redux';
import logger from 'redux-logger';
import {createWrapper, Context} from 'next-redux-wrapper';
import {createWrapper} from 'next-redux-wrapper';
import reducer, {State} from './reducer';

export const makeStore = (context: Context) => {
const store = createStore(reducer, applyMiddleware(logger));
export const makeStore = ({context, reduxWrapperMiddleware}) => {
const store = createStore(reducer, applyMiddleware(...[process.browser ? logger : null, reduxWrapperMiddleware].filter(Boolean)));

if ((module as any).hot) {
(module as any).hot.accept('./reducer', () => {
Expand Down
12 changes: 10 additions & 2 deletions packages/demo-page/src/pages/_app.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import React, {FC} from 'react';
import {AppProps} from 'next/app';
import {Provider} from 'react-redux';
import {wrapper} from '../components/store';

const MyApp: FC<AppProps> = ({Component, pageProps}) => <Component {...pageProps} />;
const MyApp: FC<AppProps> = function MyApp({Component, pageProps}) {
const store = wrapper.useStore();
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
};

export default wrapper.withRedux(MyApp);
export default MyApp;
4 changes: 2 additions & 2 deletions packages/demo-page/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export interface ConnectedPageProps {
}

// Page itself is not connected to Redux Store, it has to render Provider to allow child components to connect to Redux Store
const Page: NextPage<ConnectedPageProps> = ({custom}) => {
const Page: NextPage<ConnectedPageProps> = ({custom, ...props}: any) => {
wrapper.useHydration(props);
const {page} = useSelector<State, State>(state => state);
return (
<div className="index">
Expand All @@ -23,7 +24,6 @@ const Page: NextPage<ConnectedPageProps> = ({custom}) => {
};

export const getServerSideProps = wrapper.getServerSideProps(store => async ({req}) => {
console.log('2. Page.getServerSideProps uses the store to dispatch things');
store.dispatch({
type: 'PAGE',
payload: 'was set in index page ' + req.url,
Expand Down
4 changes: 2 additions & 2 deletions packages/demo-page/src/pages/other.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import {State} from '../components/reducer';
import {wrapper} from '../components/store';

export const getStaticProps = wrapper.getStaticProps(store => async ({previewData}) => {
console.log('2. Page.getStaticProps uses the store to dispatch things');
store.dispatch({
type: 'PAGE',
payload: 'was set in other page ' + JSON.stringify({previewData}),
});
return {props: {}};
});

const OtherPage: NextPage<State> = () => {
const OtherPage: NextPage<State> = props => {
wrapper.useHydration(props);
const {page} = useSelector<State, State>(state => state);
const dispatch = useDispatch();
const bump = () => dispatch({type: 'BUMP'});
Expand Down
4 changes: 2 additions & 2 deletions packages/demo-page/src/pages/other2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ import {State} from '../components/reducer';
import {wrapper} from '../components/store';

export const getStaticProps = wrapper.getStaticProps(store => async ({previewData}) => {
console.log('2. Page.getStaticProps uses the store to dispatch things');
store.dispatch({
type: 'PAGE',
payload: 'was set in other (SECOND) page ' + JSON.stringify({previewData}),
});
return {props: {}};
});

const OtherPage: NextPage<State> = () => {
const OtherPage: NextPage<State> = props => {
wrapper.useHydration(props);
const {page} = useSelector<State, State>(state => state);
const dispatch = useDispatch();
const bump = () => dispatch({type: 'BUMP'});
Expand Down
3 changes: 2 additions & 1 deletion packages/demo-page/src/pages/pageProps.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {State} from '../components/reducer';
import {wrapper} from '../components/store';

const PropsPage: NextPage<State> = props => {
wrapper.useHydration(props);
return (
<div className="pageProps">
<p>Using Next.js default prop in a wrapped component.</p>
Expand All @@ -16,7 +17,7 @@ const PropsPage: NextPage<State> = props => {
);
};

PropsPage.getInitialProps = wrapper.getInitialPageProps(store => async () => ({
(PropsPage as any).getInitialProps = wrapper.getInitialPageProps(store => async () => ({
prop: 'foo',
}));

Expand Down
16 changes: 8 additions & 8 deletions packages/demo-page/tests/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import {test, expect, Page} from '@playwright/test';

const openPage = (page: Page, url = '/') => page.goto(`http://localhost:4000${url}`);
const openPage = (page: Page, baseURL: string | undefined, url = '/') => page.goto(`${baseURL}${url}`);

test('shows the page', async ({page}) => {
await openPage(page);
test('shows the page', async ({page, baseURL}) => {
await openPage(page, baseURL);

await page.waitForSelector('div.index');

await expect(page.locator('body')).toContainText('"page": "was set in index page /"');
await expect(page.locator('body')).toContainText('"custom": "custom"');
});

test('clicks the button', async ({page}) => {
await openPage(page, '/other');
test('clicks the button', async ({page, baseURL}) => {
await openPage(page, baseURL, '/other');

await page.waitForSelector('div.other');

Expand All @@ -26,10 +26,10 @@ test('clicks the button', async ({page}) => {
await expect(page.locator('body')).toContainText('"custom": "custom"');
});

test('initial page props', async ({page}) => {
await openPage(page, '/pageProps');
test('initial page props', async ({page, baseURL}) => {
await openPage(page, baseURL, '/pageProps');

await page.waitForSelector('div.pageProps');

await expect(page.locator('body')).toContainText('{"prop":"foo"}');
await expect(page.locator('body')).toContainText('"prop":"foo"');
});
1 change: 0 additions & 1 deletion packages/demo-redux-toolkit/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/// <reference types="next" />
/// <reference types="next/types/global" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
Expand Down
5 changes: 5 additions & 0 deletions packages/demo-redux-toolkit/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import('next').NextConfig} */
module.exports = {
// transpilePackages: ['next-redux-wrapper'], // @see https://nextjs.org/docs/advanced-features/compiler#module-transpilation
swcMinify: true,
};
15 changes: 9 additions & 6 deletions packages/demo-redux-toolkit/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@
"dependencies": {
"@reduxjs/toolkit": "1.8.6",
"next-redux-wrapper": "*",
"react": "17.0.2",
"react-dom": "17.0.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-redux": "7.2.6",
"redux": "4.1.2"
"redux": "4.1.2",
"redux-logger": "3.0.6"
},
"devDependencies": {
"@playwright/test": "1.17.1",
"next": "12.0.4",
"playwright": "1.17.1"
"@playwright/test": "1.30.0",
"@types/react": "18.0.27",
"@types/react-dom": "18.0.10",
"next": "13.1.6",
"playwright": "1.30.0"
},
"license": "MIT"
}
Loading