├── .gitignore
├── index.js
├── docs
├── favicon.ico
├── manifest.json
├── precache-manifest.f353fe2dcce57fdbfff016a75e042fe3.js
├── asset-manifest.json
├── service-worker.js
├── static
│ ├── css
│ │ ├── main.0f84021f.chunk.css
│ │ └── main.0f84021f.chunk.css.map
│ └── js
│ │ ├── runtime~main.46fcdfae.js
│ │ ├── runtime~main.46fcdfae.js.map
│ │ ├── main.066f72df.chunk.js
│ │ └── main.066f72df.chunk.js.map
└── index.html
├── prettier.config.js
├── demo-app
├── public
│ ├── favicon.ico
│ ├── manifest.json
│ └── index.html
├── README.md
├── src
│ ├── App.test.js
│ ├── index.js
│ ├── App.css
│ ├── components
│ │ ├── NoPrefetchApp
│ │ │ └── index.js
│ │ ├── OnRenderPrefetchApp
│ │ │ └── index.js
│ │ └── NetworkInspector
│ │ │ └── index.js
│ ├── index.css
│ ├── App.js
│ └── serviceWorker.js
├── .gitignore
└── package.json
├── .babelrc
├── src
├── index.js
└── prefetcher.js
├── LICENSE
├── package.json
├── README.md
└── test
└── prefetcher.test.js
/.gitignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
3 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | export * from './dist/index';
2 | export { default } from './dist/index';
3 |
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manojVivek/react-prefetcher/HEAD/docs/favicon.ico
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | singleQuote: true,
3 | trailingComma: 'es5',
4 | };
5 |
--------------------------------------------------------------------------------
/demo-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/manojVivek/react-prefetcher/HEAD/demo-app/public/favicon.ico
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-react", "@babel/preset-env"],
3 | "plugins": ["@babel/plugin-proposal-class-properties"]
4 | }
--------------------------------------------------------------------------------
/demo-app/README.md:
--------------------------------------------------------------------------------
1 | ## React-prefetcher Demo App
2 |
3 | This app can be previewed here: https://manojvivek.github.io/react-prefetcher/
4 |
--------------------------------------------------------------------------------
/demo-app/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render( , div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/docs/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/demo-app/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/demo-app/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Prefetcher from './prefetcher';
3 |
4 | export default Prefetcher;
5 |
6 | export const OnRenderPrefetcher = ({ link, ...other }) => (
7 |
8 | );
9 |
10 | export const OnHoverPrefetcher = ({ link, ...other }) => (
11 |
12 | );
13 |
14 | export const OnClickPrefetcher = ({ link, ...other }) => (
15 |
16 | );
17 |
--------------------------------------------------------------------------------
/demo-app/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render( , document.getElementById('root'));
8 |
9 | // If you want your app to work offline and load faster, you can change
10 | // unregister() to register() below. Note this comes with some pitfalls.
11 | // Learn more about service workers: https://bit.ly/CRA-PWA
12 | serviceWorker.unregister();
13 |
--------------------------------------------------------------------------------
/demo-app/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 40vmin;
8 | pointer-events: none;
9 | }
10 |
11 | .App-header {
12 | background-color: #282c34;
13 | min-height: 100vh;
14 | display: flex;
15 | flex-direction: column;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: calc(10px + 2vmin);
19 | color: white;
20 | }
21 |
22 | .App-link {
23 | color: #61dafb;
24 | }
25 |
26 | @keyframes App-logo-spin {
27 | from {
28 | transform: rotate(0deg);
29 | }
30 | to {
31 | transform: rotate(360deg);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/demo-app/src/components/NoPrefetchApp/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class NoPrefetchApp extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | this.state = { clicked: false };
7 | }
8 |
9 | render() {
10 | return (
11 |
12 |
this.setState({ clicked: true })}
15 | >
16 | Click to show image
17 |
18 | {this.state.clicked ? (
19 |
26 | ) : null}
27 |
28 | );
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/demo-app/src/components/OnRenderPrefetchApp/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Prefetcher from 'react-prefetcher';
3 |
4 | export default class OnRenderPrefetchApp extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.state = { clicked: false };
8 | this.imageUrl =
9 | 'https://assets.imgix.net/examples/kingfisher.jpg?w=200&rand=' +
10 | this.props.rand;
11 | }
12 |
13 | render() {
14 | return (
15 |
16 |
17 | this.setState({ clicked: true })}
20 | >
21 | Click to show image
22 |
23 |
24 | {this.state.clicked ?
: null}
25 |
26 | );
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/docs/precache-manifest.f353fe2dcce57fdbfff016a75e042fe3.js:
--------------------------------------------------------------------------------
1 | self.__precacheManifest = (self.__precacheManifest || []).concat([
2 | {
3 | revision: '45e6beacb7f569ac0c559ef2e02caac9',
4 | url: 'https://manojvivek.github.io/react-prefetcher/index.html',
5 | },
6 | {
7 | revision: 'f47b8a7839495d1ac2ff',
8 | url:
9 | 'https://manojvivek.github.io/react-prefetcher/static/css/main.0f84021f.chunk.css',
10 | },
11 | {
12 | revision: 'f295713939b9d62a5fc3',
13 | url:
14 | 'https://manojvivek.github.io/react-prefetcher/static/js/2.dcc8df9a.chunk.js',
15 | },
16 | {
17 | revision: 'f47b8a7839495d1ac2ff',
18 | url:
19 | 'https://manojvivek.github.io/react-prefetcher/static/js/main.066f72df.chunk.js',
20 | },
21 | {
22 | revision: 'aca3f9a7930a1c37a08b',
23 | url:
24 | 'https://manojvivek.github.io/react-prefetcher/static/js/runtime~main.46fcdfae.js',
25 | },
26 | ]);
27 |
--------------------------------------------------------------------------------
/demo-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-prefetcher-demo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "homepage": "https://manojvivek.github.io/react-prefetcher/",
6 | "dependencies": {
7 | "react": "^16.8.6",
8 | "react-dom": "^16.8.6",
9 | "react-prefetcher": "^1.0.3",
10 | "react-scripts": "3.0.1"
11 | },
12 | "scripts": {
13 | "start": "react-scripts start",
14 | "build": "PUBLIC_URL=https://manojvivek.github.io/react-prefetcher react-scripts build && rm -rf ../docs && mv build ../docs",
15 | "test": "react-scripts test",
16 | "eject": "react-scripts eject"
17 | },
18 | "eslintConfig": {
19 | "extends": "react-app"
20 | },
21 | "browserslist": {
22 | "production": [
23 | ">0.2%",
24 | "not dead",
25 | "not op_mini all"
26 | ],
27 | "development": [
28 | "last 1 chrome version",
29 | "last 1 firefox version",
30 | "last 1 safari version"
31 | ]
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Manoj Vivek
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/asset-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "files": {
3 | "main.css": "https://manojvivek.github.io/react-prefetcher/static/css/main.0f84021f.chunk.css",
4 | "main.js": "https://manojvivek.github.io/react-prefetcher/static/js/main.066f72df.chunk.js",
5 | "main.js.map": "https://manojvivek.github.io/react-prefetcher/static/js/main.066f72df.chunk.js.map",
6 | "runtime~main.js": "https://manojvivek.github.io/react-prefetcher/static/js/runtime~main.46fcdfae.js",
7 | "runtime~main.js.map": "https://manojvivek.github.io/react-prefetcher/static/js/runtime~main.46fcdfae.js.map",
8 | "static/js/2.dcc8df9a.chunk.js": "https://manojvivek.github.io/react-prefetcher/static/js/2.dcc8df9a.chunk.js",
9 | "static/js/2.dcc8df9a.chunk.js.map": "https://manojvivek.github.io/react-prefetcher/static/js/2.dcc8df9a.chunk.js.map",
10 | "index.html": "https://manojvivek.github.io/react-prefetcher/index.html",
11 | "precache-manifest.f353fe2dcce57fdbfff016a75e042fe3.js": "https://manojvivek.github.io/react-prefetcher/precache-manifest.f353fe2dcce57fdbfff016a75e042fe3.js",
12 | "service-worker.js": "https://manojvivek.github.io/react-prefetcher/service-worker.js",
13 | "static/css/main.0f84021f.chunk.css.map": "https://manojvivek.github.io/react-prefetcher/static/css/main.0f84021f.chunk.css.map"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/demo-app/src/components/NetworkInspector/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class NetworkInspector extends React.Component {
4 | constructor(props) {
5 | super(props);
6 | this.state = { requests: [] };
7 | }
8 |
9 | componentDidMount() {
10 | this.intervalHandle = setInterval(this._refreshList, 200);
11 | }
12 |
13 | componentWillUnmount() {
14 | clearInterval(this.intervalHandle);
15 | }
16 |
17 | _refreshList = () => {
18 | this.setState({
19 | requests: performance
20 | .getEntriesByType('resource')
21 | .filter(entry => entry.name.indexOf(this.props.filter) > -1),
22 | });
23 | };
24 |
25 | render() {
26 | return (
27 |
28 |
Network Inspector:
29 |
30 |
31 | Time from Page load(ms)
32 | Resource URL
33 | Time Taken to Download(ms)
34 |
35 | {this.state.requests.map(request => (
36 |
37 | {Math.round(request.startTime)}
38 | {request.name}
39 |
40 | {Math.round(request.duration)}
41 | {request.duration < 10 && '(from cache)'}
42 |
43 |
44 | ))}
45 |
46 |
47 | );
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/docs/service-worker.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Welcome to your Workbox-powered service worker!
3 | *
4 | * You'll need to register this file in your web app and you should
5 | * disable HTTP caching for this file too.
6 | * See https://goo.gl/nhQhGp
7 | *
8 | * The rest of the code is auto-generated. Please don't update this file
9 | * directly; instead, make changes to your Workbox build configuration
10 | * and re-run your build process.
11 | * See https://goo.gl/2aRDsh
12 | */
13 |
14 | importScripts(
15 | 'https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js'
16 | );
17 |
18 | importScripts(
19 | 'https://manojvivek.github.io/react-prefetcher/precache-manifest.f353fe2dcce57fdbfff016a75e042fe3.js'
20 | );
21 |
22 | self.addEventListener('message', event => {
23 | if (event.data && event.data.type === 'SKIP_WAITING') {
24 | self.skipWaiting();
25 | }
26 | });
27 |
28 | workbox.core.clientsClaim();
29 |
30 | /**
31 | * The workboxSW.precacheAndRoute() method efficiently caches and responds to
32 | * requests for URLs in the manifest.
33 | * See https://goo.gl/S9QRab
34 | */
35 | self.__precacheManifest = [].concat(self.__precacheManifest || []);
36 | workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
37 |
38 | workbox.routing.registerNavigationRoute(
39 | workbox.precaching.getCacheKeyForURL(
40 | 'https://manojvivek.github.io/react-prefetcher/index.html'
41 | ),
42 | {
43 | blacklist: [/^\/_/, /\/[^\/]+\.[^\/]+$/],
44 | }
45 | );
46 |
--------------------------------------------------------------------------------
/demo-app/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | color: #3e3e3e;
3 | margin: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
5 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
13 | monospace;
14 | }
15 |
16 | .wrapper {
17 | display: flex;
18 | }
19 |
20 | .left {
21 | flex: 0 0 30%;
22 | }
23 |
24 | .right {
25 | flex: 1;
26 | }
27 |
28 | table {
29 | border-collapse: collapse;
30 | width: 100%;
31 | }
32 |
33 | th,
34 | td {
35 | text-align: left;
36 | padding: 8px;
37 | }
38 |
39 | tr:nth-child(even) {
40 | background-color: #f2f2f2;
41 | }
42 |
43 | .cta-button {
44 | padding: 10px 20px;
45 | background: cornflowerblue;
46 | width: fit-content;
47 | margin: 0 auto 10px;
48 | text-transform: uppercase;
49 | color: white;
50 | cursor: pointer;
51 | }
52 |
53 | .section {
54 | border: 2px solid grey;
55 | margin: 20px;
56 | padding: 20px;
57 | min-height: 200px;
58 | min-width: 244px;
59 | }
60 |
61 | .header {
62 | text-align: left;
63 | margin: 20px;
64 | }
65 |
66 | .title {
67 | font-size: 30px;
68 | font-weight: bold;
69 | }
70 |
71 | .code-link {
72 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
73 | monospace;
74 | color: inherit;
75 | text-decoration: none;
76 | }
77 |
--------------------------------------------------------------------------------
/demo-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | React-prefetcher Demo App
23 |
24 |
25 | You need to enable JavaScript to run this app.
26 |
27 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/demo-app/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './App.css';
3 | import NetworkInspector from './components/NetworkInspector';
4 | import NoPrefetchApp from './components/NoPrefetchApp';
5 | import OnRenderPrefetchApp from './components/OnRenderPrefetchApp';
6 |
7 | class App extends React.Component {
8 | noPrefetchRand = Math.random();
9 | onRenderPrefetchRand = Math.random();
10 |
11 | render() {
12 | return (
13 |
14 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | );
54 | }
55 | }
56 |
57 | export default App;
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-prefetcher",
3 | "version": "1.1.2",
4 | "description": "A react library providing components that help with interaction-based asset pre-fetching.",
5 | "main": "dist/index.js",
6 | "scripts": {
7 | "test": "nyc mocha --require @babel/register --require jsdom-global/register",
8 | "test-dev": "mocha --require @babel/register --require @babel/polyfill --require jsdom-global/register --watch",
9 | "build": "babel src --out-dir dist",
10 | "dev": "babel src --out-dir dist --watch",
11 | "prebuild": "rm -rf dist/*",
12 | "prepublish": "npm run build",
13 | "release": "np"
14 | },
15 | "files": [
16 | "dist"
17 | ],
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/manojVivek/react-prefetcher.git"
21 | },
22 | "keywords": [
23 | "prefetch",
24 | "performance",
25 | "preload",
26 | "resource",
27 | "hint",
28 | "web",
29 | "performance",
30 | "speed",
31 | "link",
32 | "cache",
33 | "react"
34 | ],
35 | "author": "Manoj Vivek (https://github.com/manojVivek)",
36 | "license": "MIT",
37 | "bugs": {
38 | "url": "https://github.com/manojVivek/react-prefetcher/issues"
39 | },
40 | "homepage": "https://github.com/manojVivek/react-prefetcher#readme",
41 | "devDependencies": {
42 | "@babel/cli": "^7.4.4",
43 | "@babel/core": "^7.4.5",
44 | "@babel/plugin-proposal-class-properties": "^7.4.4",
45 | "@babel/polyfill": "^7.4.4",
46 | "@babel/preset-env": "^7.4.5",
47 | "@babel/preset-react": "^7.0.0",
48 | "@babel/register": "^7.4.4",
49 | "chai": "^4.2.0",
50 | "chai-enzyme": "^1.0.0-beta.1",
51 | "chai-spies": "^1.0.0",
52 | "enzyme": "^3.10.0",
53 | "enzyme-adapter-react-16": "^1.14.0",
54 | "husky": "^2.4.0",
55 | "jsdom": "15.1.1",
56 | "jsdom-global": "3.0.2",
57 | "mocha": "^6.1.4",
58 | "np": "^5.0.3",
59 | "nyc": "^14.1.1",
60 | "prettier": "^1.18.2",
61 | "pretty-quick": "^1.11.0",
62 | "react": "^16.8.6",
63 | "react-dom": "^16.8.6"
64 | },
65 | "peerDependencies": {
66 | "react": "^16.8.6",
67 | "react-dom": "^16.8.6"
68 | },
69 | "husky": {
70 | "hooks": {
71 | "pre-commit": "pretty-quick --staged"
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/prefetcher.js:
--------------------------------------------------------------------------------
1 | import React, { Fragment } from 'react';
2 |
3 | const loadedUrls = {};
4 | export default class Prefetcher extends React.Component {
5 | constructor(props) {
6 | super(props);
7 | this.state = {
8 | rendered: false,
9 | hovered: false,
10 | clicked: false,
11 | };
12 | }
13 |
14 | _delay = this.props.delayMs || 500;
15 |
16 | timeoutHandles = [];
17 |
18 | _eventHappened = event =>
19 | this.timeoutHandles.push(
20 | setTimeout(() => this.setState({ [event + 'ed']: true }), this._delay)
21 | );
22 |
23 | componentDidMount() {
24 | this._eventHappened('render');
25 | }
26 |
27 | componentWillUnmount() {
28 | for (const handle of this.timeoutHandles) {
29 | clearTimeout(handle);
30 | }
31 | }
32 |
33 | render() {
34 | return (
35 |
36 | {this.props.children && (
37 | this._eventHappened('hover')}
39 | onClick={() => this._eventHappened('click')}
40 | className={this.props.className}
41 | style={{ width: 'max-content', ...this.props.style }}
42 | >
43 | {this.props.children}
44 |
45 | )}
46 | {this.state.rendered && this._prefetchAssets(this.props.onRenderAssets)}
47 | {this.state.hovered && this._prefetchAssets(this.props.onHoverAssets)}
48 | {this.state.clicked && this._prefetchAssets(this.props.onClickAssets)}
49 |
50 | );
51 | }
52 |
53 | _prefetchAssets = assets => {
54 | if (!assets) {
55 | return null;
56 | }
57 | if (assets.constructor !== Array) {
58 | return this._renderPrefetch(assets);
59 | }
60 | return assets.map(this._renderPrefetch).filter(Boolean);
61 | };
62 |
63 | _renderPrefetch = href => {
64 | if (typeof href === 'object') {
65 | this._processCustomFetcher(href);
66 | return null;
67 | }
68 |
69 | if (!href || loadedUrls[href]) {
70 | return;
71 | }
72 | return (
73 | (loadedUrls[href] = true)}
78 | />
79 | );
80 | };
81 |
82 | _processCustomFetcher = config => {
83 | if (typeof config.fetcher !== 'function') {
84 | console.warn('Invalid config to prefetch:', config);
85 | return;
86 | }
87 | if (loadedUrls[config.href]) {
88 | return;
89 | }
90 | config.fetcher();
91 | loadedUrls[config.href] = true;
92 | };
93 | }
94 |
--------------------------------------------------------------------------------
/docs/static/css/main.0f84021f.chunk.css:
--------------------------------------------------------------------------------
1 | body {
2 | color: #3e3e3e;
3 | margin: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
5 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 | code {
10 | font-family: source-code-pro, Menlo, Monaco, Consolas, Courier New, monospace;
11 | }
12 | .wrapper {
13 | display: flex;
14 | }
15 | .left {
16 | flex: 0 0 30%;
17 | }
18 | .right {
19 | flex: 1 1;
20 | }
21 | table {
22 | border-collapse: collapse;
23 | width: 100%;
24 | }
25 | td,
26 | th {
27 | text-align: left;
28 | padding: 8px;
29 | }
30 | tr:nth-child(2n) {
31 | background-color: #f2f2f2;
32 | }
33 | .cta-button {
34 | padding: 10px 20px;
35 | background: #6495ed;
36 | width: -webkit-fit-content;
37 | width: -moz-fit-content;
38 | width: fit-content;
39 | margin: 0 auto 10px;
40 | text-transform: uppercase;
41 | color: #fff;
42 | cursor: pointer;
43 | }
44 | .section {
45 | border: 2px solid grey;
46 | margin: 20px;
47 | padding: 20px;
48 | min-height: 200px;
49 | min-width: 244px;
50 | }
51 | .header {
52 | text-align: left;
53 | margin: 20px;
54 | }
55 | .title {
56 | font-size: 30px;
57 | font-weight: 700;
58 | }
59 | .code-link {
60 | font-family: source-code-pro, Menlo, Monaco, Consolas, Courier New, monospace;
61 | color: inherit;
62 | text-decoration: none;
63 | }
64 | .App {
65 | text-align: center;
66 | }
67 | .App-logo {
68 | -webkit-animation: App-logo-spin 20s linear infinite;
69 | animation: App-logo-spin 20s linear infinite;
70 | height: 40vmin;
71 | pointer-events: none;
72 | }
73 | .App-header {
74 | background-color: #282c34;
75 | min-height: 100vh;
76 | display: flex;
77 | flex-direction: column;
78 | align-items: center;
79 | justify-content: center;
80 | font-size: calc(10px + 2vmin);
81 | color: #fff;
82 | }
83 | .App-link {
84 | color: #61dafb;
85 | }
86 | @-webkit-keyframes App-logo-spin {
87 | 0% {
88 | -webkit-transform: rotate(0deg);
89 | transform: rotate(0deg);
90 | }
91 | to {
92 | -webkit-transform: rotate(1turn);
93 | transform: rotate(1turn);
94 | }
95 | }
96 | @keyframes App-logo-spin {
97 | 0% {
98 | -webkit-transform: rotate(0deg);
99 | transform: rotate(0deg);
100 | }
101 | to {
102 | -webkit-transform: rotate(1turn);
103 | transform: rotate(1turn);
104 | }
105 | }
106 | /*# sourceMappingURL=main.0f84021f.chunk.css.map */
107 |
--------------------------------------------------------------------------------
/docs/static/css/main.0f84021f.chunk.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["index.css","App.css"],"names":[],"mappings":"AAAA,KACE,aAAc,CACd,QAAS,CACT,mIAEY,CACZ,kCAAmC,CACnC,iCACF,CAEA,KACE,uEAEF,CAEA,SACE,YACF,CAEA,MACE,YACF,CAEA,OACE,QACF,CAEA,MACE,wBAAyB,CACzB,UACF,CAEA,MAEE,eAAgB,CAChB,WACF,CAEA,iBACE,wBACF,CAEA,YACE,iBAAkB,CAClB,kBAA0B,CAC1B,yBAAkB,CAAlB,sBAAkB,CAAlB,iBAAkB,CAClB,kBAAmB,CACnB,wBAAyB,CACzB,UAAY,CACZ,cACF,CAEA,SACE,qBAAsB,CACtB,WAAY,CACZ,YAAa,CACb,gBAAiB,CACjB,eACF,CAEA,QACE,eAAgB,CAChB,WACF,CAEA,OACE,cAAe,CACf,eACF,CAEA,WACE,uEACW,CACX,aAAc,CACd,oBACF,CC3EA,KACE,iBACF,CAEA,UACE,mDAA4C,CAA5C,2CAA4C,CAC5C,aAAc,CACd,mBACF,CAEA,YACE,wBAAyB,CACzB,gBAAiB,CACjB,YAAa,CACb,qBAAsB,CACtB,kBAAmB,CACnB,sBAAuB,CACvB,4BAA6B,CAC7B,UACF,CAEA,UACE,aACF,CAEA,iCACE,GACE,8BAAuB,CAAvB,sBACF,CACA,GACE,+BAAyB,CAAzB,uBACF,CACF,CAPA,yBACE,GACE,8BAAuB,CAAvB,sBACF,CACA,GACE,+BAAyB,CAAzB,uBACF,CACF","file":"main.0f84021f.chunk.css","sourcesContent":["body {\n color: #3e3e3e;\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n monospace;\n}\n\n.wrapper {\n display: flex;\n}\n\n.left {\n flex: 0 0 30%;\n}\n\n.right {\n flex: 1;\n}\n\ntable {\n border-collapse: collapse;\n width: 100%;\n}\n\nth,\ntd {\n text-align: left;\n padding: 8px;\n}\n\ntr:nth-child(even) {\n background-color: #f2f2f2;\n}\n\n.cta-button {\n padding: 10px 20px;\n background: cornflowerblue;\n width: fit-content;\n margin: 0 auto 10px;\n text-transform: uppercase;\n color: white;\n cursor: pointer;\n}\n\n.section {\n border: 2px solid grey;\n margin: 20px;\n padding: 20px;\n min-height: 200px;\n min-width: 244px;\n}\n\n.header {\n text-align: left;\n margin: 20px;\n}\n\n.title {\n font-size: 30px;\n font-weight: bold;\n}\n\n.code-link {\n font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',\n monospace;\n color: inherit;\n text-decoration: none;\n}\n",".App {\n text-align: center;\n}\n\n.App-logo {\n animation: App-logo-spin infinite 20s linear;\n height: 40vmin;\n pointer-events: none;\n}\n\n.App-header {\n background-color: #282c34;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: calc(10px + 2vmin);\n color: white;\n}\n\n.App-link {\n color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n"]}
--------------------------------------------------------------------------------
/docs/static/js/runtime~main.46fcdfae.js:
--------------------------------------------------------------------------------
1 | !(function(e) {
2 | function r(r) {
3 | for (
4 | var n, i, f = r[0], l = r[1], a = r[2], c = 0, s = [];
5 | c < f.length;
6 | c++
7 | )
8 | (i = f[c]), o[i] && s.push(o[i][0]), (o[i] = 0);
9 | for (n in l) Object.prototype.hasOwnProperty.call(l, n) && (e[n] = l[n]);
10 | for (p && p(r); s.length; ) s.shift()();
11 | return u.push.apply(u, a || []), t();
12 | }
13 | function t() {
14 | for (var e, r = 0; r < u.length; r++) {
15 | for (var t = u[r], n = !0, f = 1; f < t.length; f++) {
16 | var l = t[f];
17 | 0 !== o[l] && (n = !1);
18 | }
19 | n && (u.splice(r--, 1), (e = i((i.s = t[0]))));
20 | }
21 | return e;
22 | }
23 | var n = {},
24 | o = { 1: 0 },
25 | u = [];
26 | function i(r) {
27 | if (n[r]) return n[r].exports;
28 | var t = (n[r] = { i: r, l: !1, exports: {} });
29 | return e[r].call(t.exports, t, t.exports, i), (t.l = !0), t.exports;
30 | }
31 | (i.m = e),
32 | (i.c = n),
33 | (i.d = function(e, r, t) {
34 | i.o(e, r) || Object.defineProperty(e, r, { enumerable: !0, get: t });
35 | }),
36 | (i.r = function(e) {
37 | 'undefined' !== typeof Symbol &&
38 | Symbol.toStringTag &&
39 | Object.defineProperty(e, Symbol.toStringTag, { value: 'Module' }),
40 | Object.defineProperty(e, '__esModule', { value: !0 });
41 | }),
42 | (i.t = function(e, r) {
43 | if ((1 & r && (e = i(e)), 8 & r)) return e;
44 | if (4 & r && 'object' === typeof e && e && e.__esModule) return e;
45 | var t = Object.create(null);
46 | if (
47 | (i.r(t),
48 | Object.defineProperty(t, 'default', { enumerable: !0, value: e }),
49 | 2 & r && 'string' != typeof e)
50 | )
51 | for (var n in e)
52 | i.d(
53 | t,
54 | n,
55 | function(r) {
56 | return e[r];
57 | }.bind(null, n)
58 | );
59 | return t;
60 | }),
61 | (i.n = function(e) {
62 | var r =
63 | e && e.__esModule
64 | ? function() {
65 | return e.default;
66 | }
67 | : function() {
68 | return e;
69 | };
70 | return i.d(r, 'a', r), r;
71 | }),
72 | (i.o = function(e, r) {
73 | return Object.prototype.hasOwnProperty.call(e, r);
74 | }),
75 | (i.p = 'https://manojvivek.github.io/react-prefetcher/');
76 | var f = (window.webpackJsonp = window.webpackJsonp || []),
77 | l = f.push.bind(f);
78 | (f.push = r), (f = f.slice());
79 | for (var a = 0; a < f.length; a++) r(f[a]);
80 | var p = l;
81 | t();
82 | })([]);
83 | //# sourceMappingURL=runtime~main.46fcdfae.js.map
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React-Prefetcher  
2 |
3 | A react library providing components that help with interaction-based asset pre-fetching.
4 |
5 | ## Installation
6 |
7 | Using npm:
8 |
9 | ```bash
10 | npm install react-prefetcher
11 | ```
12 |
13 | Using yarn:
14 |
15 | ```bash
16 | yarn add react-prefetcher
17 | ```
18 |
19 | ## Usage
20 |
21 | ### OnRenderPrefetcher
22 |
23 | ```javascript
24 | import React, {Fragment} from 'react';
25 | import {OnRenderPrefetcher} from 'react-prefetcher';
26 |
27 | export default () => (
28 |
29 |
30 | Asset prefetching happens when this `
` tag is rendered
31 |
32 |
33 | );
34 | ```
35 |
36 | ### OnHoverPrefetcher
37 |
38 | ```javascript
39 | import React, {Fragment} from 'react';
40 | import {OnHoverPrefetcher} from 'react-prefetcher';
41 |
42 | export default () => (
43 |
44 |
45 | Asset prefetching happens when the user hovers this `
` tag
46 |
47 |
48 | );
49 | ```
50 |
51 | ### OnClickPrefetcher
52 |
53 | ```javascript
54 | import React, {Fragment} from 'react';
55 | import {OnClickPrefetcher} from 'react-prefetcher';
56 |
57 | export default () => (
58 |
59 |
60 | Asset prefetching happens when the user clicks this `
` tag
61 |
62 |
63 | );
64 | ```
65 |
66 | ### Prefetcher
67 |
68 | Customize prefetching by combining multiple interactions.
69 |
70 | ```javascript
71 | import React, {Fragment} from 'react';
72 | import Prefetcher from 'react-prefetcher';
73 |
74 | export default () => (
75 |
76 |
81 |
82 | 1. Prefetches https://example.com/on-render-asset-url on render of this `
` tag.
83 | 2. Prefetches https://example.com/on-hover-asset-url when the user hovers this `
` tag.
84 | 3. Prefetches https://example.com/on-click-asset-url when the user clicks this `
` tag.
85 |
86 |
87 |
88 | );
89 | ```
90 |
91 | ### Possible values for assets
92 |
93 | 1. URL
94 | 2. Array of URLs
95 | 3. Object with custom fetcher
96 |
97 | #### URL as asset:
98 |
99 | ```javascript
100 |
101 | ```
102 |
103 | #### Array of URLs:
104 |
105 | ```javascript
106 |
112 | ```
113 |
114 | #### Custom fetcher function:
115 |
116 | ```javascript
117 | {
121 | /*custom fetcher that gets invoked on render*/
122 | },
123 | }}
124 | />
125 | ```
126 |
127 | ## Contributing
128 |
129 | Pull requests are welcome.
130 |
131 | ## License
132 |
133 | [MIT](https://github.com/manojVivek/react-prefetcher/blob/master/LICENSE)
134 |
--------------------------------------------------------------------------------
/test/prefetcher.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import chai, { expect } from 'chai';
3 | import chaiEnzyme from 'chai-enzyme';
4 | import spies from 'chai-spies';
5 | import Enzyme, { shallow } from 'enzyme';
6 | import Adapter from 'enzyme-adapter-react-16';
7 |
8 | import Prefetcher from '../index';
9 |
10 | chai.use(chaiEnzyme());
11 | chai.use(spies);
12 | Enzyme.configure({ adapter: new Adapter() });
13 |
14 | const children = test
;
15 | const prefetchLink1 = `https://prefetch-link1.com`;
16 | const prefetchLink2 = `https://prefetch-link2.com`;
17 | const customPrefetcher1 = () => {};
18 | const customPrefetcher2 = () => {};
19 |
20 | describe('Children tests', () => {
21 | it('renders nothing when no children and no onRenderAssets', () => {
22 | const wrapper = shallow( );
23 | expect(wrapper.children()).to.have.lengthOf(0);
24 | });
25 |
26 | it('renders the children when no prefetching assets', () => {
27 | const wrapper = shallow({children} );
28 | expect(wrapper).to.contain(children);
29 | });
30 | });
31 |
32 | describe('onRenderAssets tests', () => {
33 | it('renders prefetch statements for single url for onRenderAssets props', () => {
34 | const wrapper = shallow(
35 | {children}
36 | );
37 | expect(wrapper).to.contain(children);
38 | // TODO: find a way with simulated events to avoid this manual setState()
39 | wrapper.setState({ rendered: true });
40 | expect(wrapper.find(`link[href='${prefetchLink1}']`)).to.have.lengthOf(1);
41 | });
42 |
43 | it('renders prefetch statements for an array of urls for onRenderAssets props', () => {
44 | const prefetchAssets = [prefetchLink1, prefetchLink2];
45 | const wrapper = shallow(
46 | {children}
47 | );
48 | expect(wrapper).to.contain(children);
49 | wrapper.setState({ rendered: true });
50 | for (const asset of prefetchAssets) {
51 | expect(wrapper.find(`link[href='${asset}']`)).to.have.lengthOf(1);
52 | }
53 | });
54 |
55 | it('invokes custom prefetcher for an single of prefetcher function for onRenderAssets props', () => {
56 | const prefetchAsset = chai.spy(customPrefetcher1);
57 | const wrapper = shallow(
58 |
59 | {children}
60 |
61 | );
62 | expect(wrapper).to.contain(children);
63 | wrapper.setState({ rendered: true });
64 | expect(prefetchAsset).to.have.been.called();
65 | });
66 |
67 | it('invokes custom prefetchers for an array of custom prefetchers for onRenderAssets props', () => {
68 | const prefetchAssets = [
69 | chai.spy(customPrefetcher1),
70 | chai.spy(customPrefetcher2),
71 | ];
72 | const wrapper = shallow(
73 | ({
75 | href: idx,
76 | fetcher,
77 | }))}
78 | >
79 | {children}
80 |
81 | );
82 | expect(wrapper).to.contain(children);
83 | wrapper.setState({ rendered: true });
84 | for (const asset of prefetchAssets) {
85 | expect(asset).to.have.been.called();
86 | }
87 | });
88 |
89 | it('works fine with a mix of urls and custom fetcher for onRenderAssets props', () => {
90 | const customFetcher = chai.spy(customPrefetcher1);
91 | const wrapper = shallow(
92 |
98 | {children}
99 |
100 | );
101 | expect(wrapper).to.contain(children);
102 | wrapper.setState({ rendered: true });
103 | expect(wrapper.find(`link[href='${prefetchLink1}']`)).to.have.lengthOf(1);
104 | expect(customFetcher).to.have.been.called();
105 | });
106 | });
107 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
15 | React-prefetcher Demo App
16 |
20 |
21 |
22 | You need to enable JavaScript to run this app.
23 |
24 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/demo-app/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/docs/static/js/runtime~main.46fcdfae.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["../webpack/bootstrap"],"names":["webpackJsonpCallback","data","moduleId","chunkId","chunkIds","moreModules","executeModules","i","resolves","length","installedChunks","push","Object","prototype","hasOwnProperty","call","modules","parentJsonpFunction","shift","deferredModules","apply","checkDeferredModules","result","deferredModule","fulfilled","j","depId","splice","__webpack_require__","s","installedModules","1","exports","module","l","m","c","d","name","getter","o","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","p","jsonpArray","window","oldJsonpFunction","slice"],"mappings":"aACA,SAAAA,EAAAC,GAQA,IAPA,IAMAC,EAAAC,EANAC,EAAAH,EAAA,GACAI,EAAAJ,EAAA,GACAK,EAAAL,EAAA,GAIAM,EAAA,EAAAC,EAAA,GACQD,EAAAH,EAAAK,OAAoBF,IAC5BJ,EAAAC,EAAAG,GACAG,EAAAP,IACAK,EAAAG,KAAAD,EAAAP,GAAA,IAEAO,EAAAP,GAAA,EAEA,IAAAD,KAAAG,EACAO,OAAAC,UAAAC,eAAAC,KAAAV,EAAAH,KACAc,EAAAd,GAAAG,EAAAH,IAKA,IAFAe,KAAAhB,GAEAO,EAAAC,QACAD,EAAAU,OAAAV,GAOA,OAHAW,EAAAR,KAAAS,MAAAD,EAAAb,GAAA,IAGAe,IAEA,SAAAA,IAEA,IADA,IAAAC,EACAf,EAAA,EAAiBA,EAAAY,EAAAV,OAA4BF,IAAA,CAG7C,IAFA,IAAAgB,EAAAJ,EAAAZ,GACAiB,GAAA,EACAC,EAAA,EAAkBA,EAAAF,EAAAd,OAA2BgB,IAAA,CAC7C,IAAAC,EAAAH,EAAAE,GACA,IAAAf,EAAAgB,KAAAF,GAAA,GAEAA,IACAL,EAAAQ,OAAApB,IAAA,GACAe,EAAAM,IAAAC,EAAAN,EAAA,KAGA,OAAAD,EAIA,IAAAQ,EAAA,GAKApB,EAAA,CACAqB,EAAA,GAGAZ,EAAA,GAGA,SAAAS,EAAA1B,GAGA,GAAA4B,EAAA5B,GACA,OAAA4B,EAAA5B,GAAA8B,QAGA,IAAAC,EAAAH,EAAA5B,GAAA,CACAK,EAAAL,EACAgC,GAAA,EACAF,QAAA,IAUA,OANAhB,EAAAd,GAAAa,KAAAkB,EAAAD,QAAAC,IAAAD,QAAAJ,GAGAK,EAAAC,GAAA,EAGAD,EAAAD,QAKAJ,EAAAO,EAAAnB,EAGAY,EAAAQ,EAAAN,EAGAF,EAAAS,EAAA,SAAAL,EAAAM,EAAAC,GACAX,EAAAY,EAAAR,EAAAM,IACA1B,OAAA6B,eAAAT,EAAAM,EAAA,CAA0CI,YAAA,EAAAC,IAAAJ,KAK1CX,EAAAgB,EAAA,SAAAZ,GACA,qBAAAa,eAAAC,aACAlC,OAAA6B,eAAAT,EAAAa,OAAAC,YAAA,CAAwDC,MAAA,WAExDnC,OAAA6B,eAAAT,EAAA,cAAiDe,OAAA,KAQjDnB,EAAAoB,EAAA,SAAAD,EAAAE,GAEA,GADA,EAAAA,IAAAF,EAAAnB,EAAAmB,IACA,EAAAE,EAAA,OAAAF,EACA,KAAAE,GAAA,kBAAAF,QAAAG,WAAA,OAAAH,EACA,IAAAI,EAAAvC,OAAAwC,OAAA,MAGA,GAFAxB,EAAAgB,EAAAO,GACAvC,OAAA6B,eAAAU,EAAA,WAAyCT,YAAA,EAAAK,UACzC,EAAAE,GAAA,iBAAAF,EAAA,QAAAM,KAAAN,EAAAnB,EAAAS,EAAAc,EAAAE,EAAA,SAAAA,GAAgH,OAAAN,EAAAM,IAAqBC,KAAA,KAAAD,IACrI,OAAAF,GAIAvB,EAAA2B,EAAA,SAAAtB,GACA,IAAAM,EAAAN,KAAAiB,WACA,WAA2B,OAAAjB,EAAA,SAC3B,WAAiC,OAAAA,GAEjC,OADAL,EAAAS,EAAAE,EAAA,IAAAA,GACAA,GAIAX,EAAAY,EAAA,SAAAgB,EAAAC,GAAsD,OAAA7C,OAAAC,UAAAC,eAAAC,KAAAyC,EAAAC,IAGtD7B,EAAA8B,EAAA,iDAEA,IAAAC,EAAAC,OAAA,aAAAA,OAAA,iBACAC,EAAAF,EAAAhD,KAAA2C,KAAAK,GACAA,EAAAhD,KAAAX,EACA2D,IAAAG,QACA,QAAAvD,EAAA,EAAgBA,EAAAoD,EAAAlD,OAAuBF,IAAAP,EAAA2D,EAAApD,IACvC,IAAAU,EAAA4C,EAIAxC","file":"static/js/runtime~main.46fcdfae.js","sourcesContent":[" \t// install a JSONP callback for chunk loading\n \tfunction webpackJsonpCallback(data) {\n \t\tvar chunkIds = data[0];\n \t\tvar moreModules = data[1];\n \t\tvar executeModules = data[2];\n\n \t\t// add \"moreModules\" to the modules object,\n \t\t// then flag all \"chunkIds\" as loaded and fire callback\n \t\tvar moduleId, chunkId, i = 0, resolves = [];\n \t\tfor(;i < chunkIds.length; i++) {\n \t\t\tchunkId = chunkIds[i];\n \t\t\tif(installedChunks[chunkId]) {\n \t\t\t\tresolves.push(installedChunks[chunkId][0]);\n \t\t\t}\n \t\t\tinstalledChunks[chunkId] = 0;\n \t\t}\n \t\tfor(moduleId in moreModules) {\n \t\t\tif(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {\n \t\t\t\tmodules[moduleId] = moreModules[moduleId];\n \t\t\t}\n \t\t}\n \t\tif(parentJsonpFunction) parentJsonpFunction(data);\n\n \t\twhile(resolves.length) {\n \t\t\tresolves.shift()();\n \t\t}\n\n \t\t// add entry modules from loaded chunk to deferred list\n \t\tdeferredModules.push.apply(deferredModules, executeModules || []);\n\n \t\t// run deferred modules when all chunks ready\n \t\treturn checkDeferredModules();\n \t};\n \tfunction checkDeferredModules() {\n \t\tvar result;\n \t\tfor(var i = 0; i < deferredModules.length; i++) {\n \t\t\tvar deferredModule = deferredModules[i];\n \t\t\tvar fulfilled = true;\n \t\t\tfor(var j = 1; j < deferredModule.length; j++) {\n \t\t\t\tvar depId = deferredModule[j];\n \t\t\t\tif(installedChunks[depId] !== 0) fulfilled = false;\n \t\t\t}\n \t\t\tif(fulfilled) {\n \t\t\t\tdeferredModules.splice(i--, 1);\n \t\t\t\tresult = __webpack_require__(__webpack_require__.s = deferredModule[0]);\n \t\t\t}\n \t\t}\n \t\treturn result;\n \t}\n\n \t// The module cache\n \tvar installedModules = {};\n\n \t// object to store loaded and loading chunks\n \t// undefined = chunk not loaded, null = chunk preloaded/prefetched\n \t// Promise = chunk loading, 0 = chunk loaded\n \tvar installedChunks = {\n \t\t1: 0\n \t};\n\n \tvar deferredModules = [];\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"https://manojvivek.github.io/react-prefetcher/\";\n\n \tvar jsonpArray = window[\"webpackJsonp\"] = window[\"webpackJsonp\"] || [];\n \tvar oldJsonpFunction = jsonpArray.push.bind(jsonpArray);\n \tjsonpArray.push = webpackJsonpCallback;\n \tjsonpArray = jsonpArray.slice();\n \tfor(var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i]);\n \tvar parentJsonpFunction = oldJsonpFunction;\n\n\n \t// run deferred modules from other chunks\n \tcheckDeferredModules();\n"],"sourceRoot":""}
--------------------------------------------------------------------------------
/docs/static/js/main.066f72df.chunk.js:
--------------------------------------------------------------------------------
1 | (window.webpackJsonp = window.webpackJsonp || []).push([
2 | [0],
3 | {
4 | 10: function(e, t, a) {
5 | e.exports = a(18);
6 | },
7 | 16: function(e, t, a) {},
8 | 17: function(e, t, a) {},
9 | 18: function(e, t, a) {
10 | 'use strict';
11 | a.r(t);
12 | var n = a(0),
13 | r = a.n(n),
14 | c = a(8),
15 | l = a.n(c),
16 | s = (a(16), a(1)),
17 | i = a(2),
18 | o = a(4),
19 | m = a(3),
20 | u = a(5),
21 | d =
22 | (a(17),
23 | (function(e) {
24 | function t(e) {
25 | var a;
26 | return (
27 | Object(s.a)(this, t),
28 | ((a = Object(o.a)(
29 | this,
30 | Object(m.a)(t).call(this, e)
31 | ))._refreshList = function() {
32 | a.setState({
33 | requests: performance
34 | .getEntriesByType('resource')
35 | .filter(function(e) {
36 | return e.name.indexOf(a.props.filter) > -1;
37 | }),
38 | });
39 | }),
40 | (a.state = { requests: [] }),
41 | a
42 | );
43 | }
44 | return (
45 | Object(u.a)(t, e),
46 | Object(i.a)(t, [
47 | {
48 | key: 'componentDidMount',
49 | value: function() {
50 | this.intervalHandle = setInterval(this._refreshList, 200);
51 | },
52 | },
53 | {
54 | key: 'componentWillUnmount',
55 | value: function() {
56 | clearInterval(this.intervalHandle);
57 | },
58 | },
59 | {
60 | key: 'render',
61 | value: function() {
62 | return r.a.createElement(
63 | 'div',
64 | { className: 'section' },
65 | r.a.createElement('h3', null, 'Network Inspector:'),
66 | r.a.createElement(
67 | 'table',
68 | null,
69 | r.a.createElement(
70 | 'tr',
71 | null,
72 | r.a.createElement(
73 | 'th',
74 | null,
75 | 'Time from Page load(ms)'
76 | ),
77 | r.a.createElement('th', null, 'Resource URL'),
78 | r.a.createElement(
79 | 'th',
80 | null,
81 | 'Time Taken to Download(ms)'
82 | )
83 | ),
84 | this.state.requests.map(function(e) {
85 | return r.a.createElement(
86 | 'tr',
87 | null,
88 | r.a.createElement(
89 | 'td',
90 | null,
91 | Math.round(e.startTime)
92 | ),
93 | r.a.createElement('td', null, e.name),
94 | r.a.createElement(
95 | 'td',
96 | null,
97 | Math.round(e.duration)
98 | )
99 | );
100 | })
101 | )
102 | );
103 | },
104 | },
105 | ]),
106 | t
107 | );
108 | })(r.a.Component)),
109 | h = (function(e) {
110 | function t(e) {
111 | var a;
112 | return (
113 | Object(s.a)(this, t),
114 | ((a = Object(o.a)(this, Object(m.a)(t).call(this, e))).state = {
115 | clicked: !1,
116 | }),
117 | a
118 | );
119 | }
120 | return (
121 | Object(u.a)(t, e),
122 | Object(i.a)(t, [
123 | {
124 | key: 'render',
125 | value: function() {
126 | var e = this;
127 | return r.a.createElement(
128 | 'div',
129 | { class: 'section' },
130 | r.a.createElement(
131 | 'div',
132 | {
133 | class: 'cta-button',
134 | onClick: function() {
135 | return e.setState({ clicked: !0 });
136 | },
137 | },
138 | 'Click to show image'
139 | ),
140 | this.state.clicked
141 | ? r.a.createElement('img', {
142 | src:
143 | 'https://assets.imgix.net/examples/kingfisher.jpg?w=200&rand=' +
144 | this.props.rand,
145 | alt: '',
146 | })
147 | : null
148 | );
149 | },
150 | },
151 | ]),
152 | t
153 | );
154 | })(r.a.Component),
155 | f = a(9),
156 | p = (function(e) {
157 | function t(e) {
158 | var a;
159 | return (
160 | Object(s.a)(this, t),
161 | ((a = Object(o.a)(this, Object(m.a)(t).call(this, e))).state = {
162 | clicked: !1,
163 | }),
164 | (a.imageUrl =
165 | 'https://assets.imgix.net/examples/kingfisher.jpg?w=200&rand=' +
166 | a.props.rand),
167 | a
168 | );
169 | }
170 | return (
171 | Object(u.a)(t, e),
172 | Object(i.a)(t, [
173 | {
174 | key: 'render',
175 | value: function() {
176 | var e = this;
177 | return r.a.createElement(
178 | 'div',
179 | { class: 'section' },
180 | r.a.createElement(
181 | f.a,
182 | { onRenderAssets: [this.imageUrl] },
183 | r.a.createElement(
184 | 'div',
185 | {
186 | class: 'cta-button',
187 | onClick: function() {
188 | return e.setState({ clicked: !0 });
189 | },
190 | },
191 | 'Click to show image'
192 | )
193 | ),
194 | this.state.clicked
195 | ? r.a.createElement('img', {
196 | src: this.imageUrl,
197 | alt: '',
198 | })
199 | : null
200 | );
201 | },
202 | },
203 | ]),
204 | t
205 | );
206 | })(r.a.Component),
207 | v = (function(e) {
208 | function t() {
209 | var e, a;
210 | Object(s.a)(this, t);
211 | for (var n = arguments.length, r = new Array(n), c = 0; c < n; c++)
212 | r[c] = arguments[c];
213 | return (
214 | ((a = Object(o.a)(
215 | this,
216 | (e = Object(m.a)(t)).call.apply(e, [this].concat(r))
217 | )).noPrefetchRand = Math.random()),
218 | (a.onRenderPrefetchRand = Math.random()),
219 | a
220 | );
221 | }
222 | return (
223 | Object(u.a)(t, e),
224 | Object(i.a)(t, [
225 | {
226 | key: 'render',
227 | value: function() {
228 | return r.a.createElement(
229 | 'div',
230 | { className: 'App' },
231 | r.a.createElement(
232 | 'div',
233 | { className: 'header' },
234 | r.a.createElement(
235 | 'span',
236 | { className: 'title' },
237 | 'Component without any Prefetching'
238 | ),
239 | r.a.createElement(
240 | 'a',
241 | {
242 | className: 'code-link',
243 | href:
244 | 'https://github.com/manojVivek/react-prefetcher/blob/master/demo/src/components/NoPrefetchApp/index.js',
245 | target: '_blank',
246 | rel: 'noopener noreferrer',
247 | },
248 | '(see code)'
249 | )
250 | ),
251 | r.a.createElement(
252 | 'div',
253 | { className: 'wrapper' },
254 | r.a.createElement(
255 | 'div',
256 | { className: 'left' },
257 | r.a.createElement(h, { rand: this.noPrefetchRand })
258 | ),
259 | r.a.createElement(
260 | 'div',
261 | { className: 'right' },
262 | r.a.createElement(d, { filter: this.noPrefetchRand })
263 | )
264 | ),
265 | r.a.createElement(
266 | 'div',
267 | { className: 'header' },
268 | r.a.createElement(
269 | 'span',
270 | { className: 'title' },
271 | 'Component with OnRender Prefetching'
272 | ),
273 | r.a.createElement(
274 | 'a',
275 | {
276 | className: 'code-link',
277 | href:
278 | 'https://github.com/manojVivek/react-prefetcher/blob/master/demo/src/components/OnRenderPrefetchApp/index.js',
279 | target: '_blank',
280 | rel: 'noopener noreferrer',
281 | },
282 | '(see code)'
283 | )
284 | ),
285 | r.a.createElement(
286 | 'div',
287 | { className: 'wrapper' },
288 | r.a.createElement(
289 | 'div',
290 | { className: 'left' },
291 | r.a.createElement(p, {
292 | rand: this.onRenderPrefetchRand,
293 | })
294 | ),
295 | r.a.createElement(
296 | 'div',
297 | { className: 'right' },
298 | r.a.createElement(d, {
299 | filter: this.onRenderPrefetchRand,
300 | })
301 | )
302 | )
303 | );
304 | },
305 | },
306 | ]),
307 | t
308 | );
309 | })(r.a.Component);
310 | Boolean(
311 | 'localhost' === window.location.hostname ||
312 | '[::1]' === window.location.hostname ||
313 | window.location.hostname.match(
314 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
315 | )
316 | );
317 | l.a.render(r.a.createElement(v, null), document.getElementById('root')),
318 | 'serviceWorker' in navigator &&
319 | navigator.serviceWorker.ready.then(function(e) {
320 | e.unregister();
321 | });
322 | },
323 | },
324 | [[10, 1, 2]],
325 | ]);
326 | //# sourceMappingURL=main.066f72df.chunk.js.map
327 |
--------------------------------------------------------------------------------
/docs/static/js/main.066f72df.chunk.js.map:
--------------------------------------------------------------------------------
1 | {"version":3,"sources":["components/NetworkRequestLister/index.js","components/NoPrefetchApp/index.js","components/OnRenderPrefetchApp/index.js","App.js","serviceWorker.js","index.js"],"names":["NetworkReqestLister","props","_this","Object","classCallCheck","this","possibleConstructorReturn","getPrototypeOf","call","_refreshList","setState","requests","performance","getEntriesByType","filter","entry","name","indexOf","state","intervalHandle","setInterval","clearInterval","react_default","a","createElement","className","map","request","Math","round","startTime","duration","React","Component","NoPrefetchApp","clicked","_this2","class","onClick","src","rand","alt","OnRenderPrefetchApp","imageUrl","react_prefetcher","onRenderAssets","App","noPrefetchRand","random","onRenderPrefetchRand","href","target","rel","NoPrefetchApp_NoPrefetchApp","NetworkRequestLister_NetworkReqestLister","OnRenderPrefetchApp_OnRenderPrefetchApp","Boolean","window","location","hostname","match","ReactDOM","render","src_App_0","document","getElementById","navigator","serviceWorker","ready","then","registration","unregister"],"mappings":"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","file":"static/js/main.066f72df.chunk.js","sourcesContent":["import React from 'react';\n\nexport default class NetworkReqestLister extends React.Component {\n constructor(props) {\n super(props);\n this.state = { requests: [] };\n }\n\n componentDidMount() {\n this.intervalHandle = setInterval(this._refreshList, 200);\n }\n\n componentWillUnmount() {\n clearInterval(this.intervalHandle);\n }\n\n _refreshList = () => {\n this.setState({\n requests: performance\n .getEntriesByType('resource')\n .filter(entry => entry.name.indexOf(this.props.filter) > -1),\n });\n };\n\n render() {\n return (\n \n
Network Inspector: \n
\n \n Time from Page load(ms) \n Resource URL \n Time Taken to Download(ms) \n \n {this.state.requests.map(request => (\n \n {Math.round(request.startTime)} \n {request.name} \n {Math.round(request.duration)} \n \n ))}\n
\n
\n );\n }\n}\n","import React from 'react';\n\nexport default class NoPrefetchApp extends React.Component {\n constructor(props) {\n super(props);\n this.state = { clicked: false };\n }\n\n render() {\n return (\n \n
this.setState({ clicked: true })}\n >\n Click to show image\n
\n {this.state.clicked ? (\n
\n ) : null}\n
\n );\n }\n}\n","import React from 'react';\nimport Prefetcher from 'react-prefetcher';\n\nexport default class OnRenderPrefetchApp extends React.Component {\n constructor(props) {\n super(props);\n this.state = { clicked: false };\n this.imageUrl =\n 'https://assets.imgix.net/examples/kingfisher.jpg?w=200&rand=' +\n this.props.rand;\n }\n\n render() {\n return (\n \n
\n this.setState({ clicked: true })}\n >\n Click to show image\n
\n \n {this.state.clicked ?
: null}\n
\n );\n }\n}\n","import React from 'react';\nimport './App.css';\nimport NetworkRequestLister from './components/NetworkRequestLister';\nimport NoPrefetchApp from './components/NoPrefetchApp';\nimport OnRenderPrefetchApp from './components/OnRenderPrefetchApp';\n\nclass App extends React.Component {\n noPrefetchRand = Math.random();\n onRenderPrefetchRand = Math.random();\n\n render() {\n return (\n \n );\n }\n}\n\nexport default App;\n","// This optional code is used to register a service worker.\n// register() is not called by default.\n\n// This lets the app load faster on subsequent visits in production, and gives\n// it offline capabilities. However, it also means that developers (and users)\n// will only see deployed updates on subsequent visits to a page, after all the\n// existing tabs open on the page have been closed, since previously cached\n// resources are updated in the background.\n\n// To learn more about the benefits of this model and instructions on how to\n// opt-in, read https://bit.ly/CRA-PWA\n\nconst isLocalhost = Boolean(\n window.location.hostname === 'localhost' ||\n // [::1] is the IPv6 localhost address.\n window.location.hostname === '[::1]' ||\n // 127.0.0.1/8 is considered localhost for IPv4.\n window.location.hostname.match(\n /^127(?:\\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/\n )\n);\n\nexport function register(config) {\n if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {\n // The URL constructor is available in all browsers that support SW.\n const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);\n if (publicUrl.origin !== window.location.origin) {\n // Our service worker won't work if PUBLIC_URL is on a different origin\n // from what our page is served on. This might happen if a CDN is used to\n // serve assets; see https://github.com/facebook/create-react-app/issues/2374\n return;\n }\n\n window.addEventListener('load', () => {\n const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;\n\n if (isLocalhost) {\n // This is running on localhost. Let's check if a service worker still exists or not.\n checkValidServiceWorker(swUrl, config);\n\n // Add some additional logging to localhost, pointing developers to the\n // service worker/PWA documentation.\n navigator.serviceWorker.ready.then(() => {\n console.log(\n 'This web app is being served cache-first by a service ' +\n 'worker. To learn more, visit https://bit.ly/CRA-PWA'\n );\n });\n } else {\n // Is not localhost. Just register service worker\n registerValidSW(swUrl, config);\n }\n });\n }\n}\n\nfunction registerValidSW(swUrl, config) {\n navigator.serviceWorker\n .register(swUrl)\n .then(registration => {\n registration.onupdatefound = () => {\n const installingWorker = registration.installing;\n if (installingWorker == null) {\n return;\n }\n installingWorker.onstatechange = () => {\n if (installingWorker.state === 'installed') {\n if (navigator.serviceWorker.controller) {\n // At this point, the updated precached content has been fetched,\n // but the previous service worker will still serve the older\n // content until all client tabs are closed.\n console.log(\n 'New content is available and will be used when all ' +\n 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'\n );\n\n // Execute callback\n if (config && config.onUpdate) {\n config.onUpdate(registration);\n }\n } else {\n // At this point, everything has been precached.\n // It's the perfect time to display a\n // \"Content is cached for offline use.\" message.\n console.log('Content is cached for offline use.');\n\n // Execute callback\n if (config && config.onSuccess) {\n config.onSuccess(registration);\n }\n }\n }\n };\n };\n })\n .catch(error => {\n console.error('Error during service worker registration:', error);\n });\n}\n\nfunction checkValidServiceWorker(swUrl, config) {\n // Check if the service worker can be found. If it can't reload the page.\n fetch(swUrl)\n .then(response => {\n // Ensure service worker exists, and that we really are getting a JS file.\n const contentType = response.headers.get('content-type');\n if (\n response.status === 404 ||\n (contentType != null && contentType.indexOf('javascript') === -1)\n ) {\n // No service worker found. Probably a different app. Reload the page.\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister().then(() => {\n window.location.reload();\n });\n });\n } else {\n // Service worker found. Proceed as normal.\n registerValidSW(swUrl, config);\n }\n })\n .catch(() => {\n console.log(\n 'No internet connection found. App is running in offline mode.'\n );\n });\n}\n\nexport function unregister() {\n if ('serviceWorker' in navigator) {\n navigator.serviceWorker.ready.then(registration => {\n registration.unregister();\n });\n }\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport './index.css';\nimport App from './App';\nimport * as serviceWorker from './serviceWorker';\n\nReactDOM.render( , document.getElementById('root'));\n\n// If you want your app to work offline and load faster, you can change\n// unregister() to register() below. Note this comes with some pitfalls.\n// Learn more about service workers: https://bit.ly/CRA-PWA\nserviceWorker.unregister();\n"],"sourceRoot":""}
--------------------------------------------------------------------------------