问题描述
我有一个使用 React & Redux 构建的(服务器端渲染)SSR 应用程序。我也使用可加载库。该应用程序托管在 Heroku 上并使用 Cloudflare 缓存。
应用程序在 Heroku 上间歇性地以 500 错误结束,我无法找到错误的根本原因。以下是错误信息
loadable-components: Failed to synchronously load component,which expected to be available {
fileName: 592,chunkName: 'home-route',error: 'Cannot convert undefined or null to object'
}
TypeError: Cannot convert undefined or null to object
at getPrototypeOf (<anonymous>)
at hoistNonReactStatics (/app/node_modules/@loadable/component/node_modules/hoist-non-react-statics/dist/hoist-non-react-statics.cjs.js:70:32)
at resolve (/app/node_modules/@loadable/component/dist/loadable.cjs.js:128:7)
at InnerLoadable.loadSync (/app/node_modules/@loadable/component/dist/loadable.cjs.js:279:24)
at new InnerLoadable (/app/node_modules/@loadable/component/dist/loadable.cjs.js:173:17)
at d (/app/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:36:320)
at $a (/app/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:39:16)
at a.b.render (/app/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:44:476)
at a.b.read (/app/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:44:18)
at Object.renderToString (/app/node_modules/react-dom/cjs/react-dom-server.node.production.min.js:54:364)
at /app/static/dist/server/server.js:79236:42
at runMicrotasks (<anonymous>)
at processticksAndRejections (internal/process/task_queues.js:97:5)
由于这种情况是间歇性发生的,我无法找到发生这种情况的根本原因。以下是发生错误的 Home 组件的详细信息
src/routes/HomeRoute.js
// Libs
import { asyncConnectWithModifications } from 'decorators/asyncConnectWithModifications'
import { compose } from 'redux'
import { connect } from 'react-redux'
import path from 'ramda/src/path'
import loadable from '@loadable/component'
// Actions
import { getTotalCampers } from 'myredux/modules/search'
import { getPagesList } from 'myredux/modules/content'
// Constants
import defaultCoords from 'routes/Search/defaultCoords'
// Components
const Home = loadable(() => import(/* webpackChunkName: "home-route" */ './Home'))
export default compose(
asyncConnectWithModifications({
getPromise: ({ store: { dispatch,getState } }) => {
const state = getState()
const totalCampers = path(['search','totalCampeRSSearchResult','Pagination','Total'],state)
const totalCampeRSSearch = path(['search','searchResult',state)
const promises = []
if (!totalCampers || (totalCampeRSSearch > totalCampers)) {
// Set default coords
const { centerLat,centerLng } = defaultCoords[state.app.country.code] || {}
promises.push(dispatch(getTotalCampers({ center_lat: centerLat,center_lng: centerLng })))
}
promises.push(dispatch(
getPagesList('posts'),))
return Promise.all(promises)
},}),connect(state => ({
locale: state.app.locale,})),)(Home)
src/routes/Home.js
...
render() {
const { app,env,search,content,locale,translate,formatNumber,lastDraftCamperId,userId } = this.props
const { bannerCamperClosed } = this.state
const totalCampers = path(['totalCampeRSSearchResult',search)
const formattedTotalCampers = formatNumber(totalCampers)
// Canonical for home page is current domain
const canonical = `https://${app.domain.name}/`
const Meta = {
title: translate({ id: 'home.pageTitle' }),description: translate({ id: 'home.pageDescription' }),link: [
{ rel: 'canonical',href: canonical },{ rel: 'alternate',href: 'https://paulcamper.de/',hrefLang: 'de-DE' },href: 'https://paulcamper.at/',hrefLang: 'de-AT' },// { rel: 'alternate',href: 'https://paulcamper.co.uk/',hrefLang: 'en-GB' },// UK domain is disabled for Now [.co.uk uncomment]
// { rel: 'alternate',href: 'https://paulcamper.es/',hrefLang: 'es-ES' },// ES domain is disabled for Now [.es uncomment]
// { rel: 'alternate',href: 'https://paulcamper.it/',hrefLang: 'it-IT' },// Italian domain is disabled for Now [.it uncomment]
{ rel: 'alternate',href: 'https://paulcamper.nl/',hrefLang: 'nl-NL' },],}
const numberOfMonths = app.breakpoint === 'xs' ? 1 : 2
const { DE } = LOCALE_LANGUAGES
const { ES,FR,IT } = LOCALE_CODES
const doHideHomeCities = [ES,IT].includes(locale.code)
return (
<nestedStatus maxage={DAY}>
<div className={styles.container}>
<DocumentMeta {...Meta}/>
<BlockedLenderBanner/>
<BodyClassName className="page-home"/>
{!bannerCamperClosed && lastDraftCamperId &&
<HomeBannerCamper
camperId={lastDraftCamperId}
userId={userId}
onClose={this.handleBannerCamperClose}
/>}
<div className={styles.head} style={{ backgroundImage: `url(${this.bgImage})` }}>
<div className={styles.headContent}>
<div className={styles.header}>
<Header
theme="light"
pageName="home"
isHomePage
isLenderButtonActive
isSearchButtonActive={false}
/>
</div>
<Grid>
<Row>
<Col xs={12}>
<div className={styles.title}>
<Row>
<Col xs={12} md={10} mdOffset={1} lg={8} lgOffset={2}>
<h1 className={styles.headTitle}>
<FormattedMessage id="home.v2.title.xp"/>
</h1>
{app.locale.language === 'nl' &&
<h2 className={styles.headSubTitle}>
<FormattedMessage id="home.subTitle"/>
</h2>}
<TrustBoxNew
withoutReviews
white
small
/>
</Col>
</Row>
</div>
</Col>
</Row>
</Grid>
<Grid>
<Row>
<Col xs={12}>
<div className={styles.search}>
<SearchFormHome
locale={locale}
numberOfMonths={numberOfMonths}
filters={search.filters}
onApply={this.handleSearchFormSubmit}
onLocationChange={this.handleLocationChange}
onFiltersChange={this.props.setFilters}
onSubmit={this.handleSearchFormSubmit}
withAutoFocus={false}
submitLocationOnBlur
/>
</div>
<div className={styles.publicRequest}>
<FormattedHTMLMessage id="home.publicRequests" values={{ total: formattedTotalCampers }}/>
{' '}
<Link to="/add-public-request/" onClick={this.handlePublickRequest}>
<FormattedMessage id="home.publicRequests.create"/>
<i className={styles.publicRequestIcon}>
<Icon src={require('icons/icon-arrow-left.svg')}/>
</i>
</Link>
</div>
</Col>
</Row>
</Grid>
{/** app.locale.language === 'de' &&
<div className={styles.firstPlaceBanner}>
<FirstPlaceBanner/>
</div> **/}
</div>
</div>
<SearchWizardTest component={(
<SearchWizardCta locale={locale} onClick={this.handleSearchWizardClick}/>
)}
/>
<div className={styles.trust}>
<HomeTrust app={app}/>
</div>
<PromiseBlock/>
<AwarenessBlock>
{locale.code === LOCALE_CODES.DE &&
<AwarenessBlockItem
buttonText="Ja,gerne"
onButtonClick={this.handleRecruitingAwareClick}
preset={2}
text="Wir führen regelmäßig Umfragen zur Website,zu Camping und Reisethemen durch. Bist du dabei?"
title="Lass uns PaulCamper noch besser machen"
trackName="test-user-recruiting"
trackPage="home"
/>}
<AwarenessBlockItem
buttonText={translate({ id: 'home.awareness.friendly-covid.buttonText' })}
onButtonClick={this.handleAwarenessFcclick}
preset={3}
text={translate({ id: 'home.awareness.friendly-covid.text' })}
title={translate({ id: 'home.awareness.friendly-covid.title' })}
trackName="friendly-covid-cancel"
trackPage="home"
/>
</AwarenessBlock>
<HomeHowPaulcamperWorks
locale={locale}
totalCampers={formattedTotalCampers}
/>
<div className={styles.renterSteps}>
<HomeRenterSteps/>
</div>
{!doHideHomeCities && // temporarily hidden section for .it,co.uk,.es domains [.it uncomment][.es uncomment][.co.uk uncomment]
<Grid>
<Row>
<Col xs={12}>
<div className={styles.cities}>
<HomeCities country={app.country.code} locale={locale}/>
</div>
</Col>
</Row>
</Grid>}
<div className={styles.community}>
<HomeCommunity locale={locale}/>
</div>
<div className={styles.sectionText}>
<Grid>
<Row>
<Col xs={12}>
<FormattedHTMLMessage id="home.text1"/>
</Col>
</Row>
</Grid>
</div>
{locale.language === DE &&
<div className={styles.posts}>
<Grid>
<Row>
<Col xs={12}>
<HomePosts breakpoint={app.breakpoint} locale={locale} posts={content.pagesList}/>
</Col>
</Row>
</Grid>
</div>}
<div className={styles.contacts}>
<Grid>
<Row>
<Col xs={12}>
<SectionQuestions isLenderView/>
</Col>
</Row>
</Grid>
</div>
<div className={styles.team}>
<HomeTeam locale={locale}/>
</div>
<div className={styles.sectionText}>
<Grid>
<Row>
<Col xs={12}>
<FormattedHTMLMessage id="home.text2"/>
</Col>
</Row>
</Grid>
</div>
<Footer location={this.props.location} trustBox={false}/>
{env.AUTOTEST_MODE !== 'true' &&
// eslint-disable-next-line react/no-danger
<script defer dangerouslySetInnerHTML={{ __html: customerSupportWidget(locale.code) }}/>}
</div>
</nestedStatus>
)
}
}
export default compose(
connect(
state => ({
app: state.app,auth: state.auth,env: getEnv(state),search: state.search,content: state.content,fromDate: state.search.fromDate,lastDraftCamperId: lastDraftCamperIdSelector(state),userId: userIdSelector(state),locale: state.app.locale,tillDate: state.search.tillDate,{ setFilter,setFilters,setLocation }),withStyles(styles),intl(),)(Home)
src/server/createRenderApp.js
...
// Critical CSS
const css = new Set()
// Global (context) variables that can be easily accessed from any React component
// https://facebook.github.io/react/docs/context.html
const appContext = {
// Enables critical path CSS rendering
// https://github.com/kriasoft/isomorphic-style-loader
insertCss: (...styles) => styles.forEach(style => css.add(style._getCss())),}
const url = req.originalUrl || req.url
// fix query and search
const location = parseUrl(url,true)
const routes = getRoutes(store)
const helpers = { client }
loadOnServer({
store,location,routes,helpers,})
.then(() => {
appContext.translations = translations[domainConfig.locale]
const routerContext = {}
const component = (
<App context={appContext}>
<Provider store={store} key="provider">
<ThemeProvider>
<StaticRouter location={location} context={routerContext}>
<ReduxAsyncConnect helpers={helpers} routes={routes} />
</StaticRouter>
</ThemeProvider>
</Provider>
</App>
)
...
任何想法或建议肯定会有所帮助。提前致谢。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)