You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/Microsoft.AspNetCore.SpaServices/README.md
+27-26Lines changed: 27 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ If you're building an ASP.NET Core application, and want to use Angular 2, React
4
4
5
5
This package enables:
6
6
7
-
*[**Server-side prerendering**](#server-sideprerendering) for *universal* (a.k.a. *isomorphic*) applications, where your Angular 2 / React / etc. components are first rendered on the server, and then transferred to the client where execution continues
7
+
*[**Server-side prerendering**](#server-side-prerendering) for *universal* (a.k.a. *isomorphic*) applications, where your Angular 2 / React / etc. components are first rendered on the server, and then transferred to the client where execution continues
8
8
*[**Webpack middleware**](#webpack-dev-middleware) so that, during development, any webpack-build resources will be generated on demand, without you having to run webpack manually or compile files to disk
9
9
*[**Hot module replacement**](#webpack-hot-module-replacement) so that, during development, your code and markup changes will be sent to your browser and updated in the running application, without even needing to reload the page
10
10
*[**Routing helpers**](#routing-helper-mapspafallbackroute) for integrating server-side routing with client-side routing
@@ -59,7 +59,7 @@ If you run your application now, and browse to whatever page renders the view yo
59
59
60
60
Create a JavaScript file at the path matching the `asp-prerender-module` value you specified above. In this example, that means creating a folder called `ClientApp` at the root of your project, and creating a file inside it called `boot-server.js`. Try putting the following into it:
61
61
62
-
```
62
+
```javascript
63
63
module.exports=function(params) {
64
64
returnnewPromise(function (resolve, reject) {
65
65
var result ='<h1>Hello world!</h1>'
@@ -80,13 +80,15 @@ As you can see, your JavaScript code receives context information (such as the U
80
80
81
81
If you want to pass some contextual data from your server-side code to your client-side code (for example, to avoid having to load the same data you just loaded on the server again on the client), you can supply a `globals` object alongside the initial `html`, e.g.:
82
82
83
-
resolve({
84
-
html: result,
85
-
globals: {
86
-
albumsList: someDataHere,
87
-
userData: someMoreDataHere
88
-
}
89
-
});
83
+
```javascript
84
+
resolve({
85
+
html: result,
86
+
globals: {
87
+
albumsList: someDataHere,
88
+
userData: someMoreDataHere
89
+
}
90
+
});
91
+
```
90
92
91
93
When the `aspnet-prerender-*` tag helper emits this result into the document, as well as injecting the `html` string, it will also emit code that populates `window.albumsList` and `window.userData` with JSON-serialized copies of the objects you passed.
92
94
@@ -118,7 +120,7 @@ Let's say you want to write your boot module and SPA code in TypeScript. First e
118
120
119
121
Next, create a file `webpack.config.js` at the root of your project, containing:
120
122
121
-
```
123
+
```javascript
122
124
module.exports= {
123
125
resolve: { extensions: [ '', '.js', '.ts' ] },
124
126
module: {
@@ -133,7 +135,7 @@ This tells webpack that it should compile `.ts` files using TypeScript, and that
133
135
134
136
Now you can delete `ClientApp/boot-server.js`, and in its place, create `ClientApp/boot-server.ts`, containing the TypeScript equivalent of what you had before:
@@ -181,7 +183,7 @@ React components can be executed synchronously on the server quite easily, altho
181
183
182
184
Let's say you want to write a React component in ES2015 code. You might install the NPM modules `react react-dom babel-loader babel-preset-react babel-preset-es2015`, and then prepare Webpack to build `.jsx` files by creating `webpack.config.js` in your project root, containing:
183
185
184
-
```
186
+
```javascript
185
187
var path =require('path');
186
188
187
189
module.exports= {
@@ -203,15 +205,15 @@ module.exports = {
203
205
204
206
You will also need a `.babelrc` file in your project root, containing:
205
207
206
-
```
208
+
```javascript
207
209
{
208
210
"presets": ["es2015", "react"]
209
211
}
210
212
```
211
213
212
214
This is enough to be able to build ES2015 `.jsx` files via Webpack. Now you could implement a simple React component, for example the following at `ClientApp/react-app.jsx`:
213
215
214
-
```
216
+
```javascript
215
217
import*asReactfrom'react';
216
218
217
219
exportclassHelloMessageextendsReact.Component
@@ -224,21 +226,21 @@ export class HelloMessage extends React.Component
224
226
225
227
... and the following code to run it in a browser at `ClientApp/boot-client.jsx`:
At this stage, run `webpack` on the command line to build `wwwroot/dist/main.js`. Or, to avoid having to do this manually, you could use the `SpaServices` package to enable Webpack dev middleware.
237
+
At this stage, run `webpack` on the command line to build `wwwroot/dist/main.js`. Or, to avoid having to do this manually, you could use the `SpaServices` package to [enable Webpack dev middleware](#webpack-dev-middleware).
236
238
237
239
You can now run your React code on the client by adding the following to one of your MVC views:
238
240
239
241
<div id="my-spa"></div>
240
242
<script src="/dist/main.js"></script>
241
-
243
+
242
244
#### Running React code on the server
243
245
244
246
Now you have React code being built using Webpack, you can enable server-side prerendering using the `aspnet-prerender-*` tag helpers as follows:
@@ -248,7 +250,7 @@ Now you have React code being built using Webpack, you can enable server-side pr
248
250
249
251
... along with the following boot module at `ClientApp/boot-server.jsx`:
250
252
251
-
```
253
+
```javascript
252
254
import*asReactfrom'react';
253
255
import { renderToString } from'react-dom/server';
254
256
import { HelloMessage } from'./react-app';
@@ -292,7 +294,7 @@ It lets you work as if the browser natively understands whatever file types you
292
294
293
295
After installing the `Microsoft.AspNetCore.SpaServices` NuGet package and the `aspnet-webpack` NPM package, go to your `Startup.cs` file, and **before your call to `UseStaticFiles`**, add the following:
294
296
295
-
```
297
+
```csharp
296
298
if (env.IsDevelopment()) {
297
299
app.UseWebpackDevMiddleware();
298
300
}
@@ -302,7 +304,7 @@ if (env.IsDevelopment()) {
302
304
303
305
You will also need to edit your webpack configuration at `webpack.config.js`. Since `UseWebpackDevMiddleware` needs to know which incoming requests to intercept, specify a `publicPath` value on your `output`, for example:
Also, to work around a temporary issue in `SpaServices`, you must ensure that your Webpack config includes a `plugins` array, even if it's empty. For example, in `webpack.config.js`:
352
354
353
-
```
355
+
```javascript
354
356
module.exports= {
355
357
// ... rest of your webpack config is here ...
356
358
@@ -372,7 +374,7 @@ If you edit any of your source files that get built by webpack, the result will
372
374
373
375
Webpack has built-in support for updating React components in place. To enable this, amend your `UseWebpackDevMiddleware` call further as follows:
@@ -404,7 +406,7 @@ If a request arrives for `/some/page`, and it doesn't match any server-side rout
404
406
405
407
To help distinguish between these cases, the `Microsoft.AspNetCore.SpaServices` NuGet package includes a routing helper, `MapSpaFallbackRoute`. For example, in your `Startup.cs` file's `Configure` method, you might add:
406
408
407
-
```
409
+
```csharp
408
410
app.UseStaticFiles();
409
411
410
412
app.UseMvc(routes=>
@@ -428,4 +430,3 @@ Then, since `MapSpaFallbackRoute` is last, any other requests **that don't appea
428
430
Any requests that do appear to be for static files (i.e., those that end with filename extensions), will *not* be handled by `MapSpaFallbackRoute`, and so will end up as 404s.
429
431
430
432
This is not a perfect solution to the problem of identifying 404s, because for example `MapSpaFallbackRoute` will not match requests for `/users/albert.einstein`, because it appears to contain a filename extension (`.einstein`). If you need your SPA to handle routes like that, then don't use `MapSpaFallbackRoute` - just use a regular MVC catch-all route. But then beware that requests for unknown static files will result in your client-side app being rendered.
0 commit comments