From 901300a4ef94a311c143b54a16760bf99a975d9c Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Thu, 2 Nov 2017 10:17:06 -0400 Subject: [PATCH 01/13] feat(Angular 5.0): update engine-etc for angular 5.0 & Domino (#437) * feat(5.0): update engine-etc for angular 5.0-rc1 WIP - More updates to come * remove ng 4 references * update source maps for faster HMR builds * use aspnetcore-engine & misc updates and fixes * update to 5.0 official Closes #434 Closes #435 Closes #430 Closes #424 --- ClientApp/app/app.component.html | 2 +- ClientApp/app/app.component.ts | 11 +- ClientApp/app/app.module.browser.ts | 10 +- ClientApp/app/app.module.server.ts | 25 +- ClientApp/app/app.module.ts | 28 +- .../components/navmenu/navmenu.component.html | 2 +- .../components/navmenu/navmenu.component.ts | 10 +- .../user-detail/user-detail.component.ts | 2 +- .../containers/counter/counter.component.ts | 2 +- .../app/containers/home/home.component.html | 12 +- .../app/containers/home/home.component.ts | 2 +- .../app/containers/lazy/lazy.component.ts | 2 +- .../not-found/not-found.component.ts | 2 +- .../app/containers/users/users.component.html | 2 +- .../app/containers/users/users.component.ts | 21 +- .../app/shared/constants/baseurl.constants.ts | 3 - ClientApp/app/shared/constants/request.ts | 3 - ClientApp/app/shared/user.service.ts | 53 ++-- ClientApp/boot.browser.ts | 2 - ClientApp/boot.server.ts | 23 +- .../transfer-http/transfer-http.module.ts | 10 - .../modules/transfer-http/transfer-http.ts | 152 ----------- .../browser-transfer-state.module.ts | 20 -- .../server-transfer-state.module.ts | 12 - .../transfer-state/server-transfer-state.ts | 36 --- .../modules/transfer-state/transfer-state.ts | 40 --- .../polyfills/temporary-aspnetcore-engine.ts | 254 ------------------ README.md | 20 +- Server/Controllers/HomeController.cs | 2 +- Startup.cs | 4 +- package.json | 37 +-- tslint.json | 3 +- webpack.config.js | 23 +- webpack.config.vendor.js | 2 +- 34 files changed, 153 insertions(+), 679 deletions(-) delete mode 100644 ClientApp/app/shared/constants/baseurl.constants.ts delete mode 100644 ClientApp/app/shared/constants/request.ts delete mode 100644 ClientApp/modules/transfer-http/transfer-http.module.ts delete mode 100644 ClientApp/modules/transfer-http/transfer-http.ts delete mode 100644 ClientApp/modules/transfer-state/browser-transfer-state.module.ts delete mode 100644 ClientApp/modules/transfer-state/server-transfer-state.module.ts delete mode 100644 ClientApp/modules/transfer-state/server-transfer-state.ts delete mode 100644 ClientApp/modules/transfer-state/transfer-state.ts delete mode 100644 ClientApp/polyfills/temporary-aspnetcore-engine.ts diff --git a/ClientApp/app/app.component.html b/ClientApp/app/app.component.html index a3e3bf9b..0345c682 100644 --- a/ClientApp/app/app.component.html +++ b/ClientApp/app/app.component.html @@ -1,5 +1,5 @@
- +
diff --git a/ClientApp/app/app.component.ts b/ClientApp/app/app.component.ts index 02b91787..7a6a75ed 100644 --- a/ClientApp/app/app.component.ts +++ b/ClientApp/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, Inject, ViewEncapsulation, RendererFactory2, PLATFORM_ID } from '@angular/core'; +import { Component, OnInit, OnDestroy, Inject, ViewEncapsulation, RendererFactory2, PLATFORM_ID, Injector } from '@angular/core'; import { Router, NavigationEnd, ActivatedRoute, PRIMARY_OUTLET } from '@angular/router'; import { Meta, Title, DOCUMENT, MetaDefinition } from '@angular/platform-browser'; import { Subscription } from 'rxjs/Subscription'; @@ -7,10 +7,10 @@ import { LinkService } from './shared/link.service'; // i18n support import { TranslateService } from '@ngx-translate/core'; -import { REQUEST } from './shared/constants/request'; +import { REQUEST } from '@nguniversal/aspnetcore-engine'; @Component({ - selector: 'app', + selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'], encapsulation: ViewEncapsulation.None @@ -23,6 +23,7 @@ export class AppComponent implements OnInit, OnDestroy { private defaultPageTitle: string = 'My App'; private routerSub$: Subscription; + private request; constructor( private router: Router, @@ -31,7 +32,7 @@ export class AppComponent implements OnInit, OnDestroy { private meta: Meta, private linkService: LinkService, public translate: TranslateService, - @Inject(REQUEST) private request + private injector: Injector ) { // this language will be used as a fallback when a translation isn't found in the current language translate.setDefaultLang('en'); @@ -39,6 +40,8 @@ export class AppComponent implements OnInit, OnDestroy { // the lang to use, if the lang isn't available, it will use the current loader to get them translate.use('en'); + this.request = this.injector.get(REQUEST); + console.log(`What's our REQUEST Object look like?`); console.log(`The Request object only really exists on the Server, but on the Browser we can at least see Cookies`); console.log(this.request); diff --git a/ClientApp/app/app.module.browser.ts b/ClientApp/app/app.module.browser.ts index ac318d44..56d1c20c 100644 --- a/ClientApp/app/app.module.browser.ts +++ b/ClientApp/app/app.module.browser.ts @@ -3,12 +3,10 @@ import { BrowserModule } from '@angular/platform-browser'; import { APP_BASE_HREF } from '@angular/common'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { ORIGIN_URL } from './shared/constants/baseurl.constants'; +import { ORIGIN_URL, REQUEST } from '@nguniversal/aspnetcore-engine'; import { AppModuleShared } from './app.module'; import { AppComponent } from './app.component'; -import { REQUEST } from './shared/constants/request'; -import { BrowserTransferStateModule } from '../modules/transfer-state/browser-transfer-state.module'; - +import { BrowserTransferStateModule } from '@angular/platform-browser'; import { BrowserPrebootModule } from 'preboot/browser'; export function getOriginUrl() { @@ -23,12 +21,8 @@ export function getRequest() { @NgModule({ bootstrap: [AppComponent], imports: [ - BrowserModule.withServerTransition({ - appId: 'my-app-id' // make sure this matches with your Server NgModule - }), BrowserPrebootModule.replayEvents(), BrowserAnimationsModule, - BrowserTransferStateModule, // Our Common AppModule AppModuleShared diff --git a/ClientApp/app/app.module.server.ts b/ClientApp/app/app.module.server.ts index 9e22b71e..25711851 100644 --- a/ClientApp/app/app.module.server.ts +++ b/ClientApp/app/app.module.server.ts @@ -5,33 +5,28 @@ import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { AppModuleShared } from './app.module'; import { AppComponent } from './app.component'; -import { ServerTransferStateModule } from '../modules/transfer-state/server-transfer-state.module'; -import { TransferState } from '../modules/transfer-state/transfer-state'; +import { ServerTransferStateModule } from '@angular/platform-server'; import { ServerPrebootModule } from 'preboot/server'; @NgModule({ bootstrap: [AppComponent], imports: [ - BrowserModule.withServerTransition({ - appId: 'my-app-id' // make sure this matches with your Browser NgModule - }), + // Our Common AppModule + AppModuleShared, + ServerModule, - ServerPrebootModule.recordEvents({ appRoot: 'app' }), + ServerPrebootModule.recordEvents({ appRoot: 'app-root' }), NoopAnimationsModule, - ServerTransferStateModule, - - // Our Common AppModule - AppModuleShared + // HttpTransferCacheModule still needs fixes for 5.0 + // Leave this commented out for now, as it breaks Server-renders + // Looking into fixes for this! - @MarkPieszak + // ServerTransferStateModule // <-- broken for the time-being with ASP.NET ] }) export class AppModule { - constructor(private transferState: TransferState) { } + constructor() { } - // Gotcha (needs to be an arrow function) - ngOnBootstrap = () => { - this.transferState.inject(); - } } diff --git a/ClientApp/app/app.module.ts b/ClientApp/app/app.module.ts index 1c492f1d..d31250c4 100644 --- a/ClientApp/app/app.module.ts +++ b/ClientApp/app/app.module.ts @@ -2,7 +2,10 @@ import { NgModule, Inject } from '@angular/core'; import { RouterModule, PreloadAllModules } from '@angular/router'; import { CommonModule, APP_BASE_HREF } from '@angular/common'; import { HttpModule, Http } from '@angular/http'; +import { HttpClientModule, HttpClient } from '@angular/common/http'; import { FormsModule } from '@angular/forms'; +import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser'; +import { TransferHttpCacheModule } from '@nguniversal/common'; import { Ng2BootstrapModule } from 'ngx-bootstrap'; @@ -16,17 +19,14 @@ import { HomeComponent } from './containers/home/home.component'; import { UsersComponent } from './containers/users/users.component'; import { UserDetailComponent } from './components/user-detail/user-detail.component'; import { CounterComponent } from './containers/counter/counter.component'; -// import { ChatComponent } from './containers/chat/chat.component'; import { NotFoundComponent } from './containers/not-found/not-found.component'; import { NgxBootstrapComponent } from './containers/ngx-bootstrap-demo/ngx-bootstrap.component'; import { LinkService } from './shared/link.service'; import { UserService } from './shared/user.service'; -// import { ConnectionResolver } from './shared/route.resolver'; -import { ORIGIN_URL } from './shared/constants/baseurl.constants'; -import { TransferHttpModule } from '../modules/transfer-http/transfer-http.module'; +import { ORIGIN_URL } from '@nguniversal/aspnetcore-engine'; -export function createTranslateLoader(http: Http, baseHref) { +export function createTranslateLoader(http: HttpClient, baseHref) { // Temporary Azure hack if (baseHref === null && typeof window !== 'undefined') { baseHref = window.location.origin; @@ -43,24 +43,28 @@ export function createTranslateLoader(http: Http, baseHref) { UsersComponent, UserDetailComponent, HomeComponent, - // ChatComponent, NotFoundComponent, NgxBootstrapComponent ], imports: [ CommonModule, - HttpModule, + BrowserModule.withServerTransition({ + appId: 'my-app-id' // make sure this matches with your Server NgModule + }), + HttpClientModule, + TransferHttpCacheModule, + BrowserTransferStateModule, + + FormsModule, Ng2BootstrapModule.forRoot(), // You could also split this up if you don't want the Entire Module imported - TransferHttpModule, // Our Http TransferData method - // i18n support TranslateModule.forRoot({ loader: { provide: TranslateLoader, useFactory: (createTranslateLoader), - deps: [Http, [ORIGIN_URL]] + deps: [HttpClient, [ORIGIN_URL]] } }), @@ -145,9 +149,9 @@ export function createTranslateLoader(http: Http, baseHref) { providers: [ LinkService, UserService, - // ConnectionResolver, TranslateModule - ] + ], + bootstrap: [AppComponent] }) export class AppModuleShared { } diff --git a/ClientApp/app/components/navmenu/navmenu.component.html b/ClientApp/app/components/navmenu/navmenu.component.html index bd6eadda..08e1b0fc 100644 --- a/ClientApp/app/components/navmenu/navmenu.component.html +++ b/ClientApp/app/components/navmenu/navmenu.component.html @@ -8,7 +8,7 @@ - Angular 4 Universal & ASP.NET Core + Angular 5 Universal & ASP.NET Core
diff --git a/ClientApp/app/components/navmenu/navmenu.component.ts b/ClientApp/app/components/navmenu/navmenu.component.ts index ac36f036..fb0cf22c 100644 --- a/ClientApp/app/components/navmenu/navmenu.component.ts +++ b/ClientApp/app/components/navmenu/navmenu.component.ts @@ -1,23 +1,23 @@ import { Component } from '@angular/core'; @Component({ - selector: 'nav-menu', + selector: 'app-nav-menu', templateUrl: './navmenu.component.html', styleUrls: ['./navmenu.component.css'] }) export class NavMenuComponent { - collapse: string = "collapse"; + collapse: string = 'collapse'; collapseNavbar(): void { if (this.collapse.length > 1) { - this.collapse = ""; + this.collapse = ''; } else { - this.collapse = "collapse"; + this.collapse = 'collapse'; } } collapseMenu() { - this.collapse = "collapse" + this.collapse = 'collapse'; } } diff --git a/ClientApp/app/components/user-detail/user-detail.component.ts b/ClientApp/app/components/user-detail/user-detail.component.ts index 9db88355..d21d3415 100644 --- a/ClientApp/app/components/user-detail/user-detail.component.ts +++ b/ClientApp/app/components/user-detail/user-detail.component.ts @@ -3,7 +3,7 @@ import { IUser } from '../../models/User'; import { UserService } from '../../shared/user.service'; @Component({ - selector: 'user-detail', + selector: 'app-user-detail', templateUrl: './user-detail.component.html' }) export class UserDetailComponent { diff --git a/ClientApp/app/containers/counter/counter.component.ts b/ClientApp/app/containers/counter/counter.component.ts index 69de17d9..5adb5195 100644 --- a/ClientApp/app/containers/counter/counter.component.ts +++ b/ClientApp/app/containers/counter/counter.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'counter', + selector: 'app-counter', templateUrl: './counter.component.html' }) export class CounterComponent { diff --git a/ClientApp/app/containers/home/home.component.html b/ClientApp/app/containers/home/home.component.html index 06d801e7..3a4db63b 100644 --- a/ClientApp/app/containers/home/home.component.html +++ b/ClientApp/app/containers/home/home.component.html @@ -1,7 +1,7 @@ 

{{ title }}

- Enjoy the latest features from .NET Core & Angular 4.0! + Enjoy the latest features from .NET Core & Angular 5.0!
For more info check the repo here: AspNetCore-Angular2-Universal repo

@@ -12,7 +12,7 @@

{{ 'HOME_FEATURE_LIST_TITLE' | translate }}

- + diff --git a/ClientApp/app/containers/users/users.component.ts b/ClientApp/app/containers/users/users.component.ts index 9dd28781..35cc8517 100644 --- a/ClientApp/app/containers/users/users.component.ts +++ b/ClientApp/app/containers/users/users.component.ts @@ -7,7 +7,7 @@ import { IUser } from '../../models/User'; import { UserService } from '../../shared/user.service'; @Component({ - selector: 'users', + selector: 'app-users', templateUrl: './users.component.html', styleUrls: ['./users.component.css'], animations: [ @@ -31,15 +31,16 @@ export class UsersComponent implements OnInit { selectedUser: IUser; // Use "constructor"s only for dependency injection - constructor(private userService: UserService) { } + constructor( + private userService: UserService + ) { } // Here you want to handle anything with @Input()'s @Output()'s // Data retrieval / etc - this is when the Component is "ready" and wired up ngOnInit() { this.userService.getUsers().subscribe(result => { - console.log('Get user result: ', result); - console.log('TransferHttp [GET] /api/users/allresult', result); - this.users = result as IUser[]; + console.log('HttpClient [GET] /api/users/allresult', result); + this.users = result; }); } @@ -50,10 +51,8 @@ export class UsersComponent implements OnInit { deleteUser(user) { this.userService.deleteUser(user).subscribe(result => { console.log('Delete user result: ', result); - if (result.ok) { - let position = this.users.indexOf(user); - this.users.splice(position, 1); - } + let position = this.users.indexOf(user); + this.users.splice(position, 1); }, error => { console.log(`There was an issue. ${error._body}.`); }); @@ -62,9 +61,7 @@ export class UsersComponent implements OnInit { addUser(newUserName) { this.userService.addUser(newUserName).subscribe(result => { console.log('Post user result: ', result); - if (result.ok) { - this.users.push(result.json()); - } + this.users.push(result); }, error => { console.log(`There was an issue. ${error._body}.`); }); diff --git a/ClientApp/app/shared/constants/baseurl.constants.ts b/ClientApp/app/shared/constants/baseurl.constants.ts deleted file mode 100644 index 58807bc4..00000000 --- a/ClientApp/app/shared/constants/baseurl.constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { InjectionToken } from '@angular/core'; - -export const ORIGIN_URL = new InjectionToken('ORIGIN_URL'); diff --git a/ClientApp/app/shared/constants/request.ts b/ClientApp/app/shared/constants/request.ts deleted file mode 100644 index 4c553d8a..00000000 --- a/ClientApp/app/shared/constants/request.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { InjectionToken } from '@angular/core'; - -export const REQUEST = new InjectionToken('REQUEST'); diff --git a/ClientApp/app/shared/user.service.ts b/ClientApp/app/shared/user.service.ts index 8bcc3bb3..9489e32f 100644 --- a/ClientApp/app/shared/user.service.ts +++ b/ClientApp/app/shared/user.service.ts @@ -1,42 +1,41 @@ -import { Injectable, Inject } from '@angular/core'; +import { Injectable, Inject, Injector } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; import { Http, URLSearchParams } from '@angular/http'; import { APP_BASE_HREF } from '@angular/common'; -import { ORIGIN_URL } from './constants/baseurl.constants'; +import { ORIGIN_URL } from '@nguniversal/aspnetcore-engine'; import { IUser } from '../models/User'; -import { TransferHttp } from '../../modules/transfer-http/transfer-http'; import { Observable } from 'rxjs/Observable'; + @Injectable() export class UserService { - constructor( - private transferHttp: TransferHttp, // Use only for GETS that you want re-used between Server render -> Client render - private http: Http, // Use for everything else - @Inject(ORIGIN_URL) private baseUrl: string) { - } + private baseUrl: string; - getUsers(): Observable { - // ** TransferHttp example / concept ** - // - Here we make an Http call on the server, save the result on the window object and pass it down with the SSR, - // The Client then re-uses this Http result instead of hitting the server again! + constructor( + private http: HttpClient, + private injector: Injector + ) { + this.baseUrl = this.injector.get(ORIGIN_URL); + } - // NOTE : transferHttp also automatically does .map(res => res.json()) for you, so no need for these calls - return this.transferHttp.get(`${this.baseUrl}/api/users`); - } + getUsers() { + return this.http.get(`${this.baseUrl}/api/users`); + } - getUser(user: IUser): Observable { - return this.transferHttp.get(`${this.baseUrl}/api/users/` + user.id); - } + getUser(user: IUser) { + return this.http.get(`${this.baseUrl}/api/users/` + user.id); + } - deleteUser(user: IUser): Observable { - return this.http.delete(`${this.baseUrl}/api/users/` + user.id); - } + deleteUser(user: IUser) { + return this.http.delete(`${this.baseUrl}/api/users/` + user.id); + } - updateUser(user: IUser): Observable { - return this.http.put(`${this.baseUrl}/api/users/` + user.id, user); - } + updateUser(user: IUser){ + return this.http.put(`${this.baseUrl}/api/users/` + user.id, user); + } - addUser(newUserName: string): Observable { - return this.http.post(`${this.baseUrl}/api/users`, { name: newUserName }) - } + addUser(newUserName: string) { + return this.http.post(`${this.baseUrl}/api/users`, { name: newUserName }); + } } diff --git a/ClientApp/boot.browser.ts b/ClientApp/boot.browser.ts index a7830543..329344f7 100644 --- a/ClientApp/boot.browser.ts +++ b/ClientApp/boot.browser.ts @@ -3,8 +3,6 @@ import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module.browser'; -const rootElemTagName = 'app'; // Update this if you change your root component selector - // // Enable either Hot Module Reloading or production mode if (module['hot']) { module['hot'].accept(); diff --git a/ClientApp/boot.server.ts b/ClientApp/boot.server.ts index 86d65086..a7c2f9f5 100644 --- a/ClientApp/boot.server.ts +++ b/ClientApp/boot.server.ts @@ -1,31 +1,34 @@ import 'zone.js/dist/zone-node'; import './polyfills/server.polyfills'; import { enableProdMode } from '@angular/core'; -import { INITIAL_CONFIG } from '@angular/platform-server'; -import { APP_BASE_HREF } from '@angular/common'; -import { createServerRenderer, RenderResult } from 'aspnet-prerendering'; +import { createServerRenderer } from 'aspnet-prerendering'; -import { ORIGIN_URL } from './app/shared/constants/baseurl.constants'; // Grab the (Node) server-specific NgModule import { AppModule } from './app/app.module.server'; -// Temporary * the engine will be on npm soon (`@universal/ng-aspnetcore-engine`) -import { ngAspnetCoreEngine, IEngineOptions, createTransferScript } from './polyfills/temporary-aspnetcore-engine'; +import { ngAspnetCoreEngine, IEngineOptions, createTransferScript } from '@nguniversal/aspnetcore-engine'; enableProdMode(); export default createServerRenderer((params) => { + console.log('server ?'); + // Platform-server provider configuration const setupOptions: IEngineOptions = { - appSelector: '', + appSelector: '', ngModule: AppModule, request: params, providers: [ - // Optional - Any other Server providers you want to pass (remember you'll have to provide them for the Browser as well) + // Optional - Any other Server providers you want to pass + // (remember you'll have to provide them for the Browser as well) ] }; return ngAspnetCoreEngine(setupOptions).then(response => { + + // console.log('\n\n\naspnet-engine!!!\n\n\n') + console.log(response) + // Apply your transferData to response.globals response.globals.transferData = createTransferScript({ someData: 'Transfer this to the client on the window.TRANSFER_CACHE {} object', @@ -33,8 +36,8 @@ export default createServerRenderer((params) => { }); return ({ - html: response.html, - globals: response.globals + html: response.html, // our serialized + globals: response.globals // all of our styles/scripts/meta-tags/link-tags for aspnet to serve up }); }); }); diff --git a/ClientApp/modules/transfer-http/transfer-http.module.ts b/ClientApp/modules/transfer-http/transfer-http.module.ts deleted file mode 100644 index c2875b33..00000000 --- a/ClientApp/modules/transfer-http/transfer-http.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { NgModule } from '@angular/core'; -import { Http, HttpModule } from '@angular/http'; -import { TransferHttp } from './transfer-http'; - -@NgModule({ - providers: [ - TransferHttp - ] -}) -export class TransferHttpModule {} diff --git a/ClientApp/modules/transfer-http/transfer-http.ts b/ClientApp/modules/transfer-http/transfer-http.ts deleted file mode 100644 index 3f9b5d84..00000000 --- a/ClientApp/modules/transfer-http/transfer-http.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { Injectable, Inject, PLATFORM_ID } from '@angular/core'; -import { ConnectionBackend, Http, Request, RequestOptions, RequestOptionsArgs, Response } from '@angular/http'; -import { Observable } from 'rxjs/Observable'; -import { Subject } from 'rxjs/Subject'; -import { TransferState } from '../transfer-state/transfer-state'; -import { isPlatformServer } from '@angular/common'; - -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/do'; -import 'rxjs/add/observable/fromPromise'; - -@Injectable() -export class TransferHttp { - - private isServer = isPlatformServer(this.platformId); - - constructor( - @Inject(PLATFORM_ID) private platformId, - private http: Http, - protected transferState: TransferState - ) { } - - request(uri: string | Request, options?: RequestOptionsArgs): Observable { - return this.getData(uri, options, (url: string, options: RequestOptionsArgs) => { - return this.http.request(url, options); - }); - } - /** - * Performs a request with `get` http method. - */ - get(url: string, options?: RequestOptionsArgs): Observable { - return this.getData(url, options, (url: string, options: RequestOptionsArgs) => { - return this.http.get(url, options); - }); - } - /** - * Performs a request with `post` http method. - */ - post(url: string, body: any, options?: RequestOptionsArgs): Observable { - return this.getPostData(url, body, options, (url: string, body: any, options: RequestOptionsArgs) => { - return this.http.post(url, body, options); - }); - } - /** - * Performs a request with `put` http method. - */ - put(url: string, body: any, options?: RequestOptionsArgs): Observable { - - return this.getPostData(url, body, options, (url: string, body: any, options: RequestOptionsArgs) => { - return this.http.put(url, body, options); - }); - } - /** - * Performs a request with `delete` http method. - */ - delete(url: string, options?: RequestOptionsArgs): Observable { - return this.getData(url, options, (url: string, options: RequestOptionsArgs) => { - return this.http.delete(url, options); - }); - } - /** - * Performs a request with `patch` http method. - */ - patch(url: string, body: any, options?: RequestOptionsArgs): Observable { - return this.getPostData(url, body, options, (url: string, body: any, options: RequestOptionsArgs) => { - return this.http.patch(url, body.options); - }); - } - /** - * Performs a request with `head` http method. - */ - head(url: string, options?: RequestOptionsArgs): Observable { - return this.getData(url, options, (url: string, options: RequestOptionsArgs) => { - return this.http.head(url, options); - }); - } - /** - * Performs a request with `options` http method. - */ - options(url: string, options?: RequestOptionsArgs): Observable { - return this.getData(url, options, (url: string, options: RequestOptionsArgs) => { - return this.http.options(url, options); - }); - } - - private getData(uri: string | Request, options: RequestOptionsArgs, callback: (uri: string | Request, options?: RequestOptionsArgs) => Observable) { - - let url = uri; - - if (typeof uri !== 'string') { - url = uri.url; - } - - const key = url + JSON.stringify(options); - - try { - return this.resolveData(key); - - } catch (e) { - return callback(url, options) - .map(res => res.json()) - .do(data => { - if (this.isServer) { - this.setCache(key, data); - } - }); - } - } - - private getPostData(uri: string | Request, body: any, options: RequestOptionsArgs, callback: (uri: string | Request, body: any, options?: RequestOptionsArgs) => Observable) { - - let url = uri; - - if (typeof uri !== 'string') { - url = uri.url; - } - - const key = url + JSON.stringify(body); - - try { - - return this.resolveData(key); - - } catch (e) { - return callback(uri, body, options) - .map(res => res.json()) - .do(data => { - if (this.isServer) { - this.setCache(key, data); - } - }); - } - } - - private resolveData(key: string) { - const data = this.getFromCache(key); - - if (!data) { - throw new Error(); - } - - return Observable.fromPromise(Promise.resolve(data)); - } - - private setCache(key, data) { - return this.transferState.set(key, data); - } - - private getFromCache(key): any { - return this.transferState.get(key); - } -} diff --git a/ClientApp/modules/transfer-state/browser-transfer-state.module.ts b/ClientApp/modules/transfer-state/browser-transfer-state.module.ts deleted file mode 100644 index 20e11421..00000000 --- a/ClientApp/modules/transfer-state/browser-transfer-state.module.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { NgModule, PLATFORM_ID } from '@angular/core'; -import { TransferState } from './transfer-state'; - -export function getTransferState(): TransferState { - const transferState = new TransferState(); - transferState.initialize(window['TRANSFER_STATE'] || {}); - return transferState; -} - -@NgModule({ - providers: [ - { - provide: TransferState, - useFactory: getTransferState - } - ] -}) -export class BrowserTransferStateModule { - -} diff --git a/ClientApp/modules/transfer-state/server-transfer-state.module.ts b/ClientApp/modules/transfer-state/server-transfer-state.module.ts deleted file mode 100644 index 1a77f653..00000000 --- a/ClientApp/modules/transfer-state/server-transfer-state.module.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { NgModule } from '@angular/core'; -import { ServerTransferState } from './server-transfer-state'; -import { TransferState } from './transfer-state'; - -@NgModule({ - providers: [ - { provide: TransferState, useClass: ServerTransferState } - ] -}) -export class ServerTransferStateModule { - -} diff --git a/ClientApp/modules/transfer-state/server-transfer-state.ts b/ClientApp/modules/transfer-state/server-transfer-state.ts deleted file mode 100644 index b2890b26..00000000 --- a/ClientApp/modules/transfer-state/server-transfer-state.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Injectable, Optional, RendererFactory2, ViewEncapsulation, Inject, PLATFORM_ID } from '@angular/core'; -import { TransferState } from './transfer-state'; -import { PlatformState } from '@angular/platform-server'; -@Injectable() -export class ServerTransferState extends TransferState { - constructor(private state: PlatformState, private rendererFactory: RendererFactory2) { - super(); - } - - /** - * Inject the State into the bottom of the - */ - inject() { - try { - const document: any = this.state.getDocument(); - const transferStateString = JSON.stringify(this.toJson()); - const renderer = this.rendererFactory.createRenderer(document, { - id: '-1', - encapsulation: ViewEncapsulation.None, - styles: [], - data: {} - }); - - const body = document.body; - - const script = renderer.createElement('script'); - renderer.setValue(script, `window['TRANSFER_STATE'] = ${transferStateString}`); - renderer.appendChild(body, script); - } catch (e) { - console.log('Failed to append TRANSFER_STATE to body'); - console.error(e); - } - } - - -} diff --git a/ClientApp/modules/transfer-state/transfer-state.ts b/ClientApp/modules/transfer-state/transfer-state.ts deleted file mode 100644 index cc963b8f..00000000 --- a/ClientApp/modules/transfer-state/transfer-state.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Injectable, Inject, PLATFORM_ID } from '@angular/core'; - -@Injectable() -export class TransferState { - private _map = new Map(); - - constructor() { } - - keys() { - return this._map.keys(); - } - - get(key: string): any { - const cachedValue = this._map.get(key); - this._map.delete(key); - return cachedValue; - } - - set(key: string, value: any): Map { - return this._map.set(key, value); - } - - toJson(): any { - const obj = {}; - Array.from(this.keys()) - .forEach(key => { - obj[key] = this.get(key); - }); - return obj; - } - - initialize(obj: any): void { - Object.keys(obj) - .forEach(key => { - this.set(key, obj[key]); - }); - } - - inject(): void { } -} diff --git a/ClientApp/polyfills/temporary-aspnetcore-engine.ts b/ClientApp/polyfills/temporary-aspnetcore-engine.ts deleted file mode 100644 index d3157a1b..00000000 --- a/ClientApp/polyfills/temporary-aspnetcore-engine.ts +++ /dev/null @@ -1,254 +0,0 @@ -/* ********* TEMPORARILY HERE ************** - * - will be on npm soon - - * import { ngAspnetCoreEngine } from `@nguniversal/aspnetcore-engine`; - */ -import { Type, NgModuleFactory, NgModuleRef, ApplicationRef, Provider, CompilerFactory, Compiler } from '@angular/core'; -import { platformServer, platformDynamicServer, PlatformState, INITIAL_CONFIG, renderModuleFactory } from '@angular/platform-server'; -import { ResourceLoader } from '@angular/compiler'; -import * as fs from 'fs'; - -import { REQUEST } from '../app/shared/constants/request'; -import { ORIGIN_URL } from '../app/shared/constants/baseurl.constants'; - -export function createTransferScript(transferData: Object): string { - return ``; -} - -export class FileLoader implements ResourceLoader { - get(url: string): Promise { - return new Promise((resolve, reject) => { - fs.readFile(url, (err: NodeJS.ErrnoException, buffer: Buffer) => { - if (err) { - return reject(err); - } - - resolve(buffer.toString()); - }); - }); - } -} - -export interface IRequestParams { - location: any; // e.g., Location object containing information '/some/path' - origin: string; // e.g., 'https://example.com:1234/' - url: string; // e.g., '/some/path' - baseUrl: string; // e.g., '' or '/myVirtualDir' - absoluteUrl: string; // e.g., 'https://example.com:1234/some/path' - domainTasks: Promise; - data: any; // any custom object passed through from .NET -} - -export interface IEngineOptions { - appSelector: string; - request: IRequestParams; - ngModule: Type<{}> | NgModuleFactory<{}>; - providers?: Provider[]; -}; - -export function ngAspnetCoreEngine( - options: IEngineOptions -): Promise<{ html: string, globals: { styles: string, title: string, meta: string, transferData?: {}, [key: string]: any } }> { - - options.providers = options.providers || []; - - const compilerFactory: CompilerFactory = platformDynamicServer().injector.get(CompilerFactory); - const compiler: Compiler = compilerFactory.createCompiler([ - { - providers: [ - { provide: ResourceLoader, useClass: FileLoader } - ] - } - ]); - - return new Promise((resolve, reject) => { - - try { - const moduleOrFactory = options.ngModule; - if (!moduleOrFactory) { - throw new Error('You must pass in a NgModule or NgModuleFactory to be bootstrapped'); - } - - const extraProviders = options.providers.concat( - options.providers, - [ - { - provide: INITIAL_CONFIG, - useValue: { - document: options.appSelector, - url: options.request.url - } - }, - { - provide: ORIGIN_URL, - useValue: options.request.origin - }, { - provide: REQUEST, - useValue: options.request.data.request - } - ] - ); - - const platform = platformServer(extraProviders); - - getFactory(moduleOrFactory, compiler) - .then((factory: NgModuleFactory<{}>) => { - - return platform.bootstrapModuleFactory(factory).then((moduleRef: NgModuleRef<{}>) => { - - const state: PlatformState = moduleRef.injector.get(PlatformState); - const appRef: ApplicationRef = moduleRef.injector.get(ApplicationRef); - - appRef.isStable - .filter((isStable: boolean) => isStable) - .first() - .subscribe((stable) => { - - // Fire the TransferState Cache - const bootstrap = moduleRef.instance['ngOnBootstrap']; - bootstrap && bootstrap(); - - // The parse5 Document itself - const AST_DOCUMENT = state.getDocument(); - - // Strip out the Angular application - const htmlDoc = state.renderToString(); - - const APP_HTML = htmlDoc.substring( - htmlDoc.indexOf('') + 6, - htmlDoc.indexOf('') - ); - - // Strip out Styles / Meta-tags / Title - const STYLES = []; - const SCRIPTS = []; - const META = []; - const LINKS = []; - let TITLE = ''; - - let STYLES_STRING: string = htmlDoc.indexOf('') + 8) - : null; - - const HEAD = AST_DOCUMENT.head; - - let count = 0; - - for (let i = 0; i < HEAD.children.length; i++) { - let element = HEAD.children[i]; - - if (element.name === 'title') { - TITLE = element.children[0].data; - } - - if (element.name === 'script') { - SCRIPTS.push( - `` - ); - } - - // Broken after 4.0 (worked in rc) - // if (element.name === 'style') { - // let styleTag = '`; - // STYLES.push(styleTag); - // } - - if (element.name === 'meta') { - count = count + 1; - let metaString = '\n`); - } - - if (element.name === 'link') { - let linkString = '\n`); - } - } - - resolve({ - html: APP_HTML, - globals: { - styles: STYLES_STRING, - title: TITLE, - scripts: SCRIPTS.join(' '), - meta: META.join(' '), - links: LINKS.join(' ') - } - }); - - moduleRef.destroy(); - - }, (err) => { - // isStable subscription error (Template / code error) - reject(err); - }); - - }, err => { - // bootstrapModuleFactory error - reject(err); - }); - - }, err => { - // getFactory error - reject(err); - }); - - } catch (ex) { - // try/catch error - reject(ex); - } - - }); - -} - -/* ********************** Private / Internal ****************** */ - -const factoryCacheMap = new Map, NgModuleFactory<{}>>(); -function getFactory( - moduleOrFactory: Type<{}> | NgModuleFactory<{}>, compiler: Compiler -): Promise> { - - return new Promise>((resolve, reject) => { - // If module has been compiled AoT - if (moduleOrFactory instanceof NgModuleFactory) { - resolve(moduleOrFactory); - return; - } else { - let moduleFactory = factoryCacheMap.get(moduleOrFactory); - - // If module factory is cached - if (moduleFactory) { - resolve(moduleFactory); - return; - } - - // Compile the module and cache it - compiler.compileModuleAsync(moduleOrFactory) - .then((factory) => { - factoryCacheMap.set(moduleOrFactory, factory); - resolve(factory); - }, (err => { - reject(err); - })); - } - }); -} diff --git a/README.md b/README.md index 60f75520..4b4bed4f 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,23 @@ -# ASP.NET Core 2.0 & Angular 4 (+) advanced starter - with Server-side prerendering (for Angular SEO)! +# ASP.NET Core 2.0 & Angular 5 (+) advanced starter - with Server-side prerendering (for Angular SEO)! > [(upcoming) Angular 5.0 demo Branch Here](https://github.com/MarkPieszak/aspnetcore-angular2-universal/tree/angular-5.0-updates)

- ASP.NET Core 2.0 Angular 4+ Starter + ASP.NET Core 2.0 Angular 5+ Starter

-### Harness the power of Angular 4+, ASP.NET Core 2.0, now with SEO ! +### Harness the power of Angular 5+, ASP.NET Core 2.0, now with SEO ! Angular SEO in action:

- ASP.NET Core Angular4 SEO + ASP.NET Core Angular5 SEO

### What is this repo? Live Demo here: http://aspnetcore-angular2-universal.azurewebsites.net This repository is maintained by [Angular](https://github.com/angular/angular) and is meant to be an advanced starter -for both ASP.NET Core 2.0 using Angular 4.0+, not only for the client-side, but to be rendered on the server for instant +for both ASP.NET Core 2.0 using Angular 5.0+, not only for the client-side, but to be rendered on the server for instant application paints (Note: If you don't need SSR [read here](#faq) on how to disable it). This is meant to be a Feature-Rich Starter application containing all of the latest technologies, best build systems available, and include many real-world examples and libraries needed in todays Single Page Applications (SPAs). @@ -51,7 +51,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual - Swagger WebAPI documentation when running in development mode - SignalR Chat demo! (Thanks to [@hakonamatata](https://github.com/hakonamatata)) -- **Angular 4.0.0** : +- **Angular 5.0.0** : - (Minimal) Angular-CLI integration - This is to be used mainly for Generating Components/Services/etc. - Usage examples: @@ -293,7 +293,7 @@ Take a look at the `_Layout.cshtml` file for example, notice how we let .NET han - @ViewData["Title"] - AspNET.Core Angular 4.0.0 (+) starter + @ViewData["Title"] - AspNET.Core Angular 5.0.0 (+) starter @@ -334,7 +334,7 @@ Well now, your Client-side Angular will take over, and you'll have a fully funct - This repository uses ASP.Net Core 2.0, which has a hard requirement on .NET Core Runtime 2.0.0 and .NET Core SDK 2.0.0. Please install these items from [here](https://github.com/dotnet/core/blob/master/release-notes/download-archives/2.0.0-download.md) -> When building components in Angular 4 there are a few things to keep in mind. +> When building components in Angular 5 there are a few things to keep in mind. - **`window`**, **`document`**, **`navigator`**, and other browser types - _do not exist on the server_ - so using them, or any library that uses them (jQuery for example) will not work. You do have some options, if you truly need some of this functionality: - If you need to use them, consider limiting them to only your client and wrapping them situationally. You can use the Object injected using the PLATFORM_ID token to check whether the current platform is browser or server. @@ -379,7 +379,7 @@ constructor(element: ElementRef, renderer: Renderer2) { ### How can I disable SSR (Server-side rendering)? Simply comment out the logic within HomeController, and replace `@Html.Raw(ViewData["SpaHtml"])` with just your applications root -AppComponent tag ("app" in our case): ``. +AppComponent tag ("app-root" in our case): ``. > You could also remove any `isPlatformBrowser/etc` logic, and delete the boot.server, app.module.browser & app.module.server files, just make sure your `boot.browser` file points to `app.module`. @@ -394,7 +394,7 @@ You'll either want to remove SSR for now, or wait as support should be coming to ### How can I use jQuery and/or some jQuery plugins with this repo? > Note: If at all possible, try to avoid using jQuery or libraries dependent on it, as there are -better, more abstract ways of dealing with the DOM in Angular (4+) such as using the Renderer, etc. +better, more abstract ways of dealing with the DOM in Angular (5+) such as using the Renderer, etc. Yes, of course but there are a few things you need to setup before doing this. First, make sure jQuery is included in webpack vendor file, and that you have a webpack Plugin setup for it. `new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' })` diff --git a/Server/Controllers/HomeController.cs b/Server/Controllers/HomeController.cs index 8a5a77f6..0a674a60 100644 --- a/Server/Controllers/HomeController.cs +++ b/Server/Controllers/HomeController.cs @@ -21,7 +21,7 @@ public async Task Index() { var prerenderResult = await Request.BuildPrerender(); - ViewData["SpaHtml"] = prerenderResult.Html; // our from Angular + ViewData["SpaHtml"] = prerenderResult.Html; // our from Angular ViewData["Title"] = prerenderResult.Globals["title"]; // set our from Angular ViewData["Styles"] = prerenderResult.Globals["styles"]; // put styles in the correct place ViewData["Scripts"] = prerenderResult.Globals["scripts"]; // scripts (that were in our header) diff --git a/Startup.cs b/Startup.cs index 7736f9e9..b7773ac0 100644 --- a/Startup.cs +++ b/Startup.cs @@ -54,7 +54,7 @@ public void ConfigureServices(IServiceCollection services) // Register the Swagger generator, defining one or more Swagger documents services.AddSwaggerGen(c => { - c.SwaggerDoc("v1", new Info { Title = "Angular 4.0 Universal & ASP.NET Core advanced starter-kit web API", Version = "v1" }); + c.SwaggerDoc("v1", new Info { Title = "Angular 5.0 Universal & ASP.NET Core advanced starter-kit web API", Version = "v1" }); }); } @@ -74,7 +74,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { HotModuleReplacement = true, - HotModuleReplacementEndpoint = "/dist/__webpack_hmr" + HotModuleReplacementEndpoint = "/dist/" }); app.UseSwagger(); app.UseSwaggerUI(c => diff --git a/package.json b/package.json index 9ebbf620..583b77d0 100644 --- a/package.json +++ b/package.json @@ -15,20 +15,21 @@ "clean": "rimraf wwwroot/dist clientapp/dist" }, "dependencies": { - "@angular/animations": "^4.3.0", - "@angular/common": "^4.3.0", - "@angular/compiler": "^4.3.0", - "@angular/compiler-cli": "^4.3.0", - "@angular/core": "^4.3.0", - "@angular/forms": "^4.3.0", - "@angular/http": "^4.3.0", - "@angular/platform-browser": "^4.3.0", - "@angular/platform-browser-dynamic": "^4.3.0", - "@angular/platform-server": "^4.3.0", - "@angular/router": "^4.3.0", - "@nguniversal/aspnetcore-engine": "^1.0.0-beta.2", - "@ngx-translate/core": "^6.0.1", - "@ngx-translate/http-loader": "0.0.3", + "@angular/animations": "^5.0.0", + "@angular/common": "^5.0.0", + "@angular/compiler": "^5.0.0", + "@angular/compiler-cli": "^5.0.0", + "@angular/core": "^5.0.0", + "@angular/forms": "^5.0.0", + "@angular/http": "^5.0.0", + "@angular/platform-browser": "^5.0.0", + "@angular/platform-browser-dynamic": "^5.0.0", + "@angular/platform-server": "^5.0.0", + "@angular/router": "^5.0.0", + "@nguniversal/aspnetcore-engine": "^5.0.0-beta.5", + "@nguniversal/common": "^5.0.0-beta.5", + "@ngx-translate/core": "^8.0.0", + "@ngx-translate/http-loader": "^2.0.0", "@types/node": "^7.0.12", "angular2-router-loader": "^0.3.5", "angular2-template-loader": "^0.6.2", @@ -49,7 +50,7 @@ "jquery": "^2.2.1", "json-loader": "^0.5.4", "moment": "2.18.1", - "ngx-bootstrap": "2.0.0-beta.3", + "ngx-bootstrap": "2.0.0-beta.6", "node-sass": "^4.5.2", "preboot": "^5.0.0", "raw-loader": "^0.5.1", @@ -58,7 +59,7 @@ "sass-loader": "^6.0.6", "style-loader": "^0.18.2", "to-string-loader": "^1.1.5", - "typescript": "2.5.2", + "typescript": "2.5.3", "url-loader": "^0.5.7", "webpack": "^3.6.0", "webpack-hot-middleware": "^2.19.1", @@ -66,8 +67,8 @@ "zone.js": "^0.8.17" }, "devDependencies": { - "@angular/cli": "^1.3.2", - "@ngtools/webpack": "^1.3.0", + "@angular/cli": "^1.5.0", + "@ngtools/webpack": "^1.8.0", "@types/chai": "^3.4.34", "@types/jasmine": "^2.5.37", "chai": "^3.5.0", diff --git a/tslint.json b/tslint.json index 657d49b6..f318a0b8 100644 --- a/tslint.json +++ b/tslint.json @@ -1,4 +1,5 @@ { + "defaultSeverity": "warn", "rules": { "align": false, "ban": false, @@ -75,7 +76,7 @@ "no-switch-case-fall-through": true, "no-trailing-whitespace": false, "no-unused-expression": true, - "no-unused-variable": false, + "no-unused-variable": true, "no-use-before-declare": true, "no-var-keyword": true, "no-var-requires": false, diff --git a/webpack.config.js b/webpack.config.js index 02ff0a01..eb440b9d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -65,7 +65,11 @@ module.exports = (env) => { entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), exclude: ['./**/*.server.ts'] }) - ]) + ]), + devtool: isDevBuild ? 'cheap-eval-source-map' : false, + node: { + fs: "empty" + } }); // Configuration for server-side (prerendering) bundle suitable for running in Node @@ -78,7 +82,19 @@ module.exports = (env) => { manifest: require('./ClientApp/dist/vendor-manifest.json'), sourceType: 'commonjs2', name: './vendor' - }) + }), + new webpack.ContextReplacementPlugin( + // fixes WARNING Critical dependency: the request of a dependency is an expression + /(.+)?angular(\\|\/)core(.+)?/, + path.join(__dirname, 'src'), // location of your src + {} // a map of your routes + ), + new webpack.ContextReplacementPlugin( + // fixes WARNING Critical dependency: the request of a dependency is an expression + /(.+)?express(\\|\/)(.+)?/, + path.join(__dirname, 'src'), + {} + ) ].concat(isDevBuild ? [] : [ new webpack.optimize.UglifyJsPlugin({ compress: false, @@ -96,7 +112,8 @@ module.exports = (env) => { path: path.join(__dirname, './ClientApp/dist') }, target: 'node', - devtool: isDevBuild ? 'inline-source-map': false + // switch to "inline-source-map" if you want to debug the TS during SSR + devtool: isDevBuild ? 'cheap-eval-source-map' : false }); return [clientBundleConfig, serverBundleConfig]; diff --git a/webpack.config.vendor.js b/webpack.config.vendor.js index 3e07b78b..6d35d3ba 100644 --- a/webpack.config.vendor.js +++ b/webpack.config.vendor.js @@ -46,7 +46,7 @@ module.exports = (env) => { plugins: [ // new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), // Maps these identifiers to the jQuery package (because Bootstrap expects it to be a global variable) new webpack.ContextReplacementPlugin(/\@angular\b.*\b(bundles|linker)/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/11580 - new webpack.ContextReplacementPlugin(/angular(\\|\/)core(\\|\/)@angular/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/14898 + new webpack.ContextReplacementPlugin(/(.+)?angular(\\|\/)core(.+)?/, path.join(__dirname, './ClientApp')), // Workaround for https://github.com/angular/angular/issues/14898 new webpack.IgnorePlugin(/^vertx$/) // Workaround for https://github.com/stefanpenner/es6-promise/issues/100 ] }; From bc2d5a21ec14c38022d9e270b07820722b7ab439 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 2 Nov 2017 10:20:18 -0400 Subject: [PATCH 02/13] docs(readme): remove 5.0 branch as its master now --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b4bed4f..bdbf3b4b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ASP.NET Core 2.0 & Angular 5 (+) advanced starter - with Server-side prerendering (for Angular SEO)! -> [(upcoming) Angular 5.0 demo Branch Here](https://github.com/MarkPieszak/aspnetcore-angular2-universal/tree/angular-5.0-updates) +> Updated to the latest Angular 5.0 - Note ServerTransferModule still in the works - fix coming soon <p align="center"> <img src="http://github.com/docs/architecture.png" alt="ASP.NET Core 2.0 Angular 5+ Starter" title="ASP.NET Core 2.0 Angular 5+ Starter"> @@ -450,6 +450,10 @@ Check out **[www.DevHelp.Online](http://DevHelp.Online)** for more info! Contact us at <hello@devhelp.online>, and let's talk about your projects needs. +<p align="center"> + <img src="https://s3.amazonaws.com/media-p.slid.es/uploads/768119/images/4272479/Screen_Shot_2017-10-27_at_6.58.34_PM.png" alt="DevHelp.Online - Angular ASPNET JavaScript Consulting Development and Training"> +</p> + ---- ## Follow me online: From 71251869ca7b1c48a57af3e1b78481d0afe3bd69 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 2 Nov 2017 15:11:14 -0400 Subject: [PATCH 03/13] chore(boot.server): remove console logs --- ClientApp/boot.server.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/ClientApp/boot.server.ts b/ClientApp/boot.server.ts index a7c2f9f5..c2c0fb47 100644 --- a/ClientApp/boot.server.ts +++ b/ClientApp/boot.server.ts @@ -11,8 +11,6 @@ enableProdMode(); export default createServerRenderer((params) => { - console.log('server ?'); - // Platform-server provider configuration const setupOptions: IEngineOptions = { appSelector: '<app-root></app-root>', @@ -26,9 +24,6 @@ export default createServerRenderer((params) => { return ngAspnetCoreEngine(setupOptions).then(response => { - // console.log('\n\n\naspnet-engine!!!\n\n\n') - console.log(response) - // Apply your transferData to response.globals response.globals.transferData = createTransferScript({ someData: 'Transfer this to the client on the window.TRANSFER_CACHE {} object', From 6954ccb25ab87b43971982f7f653fadcc45c02c0 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 2 Nov 2017 16:58:28 -0400 Subject: [PATCH 04/13] docs(readme): fix broken aspnetcore-engine link --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bdbf3b4b..67aae53e 100644 --- a/README.md +++ b/README.md @@ -139,9 +139,8 @@ export ASPNETCORE_ENVIRONMENT=Development # Upcoming Features: -- Update to use npm [ngAspnetCoreEngine](https://github.com/angular/universal/pull/682) (still need to tweak a few things there) -- Potractor e2e testing -- Add basic Redux State store (Will also hold state durijg HMR builds) +- Fix HttpTransferCacheModule & ServerTransferModule to work with aspnet-engine +- ~~Update to use npm [ngAspnetCoreEngine](https://github.com/angular/universal/pull/682) (still need to tweak a few things there)~~ ---- @@ -268,7 +267,7 @@ Angular application gets serialized into a String, sent to the Browser, along wi The short-version is that we invoke that Node process, passing in our Request object & invoke the `boot.server` file, and we get back a nice object that we pass into .NETs `ViewData` object, and sprinkle through out our `Views/Shared/_Layout.cshtml` and `/Views/Home/index.cshtml` files! -A more detailed explanation can be found here: [ng-AspnetCore-Engine Readme](https://github.com/angular/universal/tree/master/modules/ng-aspnetcore-engine) +A more detailed explanation can be found here: [ng-AspnetCore-Engine Readme](https://github.com/angular/universal/tree/master/modules/aspnetcore-engine) ```csharp // Prerender / Serialize application From 0ab9dbf1ce7f0255b74f5560e763b568a789865b Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Fri, 3 Nov 2017 09:03:31 -0400 Subject: [PATCH 05/13] fix(webpack): remove AoTPlugin for AngularCompilerPlugin closes #453 --- webpack.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webpack.config.js b/webpack.config.js index eb440b9d..26570995 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,7 +11,7 @@ const path = require('path'); const webpack = require('webpack'); const merge = require('webpack-merge'); -const AotPlugin = require('@ngtools/webpack').AotPlugin; +const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin; const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin; const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; @@ -60,7 +60,7 @@ module.exports = (env) => { // new BundleAnalyzerPlugin(), // Plugins that apply in production builds only new webpack.optimize.UglifyJsPlugin(), - new AotPlugin({ + new AngularCompilerPlugin({ tsConfigPath: './tsconfig.json', entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), exclude: ['./**/*.server.ts'] @@ -101,7 +101,7 @@ module.exports = (env) => { mangle: false }), // Plugins that apply in production builds only - new AotPlugin({ + new AngularCompilerPlugin({ tsConfigPath: './tsconfig.json', entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'), exclude: ['./**/*.browser.ts'] From 4c28d00ae0466d94a5b8d7975c87e923fe1de334 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Sat, 25 Nov 2017 16:09:45 -0500 Subject: [PATCH 06/13] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 67aae53e..a50cc5b7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ -# ASP.NET Core 2.0 & Angular 5 (+) advanced starter - with Server-side prerendering (for Angular SEO)! +# ASP.NET Core 2.0 & Angular 5(+) Advanced Starter - with Server-side prerendering (for Angular SEO)! -> Updated to the latest Angular 5.0 - Note ServerTransferModule still in the works - fix coming soon +## By [DevHelp.Online](http://www.DevHelp.Online) + +> Updated to the latest Angular 5.0 - +> Note ServerTransferModule still in the works - fix coming soon +> Note there are still some Production issues we're working out when Publishing <p align="center"> <img src="http://github.com/docs/architecture.png" alt="ASP.NET Core 2.0 Angular 5+ Starter" title="ASP.NET Core 2.0 Angular 5+ Starter"> From 129ff0b9870f7692c29c315aa02497e32400c3b0 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Sat, 25 Nov 2017 16:10:21 -0500 Subject: [PATCH 07/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a50cc5b7..049db6f7 100644 --- a/README.md +++ b/README.md @@ -449,7 +449,7 @@ Copyright (c) 2016-2017 [Mark Pieszak](https://github.com/MarkPieszak) # DevHelp.Online - Angular & ASP.NET - Consulting | Training | Development -Check out **[www.DevHelp.Online](http://DevHelp.Online)** for more info! +Check out **[www.DevHelp.Online](http://DevHelp.Online)** for more info! Twitter [@DevHelpOnline](http://www.twitter.com/DevHelpOnline) Contact us at <hello@devhelp.online>, and let's talk about your projects needs. From 35c336b6625ccbef405804cb99303656720c9b90 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Sat, 25 Nov 2017 16:25:12 -0500 Subject: [PATCH 08/13] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 049db6f7..fdac21c8 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,10 @@ ## By [DevHelp.Online](http://www.DevHelp.Online) > Updated to the latest Angular 5.0 - + > Note ServerTransferModule still in the works - fix coming soon -> Note there are still some Production issues we're working out when Publishing + +> Note: There are still some errors when building Production (with this latest v5 version), use v4 if you need to have a production version right now <p align="center"> <img src="http://github.com/docs/architecture.png" alt="ASP.NET Core 2.0 Angular 5+ Starter" title="ASP.NET Core 2.0 Angular 5+ Starter"> From 6bc3cba5828ff021ce407935e7b79dbe5939d082 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 7 Dec 2017 21:56:08 -0500 Subject: [PATCH 09/13] Fix: remove SSR for now - until completely fixed --- Server/Controllers/HomeController.cs | 18 +++++++++--------- Views/Home/Index.cshtml | 4 +++- webpack.config.js | 24 +++++++++++++----------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Server/Controllers/HomeController.cs b/Server/Controllers/HomeController.cs index 0a674a60..ca660d9f 100644 --- a/Server/Controllers/HomeController.cs +++ b/Server/Controllers/HomeController.cs @@ -19,15 +19,15 @@ public class HomeController : Controller [HttpGet] public async Task<IActionResult> Index() { - var prerenderResult = await Request.BuildPrerender(); - - ViewData["SpaHtml"] = prerenderResult.Html; // our <app-root /> from Angular - ViewData["Title"] = prerenderResult.Globals["title"]; // set our <title> from Angular - ViewData["Styles"] = prerenderResult.Globals["styles"]; // put styles in the correct place - ViewData["Scripts"] = prerenderResult.Globals["scripts"]; // scripts (that were in our header) - ViewData["Meta"] = prerenderResult.Globals["meta"]; // set our <meta> SEO tags - ViewData["Links"] = prerenderResult.Globals["links"]; // set our <link rel="canonical"> etc SEO tags - ViewData["TransferData"] = prerenderResult.Globals["transferData"]; // our transfer data set to window.TRANSFER_CACHE = {}; + // var prerenderResult = await Request.BuildPrerender(); + + // ViewData["SpaHtml"] = prerenderResult.Html; // our <app-root /> from Angular + // ViewData["Title"] = prerenderResult.Globals["title"]; // set our <title> from Angular + // ViewData["Styles"] = prerenderResult.Globals["styles"]; // put styles in the correct place + // ViewData["Scripts"] = prerenderResult.Globals["scripts"]; // scripts (that were in our header) + // ViewData["Meta"] = prerenderResult.Globals["meta"]; // set our <meta> SEO tags + // ViewData["Links"] = prerenderResult.Globals["links"]; // set our <link rel="canonical"> etc SEO tags + // ViewData["TransferData"] = prerenderResult.Globals["transferData"]; // our transfer data set to window.TRANSFER_CACHE = {}; return View(); } diff --git a/Views/Home/Index.cshtml b/Views/Home/Index.cshtml index b0796562..dfe05a7a 100644 --- a/Views/Home/Index.cshtml +++ b/Views/Home/Index.cshtml @@ -1,4 +1,6 @@ -@Html.Raw(ViewData["SpaHtml"]) +<!-- @Html.Raw(ViewData["SpaHtml"]) --> + +<app-root></app-root> <script src="http://github.com/~/dist/vendor.js" asp-append-version="true"></script> @section scripts { diff --git a/webpack.config.js b/webpack.config.js index 26570995..7bd2ae82 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -59,11 +59,12 @@ module.exports = (env) => { ] : [ // new BundleAnalyzerPlugin(), // Plugins that apply in production builds only - new webpack.optimize.UglifyJsPlugin(), + // new webpack.optimize.UglifyJsPlugin(), new AngularCompilerPlugin({ - tsConfigPath: './tsconfig.json', - entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), - exclude: ['./**/*.server.ts'] + mainPath: path.join(__dirname, 'ClientApp/boot.browser.ts'), + tsConfigPath: './tsconfig.json', + entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), + exclude: ['./**/*.server.ts'] }) ]), devtool: isDevBuild ? 'cheap-eval-source-map' : false, @@ -96,15 +97,16 @@ module.exports = (env) => { {} ) ].concat(isDevBuild ? [] : [ - new webpack.optimize.UglifyJsPlugin({ - compress: false, - mangle: false - }), + // new webpack.optimize.UglifyJsPlugin({ + // compress: false, + // mangle: false + // }), // Plugins that apply in production builds only new AngularCompilerPlugin({ - tsConfigPath: './tsconfig.json', - entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'), - exclude: ['./**/*.browser.ts'] + mainPath: path.join(__dirname, 'ClientApp/boot.server.ts'), + tsConfigPath: './tsconfig.json', + entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'), + exclude: ['./**/*.browser.ts'] }) ]), output: { From b8595689813a2e5b95e165e839319517c18a6b43 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 7 Dec 2017 21:57:46 -0500 Subject: [PATCH 10/13] docs(readme): note that ssr has been removed temporarily until fixed --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fdac21c8..1e4b16af 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # ASP.NET Core 2.0 & Angular 5(+) Advanced Starter - with Server-side prerendering (for Angular SEO)! +> **NOTE** Currently issues with SSR and 5.x - SSR temporarily removed ## By [DevHelp.Online](http://www.DevHelp.Online) > Updated to the latest Angular 5.0 - From 56f3014311cbfc6907306c8da56d952889de2447 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 7 Dec 2017 22:03:33 -0500 Subject: [PATCH 11/13] WIP - Angular 5.0 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 583b77d0..376aa936 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "build:dev": "npm run build:vendor && npm run build:webpack", "build:webpack": "webpack --progress --color", "build:prod": "npm run clean && npm run build:vendor -- --env.prod && npm run build:webpack -- --env.prod", + "build:p": "npm run build:webpack -- --env.prod", "build:vendor": "webpack --config webpack.config.vendor.js --progress --color", "clean": "rimraf wwwroot/dist clientapp/dist" }, @@ -68,7 +69,7 @@ }, "devDependencies": { "@angular/cli": "^1.5.0", - "@ngtools/webpack": "^1.8.0", + "@ngtools/webpack": "^1.9.0", "@types/chai": "^3.4.34", "@types/jasmine": "^2.5.37", "chai": "^3.5.0", From 6eca769d1c69be6caaa0175ea5d135f4112e1c71 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Tue, 23 Jan 2018 14:54:53 -0500 Subject: [PATCH 12/13] feature(5.0): Upgrade to working copy of Angular 5.0 + Universal --- ClientApp/boot.server.PRODUCTION.ts | 38 ++++++++++++++++++++++++++++ ClientApp/tsconfig.app.json | 3 ++- Server/Controllers/HomeController.cs | 18 ++++++------- Views/Home/Index.cshtml | 6 +++-- package.json | 8 +++--- webpack.config.js | 16 ++++++++---- 6 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 ClientApp/boot.server.PRODUCTION.ts diff --git a/ClientApp/boot.server.PRODUCTION.ts b/ClientApp/boot.server.PRODUCTION.ts new file mode 100644 index 00000000..30f8deb0 --- /dev/null +++ b/ClientApp/boot.server.PRODUCTION.ts @@ -0,0 +1,38 @@ +import 'zone.js/dist/zone-node'; +import './polyfills/server.polyfills'; +import { enableProdMode } from '@angular/core'; +import { createServerRenderer } from 'aspnet-prerendering'; + +// Grab the (Node) server-specific NgModule +const { AppModuleNgFactory } = require('./app/app.module.server.ngfactory'); // <-- ignore this - this is Production only +import { ngAspnetCoreEngine, IEngineOptions, createTransferScript } from '@nguniversal/aspnetcore-engine'; + +enableProdMode(); + +export default createServerRenderer((params) => { + + // Platform-server provider configuration + const setupOptions: IEngineOptions = { + appSelector: '<app-root></app-root>', + ngModule: AppModuleNgFactory, + request: params, + providers: [ + // Optional - Any other Server providers you want to pass + // (remember you'll have to provide them for the Browser as well) + ] + }; + + return ngAspnetCoreEngine(setupOptions).then(response => { + + // Apply your transferData to response.globals + response.globals.transferData = createTransferScript({ + someData: 'Transfer this to the client on the window.TRANSFER_CACHE {} object', + fromDotnet: params.data.thisCameFromDotNET // example of data coming from dotnet, in HomeController + }); + + return ({ + html: response.html, // our <app-root> serialized + globals: response.globals // all of our styles/scripts/meta-tags/link-tags for aspnet to serve up + }); + }); +}); diff --git a/ClientApp/tsconfig.app.json b/ClientApp/tsconfig.app.json index 5e2507db..3f094c64 100644 --- a/ClientApp/tsconfig.app.json +++ b/ClientApp/tsconfig.app.json @@ -8,6 +8,7 @@ }, "exclude": [ "test.ts", - "**/*.spec.ts" + "**/*.spec.ts", + "boot.server.PRODUCTION.ts" ] } diff --git a/Server/Controllers/HomeController.cs b/Server/Controllers/HomeController.cs index ca660d9f..0a674a60 100644 --- a/Server/Controllers/HomeController.cs +++ b/Server/Controllers/HomeController.cs @@ -19,15 +19,15 @@ public class HomeController : Controller [HttpGet] public async Task<IActionResult> Index() { - // var prerenderResult = await Request.BuildPrerender(); - - // ViewData["SpaHtml"] = prerenderResult.Html; // our <app-root /> from Angular - // ViewData["Title"] = prerenderResult.Globals["title"]; // set our <title> from Angular - // ViewData["Styles"] = prerenderResult.Globals["styles"]; // put styles in the correct place - // ViewData["Scripts"] = prerenderResult.Globals["scripts"]; // scripts (that were in our header) - // ViewData["Meta"] = prerenderResult.Globals["meta"]; // set our <meta> SEO tags - // ViewData["Links"] = prerenderResult.Globals["links"]; // set our <link rel="canonical"> etc SEO tags - // ViewData["TransferData"] = prerenderResult.Globals["transferData"]; // our transfer data set to window.TRANSFER_CACHE = {}; + var prerenderResult = await Request.BuildPrerender(); + + ViewData["SpaHtml"] = prerenderResult.Html; // our <app-root /> from Angular + ViewData["Title"] = prerenderResult.Globals["title"]; // set our <title> from Angular + ViewData["Styles"] = prerenderResult.Globals["styles"]; // put styles in the correct place + ViewData["Scripts"] = prerenderResult.Globals["scripts"]; // scripts (that were in our header) + ViewData["Meta"] = prerenderResult.Globals["meta"]; // set our <meta> SEO tags + ViewData["Links"] = prerenderResult.Globals["links"]; // set our <link rel="canonical"> etc SEO tags + ViewData["TransferData"] = prerenderResult.Globals["transferData"]; // our transfer data set to window.TRANSFER_CACHE = {}; return View(); } diff --git a/Views/Home/Index.cshtml b/Views/Home/Index.cshtml index dfe05a7a..8c18039d 100644 --- a/Views/Home/Index.cshtml +++ b/Views/Home/Index.cshtml @@ -1,6 +1,8 @@ -<!-- @Html.Raw(ViewData["SpaHtml"]) --> +<!-- Remove this if you want to remove Server-side rendering --> +@Html.Raw(ViewData["SpaHtml"]) -<app-root></app-root> +<!-- if you only want Client-side rendering uncomment this --> +<!-- <app-root></app-root> --> <script src="http://github.com/~/dist/vendor.js" asp-append-version="true"></script> @section scripts { diff --git a/package.json b/package.json index 376aa936..b86fbe7f 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ "@angular/animations": "^5.0.0", "@angular/common": "^5.0.0", "@angular/compiler": "^5.0.0", - "@angular/compiler-cli": "^5.0.0", "@angular/core": "^5.0.0", "@angular/forms": "^5.0.0", "@angular/http": "^5.0.0", @@ -56,11 +55,11 @@ "preboot": "^5.0.0", "raw-loader": "^0.5.1", "rimraf": "^2.6.2", - "rxjs": "^5.4.3", + "rxjs": "^5.5.6", "sass-loader": "^6.0.6", "style-loader": "^0.18.2", "to-string-loader": "^1.1.5", - "typescript": "2.5.3", + "typescript": "~2.5.0", "url-loader": "^0.5.7", "webpack": "^3.6.0", "webpack-hot-middleware": "^2.19.1", @@ -68,7 +67,8 @@ "zone.js": "^0.8.17" }, "devDependencies": { - "@angular/cli": "^1.5.0", + "@angular/cli": "^1.7.0-beta.1", + "@angular/compiler-cli": "^5.2.1", "@ngtools/webpack": "^1.9.0", "@types/chai": "^3.4.34", "@types/jasmine": "^2.5.37", diff --git a/webpack.config.js b/webpack.config.js index 7bd2ae82..02ee879f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -59,14 +59,17 @@ module.exports = (env) => { ] : [ // new BundleAnalyzerPlugin(), // Plugins that apply in production builds only - // new webpack.optimize.UglifyJsPlugin(), new AngularCompilerPlugin({ mainPath: path.join(__dirname, 'ClientApp/boot.browser.ts'), tsConfigPath: './tsconfig.json', entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), exclude: ['./**/*.server.ts'] - }) - ]), + }), + // new webpack.optimize.UglifyJsPlugin({ + // compress: false, + // mangle: false + // }) + ]), devtool: isDevBuild ? 'cheap-eval-source-map' : false, node: { fs: "empty" @@ -76,7 +79,10 @@ module.exports = (env) => { // Configuration for server-side (prerendering) bundle suitable for running in Node const serverBundleConfig = merge(sharedConfig, { // resolve: { mainFields: ['main'] }, - entry: { 'main-server': './ClientApp/boot.server.ts' }, + entry: { + 'main-server': + isDevBuild ? './ClientApp/boot.server.ts' : './ClientApp/boot.server.PRODUCTION.ts' + }, plugins: [ new webpack.DllReferencePlugin({ context: __dirname, @@ -103,7 +109,7 @@ module.exports = (env) => { // }), // Plugins that apply in production builds only new AngularCompilerPlugin({ - mainPath: path.join(__dirname, 'ClientApp/boot.server.ts'), + mainPath: path.join(__dirname, 'ClientApp/boot.server.PRODUCTION.ts'), tsConfigPath: './tsconfig.json', entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'), exclude: ['./**/*.browser.ts'] From ada2a7a112acade0e8b8149b9197dbc486c61ea5 Mon Sep 17 00:00:00 2001 From: electricessence <oren@electrified.net> Date: Fri, 23 Mar 2018 17:23:15 -0700 Subject: [PATCH 13/13] chore(ewbpack): fix webpack warnings & sitemap.xml * Migrated plugin to shared config. Eliminates webpack warning. * Added placeholder awaits. Eliminates initial warnings. * Changed to pure XML with format string. "localhost" removed as well. * format update. * Revised after testing. --- Server/Controllers/HomeController.cs | 35 ++++++++++++++-------------- webpack.config.js | 24 ++++++++----------- 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/Server/Controllers/HomeController.cs b/Server/Controllers/HomeController.cs index 0a674a60..a226da8a 100644 --- a/Server/Controllers/HomeController.cs +++ b/Server/Controllers/HomeController.cs @@ -11,6 +11,7 @@ using System.Diagnostics; using System; using Asp2017.Server.Models; +using System.Text.RegularExpressions; namespace AspCoreServer.Controllers { @@ -32,26 +33,24 @@ public async Task<IActionResult> Index() return View(); } + const string SITEMAP_XML = + @"<?xml version=""1.0"" encoding=""utf-8""?> + <sitemapindex xmlns=""http://www.sitemaps.org/schemas/sitemap/0.9""> + <sitemap> + <loc>/home</loc> + <lastmod>{0}</lastmod> + </sitemap> + <sitemap> + <loc>/counter</loc> + <lastmod>{0}</lastmod> + </sitemap> + </sitemapindex> + "; + [HttpGet] [Route("sitemap.xml")] - public async Task<IActionResult> SitemapXml() - { - String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"; - - xml += "<sitemapindex xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9/">"; - xml += "<sitemap>"; - xml += "<loc>http://localhost:4251/home</loc>"; - xml += "<lastmod>" + DateTime.Now.ToString("yyyy-MM-dd") + "</lastmod>"; - xml += "</sitemap>"; - xml += "<sitemap>"; - xml += "<loc>http://localhost:4251/counter</loc>"; - xml += "<lastmod>" + DateTime.Now.ToString("yyyy-MM-dd") + "</lastmod>"; - xml += "</sitemap>"; - xml += "</sitemapindex>"; - - return Content(xml, "text/xml"); - - } + public IActionResult SitemapXml() + => Content(string.Format(SITEMAP_XML, DateTime.Now.ToString("yyyy-MM-dd"))); public IActionResult Error() { diff --git a/webpack.config.js b/webpack.config.js index 02ee879f..d307b23b 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -37,7 +37,15 @@ module.exports = (env) => { ...sharedModuleRules ] }, - plugins: [new CheckerPlugin()] + plugins: [ + new CheckerPlugin(), + new webpack.ContextReplacementPlugin( + // fixes WARNING Critical dependency: the request of a dependency is an expression + /(.+)?angular(\\|\/)core(.+)?/, + path.join(__dirname, 'src'), // location of your src + {} // a map of your routes + ), + ] }; // Configuration for client-side bundle suitable for running in browsers @@ -89,19 +97,7 @@ module.exports = (env) => { manifest: require('./ClientApp/dist/vendor-manifest.json'), sourceType: 'commonjs2', name: './vendor' - }), - new webpack.ContextReplacementPlugin( - // fixes WARNING Critical dependency: the request of a dependency is an expression - /(.+)?angular(\\|\/)core(.+)?/, - path.join(__dirname, 'src'), // location of your src - {} // a map of your routes - ), - new webpack.ContextReplacementPlugin( - // fixes WARNING Critical dependency: the request of a dependency is an expression - /(.+)?express(\\|\/)(.+)?/, - path.join(__dirname, 'src'), - {} - ) + }) ].concat(isDevBuild ? [] : [ // new webpack.optimize.UglifyJsPlugin({ // compress: false,