2016-10-10 30 views
3

我有一個react-redux應用程序在aspnet核心上運行,服務器端渲染使用aspnet預渲染。Aspnet服務器渲染調試

可以說我犯了一個編程錯誤,在兒童組件中,我嘗試訪問一個未定義的道具,因爲一個愚蠢的錯字。

import {Child} from './child' 
export class Parent extends React.Component { 
    render() { 
    const someProp = { 
     something: "something" 
    }; 
    return <Child someProp={someProp} />; 
    } 
} 

export class Child extends React.Component { 
    render() { 
    return <div>this.props.someprop.something</div>; 
     //typo: should be someProp instead of someprop 
} 

沒有服務器渲染,我會得到類似這樣的錯誤:在x行不能訪問的不確定的東西:YY 但隨着serverrendering我得到一個:

An unhandled exception occurred while processing the request.

Exception: Call to Node module failed with error: Prerendering timed out after 30000ms because the boot function in 'ClientApp/src/boot-server' returned a promise that did not resolve or reject. Make sure that your boot function always resolves or rejects its promise. You can change the timeout value using the 'asp-prerender-timeout' tag helper.

這使得調試很難,當你沒有得到任何錯誤的反饋。 任何人知道如何設置一個拒絕,如果失敗了?或者甚至有可能調試服務器端呈現的代碼?

這裏是我的啓動服務器文件,告訴我你是否需要更多的文件。

import * as React from 'react'; 
import { Provider } from 'react-redux'; 
import { renderToString } from 'react-dom/server'; 
import configureStore from './store/configureStore'; 
import {getFormById} from './actions/getFormActions'; 
import {updateUserLocale} from './actions/userLocaleActions'; 
import FormResponder from './components/mainComponents/formResponder'; 

export default function renderApp (params) { 

    return new Promise((resolve, reject) => { 

     const store = configureStore(); 
     store.dispatch(getFormById(params.data.id, params.data.config, params.data.authenticationToken)); 
     store.dispatch(updateUserLocale(params.data.userLocale)); 
     const app = (
      <Provider store={ store }> 
       <FormResponder /> 
      </Provider> 
     ); 

    // Perform an initial render that will cause any async tasks (e.g., data access) to begin 
    renderToString(app); 

    // Once the tasks are done, we can perform the final render 
    // We also send the redux store state, so the client can continue execution where the server left off 
    params.domainTasks.then(() => { 
     resolve({ 
      html: renderToString(app), 
      globals: { 
       initialReduxState: store.getState(), 
       authenticationToken: params.data.authenticationToken, 
       config: params.data.config 
      } 
     }); 
    }, reject); // Also propagate any errors back into the host application 
}); 
} 

回答

1

發現,對於我工作的解決方案:我插一試 /風行最終的renderToString。 在catch中我發送一個包含錯誤的調度。

更新引導server.jsx

params.domainTasks.then(() => { 
     let html; 
     try { 
      html = renderToString(app); 
     } 
     catch (err) { 
      store.dispatch(loadFormFailed({message: err.toString() })); 
     } 

     resolve({ 
      html: html, 
      globals: { 
       initialReduxState: store.getState(), 
       authenticationToken: params.data.authenticationToken, 
       config: params.data.config, 
       disableReactServerRendring: false 
      } 
     }); 
     }, reject); 
     // Also propagate any errors back into the host application 
    }); 
2

我已經做了索姆研究,並得出結論:這是不可能的時間beeing調試初始服務器渲染代碼。

我做的反而是實現邏輯,以便我可以禁用服務器渲染。

這是它的樣子:

public async Task<IActionResult> Index(string id, string userLocale = "en", bool server = true) 
{ 
    Guid positionId; 
    if (!Guid.TryParse(id, out positionId)) 
    { 
     throw new Exception("Invalid position id");   
    } 

    var token = await _apiClient.GetToken(); 

    var formData = new ApplicationFormViewModel() 
    { 
     Id = positionId, 
     UserLocale = userLocale, 
     AuthenticationToken = token.AccessToken, 
     Server = server 
    }; 
    return View(formData); 
} 

view.cshtml:

@{if (@Model.Server) { 
    <div 
    class="container" 
    id="react-app" 
    asp-prerender-module="ClientApp/src/boot-server" 
    asp-prerender-data="new { 
     Id = @Model.Id, 
     UserLocale = @Model.UserLocale, 
     AuthenticationToken = @Model.AuthenticationToken, 
     Config = new { 
      ApplicationPostUrl = @Url.Action("SaveApplication"), 
      AttachmentPostUrl = @Url.Action("UploadAttachment"), 
      FormGetUrl = @Url.Action("GetForm") 
     } 
    }" 
    asp-prerender-webpack-config="webpack.config.js" > 
     Loading... 
</div> 
} 
else { 
    <script> 
     var id= '@Model.Id'; 
     var config= { 
      applicationPostUrl: '@Url.Action("SaveApplication")', 
      attachmentPostUrl: '@Url.Action("UploadAttachment")', 
      formGetUrl: '@Url.Action("GetForm")' 
     }; 
     var userLocale='@Model.UserLocale'; 
     var authenticationToken='@Model.AuthenticationToken'; 
     var server = false; 
    </script> 
    <div class="container" id="react-app">loading</div> 

} 
} 



@section scripts { 

    <script src="~/dist/main.js" asp-append-version="true"></script> 
} 

啓動server.jsx:

export default function renderApp (params) { 

    return new Promise((resolve, reject) => { 

     const store = configureStore(); 
     store.dispatch(getFormById(params.data.id, params.data.config, params.data.authenticationToken)); 
     store.dispatch(updateUserLocale(params.data.userLocale)); 
     const app = (
      <Provider store={ store }> 
       <FormResponder /> 
      </Provider> 
     ); 

    // Perform an initial render that will cause any async tasks (e.g., data access) to begin 
    renderToString(app); 

    // Once the tasks are done, we can perform the final render 
    // We also send the redux store state, so the client can continue execution where the server left off 
    params.domainTasks.then(() => { 
     resolve({ 
      html: renderToString(app), 
      globals: { 
       initialReduxState: store.getState(), 
       authenticationToken: params.data.authenticationToken, 
       config: params.data.config, 
       server: true 
      } 
     }); 
     }, reject); // Also propagate any errors back into the host application 
}); 
} 

啓動client.jsx:

// Grab the state from a global injected into server-generated HTML 
const {id, initialReduxState, authenticationToken, config, server, userLocale } = window; 

if (server) { 


// Get the application-wide store instance, prepopulating with state from the server where available. 
const store = configureStore(initialReduxState); 
// This code starts up the React app when it runs in a browser. 
ReactDOM.render(
    <Provider store={ store }> 
     <FormResponder authenticationToken={authenticationToken} config={config} /> 
    </Provider>, 
    document.getElementById('react-app') 
); 


} 
else { 

    const store = configureStore(); 
    store.dispatch(getFormById(id, config, authenticationToken)); 
    store.dispatch(updateUserLocale(userLocale)); 

    render(
     <Provider store ={store}> 
      <FormResponder authenticationToken={authenticationToken} config={config} /> 
     </Provider>, 
     document.getElementById('react-app') 
    ); // Take our FormBuilder component and attach it with DOM element "app" 
} 

所以現在我可以簡單地通過在URL的末尾添加服務器=假開啓服務器渲染,並開始調試:)

4

我有過類似的經歷與Visual Studio 2017年的工作我最終意識到,原來的(多個)錯誤診斷的信息實際上在輸出窗口。

+0

你剛剛救了我瘋了! – racamp101