Skip to content

Commit

Permalink
Hydration fix (#523)
Browse files Browse the repository at this point in the history
* Hydration fix
* HOCs removed
* Proper GIAP+GSP/GSSP
* Removed HYDRATE
* Coverage

---------

Co-authored-by: bjoluc <mail@bjoluc.de>
  • Loading branch information
kirill-konshin and bjoluc authored Feb 3, 2023
1 parent 726d0d1 commit 29fa507
Show file tree
Hide file tree
Showing 63 changed files with 11,747 additions and 16,724 deletions.
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

0 comments on commit 29fa507

Please sign in to comment.