/* * MIT License * * Copyright (c) 2018 Choko (choko@curioswitch.org) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ // tslint:disable:jsx-no-lambda import { createLocation, createMemoryHistory as createHistory, LocationDescriptor, } from 'history'; import { Parser } from 'html-to-react'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; import { Helmet } from 'react-helmet'; import Loadable from 'react-loadable'; import { Provider } from 'react-redux'; import { StaticRouter } from 'react-router-dom'; import { Store } from 'redux'; import serialize from 'serialize-javascript'; import { ServerStyleSheet, ThemeProvider } from 'styled-components'; import { appConfig } from '../app'; import LanguageProvider, { LocaleMessages, } from '../containers/LanguageProvider'; import { PrerenderConfig } from '../index'; import initRedux from '../state/init'; import { routeInitialState } from '../state/reducers'; import Template from './template'; // eslint-disable-next-line @typescript-eslint/no-var-requires,import/no-dynamic-require const LOADED_MODULES = require(process.env.LOADABLE_JSON_PATH!); // eslint-disable-next-line @typescript-eslint/no-var-requires,import/no-dynamic-require const ICON_STATS = require(process.env.ICONSTATS_JSON_PATH!); // eslint-disable-next-line @typescript-eslint/no-var-requires,import/no-dynamic-require const PRERENDER_CONFIG: PrerenderConfig = require(process.env .PRERENDER_CONFIG_PATH!).default; interface Props { messages: LocaleMessages; store: Store; location: LocationDescriptor; component: JSX.Element; theme: any; modules: string[]; } function RenderedPage({ messages, store, location, modules, component, theme, }: Props) { return ( modules.push(name)}> {component} ); } function getBundles(manifest: any, moduleIds: string[]): any { return moduleIds.reduce( (bundles, moduleId) => bundles.concat(manifest[moduleId]), [], ); } async function run(locals: any) { await Loadable.preloadAll(); const p = locals.path.replace('.html', ''); // Create redux store with history const initialState = { ...appConfig.initialState, router: routeInitialState.set('location', createLocation(p)), ...locals.pathStates[locals.path], }; const history = createHistory(); const store = initRedux(initialState, history); const sheet = new ServerStyleSheet(); const modules: string[] = []; const WrappingComponent = PRERENDER_CONFIG.wrappingComponent; const component = WrappingComponent ? ( ) : ( ); const page = sheet.collectStyles( , ); const renderedContent = ReactDOMServer.renderToString(page); const helmet = Helmet.renderStatic(); const prerenderedBundleSources = getBundles(LOADED_MODULES, modules).map( (bundle: any) => `/static/${bundle.file}`, ); // There is only one entry called main, so if we find a match we know it's filename. let mainScriptFilename; const chunkLists: any[][] = Object.values(LOADED_MODULES); for (const chunkList of chunkLists) { for (const chunk of chunkList) { if (chunk.file.startsWith('main.') && chunk.file.endsWith('.js')) { mainScriptFilename = chunk.file; break; } } if (mainScriptFilename) { break; } } const scripts = [ ...prerenderedBundleSources, `/static/${mainScriptFilename!}`, ]; const htmlParser = new Parser(); const iconLinks = ICON_STATS.html.map((link: string) => htmlParser.parse(link), ); return ReactDOMServer.renderToStaticMarkup(