mirror of
https://github.com/aspnet/JavaScriptServices.git
synced 2025-12-22 17:47:53 +00:00
Implement and document asp-prerender-data
This commit is contained in:
@@ -19,6 +19,7 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
|
|||||||
private const string PrerenderModuleAttributeName = "asp-prerender-module";
|
private const string PrerenderModuleAttributeName = "asp-prerender-module";
|
||||||
private const string PrerenderExportAttributeName = "asp-prerender-export";
|
private const string PrerenderExportAttributeName = "asp-prerender-export";
|
||||||
private const string PrerenderWebpackConfigAttributeName = "asp-prerender-webpack-config";
|
private const string PrerenderWebpackConfigAttributeName = "asp-prerender-webpack-config";
|
||||||
|
private const string PrerenderDataAttributeName = "asp-prerender-data";
|
||||||
private static INodeServices _fallbackNodeServices; // Used only if no INodeServices was registered with DI
|
private static INodeServices _fallbackNodeServices; // Used only if no INodeServices was registered with DI
|
||||||
|
|
||||||
private readonly string _applicationBasePath;
|
private readonly string _applicationBasePath;
|
||||||
@@ -51,6 +52,9 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
|
|||||||
[HtmlAttributeName(PrerenderWebpackConfigAttributeName)]
|
[HtmlAttributeName(PrerenderWebpackConfigAttributeName)]
|
||||||
public string WebpackConfigPath { get; set; }
|
public string WebpackConfigPath { get; set; }
|
||||||
|
|
||||||
|
[HtmlAttributeName(PrerenderDataAttributeName)]
|
||||||
|
public object CustomDataParameter { get; set; }
|
||||||
|
|
||||||
[HtmlAttributeNotBound]
|
[HtmlAttributeNotBound]
|
||||||
[ViewContext]
|
[ViewContext]
|
||||||
public ViewContext ViewContext { get; set; }
|
public ViewContext ViewContext { get; set; }
|
||||||
@@ -67,7 +71,8 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
|
|||||||
WebpackConfig = WebpackConfigPath
|
WebpackConfig = WebpackConfigPath
|
||||||
},
|
},
|
||||||
request.GetEncodedUrl(),
|
request.GetEncodedUrl(),
|
||||||
request.Path + request.QueryString.Value);
|
request.Path + request.QueryString.Value,
|
||||||
|
CustomDataParameter);
|
||||||
output.Content.SetHtmlContent(result.Html);
|
output.Content.SetHtmlContent(result.Html);
|
||||||
|
|
||||||
// Also attach any specified globals to the 'window' object. This is useful for transferring
|
// Also attach any specified globals to the 'window' object. This is useful for transferring
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
|
|||||||
INodeServices nodeServices,
|
INodeServices nodeServices,
|
||||||
JavaScriptModuleExport bootModule,
|
JavaScriptModuleExport bootModule,
|
||||||
string requestAbsoluteUrl,
|
string requestAbsoluteUrl,
|
||||||
string requestPathAndQuery)
|
string requestPathAndQuery,
|
||||||
|
object customDataParameter)
|
||||||
{
|
{
|
||||||
return nodeServices.InvokeExport<RenderToStringResult>(
|
return nodeServices.InvokeExport<RenderToStringResult>(
|
||||||
NodeScript.Value.FileName,
|
NodeScript.Value.FileName,
|
||||||
@@ -30,7 +31,8 @@ namespace Microsoft.AspNetCore.SpaServices.Prerendering
|
|||||||
applicationBasePath,
|
applicationBasePath,
|
||||||
bootModule,
|
bootModule,
|
||||||
requestAbsoluteUrl,
|
requestAbsoluteUrl,
|
||||||
requestPathAndQuery);
|
requestPathAndQuery,
|
||||||
|
customDataParameter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,6 +81,34 @@ If you try running your app now, you should see the HTML snippet generated by yo
|
|||||||
|
|
||||||
As you can see, your JavaScript code receives context information (such as the URL being requested), and returns a `Promise` so that it can asynchronously supply the markup to be injected into the page. You can put whatever logic you like here, but typically you'll want to execute a component from your Angular 2 / React / etc. application.
|
As you can see, your JavaScript code receives context information (such as the URL being requested), and returns a `Promise` so that it can asynchronously supply the markup to be injected into the page. You can put whatever logic you like here, but typically you'll want to execute a component from your Angular 2 / React / etc. application.
|
||||||
|
|
||||||
|
**Passing data from .NET code into JavaScript code**
|
||||||
|
|
||||||
|
If you want to supply additional data to the JavaScript function that performs your prerendering, you can use the `asp-prerender-data` attribute. You can give any value as long as it's JSON-serializable. Bear in mind that it will be serialized and sent as part of the remote procedure call (RPC) to Node.js, so avoid trying to pass massive amounts of data.
|
||||||
|
|
||||||
|
For example, in your `cshtml`,
|
||||||
|
|
||||||
|
<div id="my-spa" asp-prerender-module="ClientApp/boot-server"
|
||||||
|
asp-prerender-data="new {
|
||||||
|
IsGoldUser = true,
|
||||||
|
Cookies = ViewContext.HttpContext.Request.Cookies
|
||||||
|
}""></div>
|
||||||
|
|
||||||
|
Now in your JavaScript prerendering function, you can access this data by reading `params.data`, e.g.:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
module.exports = function(params) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
var result = '<h1>Hello world!</h1>'
|
||||||
|
+ '<p>Is gold user: ' + params.data.isGoldUser + '</p>'
|
||||||
|
+ '<p>Number of cookies: ' + params.data.cookies.length + '</p>';
|
||||||
|
|
||||||
|
resolve({ html: result });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Notice that the property names are received in JavaScript-style casing (e.g., `isGoldUser`) even though they were sent in C#-style casing (e.g., `IsGoldUser`). This is because of how the JSON serialization is configured by default.
|
||||||
|
|
||||||
**Passing data from server-side to client-side code**
|
**Passing data from server-side to client-side code**
|
||||||
|
|
||||||
If, as well as returning HTML, you also want to pass some contextual data from your server-side code to your client-side code, you can supply a `globals` object alongside the initial `html`, e.g.:
|
If, as well as returning HTML, you also want to pass some contextual data from your server-side code to your client-side code, you can supply a `globals` object alongside the initial `html`, e.g.:
|
||||||
@@ -245,7 +273,7 @@ At this stage, run `webpack` on the command line to build `wwwroot/dist/main.js`
|
|||||||
|
|
||||||
You can now run your React code on the client by adding the following to one of your MVC views:
|
You can now run your React code on the client by adding the following to one of your MVC views:
|
||||||
|
|
||||||
<div id="my-spa"></div>
|
<div id="my-spa"></div>
|
||||||
<script src="/dist/main.js"></script>
|
<script src="/dist/main.js"></script>
|
||||||
|
|
||||||
#### Running React code on the server
|
#### Running React code on the server
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "aspnet-prerendering",
|
"name": "aspnet-prerendering",
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"description": "Helpers for server-side rendering of JavaScript applications in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
|
"description": "Helpers for server-side rendering of JavaScript applications in ASP.NET Core projects. Works in conjunction with the Microsoft.AspNetCore.SpaServices NuGet package.",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export interface BootFuncParams {
|
|||||||
url: string; // e.g., '/some/path'
|
url: string; // e.g., '/some/path'
|
||||||
absoluteUrl: string; // e.g., 'https://example.com:1234/some/path'
|
absoluteUrl: string; // e.g., 'https://example.com:1234/some/path'
|
||||||
domainTasks: Promise<any>;
|
domainTasks: Promise<any>;
|
||||||
|
data: any; // any custom object passed through from .NET
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BootModuleInfo {
|
export interface BootModuleInfo {
|
||||||
@@ -32,7 +33,7 @@ export interface BootModuleInfo {
|
|||||||
webpackConfig?: string;
|
webpackConfig?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function renderToString(callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string) {
|
export function renderToString(callback: RenderToStringCallback, applicationBasePath: string, bootModule: BootModuleInfo, absoluteRequestUrl: string, requestPathAndQuery: string, customDataParameter: any) {
|
||||||
findBootFunc(applicationBasePath, bootModule, (findBootFuncError, bootFunc) => {
|
findBootFunc(applicationBasePath, bootModule, (findBootFuncError, bootFunc) => {
|
||||||
if (findBootFuncError) {
|
if (findBootFuncError) {
|
||||||
callback(findBootFuncError, null);
|
callback(findBootFuncError, null);
|
||||||
@@ -51,7 +52,8 @@ export function renderToString(callback: RenderToStringCallback, applicationBase
|
|||||||
origin: parsedAbsoluteRequestUrl.protocol + '//' + parsedAbsoluteRequestUrl.host,
|
origin: parsedAbsoluteRequestUrl.protocol + '//' + parsedAbsoluteRequestUrl.host,
|
||||||
url: requestPathAndQuery,
|
url: requestPathAndQuery,
|
||||||
absoluteUrl: absoluteRequestUrl,
|
absoluteUrl: absoluteRequestUrl,
|
||||||
domainTasks: domainTaskCompletionPromise
|
domainTasks: domainTaskCompletionPromise,
|
||||||
|
data: customDataParameter
|
||||||
};
|
};
|
||||||
|
|
||||||
// Open a new domain that can track all the async tasks involved in the app's execution
|
// Open a new domain that can track all the async tasks involved in the app's execution
|
||||||
@@ -86,7 +88,7 @@ function findBootModule<T>(applicationBasePath: string, bootModule: BootModuleIn
|
|||||||
const bootModuleNameFullPath = path.resolve(applicationBasePath, bootModule.moduleName);
|
const bootModuleNameFullPath = path.resolve(applicationBasePath, bootModule.moduleName);
|
||||||
if (bootModule.webpackConfig) {
|
if (bootModule.webpackConfig) {
|
||||||
const webpackConfigFullPath = path.resolve(applicationBasePath, bootModule.webpackConfig);
|
const webpackConfigFullPath = path.resolve(applicationBasePath, bootModule.webpackConfig);
|
||||||
|
|
||||||
let aspNetWebpackModule: any;
|
let aspNetWebpackModule: any;
|
||||||
try {
|
try {
|
||||||
aspNetWebpackModule = require('aspnet-webpack');
|
aspNetWebpackModule = require('aspnet-webpack');
|
||||||
|
|||||||
Reference in New Issue
Block a user