Skip to content
This repository has been archived by the owner on Apr 8, 2020. It is now read-only.

[Feature Request] - Add an SPA View Engine that gives the ability to render the entire page instead of using Razor #182

Closed
AustinWinstanley opened this issue Jul 14, 2016 · 4 comments

Comments

@AustinWinstanley
Copy link

For example in React with Webpack, an entire page can be rendered with the Html React component looking something like this:

Html.js

import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom/server';
import Helmet from 'react-helmet';
import serialize from 'serialize-javascript';

const head = Helmet.rewind();

const Html = ({ component, store }) => {
    const _content = component ? ReactDOM.renderToString(component) : '';

    return (
        <html lang="en-us">
            <head>
                {head.base.toComponent()}
                {head.title.toComponent()}
                {head.meta.toComponent()}
                {head.link.toComponent()}
                {head.script.toComponent()}
                <link rel="shortcut icon" href="/favicon.ico" />
                <meta name="viewport" content="width=device-width, initial-scale=1" />
            </head>
            <body>
                <div id="content" dangerouslySetInnerHTML={{ __html: _content }} />
                <script dangerouslySetInnerHTML={{ __html: `window.__data=${serialize(store.getState())};` }} />
                <script src="/dist/client.generated.js" />
            </body>
        </html>
    );
};

Html.propTypes = {
    component: PropTypes.node,
    store: PropTypes.object
};

export default Html;

Currently, it looks like the Razor view engine requires a layout and partial page.

It's possible to get around this somewhat by setting IgnoreBody() at the top of the _Layout and a placeholder view, but then you have to workaround the view by returning View("index", model) every time.

_Layout.cshtml

@{
    IgnoreBody();
}

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Hello World</title>
</head>
<body>
    <div
        id="content"
        asp-prerender-module="Public/Server"
        asp-prerender-webpack-config="webpack.config.js"
        asp-prerender-data="@Model">
    </div>
</body>
</html>

Index.cshtml

@*
    // View Placeholder
*@

Controller

public IActionResult MyView()
{
    return View("Index", new MyViewModel());
}

The routing is handled by React Router.

This way works, but it seems like a lot of extra effort if a view engine could be created that could server the entire page, skipping Razor entirely.

@SteveSandersonMS
Copy link
Member

Great suggestion.

Do you think it needs to be a view engine, or would a custom ActionResult meet your needs? I started prototyping it as a view engine, but it seemed to offer no benefit vs an action result, and yet an action result was far simpler.

I added a sample in commit 749c7c showing how this can be done. If you want to try this in your project, copy the PrerenderResult.cs and PrerenderResultExtensions.cs into your project, then you'll be able to return this.Prerender(...); from your action methods as in this example.

The example I've given isn't specific to React but the code you've posted above should work to perform the actual calls into React. You'd just need to wrap it in a promise as per the example here (this ensures that you can do async prerendering too if you need).

What do you think? If more people ask for something like this, we could move PrerenderResult into the SpaServices package.

@antonchanshaw
Copy link

👍

@laskoviymishka
Copy link
Contributor

@SteveSandersonMS May be it reasonable to have something like a Middleware.
So usage be like there:

app.UseMvc(routes =>
            {
                    routes.MapSpa('/fancy-spa-route', new SpaConfig { webpackStuff= 'etc' });
            }

This is reasonable for apps that use ASPNET like a Advanced file server with some rest api feature, so any controllers and view is not really needed for them 😄

@SteveSandersonMS
Copy link
Member

@laskoviymishka That sounds totally reasonable. If you can supply a proposed implementation and usage examples, we can definitely consider including some middleware like that!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants