Compare commits

..

1 Commits

Author SHA1 Message Date
Steve Sanderson
1287709feb Use HttpWithStateTransferModule in Angular template 2017-08-02 10:55:55 +01:00
244 changed files with 861 additions and 1104 deletions

9
.gitignore vendored
View File

@@ -29,7 +29,16 @@ nuget.exe
npm-debug.log
/.build/
# The templates can't contain their own .gitignore files, because Yeoman has strange default handling for
# files with that name (https://github.com/npm/npm/issues/1862). So, each template instead has a template_gitignore
# file which gets renamed after the files are copied. And so any files that need to be excluded in the source
# repo have to be excluded here.
/templates/*/node_modules/
/templates/*/wwwroot/dist/
/templates/*/ClientApp/dist/
/templates/*/yarn.lock
.vscode/
/templates/*/Properties/launchSettings.json
global.json
korebuild-lock.txt

View File

@@ -18,7 +18,9 @@ build_script:
- npm run build
- ps: Pop-Location
artifacts:
- path: templates\package-builder\artifacts\*.nupkg
- path: templates\package-builder\dist\artifacts\generator-aspnetcore-spa.tar.gz
name: generator-aspnetcore-spa
- path: templates\package-builder\dist\artifacts\*.nupkg
name: Microsoft.AspNetCore.SpaTemplates
type: NuGetPackage
# - ps: .\build.ps1

View File

@@ -99,11 +99,9 @@ __get_remote_file() {
return 0
fi
local failed=false
failed=false
if __machine_has wget; then
wget --tries 10 --quiet -O "$local_path" "$remote_path" || failed=true
else
failed=true
fi
if [ "$failed" = true ] && __machine_has curl; then

View File

@@ -21,6 +21,7 @@ namespace ConsoleApplication
// Since .NET Core 1.1, the HTTP hosting model has become basically as fast as the Socket hosting model
//options.UseSocketHosting();
options.ProjectPath = Directory.GetCurrentDirectory();
options.WatchFileExtensions = new string[] {}; // Don't watch anything
});
var serviceProvider = services.BuildServiceProvider();

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Microsoft.AspNetCore.NodeServices.HostingModels;
using Microsoft.Extensions.Logging;
@@ -35,18 +34,14 @@ namespace Microsoft.AspNetCore.NodeServices
InvocationTimeoutMilliseconds = DefaultInvocationTimeoutMilliseconds;
WatchFileExtensions = (string[])DefaultWatchFileExtensions.Clone();
// In an ASP.NET environment, we can use the IHostingEnvironment data to auto-populate a few
// things that you'd otherwise have to specify manually
var hostEnv = serviceProvider.GetService<IHostingEnvironment>();
if (hostEnv != null)
{
// In an ASP.NET environment, we can use the IHostingEnvironment data to auto-populate a few
// things that you'd otherwise have to specify manually
ProjectPath = hostEnv.ContentRootPath;
EnvironmentVariables["NODE_ENV"] = hostEnv.IsDevelopment() ? "development" : "production"; // De-facto standard values for Node
}
else
{
ProjectPath = Directory.GetCurrentDirectory();
}
var applicationLifetime = serviceProvider.GetService<IApplicationLifetime>();
if (applicationLifetime != null)

View File

@@ -317,7 +317,7 @@ module.exports = {
## Hosting models
NodeServices has a pluggable hosting/transport mechanism, because it is an abstraction over various possible ways to invoke Node.js from .NET. This allows more high-level facilities (e.g., for Angular prerendering) to be agnostic to the details of launching Node and communicating with it - those high-level facilities can just trust that *somehow* we can invoke code in Node for them.
NodeServices has a pluggable hosting/transport mechanism, because it is an abstraction over various possible ways to invoke Node.js from .NET. This allows more high-level facilities (e.g., for Angular prerendering) to be agnostic to the details of launching Node and communicating it - those high-level facilities can just trust that *somehow* we can invoke code in Node for them.
Using this abstraction, we could run Node inside the .NET process, in a separate process on the same machine, or even on a different machine altogether. At the time of writing, all the built-in hosting mechanisms work by launching Node as a separate process on the same machine as your .NET code.

View File

@@ -15,12 +15,6 @@ namespace Microsoft.AspNetCore.Builder
{
private const string DefaultConfigFile = "webpack.config.js";
private static readonly JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings
{
ContractResolver = new CamelCasePropertyNamesContractResolver(),
TypeNameHandling = TypeNameHandling.None
};
/// <summary>
/// Enables Webpack dev middleware support. This hosts an instance of the Webpack compiler in memory
/// in your application so that you can always serve up-to-date Webpack-built resources without having
@@ -94,7 +88,7 @@ namespace Microsoft.AspNetCore.Builder
};
var devServerInfo =
nodeServices.InvokeExportAsync<WebpackDevServerInfo>(nodeScript.FileName, "createWebpackDevServer",
JsonConvert.SerializeObject(devServerOptions, jsonSerializerSettings)).Result;
JsonConvert.SerializeObject(devServerOptions, new JsonSerializerSettings() { ContractResolver = new DefaultContractResolver() })).Result;
// If we're talking to an older version of aspnet-webpack, it will return only a single PublicPath,
// not an array of PublicPaths. Handle that scenario.

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -2,14 +2,12 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppModuleShared } from './app.module.shared';
import { AppComponent } from './components/app/app.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
bootstrap: [ AppComponent ],
imports: [
BrowserModule,
AppModuleShared,
BrowserAnimationsModule
AppModuleShared
],
providers: [
{ provide: 'BASE_URL', useFactory: getBaseUrl }

View File

@@ -2,14 +2,12 @@ import { NgModule } from '@angular/core';
import { ServerModule } from '@angular/platform-server';
import { AppModuleShared } from './app.module.shared';
import { AppComponent } from './components/app/app.component';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
bootstrap: [ AppComponent ],
imports: [
ServerModule,
AppModuleShared,
NoopAnimationsModule
AppModuleShared
]
})
export class AppModule {

View File

@@ -3,6 +3,7 @@ import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';
import { RouterModule } from '@angular/router';
import { HttpWithStateTransferModule } from 'aspnet-angular';
import { AppComponent } from './components/app/app.component';
import { NavMenuComponent } from './components/navmenu/navmenu.component';
@@ -21,6 +22,7 @@ import { CounterComponent } from './components/counter/counter.component';
imports: [
CommonModule,
HttpModule,
HttpWithStateTransferModule,
FormsModule,
RouterModule.forRoot([
{ path: '', redirectTo: 'home', pathMatch: 'full' },

View File

@@ -14,7 +14,7 @@
</tr>
</thead>
<tbody>
<tr *ngFor="let forecast of forecasts" [@itemAnim]>
<tr *ngFor="let forecast of forecasts">
<td>{{ forecast.dateFormatted }}</td>
<td>{{ forecast.temperatureC }}</td>
<td>{{ forecast.temperatureF }}</td>

View File

@@ -1,23 +1,14 @@
import { Component, Inject } from '@angular/core';
import { Http } from '@angular/http';
import { trigger, style, transition, animate } from '@angular/animations';
import { HttpWithStateTransfer } from 'aspnet-angular';
@Component({
selector: 'fetchdata',
templateUrl: './fetchdata.component.html',
animations: [
trigger('itemAnim', [
transition(':enter', [
style({ transform: 'translateX(-100%)' }),
animate(350)
])
])
]
templateUrl: './fetchdata.component.html'
})
export class FetchDataComponent {
public forecasts: WeatherForecast[];
constructor(http: Http, @Inject('BASE_URL') baseUrl: string) {
constructor(http: HttpWithStateTransfer, @Inject('BASE_URL') baseUrl: string) {
http.get(baseUrl + 'api/SampleData/WeatherForecasts').subscribe(result => {
this.forecasts = result.json() as WeatherForecast[];
}, error => console.error(error));

View File

@@ -7,7 +7,7 @@
<span class='icon-bar'></span>
<span class='icon-bar'></span>
</button>
<a class='navbar-brand' [routerLink]="['/home']">AngularSpa</a>
<a class='navbar-brand' [routerLink]="['/home']">WebApplicationBasic</a>
</div>
<div class='clearfix'></div>
<div class='navbar-collapse collapse'>

View File

@@ -6,6 +6,7 @@ import { enableProdMode, ApplicationRef, NgZone, ValueProvider } from '@angular/
import { platformDynamicServer, PlatformState, INITIAL_CONFIG } from '@angular/platform-server';
import { createServerRenderer, RenderResult } from 'aspnet-prerendering';
import { AppModule } from './app/app.module.server';
import { HttpWithStateTransfer } from 'aspnet-angular';
enableProdMode();
@@ -20,6 +21,7 @@ export default createServerRenderer(params => {
const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef);
const state = moduleRef.injector.get(PlatformState);
const zone = moduleRef.injector.get(NgZone);
const http: HttpWithStateTransfer = moduleRef.injector.get(HttpWithStateTransfer);
return new Promise<RenderResult>((resolve, reject) => {
zone.onError.subscribe((errorInfo: any) => reject(errorInfo));
@@ -28,7 +30,8 @@ export default createServerRenderer(params => {
// completing the request in case there's an error to report
setImmediate(() => {
resolve({
html: state.renderToString()
html: state.renderToString(),
globals: { ...http.stateForTransfer() }
});
moduleRef.destroy();
});

View File

@@ -5,7 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace KnockoutSpa.Controllers
namespace WebApplicationBasic.Controllers
{
public class HomeController : Controller
{

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace ReactSpa.Controllers
namespace WebApplicationBasic.Controllers
{
[Route("api/[controller]")]
public class SampleDataController : Controller

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace VueSpa
namespace WebApplicationBasic
{
public class Program
{

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace VueSpa
namespace WebApplicationBasic
{
public class Startup
{

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - AureliaSpa</title>
<title>@ViewData["Title"] - WebApplicationBasic</title>
<base href="~/" />
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />

View File

@@ -1,3 +1,3 @@
@using AureliaSpa
@using WebApplicationBasic
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.AspNetCore.SpaServices

View File

@@ -1,5 +1,5 @@
{
"name": "AngularSpa",
"name": "WebApplicationBasic",
"version": "0.0.0",
"dependencies": {
"@angular/animations": {
@@ -273,6 +273,11 @@
"from": "asn1.js@>=4.0.0 <5.0.0",
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz"
},
"aspnet-angular": {
"version": "0.1.1",
"from": "aspnet-angular@0.1.1",
"resolved": "https://registry.npmjs.org/aspnet-angular/-/aspnet-angular-0.1.1.tgz"
},
"aspnet-prerendering": {
"version": "3.0.1",
"from": "aspnet-prerendering@3.0.1",

View File

@@ -1,11 +1,11 @@
{
"name": "AngularSpa",
"name": "WebApplicationBasic",
"private": true,
"version": "0.0.0",
"scripts": {
"test": "karma start ClientApp/test/karma.conf.js"
},
"devDependencies": {
"dependencies": {
"@angular/animations": "4.2.5",
"@angular/common": "4.2.5",
"@angular/compiler": "4.2.5",
@@ -18,16 +18,13 @@
"@angular/platform-server": "4.2.5",
"@angular/router": "4.2.5",
"@ngtools/webpack": "1.5.0",
"@types/chai": "4.0.1",
"@types/jasmine": "2.5.53",
"@types/webpack-env": "1.13.0",
"angular2-router-loader": "0.3.5",
"angular2-template-loader": "0.6.2",
"aspnet-angular": "^0.1.1",
"aspnet-prerendering": "^3.0.1",
"aspnet-webpack": "^2.0.1",
"awesome-typescript-loader": "3.2.1",
"bootstrap": "3.3.7",
"chai": "4.0.2",
"css": "2.2.1",
"css-loader": "0.28.4",
"es6-shim": "0.35.3",
@@ -37,15 +34,8 @@
"file-loader": "0.11.2",
"html-loader": "0.4.5",
"isomorphic-fetch": "2.2.1",
"jasmine-core": "2.6.4",
"jquery": "3.2.1",
"json-loader": "0.5.4",
"karma": "1.7.0",
"karma-chai": "0.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-jasmine": "1.1.0",
"karma-webpack": "2.0.3",
"preboot": "4.5.2",
"raw-loader": "0.5.1",
"reflect-metadata": "0.1.10",
@@ -58,5 +48,17 @@
"webpack-hot-middleware": "2.18.2",
"webpack-merge": "4.1.0",
"zone.js": "0.8.12"
},
"devDependencies": {
"@types/chai": "4.0.1",
"@types/jasmine": "2.5.53",
"chai": "4.0.2",
"jasmine-core": "2.6.4",
"karma": "1.7.0",
"karma-chai": "0.1.0",
"karma-chrome-launcher": "2.2.0",
"karma-cli": "1.0.1",
"karma-jasmine": "1.1.0",
"karma-webpack": "2.0.3"
}
}

View File

@@ -17,7 +17,7 @@ module.exports = (env) => {
},
module: {
rules: [
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '@ngtools/webpack' },
{ test: /\.ts$/, include: /ClientApp/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader'] : '@ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -9,7 +9,7 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#/home">AureliaSpa</a>
<a class="navbar-brand" href="#/home">WebApplicationBasic</a>
</div>
<div class="clearfix"></div>
<div class="navbar-collapse collapse">

View File

@@ -5,7 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace AngularSpa.Controllers
namespace WebApplicationBasic.Controllers
{
public class HomeController : Controller
{

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace AureliaSpa.Controllers
namespace WebApplicationBasic.Controllers
{
[Route("api/[controller]")]
public class SampleDataController : Controller

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace AureliaSpa
namespace WebApplicationBasic
{
public class Program
{

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace AngularSpa
namespace WebApplicationBasic
{
public class Startup
{

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - AngularSpa</title>
<title>@ViewData["Title"] - WebApplicationBasic</title>
<base href="~/" />
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" />

View File

@@ -1,3 +1,3 @@
@using KnockoutSpa
@using WebApplicationBasic
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.AspNetCore.SpaServices

View File

@@ -1,5 +1,5 @@
{
"name": "AureliaSpa",
"name": "WebApplicationBasic",
"version": "0.0.0",
"dependencies": {
"@types/webpack-env": {

View File

@@ -1,24 +1,26 @@
{
"name": "AureliaSpa",
"name": "WebApplicationBasic",
"private": true,
"version": "0.0.0",
"devDependencies": {
"@types/webpack-env": "^1.13.0",
"aspnet-webpack": "^2.0.1",
"dependencies": {
"aurelia-bootstrapper": "^2.0.1",
"aurelia-fetch-client": "^1.0.1",
"aurelia-framework": "^1.1.0",
"aurelia-loader-webpack": "^2.0.0",
"aurelia-pal": "^1.3.0",
"aurelia-router": "^1.2.1",
"aurelia-webpack-plugin": "^2.0.0-rc.2",
"bootstrap": "^3.3.7",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.2.1"
},
"devDependencies": {
"@types/webpack-env": "^1.13.0",
"aspnet-webpack": "^2.0.1",
"aurelia-webpack-plugin": "^2.0.0-rc.2",
"css-loader": "^0.28.0",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.11.1",
"html-loader": "^0.4.5",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.2.1",
"json-loader": "^0.5.4",
"style-loader": "^0.16.1",
"ts-loader": "^2.0.3",

View File

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 83 KiB

View File

Before

Width:  |  Height:  |  Size: 6.0 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -7,7 +7,7 @@
<span class='icon-bar'></span>
<span class='icon-bar'></span>
</button>
<a class='navbar-brand' href='/'>KnockoutSpa</a>
<a class='navbar-brand' href='/'>WebApplicationBasic</a>
</div>
<div class='clearfix'></div>
<div class='navbar-collapse collapse'>

View File

@@ -43,7 +43,8 @@ export class Router {
$(document).on('click', 'a', this.clickEventListener);
// Initialize Crossroads with starting location
crossroads.parse(history.location.pathname);
// Need to cast history to 'any' because @types/history is out-of-date
crossroads.parse((history as any).location.pathname);
}
public link(url: string): string {

View File

@@ -5,7 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace VueSpa.Controllers
namespace WebApplicationBasic.Controllers
{
public class HomeController : Controller
{

View File

@@ -4,7 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
namespace KnockoutSpa.Controllers
namespace WebApplicationBasic.Controllers
{
[Route("api/[controller]")]
public class SampleDataController : Controller

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace KnockoutSpa
namespace WebApplicationBasic
{
public class Program
{

View File

@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.SpaServices.Webpack;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace AureliaSpa
namespace WebApplicationBasic
{
public class Startup
{

Some files were not shown because too many files have changed in this diff Show More