UNPKG

4.56 kBJSXView Raw
1/* eslint react/display-name:0 */
2
3import {setConfig} from "react-hot-loader";
4setConfig({logLevel: "error", showReactDomPatchNotification: false});
5
6import React from "react";
7import {hydrate} from "react-dom";
8import {createHistory} from "history";
9import {applyRouterMiddleware, Router, RouterContext, useRouterHistory} from "react-router";
10import {syncHistoryWithStore} from "react-router-redux";
11import {animateScroll} from "react-scroll";
12import {I18nextProvider} from "react-i18next";
13import {Provider} from "react-redux";
14import {selectAll} from "d3-selection";
15import createRoutes from "routes";
16import configureStore from "./storeConfig";
17import {LOADING_END, LOADING_START} from "./consts";
18import preRenderMiddleware from "./middlewares/preRenderMiddleware";
19
20const {basename} = window.__INITIAL_STATE__.location;
21const browserHistory = useRouterHistory(createHistory)({basename});
22
23import canonConfig from "canon.js";
24const reduxMiddleware = canonConfig.reduxMiddleware || false;
25
26const store = configureStore(window.__INITIAL_STATE__, browserHistory, reduxMiddleware);
27const history = syncHistoryWithStore(browserHistory, store);
28const routes = createRoutes(store);
29
30import i18n from "i18next";
31import yn from "yn";
32
33import defaultTranslations from "./i18n/canon";
34import CanonProvider from "./CanonProvider";
35
36const {locale, resources} = window.__INITIAL_STATE__.i18n;
37const {CANON_LOGLOCALE, NODE_ENV} = window.__INITIAL_STATE__.env;
38const name = window.__APP_NAME__;
39
40const resourceObj = {canon: {[name]: defaultTranslations}};
41if (locale !== "canon") resourceObj[locale] = {[name]: resources};
42
43i18n
44 .init({
45 fallbackLng: "canon",
46 lng: locale,
47 debug: NODE_ENV !== "production" ? yn(CANON_LOGLOCALE) : false,
48 ns: [name],
49 defaultNS: name,
50 react: {
51 wait: true,
52 withRef: true
53 },
54 resources: resourceObj
55 });
56
57/**
58 Scrolls to a page element if it exists on the page.
59*/
60function scrollToHash(hash, wait = true) {
61 const elem = hash && hash.indexOf("#") === 0 ? document.getElementById(hash.slice(1)) : false;
62 if (elem) {
63 const offset = elem.getBoundingClientRect().top;
64 if (offset) {
65 animateScroll.scrollMore(offset);
66 setTimeout(() => {
67 elem.focus();
68 }, 100);
69 }
70 }
71 else if (wait) {
72 setTimeout(() => {
73 scrollToHash(hash, false);
74 }, 100);
75 }
76}
77
78/**
79 Middleware that captures all router requests and detects the following:
80 * Smooth scrolling to anchor links
81 * Initiatlize SSR needs loading
82*/
83function renderMiddleware() {
84
85 return {
86 renderRouterContext: (child, props) => {
87
88 const needs = props.components.filter(comp => comp && (comp.need || comp.preneed || comp.postneed));
89 const {action, hash, pathname, query, search, state} = props.location;
90
91 const postRender = function() {
92 if (!window.__SSR__) {
93 if (typeof window.ga === "function") {
94 setTimeout(() => {
95 window.ga("set", "title", document.title);
96 window.ga("set", "page", pathname + search);
97 window.ga("send", "pageview");
98 }, 0);
99 }
100 }
101 if (hash) scrollToHash(hash);
102 else window.scrollTo(0, 0);
103 };
104
105 if (action !== "REPLACE" || !Object.keys(query).length) {
106 selectAll(".d3plus-tooltip").remove();
107 if (window.__SSR__ || state === "HASH" || !needs.length) {
108 postRender();
109 window.__SSR__ = false;
110 }
111 else {
112 store.dispatch({type: LOADING_START});
113 document.body.scrollTop = document.documentElement.scrollTop = 0;
114 preRenderMiddleware(store, props)
115 .then(() => {
116 store.dispatch({type: LOADING_END});
117 postRender();
118 });
119 }
120 }
121
122 return <RouterContext {...props}/>;
123
124 }
125 };
126
127}
128
129const helmet = window.__HELMET_DEFAULT__;
130
131/**
132 Wraps the top-level router component in the CanonProvider
133*/
134function createElement(Component, props) {
135
136 if (props.children && props.route.path === "/") {
137 return <CanonProvider router={props.router} helmet={helmet} locale={locale}>
138 <Component {...props} />
139 </CanonProvider>;
140 }
141 else {
142 return <Component {...props} />;
143 }
144
145}
146
147hydrate(
148 <I18nextProvider i18n={i18n}>
149 <Provider store={store}>
150 <Router createElement={createElement} history={history} render={applyRouterMiddleware(renderMiddleware())}>
151 {routes}
152 </Router>
153 </Provider>
154 </I18nextProvider>,
155 document.getElementById("React-Container"));