Skip to content

[Components] Prerrendering startup experience #7770

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

javiercn
Copy link
Member

Runtime changes to support the new components startup experience.

I still need to do a bit of cleanup and add more tests, but the main pieces and functional tests are in to show that it works.

I'll expand the PR tomorrow morning with the changes to the components template.

@javiercn javiercn force-pushed the javiercn/prerrenderer-startup-experience branch from 1dc83a2 to d5d8ea3 Compare February 20, 2019 23:15
@javiercn javiercn force-pushed the javiercn/prerrenderer-startup-experience branch from d5d8ea3 to 4f97821 Compare February 20, 2019 23:25
public IServiceProvider Services { get; }

public Task<IEnumerable<string>> PrerrenderComponentAsync(Type componentType, ParameterCollection parameters)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still don't love that this is IEnumerable<string> but it seem OK for now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rynowak For the MVC case we need to buffer the output as we need to write it synchronously. We could buffer it on a byte array, but I believe that would be more painful.
Another option would be to abstract it behind a type and provide overloads to write it to a stream/pipe (essentially an IHtmlContentResult like type).

var prepareResponse = options.OnPrepareResponse;
if (prepareResponse == null)
{
options.OnPrepareResponse = BlazorApplicationBuilderExtensions.SetCacheHeaders;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmmm

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is one of the first things I've seen (based on this approach) which makes me wonder if it's not totally generic.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, it's totally generic, but IMO in general it's easy for us to get it right, but easy for users to get wrong. It also makes it really hard to reorganize individual callbacks,etc in order to resolve conflicts (what if you have two pieces that add a callback and override each other).

In general, when we have this type of composition, I like it when it's backed by primitives and visible, so that:

  1. I get a clear understanding of how the system works.
  2. I can reorder/reconfigure the system to suit my needs without having to go bonkers or digging into the details of how each component on the stack works.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we extend the static files system to have a more native mechanism for plugging in multiple content sources, perhaps it also needs to be able to have things like response header defaults on a per-content-source basis.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah Steve found a better way of saying what I was thinking. It's a bit of a heavy hand for us configure caching settings for all static files, yet we do care about having this set for our stuff.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK to have their quirk in this release, but we should known issues or release notes this.

@javiercn javiercn force-pushed the javiercn/prerrenderer-startup-experience branch from 66a3e48 to 7a6f848 Compare February 21, 2019 13:58
@javiercn javiercn changed the base branch from master to release/3.0-preview3 February 21, 2019 14:08
@javiercn javiercn force-pushed the javiercn/prerrenderer-startup-experience branch from 32f17dc to 96f9a13 Compare February 21, 2019 14:38
Copy link
Contributor

@pranavkm pranavkm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's a couple of design questions we need to resolve, but this PR looks great for preview3

@javiercn
Copy link
Member Author

@pranavkm filed #7807 to track the layering issue

/// <param name="builder">The <see cref="IEndpointConventionBuilder"/>.</param>
/// <param name="selector">A CSS selector that identifies the DOM element into which the <typeparamref name="TComponent"/> will be placed.</param>
/// <returns>The <paramref name="builder"/>.</returns>
public static IEndpointConventionBuilder AddComponent<TComponent>(this IEndpointConventionBuilder builder, string selector)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should builder be a strong type instead of the interface? This will offer these suggestions on all of the builders.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, but that has its drawbacks too. If we wrap the builder then other conventions can't reliably downcast it to RouteEndpointConventionBuilder and you can't do things based on Order or Pattern.

I think its fine for now to leave it as it is. I have an email thread where I lay out the issues and discuss the pros/cons. I can file an issue to track it for preview4

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this might be your solution to manually registering signalR. I think it's a fine choice to leave this as-is for now 👍

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this might be your solution to manually registering signalR. I think it's a fine choice to leave this as-is for now 👍

That too, but I'm just too tired to pull thoughts out of my head 😄

Copy link
Member

@rynowak rynowak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: from me! I'm really excited about the final shape of this!

@javiercn javiercn force-pushed the javiercn/prerrenderer-startup-experience branch from 19d88f0 to 9524dd6 Compare February 21, 2019 22:54
@javiercn
Copy link
Member Author

Ubuntu has a failing unrelated test: Microsoft.DotNet.Watcher.Tools.FunctionalTests.DotNetWatcherTests.RunsWithIterationEnvVariable

@davidfowl
Copy link
Member

Ubuntu has a failing unrelated test: Microsoft.DotNet.Watcher.Tools.FunctionalTests.DotNetWatcherTests.RunsWithIterationEnvVariable

Time to disable that test, it fails EVERYWHERE

@javiercn
Copy link
Member Author

The only thing failing here is that one test in Ubuntu. @mkArtakMSFT please override.

image

Squash and merge with the following message

[Components] Prerrendering startup experience
* Introduces an IComponentPrerrenderer to handle Prerrendering
  * MVC registers a basic static prerrrenderer.
  * Components registers a more feature complete prerrender that will
    handle reconnection to the original circuit after prerrendering in
    the future to allow for prerrendered interactive components.
* Removes UseRazorComponents
  * Removes the SPA fallback in favor of a catch all route in
    Index.cshtml
  * Moves the framework files to be served by the default StaticFiles
    middleware in the pipeline by way of plugging specific providers
    through options.
  * Lifts UseSignalR(r => r.MapHub<ComponentHub>()) into startup and
    replaces it with a shorthand for MapHub using endpoint routing.
  * Adds extension methods to map components to selectors for a given
    hub.
* Updates the razor component templates to include prerendering and use a razor page as the entry 
   point.

@mkArtakMSFT mkArtakMSFT merged commit 2d9cba8 into release/3.0-preview3 Feb 22, 2019
@javiercn javiercn mentioned this pull request Feb 22, 2019
@javiercn javiercn deleted the javiercn/prerrenderer-startup-experience branch February 22, 2019 00:32
@plasticalligator
Copy link

I just wanted to say, thank you for your hard work!

app.UseRouting(builder =>
{
builder.MapRazorPages();
builder.MapComponentHub<App.App>("app");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks so good now! Awesome job, @javiercn!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does. It’s also fast to load because of the pre-rendering

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-mvc Includes: MVC, Actions and Controllers, Localization, CORS, most templates
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants