Skip to content

Commit bfac2a3

Browse files
committed
split into smaller components
1 parent 34e4e6b commit bfac2a3

15 files changed

+1654
-3131
lines changed

.babelrc.js

Lines changed: 0 additions & 14 deletions
This file was deleted.

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
node_modules
22
dist
3-
.rts2*
3+
types

package.json

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,21 @@
44
"description": "Lazy Hydration for Server Rendered React Components",
55
"source": "src/index.tsx",
66
"main": "dist/index.js",
7-
"module": "dist/index.m.js",
8-
"typings": "dist/index.d.ts",
7+
"module": "dist/index.esm.js",
8+
"browser": {
9+
"dist/index.js": "dist/index.browser.js",
10+
"dist/index.esm.js": "dist/index.brower.esm.js"
11+
},
12+
"typings": "types/index.d.ts",
913
"author": {
1014
"name": "Hadeeb Farhan",
1115
"email": "hadeebfarhan1@gmail.com"
1216
},
1317
"license": "MIT",
1418
"sideEffects": false,
1519
"files": [
16-
"src",
17-
"dist"
20+
"dist",
21+
"types"
1822
],
1923
"repository": {
2024
"type": "git",
@@ -31,42 +35,58 @@
3135
"hydration"
3236
],
3337
"scripts": {
34-
"build": "microbundle build --raw -f es,cjs",
38+
"prebuild": "rimraf dist types",
39+
"build": "rollup -c",
40+
"postbuild": "tsc",
3541
"prepublishOnly": "yarn build",
3642
"lint": "eslint src/** --fix"
3743
},
44+
"dependencies": {
45+
"@babel/runtime": "^7.9.2"
46+
},
3847
"peerDependencies": {
3948
"react": ">=16.8.0"
4049
},
4150
"devDependencies": {
42-
"@types/react": "^16.9.17",
43-
"@typescript-eslint/eslint-plugin": "^2.16.0",
44-
"@typescript-eslint/parser": "^2.16.0",
45-
"babel-eslint": "^10.0.3",
51+
"@babel/core": "^7.9.0",
52+
"@babel/helper-module-imports": "^7.8.3",
53+
"@babel/plugin-transform-react-jsx": "^7.9.4",
54+
"@babel/plugin-transform-runtime": "^7.9.0",
55+
"@babel/preset-env": "^7.9.5",
56+
"@babel/preset-typescript": "^7.9.0",
57+
"@types/react": "^16.9.32",
58+
"@typescript-eslint/eslint-plugin": "^2.27.0",
59+
"@typescript-eslint/parser": "^2.27.0",
60+
"babel-eslint": "^10.1.0",
61+
"babel-plugin-macros": "^2.8.0",
4662
"eslint": "^6.8.0",
47-
"eslint-config-prettier": "^6.9.0",
48-
"eslint-config-react-app": "^5.1.0",
49-
"eslint-plugin-flowtype": "^4.6.0",
50-
"eslint-plugin-import": "^2.20.0",
63+
"eslint-config-prettier": "^6.10.1",
64+
"eslint-config-react-app": "^5.2.1",
65+
"eslint-plugin-flowtype": "^4.7.0",
66+
"eslint-plugin-import": "^2.20.2",
5167
"eslint-plugin-jsx-a11y": "^6.2.3",
5268
"eslint-plugin-prettier": "^3.1.2",
53-
"eslint-plugin-react": "^7.18.0",
54-
"eslint-plugin-react-hooks": "^2.3.0",
55-
"eslint-plugin-simple-import-sort": "^5.0.0",
56-
"husky": "^4.0.10",
57-
"lint-staged": "^9.5.0",
58-
"microbundle": "^0.11.0",
69+
"eslint-plugin-react": "^7.19.0",
70+
"eslint-plugin-react-hooks": "^3.0.0",
71+
"eslint-plugin-simple-import-sort": "^5.0.2",
72+
"husky": "^4.2.3",
73+
"lint-staged": "^10.1.2",
5974
"prettier": "^1.19.1",
60-
"react": "^16.12.0",
61-
"typescript": "^3.7.5"
75+
"react": "^16.13.1",
76+
"rimraf": "^3.0.2",
77+
"rollup": "^2.4.0",
78+
"rollup-plugin-babel": "^4.4.0",
79+
"rollup-plugin-node-resolve": "^5.2.0",
80+
"rollup-plugin-replace": "^2.2.0",
81+
"typescript": "^3.8.3"
6282
},
6383
"husky": {
6484
"hooks": {
6585
"pre-commit": "lint-staged"
6686
}
6787
},
6888
"lint-staged": {
69-
"*.js": [
89+
"*.{js,ts,tsx}": [
7090
"eslint --fix",
7191
"git add"
7292
]

rollup.config.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import babel from "rollup-plugin-babel";
2+
import nodeResolve from "rollup-plugin-node-resolve";
3+
import replace from "rollup-plugin-replace";
4+
5+
import pkg from "./package.json";
6+
7+
const extensions = [".tsx", ".ts", ".js"];
8+
9+
const external = [
10+
...Object.keys(pkg.peerDependencies || {}),
11+
...Object.keys(pkg.dependencies || {})
12+
];
13+
14+
const loose = true;
15+
16+
const createBabelConfig = isESM => {
17+
return {
18+
presets: [
19+
["@babel/preset-typescript", { loose, modules: false }],
20+
["@babel/preset-env", { loose, modules: false }]
21+
],
22+
plugins: [
23+
"babel-plugin-macros",
24+
["@babel/plugin-transform-runtime", { useESModules: isESM }],
25+
"@babel/plugin-transform-react-jsx"
26+
]
27+
};
28+
};
29+
30+
const createExternalPredicate = externalArr => {
31+
if (externalArr.length === 0) {
32+
return () => false;
33+
}
34+
const pattern = new RegExp(`^(${externalArr.join("|")})($|/)`);
35+
return id => pattern.test(id);
36+
};
37+
38+
const createConfig = ({ output, browser = false, isESM = false }) => ({
39+
input: "src/index.tsx",
40+
output: output.map(format => ({ exports: "named", ...format })),
41+
external: createExternalPredicate(external),
42+
plugins: [
43+
nodeResolve({ extensions }),
44+
babel({ extensions, runtimeHelpers: true, ...createBabelConfig(isESM) }),
45+
replace({
46+
"process.env.BROWSER": JSON.stringify(browser)
47+
})
48+
]
49+
});
50+
51+
export default [
52+
createConfig({
53+
output: [{ file: pkg.main, format: "cjs" }]
54+
}),
55+
createConfig({
56+
output: [{ file: pkg.module, format: "esm" }],
57+
isESM: true
58+
}),
59+
createConfig({
60+
output: [{ file: pkg.browser[pkg.main], format: "cjs" }],
61+
browser: true
62+
}),
63+
createConfig({
64+
output: [{ file: pkg.browser[pkg.module], format: "esm" }],
65+
browser: true,
66+
isESM: true
67+
})
68+
];

src/constants.macro.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const isBrowser: boolean;
2+
export const isDev: boolean;

src/constants.macro.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//@ts-check
2+
const { createMacro, MacroError } = require("babel-plugin-macros");
3+
const { addDefault } = require("@babel/helper-module-imports");
4+
5+
module.exports = createMacro(function({ references, babel }) {
6+
const templ = babel.template;
7+
8+
for (let key in references) {
9+
const refs = references[key];
10+
/**
11+
* @type {string}
12+
*/
13+
let str;
14+
15+
switch (key) {
16+
case "isBrowser": {
17+
const { name: insertedName } = addDefault(refs[0], "./isBrowser", {
18+
nameHint: "isBrowser"
19+
});
20+
str = `process.env.BROWSER || ${insertedName}`;
21+
break;
22+
}
23+
case "isDev":
24+
str = "'production' !== process.env.NODE_ENV";
25+
break;
26+
default:
27+
throw new MacroError(`unknown constant ${key}`);
28+
}
29+
30+
const template = templ(str, {
31+
placeholderPattern: false
32+
});
33+
/**
34+
* @type {babel.types.Expression}
35+
*/
36+
// @ts-ignore
37+
const expression = template().expression;
38+
39+
refs.forEach(ref => {
40+
ref.replaceWith(expression);
41+
});
42+
}
43+
});

src/index.tsx

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
import * as React from "react";
22

3+
import { isDev } from "./constants.macro";
4+
import { warnAboutDeprecation } from "./utils";
5+
6+
export * from "./onEvents";
7+
export * from "./ssrOnly";
8+
export * from "./whenIdle";
9+
export * from "./whenVisible";
10+
311
export type LazyProps = {
412
ssrOnly?: boolean;
513
whenIdle?: boolean;
@@ -43,13 +51,7 @@ const LazyHydrate: React.FunctionComponent<Props> = function(props) {
4351

4452
const { ssrOnly, whenIdle, whenVisible, on = [], children, ...rest } = props;
4553

46-
if (
47-
process.env.NODE_ENV !== "production" &&
48-
!ssrOnly &&
49-
!whenIdle &&
50-
!whenVisible &&
51-
!on.length
52-
) {
54+
if (isDev && !ssrOnly && !whenIdle && !whenVisible && !on.length) {
5355
console.error(
5456
`LazyHydration: Enable atleast one trigger for hydration.\n` +
5557
`If you don't want to hydrate, use ssrOnly`
@@ -63,6 +65,11 @@ const LazyHydrate: React.FunctionComponent<Props> = function(props) {
6365
}
6466
}, []);
6567

68+
React.useEffect(() => {
69+
warnAboutDeprecation({ on, ssrOnly, whenIdle, whenVisible });
70+
// eslint-disable-next-line react-hooks/exhaustive-deps
71+
}, []);
72+
6673
React.useEffect(() => {
6774
if (ssrOnly || hydrated) return;
6875
const cleanupFns: VoidFunction[] = [];

src/isBrowser.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const isBrowser = typeof document !== "undefined";
2+
export default isBrowser;

src/onEvents.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import * as React from "react";
2+
3+
import { defaultStyle, useHydrationState } from "./utils";
4+
5+
type Props = Omit<
6+
React.HTMLProps<HTMLDivElement>,
7+
"dangerouslySetInnerHTML"
8+
> & { on?: (keyof HTMLElementEventMap)[] | keyof HTMLElementEventMap };
9+
10+
function HydrateOn({ children, on, ...rest }: Props) {
11+
const [childRef, hydrated, hydrate] = useHydrationState();
12+
13+
React.useEffect(() => {
14+
if (hydrated) return;
15+
16+
const cleanupFns: VoidFunction[] = [];
17+
18+
function cleanup() {
19+
for (let i = 0; i < cleanupFns.length; i++) {
20+
cleanupFns[i]();
21+
}
22+
}
23+
24+
let events = Array.isArray(on) ? on.slice() : [on];
25+
26+
events.forEach(event => {
27+
childRef.current.addEventListener(event, hydrate, {
28+
once: true,
29+
capture: true,
30+
passive: true
31+
});
32+
cleanupFns.push(() => {
33+
childRef.current.removeEventListener(event, hydrate, { capture: true });
34+
});
35+
});
36+
37+
return cleanup;
38+
}, [hydrated, hydrate, on, childRef]);
39+
40+
if (hydrated) {
41+
return (
42+
<div ref={childRef} style={defaultStyle} {...rest}>
43+
{children}
44+
</div>
45+
);
46+
} else {
47+
return (
48+
<div
49+
ref={childRef}
50+
style={defaultStyle}
51+
suppressHydrationWarning
52+
{...rest}
53+
dangerouslySetInnerHTML={{ __html: "" }}
54+
/>
55+
);
56+
}
57+
}
58+
59+
export { HydrateOn };

src/ssrOnly.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as React from "react";
2+
3+
import { defaultStyle, useHydrationState } from "./utils";
4+
5+
type Props = Omit<React.HTMLProps<HTMLDivElement>, "dangerouslySetInnerHTML">;
6+
7+
function SsrOnly({ children, ...rest }: Props) {
8+
const [childRef, hydrated] = useHydrationState();
9+
10+
if (hydrated) {
11+
return (
12+
<div ref={childRef} style={defaultStyle} {...rest}>
13+
{children}
14+
</div>
15+
);
16+
} else {
17+
return (
18+
<div
19+
ref={childRef}
20+
style={defaultStyle}
21+
suppressHydrationWarning
22+
{...rest}
23+
dangerouslySetInnerHTML={{ __html: "" }}
24+
/>
25+
);
26+
}
27+
}
28+
29+
export { SsrOnly };

0 commit comments

Comments
 (0)