From a83a6a9bef283c39845467457dd50358b007c6f8 Mon Sep 17 00:00:00 2001 From: nemad Date: Tue, 1 Aug 2017 01:13:07 +0200 Subject: [PATCH 001/103] #336 Fixed duplicate pages on hot module reload (#346) Closes #336 --- Client/main.browser.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Client/main.browser.ts b/Client/main.browser.ts index f1e76b9d..01723608 100644 --- a/Client/main.browser.ts +++ b/Client/main.browser.ts @@ -9,10 +9,6 @@ const rootElemTagName = 'app'; // Update this if you change your root component if (module['hot']) { module['hot'].accept(); module['hot'].dispose(() => { - // Before restarting the app, we create a new root element and dispose the old one - const oldRootElem = document.querySelector(rootElemTagName); - const newRootElem = document.createElement(rootElemTagName); - oldRootElem.parentNode.insertBefore(newRootElem, oldRootElem); modulePromise.then(appModule => appModule.destroy()); }); } else { From 9cfd9c5b64e4c37b3330603c75ac7afae6194e3b Mon Sep 17 00:00:00 2001 From: Isaac Levin Date: Fri, 18 Aug 2017 10:08:16 -0400 Subject: [PATCH 002/103] Port Project to .NET CORE 2.0/EFCore 2.0/.NET Standard 2.0 (#371) Also fixed issue with Lazy Module (took + out of path) Closes #369 --- Asp2017.csproj | 18 +- Client/app/app.module.ts | 4 +- .../{+lazy => lazy}/lazy.component.ts | 0 .../containers/{+lazy => lazy}/lazy.module.ts | 0 Server/Controllers/HomeController.cs | 159 +++++++++--------- Startup.cs | 48 +++--- global.json | 3 - 7 files changed, 114 insertions(+), 118 deletions(-) rename Client/app/containers/{+lazy => lazy}/lazy.component.ts (100%) rename Client/app/containers/{+lazy => lazy}/lazy.module.ts (100%) delete mode 100644 global.json diff --git a/Asp2017.csproj b/Asp2017.csproj index 0cb19457..712d1b94 100644 --- a/Asp2017.csproj +++ b/Asp2017.csproj @@ -1,18 +1,16 @@  - netcoreapp1.1 + netcoreapp2.0 true false - - - - - - - - + + + + + + @@ -45,7 +43,7 @@ - + diff --git a/Client/app/app.module.ts b/Client/app/app.module.ts index 7c92f103..753aed35 100644 --- a/Client/app/app.module.ts +++ b/Client/app/app.module.ts @@ -1,4 +1,4 @@ -import { NgModule, Inject } from '@angular/core'; +import { NgModule, Inject } from '@angular/core'; import { RouterModule } from '@angular/router'; import { CommonModule, APP_BASE_HREF } from '@angular/common'; import { HttpModule, Http } from '@angular/http'; @@ -135,7 +135,7 @@ export function createTranslateLoader(http: Http, baseHref) { } }, - { path: 'lazy', loadChildren: './containers/+lazy/lazy.module#LazyModule'}, + { path: 'lazy', loadChildren: './containers/lazy/lazy.module#LazyModule'}, { path: '**', component: NotFoundComponent, diff --git a/Client/app/containers/+lazy/lazy.component.ts b/Client/app/containers/lazy/lazy.component.ts similarity index 100% rename from Client/app/containers/+lazy/lazy.component.ts rename to Client/app/containers/lazy/lazy.component.ts diff --git a/Client/app/containers/+lazy/lazy.module.ts b/Client/app/containers/lazy/lazy.module.ts similarity index 100% rename from Client/app/containers/+lazy/lazy.module.ts rename to Client/app/containers/lazy/lazy.module.ts diff --git a/Server/Controllers/HomeController.cs b/Server/Controllers/HomeController.cs index 7311cf45..3f19192d 100644 --- a/Server/Controllers/HomeController.cs +++ b/Server/Controllers/HomeController.cs @@ -12,32 +12,37 @@ namespace AspCoreServer.Controllers { - public class HomeController : Controller + public class HomeController : Controller + { + [HttpGet] + public async Task Index() { - [HttpGet] - public async Task Index() - { - var nodeServices = Request.HttpContext.RequestServices.GetRequiredService(); - var hostEnv = Request.HttpContext.RequestServices.GetRequiredService(); - - var applicationBasePath = hostEnv.ContentRootPath; - var requestFeature = Request.HttpContext.Features.Get(); - var unencodedPathAndQuery = requestFeature.RawTarget; - var unencodedAbsoluteUrl = $"{Request.Scheme}://{Request.Host}{unencodedPathAndQuery}"; - - // ** TransferData concept ** - // Here we can pass any Custom Data we want ! - - // By default we're passing down Cookies, Headers, Host from the Request object here - TransferData transferData = new TransferData(); - transferData.request = AbstractHttpContextRequestInfo(Request); - transferData.thisCameFromDotNET = "Hi Angular it's asp.net :)"; - // Add more customData here, add it to the TransferData class - - // Prerender / Serialize application (with Universal) - var prerenderResult = await Prerenderer.RenderToString( + var nodeServices = Request.HttpContext.RequestServices.GetRequiredService(); + var hostEnv = Request.HttpContext.RequestServices.GetRequiredService(); + + var applicationBasePath = hostEnv.ContentRootPath; + var requestFeature = Request.HttpContext.Features.Get(); + var unencodedPathAndQuery = requestFeature.RawTarget; + var unencodedAbsoluteUrl = $"{Request.Scheme}://{Request.Host}{unencodedPathAndQuery}"; + + // ** TransferData concept ** + // Here we can pass any Custom Data we want ! + + // By default we're passing down Cookies, Headers, Host from the Request object here + TransferData transferData = new TransferData(); + transferData.request = AbstractHttpContextRequestInfo(Request); + transferData.thisCameFromDotNET = "Hi Angular it's asp.net :)"; + // Add more customData here, add it to the TransferData class + + //Prerender now needs CancellationToken + System.Threading.CancellationTokenSource cancelSource = new System.Threading.CancellationTokenSource(); + System.Threading.CancellationToken cancelToken = cancelSource.Token; + + // Prerender / Serialize application (with Universal) + var prerenderResult = await Prerenderer.RenderToString( "/", nodeServices, + cancelToken, new JavaScriptModuleExport(applicationBasePath + "/Client/dist/main-server"), unencodedAbsoluteUrl, unencodedPathAndQuery, @@ -46,66 +51,66 @@ public async Task Index() Request.PathBase.ToString() ); - 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["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(); - } - - [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 Error() - { - return View(); - } - - private IRequest AbstractHttpContextRequestInfo(HttpRequest request) - { - - IRequest requestSimplified = new IRequest(); - requestSimplified.cookies = request.Cookies; - requestSimplified.headers = request.Headers; - requestSimplified.host = request.Host; - - return requestSimplified; - } + ViewData["SpaHtml"] = prerenderResult.Html; // our <app> from Angular + ViewData["Title"] = prerenderResult.Globals["title"]; // set our <title> from Angular + ViewData["Styles"] = prerenderResult.Globals["styles"]; // put styles in the correct place + 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(); } - public class IRequest + [HttpGet] + [Route("sitemap.xml")] + public async Task<IActionResult> SitemapXml() { - public object cookies { get; set; } - public object headers { get; set; } - public object host { get; set; } + 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 Error() + { + return View(); } - public class TransferData + private IRequest AbstractHttpContextRequestInfo(HttpRequest request) { - public dynamic request { get; set; } - // Your data here ? - public object thisCameFromDotNET { get; set; } + IRequest requestSimplified = new IRequest(); + requestSimplified.cookies = request.Cookies; + requestSimplified.headers = request.Headers; + requestSimplified.host = request.Host; + + return requestSimplified; } + } + + public class IRequest + { + public object cookies { get; set; } + public object headers { get; set; } + public object host { get; set; } + } + + public class TransferData + { + public dynamic request { get; set; } + + // Your data here ? + public object thisCameFromDotNET { get; set; } + } } diff --git a/Startup.cs b/Startup.cs index 54e456be..00fc9291 100644 --- a/Startup.cs +++ b/Startup.cs @@ -1,17 +1,12 @@ -using System; +using System; using System.IO; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Antiforgery; - using Microsoft.AspNetCore.SpaServices.Webpack; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; - -using Microsoft.AspNetCore.NodeServices; using AspCoreServer.Data; using Swashbuckle.AspNetCore.Swagger; @@ -69,26 +64,27 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); - app.UseStaticFiles(); + app.UseStaticFiles(); - DbInitializer.Initialize(context); + DbInitializer.Initialize(context); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); - app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { + app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions + { HotModuleReplacement = true }); - app.UseSwagger(); - - // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint. app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); }); - app.MapWhen(x => !x.Request.Path.Value.StartsWith("/swagger"), builder => + // Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint. + + + app.MapWhen(x => !x.Request.Path.Value.StartsWith("/swagger", StringComparison.OrdinalIgnoreCase), builder => { builder.UseMvc(routes => { @@ -101,19 +97,19 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF else { app.UseMvc(routes => - { - routes.MapRoute( - name: "default", - template: "{controller=Home}/{action=Index}/{id?}"); - - routes.MapRoute( - "Sitemap", - "sitemap.xml", - new { controller = "Home", action = "SitemapXml" }); - - routes.MapSpaFallbackRoute( - name: "spa-fallback", - defaults: new { controller = "Home", action = "Index" }); + { + routes.MapRoute( + name: "default", + template: "{controller=Home}/{action=Index}/{id?}"); + + routes.MapRoute( + "Sitemap", + "sitemap.xml", + new { controller = "Home", action = "SitemapXml" }); + + routes.MapSpaFallbackRoute( + name: "spa-fallback", + defaults: new { controller = "Home", action = "Index" }); }); app.UseExceptionHandler("/Home/Error"); diff --git a/global.json b/global.json deleted file mode 100644 index 5c5ead2f..00000000 --- a/global.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "sdk": { "version": "1.0.0" } -} From cae82e8e3065ec67d5146820a85acc273fa8034c Mon Sep 17 00:00:00 2001 From: Isaac Levin <isaac2004@users.noreply.github.com> Date: Fri, 18 Aug 2017 10:36:19 -0400 Subject: [PATCH 003/103] Update Readme file to show Core 2.0 Support (#374) * Port Project to .NET CORE 2.0/EFCore 2.0/.NET Standard 2.0 Also fixed issue with Lazy Module (took + out of path) * update readme for Core 2.0 --- README.md | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 8f2e730b..84e58f91 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# ASP.NET Core & Angular 4 (+) advanced starter - with Server-side prerendering (for Angular SEO)! +# ASP.NET Core 2.0 & Angular 4 (+) advanced starter - with Server-side prerendering (for Angular SEO)! <p align="center"> - <img src="http://github.com/docs/architecture.png" alt="ASP.NET Core Angular 2+ Starter" title="ASP.NET Core Angular 2+ Starter"> + <img src="http://github.com/docs/architecture.png" alt="ASP.NET Core 2.0 Angular 2+ Starter" title="ASP.NET Core 2.0 Angular 2+ Starter"> </p> -### Harness the power of Angular 2+, ASP.NET Core, now with SEO ! +### Harness the power of Angular 2+, ASP.NET Core 2.0, now with SEO ! Angular SEO in action: @@ -15,7 +15,7 @@ Angular SEO in action: ### What is this repo? Live Demo here: http://aspnetcore-angular2-universal.azurewebsites.net This repository is maintained by [Angular Universal](https://github.com/angular/universal) and is meant to be an advanced starter -for both ASP.NET Core 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 4.0+, not only for the client-side, but to be rendered on the server for instant application paints (Note: If you don't need Universal (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). @@ -40,7 +40,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual > These are just some of the features found in this starter! -- ASP.NET 1.0 - VS2017 support now! +- ASP.NET 2.0 - VS2017 15.3 support now! - Azure delpoyment straight from VS2017 - Built in docker support through VS2017 - RestAPI (WebAPI) integration @@ -68,9 +68,8 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual - Typescript 2 - Codelyzer (for Real-time static code analysis) - VSCode & Atom provide real-time analysis out of the box. - - **NOTE**: Does not fully work with Visual Studio yet. (Even with VS2017 and .NET core 1.0) -- **ASP.NET Core 1.1** +- **ASP.NET Core 2.0** - Integration with NodeJS to provide pre-rendering, as well as any other Node module asset you want to use. @@ -100,7 +99,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual ### Visual Studio 2017 -Make sure you have .NET Core 1.0+ installed and/or VS2017. +Make sure you have .NET Core 2.0 installed and/or VS2017 15.3. VS2017 will automatically install all the neccessary npm & .NET dependencies when you open the project. Simply push F5 to start debugging ! @@ -134,12 +133,6 @@ export ASPNETCORE_ENVIRONMENT=Development - 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) -- ~~Add Azure application insights module (or at least demo how to use it)~~ -- ~~Add i18n support~~ -- ~~DONE - Fix old README to match new project~~ -- ~~Add AoT compilation~~ -- ~~Add Bootstrap with SCSS~~ -- ~~Add REST API CRUD Demo~~ ---- From 8b5d2e08e3727de4f9802bd5b91b3b37af5d5bae Mon Sep 17 00:00:00 2001 From: Bill <OceansideBill@users.noreply.github.com> Date: Fri, 18 Aug 2017 07:37:49 -0700 Subject: [PATCH 004/103] Pull Request: 1.Changes to the top level scss file to support multiple display widths. 2.Changes to the navmenu component to make the 'hamburger' menu visible on mobile displays. (#372) --- Client/app/app.component.scss | 45 ++++++++++++++-- .../components/navmenu/navmenu.component.css | 51 ++++++++++++++++++- .../components/navmenu/navmenu.component.html | 20 ++++---- .../components/navmenu/navmenu.component.ts | 12 ++++- 4 files changed, 112 insertions(+), 16 deletions(-) diff --git a/Client/app/app.component.scss b/Client/app/app.component.scss index 9ba6e4bf..481063dc 100644 --- a/Client/app/app.component.scss +++ b/Client/app/app.component.scss @@ -14,13 +14,50 @@ $icon-font-path: '~bootstrap-sass/assets/fonts/bootstrap/'; Note: This Component has ViewEncapsulation.None so the styles will bleed out */ +@media (max-width: 767px) { + body { + background: #f1f1f1; + line-height: 18px; + padding-top: 30px; + } + + h1 { + border-bottom: 3px #4189C7 solid; + font-size: 24px; + } + + h2 { + font-size: 20px; + } + + h1, h2, h3 { + padding: 3px 0; + } +} + +@media (min-width: 768px) { + body { + background: #f1f1f1; + line-height: 18px; + padding-top: 0px; + } + + h1 { + border-bottom: 5px #4189C7 solid; + font-size: 36px; + } + + h2 { + font-size: 30px; + } + + h1, h2, h3 { + padding: 10px 0; + } +} -body { background: #f1f1f1; line-height: 18px; } ul { padding: 10px 25px; } ul li { padding: 5px 0; } -h1 { border-bottom: 5px #4189C7 solid; } -h1, h2, h3 { padding: 10px 0; } - blockquote { margin: 25px 10px; padding: 10px 35px 10px 10px; border-left: 10px #158a15 solid; background: #edffed; } blockquote a, blockquote a:hover { color: #068006; } diff --git a/Client/app/components/navmenu/navmenu.component.css b/Client/app/components/navmenu/navmenu.component.css index e15c6128..8d86aa03 100644 --- a/Client/app/components/navmenu/navmenu.component.css +++ b/Client/app/components/navmenu/navmenu.component.css @@ -1,4 +1,4 @@ -li .glyphicon { +li .glyphicon { margin-right: 10px; } @@ -19,10 +19,51 @@ li.link-active a:focus { z-index: 1; } +.icon-bar { + background-color: #4189C7; +} + + +@media (max-width: 767px) { + /* Apply for small displays */ + .main-nav { + width: 100%; + } + + .navbar-brand { + font-size: 14px; + background-color: #f1f1f1; + } + .navbar-toggle { + padding: 0px 5px; + margin-top: 0px; + height: 26px; + } + + .navbar-link { + margin-top: 4px; + margin-left: 45px; + position: fixed; + } + + .navbar-collapse { + background-color: white; + } + + .navbar a { + /* If a menu item's text is too long, truncate it */ + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + padding-right: 5px; + } +} + @media (min-width: 768px) { /* On small screens, convert the nav menu to a vertical sidebar */ .main-nav { height: 100%; + max-width: 330px; width: calc(25% - 20px); } .navbar { @@ -30,6 +71,13 @@ li.link-active a:focus { border-width: 0px; height: 100%; } + .navbar-brand{ + width: 100%; + } + .navbar-link { + display: block; + width: 100% + } .navbar-header { float: none; } @@ -51,7 +99,6 @@ li.link-active a:focus { } .navbar a { /* If a menu item's text is too long, truncate it */ - width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; diff --git a/Client/app/components/navmenu/navmenu.component.html b/Client/app/components/navmenu/navmenu.component.html index 277923a1..b92d8671 100644 --- a/Client/app/components/navmenu/navmenu.component.html +++ b/Client/app/components/navmenu/navmenu.component.html @@ -1,16 +1,18 @@ -<div class='main-nav'> +<div class='main-nav'> <div class='navbar'> <div class='navbar-header'> - <button type='button' class='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'> - <span class='sr-only'>Toggle navigation</span> - <span class='icon-bar'></span> - <span class='icon-bar'></span> - <span class='icon-bar'></span> - </button> - <a class='navbar-brand' [routerLink]="['/home']">Angular 4 Universal & ASP.NET Core </a> + <div class='navbar-brand'> + <button type='button' class='navbar-toggle' (click)="collapseNavbar()"> + <span class='sr-only'>Toggle navigation</span> + <span class='icon-bar'></span> + <span class='icon-bar'></span> + <span class='icon-bar'></span> + </button> + <a [routerLink]="['/home']" class='navbar-link'>Angular 4 Universal & ASP.NET Core</a> + </div> </div> <div class='clearfix'></div> - <div class='navbar-collapse collapse'> + <div class='navbar-collapse {{collapse}}'> <ul class='nav navbar-nav'> <li [routerLinkActive]="['link-active']"> <a [routerLink]="['/home']"> diff --git a/Client/app/components/navmenu/navmenu.component.ts b/Client/app/components/navmenu/navmenu.component.ts index 7a1691cb..3287431d 100644 --- a/Client/app/components/navmenu/navmenu.component.ts +++ b/Client/app/components/navmenu/navmenu.component.ts @@ -1,9 +1,19 @@ -import { Component } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'nav-menu', templateUrl: './navmenu.component.html', styleUrls: ['./navmenu.component.css'] }) + export class NavMenuComponent { + collapse: string = "collapse"; + + collapseNavbar(): void { + if (this.collapse.length > 1) { + this.collapse = ""; + } else { + this.collapse = "collapse"; + } + } } From 309b61681e3d0d3e7388273e20ee6615a97a2a59 Mon Sep 17 00:00:00 2001 From: markoj21 <markoj21@gmail.com> Date: Fri, 18 Aug 2017 07:38:06 -0700 Subject: [PATCH 005/103] Update transfer-http.ts (#321) Fixed the missing body parameters, which caused issues with the options. --- Client/modules/transfer-http/transfer-http.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Client/modules/transfer-http/transfer-http.ts b/Client/modules/transfer-http/transfer-http.ts index e8667b58..3f9b5d84 100644 --- a/Client/modules/transfer-http/transfer-http.ts +++ b/Client/modules/transfer-http/transfer-http.ts @@ -37,7 +37,7 @@ export class TransferHttp { * Performs a request with `post` http method. */ post(url: string, body: any, options?: RequestOptionsArgs): Observable<any> { - return this.getPostData(url, body, options, (url: string, options: RequestOptionsArgs) => { + return this.getPostData(url, body, options, (url: string, body: any, options: RequestOptionsArgs) => { return this.http.post(url, body, options); }); } @@ -46,7 +46,7 @@ export class TransferHttp { */ put(url: string, body: any, options?: RequestOptionsArgs): Observable<any> { - return this.getPostData(url, body, options, (url: string, options: RequestOptionsArgs) => { + return this.getPostData(url, body, options, (url: string, body: any, options: RequestOptionsArgs) => { return this.http.put(url, body, options); }); } @@ -62,7 +62,7 @@ export class TransferHttp { * Performs a request with `patch` http method. */ patch(url: string, body: any, options?: RequestOptionsArgs): Observable<any> { - return this.getPostData(url, body, options, (url: string, options: RequestOptionsArgs) => { + return this.getPostData(url, body, options, (url: string, body: any, options: RequestOptionsArgs) => { return this.http.patch(url, body.options); }); } From fe9ab9c151c79a8ff919ff2f71253c243e2ffb97 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Fri, 18 Aug 2017 10:42:21 -0400 Subject: [PATCH 006/103] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 84e58f91..183ab0b0 100644 --- a/README.md +++ b/README.md @@ -408,6 +408,7 @@ To support IE9 through IE11 open the `polyfills.ts` file in the `polyfills` fold Many thanks go out to Steve Sanderson ([@SteveSandersonMS](https://github.com/SteveSandersonMS)) from Microsoft and his amazing work on JavaScriptServices and integrating the world of Node with ASP.NET Core. Also thank you to the many Contributors ! +- [@Isaac2004](https://github.com/Isaac2004) - [@AbrarJahin](https://github.com/AbrarJahin) - [@LiverpoolOwen](https://github.com/LiverpoolOwen) - [@hakonamatata](https://github.com/hakonamatata) From 55684364d0bfcfa9bee99a98deb6c1829bf446bd Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 24 Aug 2017 10:15:06 -0400 Subject: [PATCH 007/103] WIP - Re-sync with JavaScriptServices (#376) * WIP - Re-sync with JavaScriptServices Main goal is to re-align a bit more with JavaScriptServices to ensure people coming from there, wanting to add additional features, have an easier time syncing with this repo. Adds back vendor builds, Adds back fast HMR (but waiting for https://github.com/aspnet/JavaScriptServices/issues/1204) AoT faster Cleans up multiple tsconfigs etc etc... * fix gitignore * fix HMR, VS builds, misc updates * add package-lock to gitignore closes #307 closes #318 closes #296 closes #294 closes #271 closes #267 closes #230 closes #161 --- .gitignore | 6 +- .vscode/launch.json | 6 +- Asp2017.csproj | 67 ++++++---- Client/main.server.aot.ts | 41 ------ Client/tsconfig.browser.json | 9 -- Client/tsconfig.server.aot.json | 8 -- Client/tsconfig.server.json | 9 -- {Client => ClientApp}/app/app.component.html | 2 +- {Client => ClientApp}/app/app.component.scss | 0 {Client => ClientApp}/app/app.component.ts | 0 .../app/app.module.browser.ts | 7 +- .../app/app.module.server.ts | 6 +- {Client => ClientApp}/app/app.module.ts | 15 ++- .../components/navmenu/navmenu.component.css | 0 .../components/navmenu/navmenu.component.html | 0 .../components/navmenu/navmenu.component.ts | 0 .../user-detail/user-detail.component.html | 0 .../user-detail/user-detail.component.ts | 0 .../app/containers/chat/chat.component.html | 0 .../app/containers/chat/chat.component.scss | 0 .../app/containers/chat/chat.component.ts | 2 +- .../containers/counter/counter.component.html | 0 .../counter/counter.component.spec.ts | 0 .../containers/counter/counter.component.ts | 0 .../app/containers/home/home.component.html | 15 +-- .../app/containers/home/home.component.ts | 6 +- .../app/containers/lazy/lazy.component.ts | 0 .../app/containers/lazy/lazy.module.ts | 0 .../ngx-bootstrap.component.html | 0 .../ngx-bootstrap.component.ts | 0 .../not-found/not-found.component.html | 0 .../not-found/not-found.component.ts | 0 .../app/containers/users/users.component.css | 0 .../app/containers/users/users.component.html | 0 .../app/containers/users/users.component.ts | 0 {Client => ClientApp}/app/models/User.ts | 0 .../app/shared/constants/baseurl.constants.ts | 0 .../app/shared/constants/request.ts | 0 .../app/shared/link.service.ts | 0 .../app/shared/route.resolver.ts | 0 .../app/shared/user.service.ts | 0 .../boot.browser.ts | 4 +- .../boot.server.ts | 4 +- .../transfer-http/transfer-http.module.ts | 0 .../modules/transfer-http/transfer-http.ts | 0 .../browser-transfer-state.module.ts | 0 .../server-transfer-state.module.ts | 0 .../transfer-state/server-transfer-state.ts | 0 .../modules/transfer-state/transfer-state.ts | 0 .../polyfills/browser.polyfills.ts | 0 {Client => ClientApp}/polyfills/polyfills.ts | 0 {Client => ClientApp}/polyfills/rx-imports.ts | 0 .../polyfills/server.polyfills.ts | 0 .../polyfills/temporary-aspnetcore-engine.ts | 0 {Client => ClientApp}/test/jestGlobalMocks.ts | 0 {Client => ClientApp}/test/setupJest.ts | 0 {Client => ClientApp}/tsconfig.spec.json | 0 {Client => ClientApp}/typings.d.ts | 0 README.md | 3 +- Server/Controllers/HomeController.cs | 2 +- Startup.cs | 3 +- Views/Home/Index.cshtml | 3 +- Views/Shared/_Layout.cshtml | 43 +++--- package.json | 43 +++--- tsconfig.json | 7 +- webpack.additions.js | 18 +++ webpack.config.js | 125 ++++++++++++------ webpack.config.vendor.js | 97 ++++++++++++++ 68 files changed, 341 insertions(+), 210 deletions(-) delete mode 100644 Client/main.server.aot.ts delete mode 100644 Client/tsconfig.browser.json delete mode 100644 Client/tsconfig.server.aot.json delete mode 100644 Client/tsconfig.server.json rename {Client => ClientApp}/app/app.component.html (94%) rename {Client => ClientApp}/app/app.component.scss (100%) rename {Client => ClientApp}/app/app.component.ts (100%) rename Client/app/browser-app.module.ts => ClientApp/app/app.module.browser.ts (94%) rename Client/app/server-app.module.ts => ClientApp/app/app.module.server.ts (90%) rename {Client => ClientApp}/app/app.module.ts (96%) rename {Client => ClientApp}/app/components/navmenu/navmenu.component.css (100%) rename {Client => ClientApp}/app/components/navmenu/navmenu.component.html (100%) rename {Client => ClientApp}/app/components/navmenu/navmenu.component.ts (100%) rename {Client => ClientApp}/app/components/user-detail/user-detail.component.html (100%) rename {Client => ClientApp}/app/components/user-detail/user-detail.component.ts (100%) rename {Client => ClientApp}/app/containers/chat/chat.component.html (100%) rename Client/app/containers/chat/chat.component.css => ClientApp/app/containers/chat/chat.component.scss (100%) rename {Client => ClientApp}/app/containers/chat/chat.component.ts (97%) rename {Client => ClientApp}/app/containers/counter/counter.component.html (100%) rename {Client => ClientApp}/app/containers/counter/counter.component.spec.ts (100%) rename {Client => ClientApp}/app/containers/counter/counter.component.ts (100%) rename {Client => ClientApp}/app/containers/home/home.component.html (90%) rename {Client => ClientApp}/app/containers/home/home.component.ts (78%) rename {Client => ClientApp}/app/containers/lazy/lazy.component.ts (100%) rename {Client => ClientApp}/app/containers/lazy/lazy.module.ts (100%) rename {Client => ClientApp}/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.html (100%) rename {Client => ClientApp}/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.ts (100%) rename {Client => ClientApp}/app/containers/not-found/not-found.component.html (100%) rename {Client => ClientApp}/app/containers/not-found/not-found.component.ts (100%) rename {Client => ClientApp}/app/containers/users/users.component.css (100%) rename {Client => ClientApp}/app/containers/users/users.component.html (100%) rename {Client => ClientApp}/app/containers/users/users.component.ts (100%) rename {Client => ClientApp}/app/models/User.ts (100%) rename {Client => ClientApp}/app/shared/constants/baseurl.constants.ts (100%) rename {Client => ClientApp}/app/shared/constants/request.ts (100%) rename {Client => ClientApp}/app/shared/link.service.ts (100%) rename {Client => ClientApp}/app/shared/route.resolver.ts (100%) rename {Client => ClientApp}/app/shared/user.service.ts (100%) rename Client/main.browser.ts => ClientApp/boot.browser.ts (77%) rename Client/main.server.ts => ClientApp/boot.server.ts (94%) rename {Client => ClientApp}/modules/transfer-http/transfer-http.module.ts (100%) rename {Client => ClientApp}/modules/transfer-http/transfer-http.ts (100%) rename {Client => ClientApp}/modules/transfer-state/browser-transfer-state.module.ts (100%) rename {Client => ClientApp}/modules/transfer-state/server-transfer-state.module.ts (100%) rename {Client => ClientApp}/modules/transfer-state/server-transfer-state.ts (100%) rename {Client => ClientApp}/modules/transfer-state/transfer-state.ts (100%) rename {Client => ClientApp}/polyfills/browser.polyfills.ts (100%) rename {Client => ClientApp}/polyfills/polyfills.ts (100%) rename {Client => ClientApp}/polyfills/rx-imports.ts (100%) rename {Client => ClientApp}/polyfills/server.polyfills.ts (100%) rename {Client => ClientApp}/polyfills/temporary-aspnetcore-engine.ts (100%) rename {Client => ClientApp}/test/jestGlobalMocks.ts (100%) rename {Client => ClientApp}/test/setupJest.ts (100%) rename {Client => ClientApp}/tsconfig.spec.json (100%) rename {Client => ClientApp}/typings.d.ts (100%) create mode 100644 webpack.additions.js create mode 100644 webpack.config.vendor.js diff --git a/.gitignore b/.gitignore index 9812c3c4..2f41fd03 100644 --- a/.gitignore +++ b/.gitignore @@ -35,7 +35,7 @@ Obj/ .vs/ /wwwroot/dist/ -/Client/dist/ +/ClientApp/dist/ # MSTest test Results [Tt]est[Rr]esult*/ @@ -187,6 +187,7 @@ BundleArtifacts/ !*.[Cc]ache/ # Others +*.db ClientBin/ ~$* *~ @@ -259,3 +260,6 @@ _Pvt_Extensions # Jest Code Coverage report coverage/ + +.DS_Store +package-lock.json diff --git a/.vscode/launch.json b/.vscode/launch.json index c3669663..08d4edf9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -20,7 +20,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp1.1/Asp2017.dll", + "program": "${workspaceRoot}/bin/Debug/netcoreapp2.0/Asp2017.dll", "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, @@ -51,7 +51,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp1.1/Asp2017.dll", + "program": "${workspaceRoot}/bin/Debug/netcoreapp2.0/Asp2017.dll", "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, @@ -82,7 +82,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp1.1/Asp2017.dll", + "program": "${workspaceRoot}/bin/Debug/netcoreapp2.0/Asp2017.dll", "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, diff --git a/Asp2017.csproj b/Asp2017.csproj index 712d1b94..e373e9ae 100644 --- a/Asp2017.csproj +++ b/Asp2017.csproj @@ -1,51 +1,68 @@ <Project ToolsVersion="15.0" Sdk="Microsoft.NET.Sdk.Web"> + <PropertyGroup> - <TargetFramework>netcoreapp2.0</TargetFramework> + <TargetFramework Condition="'$(TargetFrameworkOverride)' == ''">netcoreapp2.0</TargetFramework> + <TargetFramework Condition="'$(TargetFrameworkOverride)' != ''">TargetFrameworkOverride</TargetFramework> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> + <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion> <IsPackable>false</IsPackable> </PropertyGroup> - <ItemGroup> - <!-- New Meta Package has SpaServices in It --> + + <ItemGroup Condition="'$(TargetFrameworkOverride)' == ''"> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> + </ItemGroup> + <ItemGroup Condition="'$(TargetFrameworkOverride)' != ''"> + <PackageReference Include="Microsoft.AspNetCore" Version="2.0.0" /> + <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0" /> + <PackageReference Include="Microsoft.AspNetCore.SpaServices" Version="2.0.0" /> + <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.0.0" /> + </ItemGroup> + <ItemGroup> <PackageReference Include="NETStandard.Library" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" /> </ItemGroup> - <ItemGroup> - <!-- Files not to show in IDE --> - <None Remove="yarn.lock" /> - <Content Remove="wwwroot\dist\**" /> - <None Remove="Client\dist\**" /> - <Content Remove="coverage\**" /> - <!-- Files not to publish (note that the 'dist' subfolders are re-added below) --> - <Content Remove="Client\**" /> + <ItemGroup> + <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0" /> </ItemGroup> + <ItemGroup> - <Content Include="Client\tsconfig.browser.json" /> - <Content Include="Client\tsconfig.server.aot.json" /> - <Content Include="Client\tsconfig.server.json" /> + <!-- Files not to publish (note that the 'dist' subfolders are re-added below) --> + <Content Remove="ClientApp\**" /> </ItemGroup> - <Target Name="RunWebpack" AfterTargets="ComputeFilesToPublish"> + + <!--/-:cnd:noEmit --> + <Target Name="DebugRunWebpack" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('wwwroot\dist') "> + <!-- Ensure Node.js is installed --> + <Exec Command="node --version" ContinueOnError="true"> + <Output TaskParameter="ExitCode" PropertyName="ErrorCode" /> + </Exec> + <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." /> + + <!-- In development, the dist files won't exist on the first run or when cloning to + a different machine, so rebuild them if not already present. --> + <Message Importance="high" Text="Performing first-run Webpack build..." /> + <Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js" /> + <Exec Command="node node_modules/webpack/bin/webpack.js" /> + </Target> + <!--/+:cnd:noEmit --> + + <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish"> <!-- As part of publishing, ensure the JS resources are freshly built in production mode --> <Exec Command="npm install" /> - <Exec Command="node node_modules/webpack/bin/webpack.js --env.aot --env.client" /> - <Exec Command="node node_modules/webpack/bin/webpack.js --env.aot --env.server" /> + <Exec Command="node node_modules/webpack/bin/webpack.js --config webpack.config.vendor.js --env.prod" /> + <Exec Command="node node_modules/webpack/bin/webpack.js --env.prod" /> + <!-- Include the newly-built files in the publish output --> <ItemGroup> - <DistFiles Include="wwwroot\dist\**; Client\dist\**" /> + <DistFiles Include="wwwroot\dist\**; ClientApp\dist\**" /> <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)"> <RelativePath>%(DistFiles.Identity)</RelativePath> <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory> </ResolvedFileToPublish> </ItemGroup> </Target> - <Target Name="CleanDist" AfterTargets="Clean"> - <ItemGroup> - <FilesToDelete Include="Client\dist\**; wwwroot\dist\**" /> - </ItemGroup> - <Delete Files="@(FilesToDelete)" /> - <RemoveDir Directories="Client\dist; wwwroot\dist" /> - </Target> + </Project> diff --git a/Client/main.server.aot.ts b/Client/main.server.aot.ts deleted file mode 100644 index eb4f0699..00000000 --- a/Client/main.server.aot.ts +++ /dev/null @@ -1,41 +0,0 @@ -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 { ORIGIN_URL } from './app/shared/constants/baseurl.constants'; -// Grab the (Node) server-specific NgModule -import { ServerAppModuleNgFactory } from './ngfactory/app/server-app.module.ngfactory'; -// Temporary * the engine will be on npm soon (`@universal/ng-aspnetcore-engine`) -import { ngAspnetCoreEngine, IEngineOptions, createTransferScript } from './polyfills/temporary-aspnetcore-engine'; - -enableProdMode(); - -export default createServerRenderer(params => { - - // Platform-server provider configuration - const setupOptions: IEngineOptions = { - appSelector: '<app></app>', - ngModule: ServerAppModuleNgFactory, - 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' - }); - - return ({ - html: response.html, - globals: response.globals - }); - }); -}); - -/* -------- THIS FILE IS TEMPORARY and will be gone when @ngtools/webpack can handle dual files (w server) ---------- */ diff --git a/Client/tsconfig.browser.json b/Client/tsconfig.browser.json deleted file mode 100644 index d04b9e60..00000000 --- a/Client/tsconfig.browser.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../tsconfig.json", - "angularCompilerOptions": { - "entryModule": "./app/browser-app.module#BrowserAppModule" - }, - "exclude": [ - "./main.server.aot.ts" - ] -} diff --git a/Client/tsconfig.server.aot.json b/Client/tsconfig.server.aot.json deleted file mode 100644 index 2407460a..00000000 --- a/Client/tsconfig.server.aot.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig.server.json", - "angularCompilerOptions": { - "genDir": "ngfactory", - "entryModule": "./app/server-app.module#ServerAppModule" - }, - "exclude": [] -} diff --git a/Client/tsconfig.server.json b/Client/tsconfig.server.json deleted file mode 100644 index 6fecd055..00000000 --- a/Client/tsconfig.server.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../tsconfig.json", - "angularCompilerOptions": { - "entryModule": "./app/server-app.module#ServerAppModule" - }, - "exclude": [ - "./main.server.aot.ts" - ] -} diff --git a/Client/app/app.component.html b/ClientApp/app/app.component.html similarity index 94% rename from Client/app/app.component.html rename to ClientApp/app/app.component.html index 12a962a5..a3e3bf9b 100644 --- a/Client/app/app.component.html +++ b/ClientApp/app/app.component.html @@ -3,4 +3,4 @@ </div> <div class="col-sm-9 body-content"> <router-outlet></router-outlet> -</div> \ No newline at end of file +</div> diff --git a/Client/app/app.component.scss b/ClientApp/app/app.component.scss similarity index 100% rename from Client/app/app.component.scss rename to ClientApp/app/app.component.scss diff --git a/Client/app/app.component.ts b/ClientApp/app/app.component.ts similarity index 100% rename from Client/app/app.component.ts rename to ClientApp/app/app.component.ts diff --git a/Client/app/browser-app.module.ts b/ClientApp/app/app.module.browser.ts similarity index 94% rename from Client/app/browser-app.module.ts rename to ClientApp/app/app.module.browser.ts index 0150d22c..0af291d4 100644 --- a/Client/app/browser-app.module.ts +++ b/ClientApp/app/app.module.browser.ts @@ -6,7 +6,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { SignalRModule, SignalRConfiguration } from 'ng2-signalr'; import { ORIGIN_URL } from './shared/constants/baseurl.constants'; -import { AppModule } from './app.module'; +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'; @@ -41,7 +41,7 @@ export function getRequest() { BrowserTransferStateModule, // Our Common AppModule - AppModule, + AppModuleShared, SignalRModule.forRoot(createConfig) ], @@ -58,5 +58,4 @@ export function getRequest() { } ] }) -export class BrowserAppModule { -} +export class AppModule { } diff --git a/Client/app/server-app.module.ts b/ClientApp/app/app.module.server.ts similarity index 90% rename from Client/app/server-app.module.ts rename to ClientApp/app/app.module.server.ts index ac91990a..9ccbfb52 100644 --- a/Client/app/server-app.module.ts +++ b/ClientApp/app/app.module.server.ts @@ -3,7 +3,7 @@ import { ServerModule } from '@angular/platform-server'; import { BrowserModule } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { AppModule } from './app.module'; +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'; @@ -20,10 +20,10 @@ import { TransferState } from '../modules/transfer-state/transfer-state'; ServerTransferStateModule, // Our Common AppModule - AppModule + AppModuleShared ] }) -export class ServerAppModule { +export class AppModule { constructor(private transferState: TransferState) { } diff --git a/Client/app/app.module.ts b/ClientApp/app/app.module.ts similarity index 96% rename from Client/app/app.module.ts rename to ClientApp/app/app.module.ts index 753aed35..57498bb8 100644 --- a/Client/app/app.module.ts +++ b/ClientApp/app/app.module.ts @@ -1,5 +1,5 @@ import { NgModule, Inject } from '@angular/core'; -import { RouterModule } from '@angular/router'; +import { RouterModule, PreloadAllModules } from '@angular/router'; import { CommonModule, APP_BASE_HREF } from '@angular/common'; import { HttpModule, Http } from '@angular/http'; import { FormsModule } from '@angular/forms'; @@ -134,9 +134,9 @@ export function createTranslateLoader(http: Http, baseHref) { ] } }, - + { path: 'lazy', loadChildren: './containers/lazy/lazy.module#LazyModule'}, - + { path: '**', component: NotFoundComponent, data: { @@ -148,7 +148,12 @@ export function createTranslateLoader(http: Http, baseHref) { ] } } - ]) + ], { + // Router options + useHash: false, + preloadingStrategy: PreloadAllModules, + initialNavigation: 'enabled' + }) ], providers: [ LinkService, @@ -157,5 +162,5 @@ export function createTranslateLoader(http: Http, baseHref) { TranslateModule ] }) -export class AppModule { +export class AppModuleShared { } diff --git a/Client/app/components/navmenu/navmenu.component.css b/ClientApp/app/components/navmenu/navmenu.component.css similarity index 100% rename from Client/app/components/navmenu/navmenu.component.css rename to ClientApp/app/components/navmenu/navmenu.component.css diff --git a/Client/app/components/navmenu/navmenu.component.html b/ClientApp/app/components/navmenu/navmenu.component.html similarity index 100% rename from Client/app/components/navmenu/navmenu.component.html rename to ClientApp/app/components/navmenu/navmenu.component.html diff --git a/Client/app/components/navmenu/navmenu.component.ts b/ClientApp/app/components/navmenu/navmenu.component.ts similarity index 100% rename from Client/app/components/navmenu/navmenu.component.ts rename to ClientApp/app/components/navmenu/navmenu.component.ts diff --git a/Client/app/components/user-detail/user-detail.component.html b/ClientApp/app/components/user-detail/user-detail.component.html similarity index 100% rename from Client/app/components/user-detail/user-detail.component.html rename to ClientApp/app/components/user-detail/user-detail.component.html diff --git a/Client/app/components/user-detail/user-detail.component.ts b/ClientApp/app/components/user-detail/user-detail.component.ts similarity index 100% rename from Client/app/components/user-detail/user-detail.component.ts rename to ClientApp/app/components/user-detail/user-detail.component.ts diff --git a/Client/app/containers/chat/chat.component.html b/ClientApp/app/containers/chat/chat.component.html similarity index 100% rename from Client/app/containers/chat/chat.component.html rename to ClientApp/app/containers/chat/chat.component.html diff --git a/Client/app/containers/chat/chat.component.css b/ClientApp/app/containers/chat/chat.component.scss similarity index 100% rename from Client/app/containers/chat/chat.component.css rename to ClientApp/app/containers/chat/chat.component.scss diff --git a/Client/app/containers/chat/chat.component.ts b/ClientApp/app/containers/chat/chat.component.ts similarity index 97% rename from Client/app/containers/chat/chat.component.ts rename to ClientApp/app/containers/chat/chat.component.ts index ca9dc8ea..8bbd9ed9 100644 --- a/Client/app/containers/chat/chat.component.ts +++ b/ClientApp/app/containers/chat/chat.component.ts @@ -11,7 +11,7 @@ export class ChatMessage { @Component({ selector: 'chat', templateUrl: './chat.component.html', - styleUrls: ['./chat.component.css'] + styleUrls: ['./chat.component.scss'] }) export class ChatComponent implements OnInit { diff --git a/Client/app/containers/counter/counter.component.html b/ClientApp/app/containers/counter/counter.component.html similarity index 100% rename from Client/app/containers/counter/counter.component.html rename to ClientApp/app/containers/counter/counter.component.html diff --git a/Client/app/containers/counter/counter.component.spec.ts b/ClientApp/app/containers/counter/counter.component.spec.ts similarity index 100% rename from Client/app/containers/counter/counter.component.spec.ts rename to ClientApp/app/containers/counter/counter.component.spec.ts diff --git a/Client/app/containers/counter/counter.component.ts b/ClientApp/app/containers/counter/counter.component.ts similarity index 100% rename from Client/app/containers/counter/counter.component.ts rename to ClientApp/app/containers/counter/counter.component.ts diff --git a/Client/app/containers/home/home.component.html b/ClientApp/app/containers/home/home.component.html similarity index 90% rename from Client/app/containers/home/home.component.html rename to ClientApp/app/containers/home/home.component.html index 3f872f90..06d801e7 100644 --- a/Client/app/containers/home/home.component.html +++ b/ClientApp/app/containers/home/home.component.html @@ -1,23 +1,20 @@ -<h1> - {{ title }}</h1> +<h1>{{ title }}</h1> <blockquote> <strong>Enjoy the latest features from .NET Core & Angular 4.0!</strong> <br> For more info check the repo here: <a href="https://github.com/MarkPieszak/aspnetcore-angular2-universal">AspNetCore-Angular2-Universal repo</a> - <br><br> </blockquote> - <div class="row"> <div class="col-lg-6"> <h2>{{ 'HOME_FEATURE_LIST_TITLE' | translate }} </h2> <ul> - <li>ASP.NET Core 1.1 :: ( Visual Studio 2017 )</li> + <li>ASP.NET Core 2.0 :: ( Visual Studio 2017 )</li> <li> Angular 4.* front-end UI framework <ul> - <li>Angular **platform-server** (Universal moved into Core here) - server-side rendering for SEO, deep-linking, and + <li>Angular **platform-server** (aka: Universal) - server-side rendering for SEO, deep-linking, and incredible performance.</li> <!--<li>HMR State Management - Don't lose your applications state during HMR!</li>--> <li>AoT (Ahead-of-time) production compilation for even faster Prod builds.</li> @@ -33,7 +30,7 @@ <h2>{{ 'HOME_FEATURE_LIST_TITLE' | translate }} </h2> </ul>--> </li> <li> - Webpack 2 + Webpack <ul> <!--<li>TS2 aware path support</li>--> <li>Hot Module Reloading/Replacement for an amazing development experience.</li> @@ -65,11 +62,11 @@ <h2>{{ 'HOME_ISSUES_TITLE' | translate }}</h2> <h2> {{ 'SWITCH_LANGUAGE' | translate }}</h2> <button class="btn btn-default" (click)="setLanguage('en')"> - <span class="flag-icon flag-icon-us"></span> {{ 'ENGLISH' | translate }} + <span class="flag-icon flag-icon-us"></span> {{ 'ENGLISH' | translate }} </button> <button class="btn btn-default" (click)="setLanguage('no')"> - <span class="flag-icon flag-icon-no"></span> {{ 'NORWEGIAN' | translate }} + <span class="flag-icon flag-icon-no"></span> {{ 'NORWEGIAN' | translate }} </button> </div> diff --git a/Client/app/containers/home/home.component.ts b/ClientApp/app/containers/home/home.component.ts similarity index 78% rename from Client/app/containers/home/home.component.ts rename to ClientApp/app/containers/home/home.component.ts index ed7e6f0a..3065c0b1 100644 --- a/Client/app/containers/home/home.component.ts +++ b/ClientApp/app/containers/home/home.component.ts @@ -8,10 +8,12 @@ import { TranslateService } from '@ngx-translate/core'; }) export class HomeComponent implements OnInit { - title: string = 'Angular 4.0 Universal & ASP.NET Core advanced starter-kit'; + title: string = 'Angular 4.0 Universal & ASP.NET Core 2.0 advanced starter-kit'; // Use "constructor"s only for dependency injection - constructor(public translate: TranslateService) { } + constructor( + public translate: TranslateService + ) { } // Here you want to handle anything with @Input()'s @Output()'s // Data retrieval / etc - this is when the Component is "ready" and wired up diff --git a/Client/app/containers/lazy/lazy.component.ts b/ClientApp/app/containers/lazy/lazy.component.ts similarity index 100% rename from Client/app/containers/lazy/lazy.component.ts rename to ClientApp/app/containers/lazy/lazy.component.ts diff --git a/Client/app/containers/lazy/lazy.module.ts b/ClientApp/app/containers/lazy/lazy.module.ts similarity index 100% rename from Client/app/containers/lazy/lazy.module.ts rename to ClientApp/app/containers/lazy/lazy.module.ts diff --git a/Client/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.html b/ClientApp/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.html similarity index 100% rename from Client/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.html rename to ClientApp/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.html diff --git a/Client/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.ts b/ClientApp/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.ts similarity index 100% rename from Client/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.ts rename to ClientApp/app/containers/ngx-bootstrap-demo/ngx-bootstrap.component.ts diff --git a/Client/app/containers/not-found/not-found.component.html b/ClientApp/app/containers/not-found/not-found.component.html similarity index 100% rename from Client/app/containers/not-found/not-found.component.html rename to ClientApp/app/containers/not-found/not-found.component.html diff --git a/Client/app/containers/not-found/not-found.component.ts b/ClientApp/app/containers/not-found/not-found.component.ts similarity index 100% rename from Client/app/containers/not-found/not-found.component.ts rename to ClientApp/app/containers/not-found/not-found.component.ts diff --git a/Client/app/containers/users/users.component.css b/ClientApp/app/containers/users/users.component.css similarity index 100% rename from Client/app/containers/users/users.component.css rename to ClientApp/app/containers/users/users.component.css diff --git a/Client/app/containers/users/users.component.html b/ClientApp/app/containers/users/users.component.html similarity index 100% rename from Client/app/containers/users/users.component.html rename to ClientApp/app/containers/users/users.component.html diff --git a/Client/app/containers/users/users.component.ts b/ClientApp/app/containers/users/users.component.ts similarity index 100% rename from Client/app/containers/users/users.component.ts rename to ClientApp/app/containers/users/users.component.ts diff --git a/Client/app/models/User.ts b/ClientApp/app/models/User.ts similarity index 100% rename from Client/app/models/User.ts rename to ClientApp/app/models/User.ts diff --git a/Client/app/shared/constants/baseurl.constants.ts b/ClientApp/app/shared/constants/baseurl.constants.ts similarity index 100% rename from Client/app/shared/constants/baseurl.constants.ts rename to ClientApp/app/shared/constants/baseurl.constants.ts diff --git a/Client/app/shared/constants/request.ts b/ClientApp/app/shared/constants/request.ts similarity index 100% rename from Client/app/shared/constants/request.ts rename to ClientApp/app/shared/constants/request.ts diff --git a/Client/app/shared/link.service.ts b/ClientApp/app/shared/link.service.ts similarity index 100% rename from Client/app/shared/link.service.ts rename to ClientApp/app/shared/link.service.ts diff --git a/Client/app/shared/route.resolver.ts b/ClientApp/app/shared/route.resolver.ts similarity index 100% rename from Client/app/shared/route.resolver.ts rename to ClientApp/app/shared/route.resolver.ts diff --git a/Client/app/shared/user.service.ts b/ClientApp/app/shared/user.service.ts similarity index 100% rename from Client/app/shared/user.service.ts rename to ClientApp/app/shared/user.service.ts diff --git a/Client/main.browser.ts b/ClientApp/boot.browser.ts similarity index 77% rename from Client/main.browser.ts rename to ClientApp/boot.browser.ts index 01723608..a7830543 100644 --- a/Client/main.browser.ts +++ b/ClientApp/boot.browser.ts @@ -1,7 +1,7 @@ import './polyfills/browser.polyfills'; import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; -import { BrowserAppModule } from './app/browser-app.module'; +import { AppModule } from './app/app.module.browser'; const rootElemTagName = 'app'; // Update this if you change your root component selector @@ -15,4 +15,4 @@ if (module['hot']) { enableProdMode(); } -const modulePromise = platformBrowserDynamic().bootstrapModule(BrowserAppModule); +const modulePromise = platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/Client/main.server.ts b/ClientApp/boot.server.ts similarity index 94% rename from Client/main.server.ts rename to ClientApp/boot.server.ts index e20e4f9f..d93a4f56 100644 --- a/Client/main.server.ts +++ b/ClientApp/boot.server.ts @@ -7,7 +7,7 @@ import { createServerRenderer, RenderResult } from 'aspnet-prerendering'; import { ORIGIN_URL } from './app/shared/constants/baseurl.constants'; // Grab the (Node) server-specific NgModule -import { ServerAppModule } from './app/server-app.module'; +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'; @@ -18,7 +18,7 @@ export default createServerRenderer((params: BootFuncParams) => { // Platform-server provider configuration const setupOptions: IEngineOptions = { appSelector: '<app></app>', - ngModule: ServerAppModule, + 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) diff --git a/Client/modules/transfer-http/transfer-http.module.ts b/ClientApp/modules/transfer-http/transfer-http.module.ts similarity index 100% rename from Client/modules/transfer-http/transfer-http.module.ts rename to ClientApp/modules/transfer-http/transfer-http.module.ts diff --git a/Client/modules/transfer-http/transfer-http.ts b/ClientApp/modules/transfer-http/transfer-http.ts similarity index 100% rename from Client/modules/transfer-http/transfer-http.ts rename to ClientApp/modules/transfer-http/transfer-http.ts diff --git a/Client/modules/transfer-state/browser-transfer-state.module.ts b/ClientApp/modules/transfer-state/browser-transfer-state.module.ts similarity index 100% rename from Client/modules/transfer-state/browser-transfer-state.module.ts rename to ClientApp/modules/transfer-state/browser-transfer-state.module.ts diff --git a/Client/modules/transfer-state/server-transfer-state.module.ts b/ClientApp/modules/transfer-state/server-transfer-state.module.ts similarity index 100% rename from Client/modules/transfer-state/server-transfer-state.module.ts rename to ClientApp/modules/transfer-state/server-transfer-state.module.ts diff --git a/Client/modules/transfer-state/server-transfer-state.ts b/ClientApp/modules/transfer-state/server-transfer-state.ts similarity index 100% rename from Client/modules/transfer-state/server-transfer-state.ts rename to ClientApp/modules/transfer-state/server-transfer-state.ts diff --git a/Client/modules/transfer-state/transfer-state.ts b/ClientApp/modules/transfer-state/transfer-state.ts similarity index 100% rename from Client/modules/transfer-state/transfer-state.ts rename to ClientApp/modules/transfer-state/transfer-state.ts diff --git a/Client/polyfills/browser.polyfills.ts b/ClientApp/polyfills/browser.polyfills.ts similarity index 100% rename from Client/polyfills/browser.polyfills.ts rename to ClientApp/polyfills/browser.polyfills.ts diff --git a/Client/polyfills/polyfills.ts b/ClientApp/polyfills/polyfills.ts similarity index 100% rename from Client/polyfills/polyfills.ts rename to ClientApp/polyfills/polyfills.ts diff --git a/Client/polyfills/rx-imports.ts b/ClientApp/polyfills/rx-imports.ts similarity index 100% rename from Client/polyfills/rx-imports.ts rename to ClientApp/polyfills/rx-imports.ts diff --git a/Client/polyfills/server.polyfills.ts b/ClientApp/polyfills/server.polyfills.ts similarity index 100% rename from Client/polyfills/server.polyfills.ts rename to ClientApp/polyfills/server.polyfills.ts diff --git a/Client/polyfills/temporary-aspnetcore-engine.ts b/ClientApp/polyfills/temporary-aspnetcore-engine.ts similarity index 100% rename from Client/polyfills/temporary-aspnetcore-engine.ts rename to ClientApp/polyfills/temporary-aspnetcore-engine.ts diff --git a/Client/test/jestGlobalMocks.ts b/ClientApp/test/jestGlobalMocks.ts similarity index 100% rename from Client/test/jestGlobalMocks.ts rename to ClientApp/test/jestGlobalMocks.ts diff --git a/Client/test/setupJest.ts b/ClientApp/test/setupJest.ts similarity index 100% rename from Client/test/setupJest.ts rename to ClientApp/test/setupJest.ts diff --git a/Client/tsconfig.spec.json b/ClientApp/tsconfig.spec.json similarity index 100% rename from Client/tsconfig.spec.json rename to ClientApp/tsconfig.spec.json diff --git a/Client/typings.d.ts b/ClientApp/typings.d.ts similarity index 100% rename from Client/typings.d.ts rename to ClientApp/typings.d.ts diff --git a/README.md b/README.md index 183ab0b0..040dc0e0 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ npm install && npm run build:dev && dotnet restore # or yarn install ``` -If you're running the project from command line with `dotnet run` make sure you set your environment variables to Development (otherwise things like HMR won't work). +If you're running the project from command line with `dotnet run` make sure you set your environment variables to Development (otherwise things like HMR might not work). ```bash # on Windows: @@ -129,7 +129,6 @@ export ASPNETCORE_ENVIRONMENT=Development # Upcoming Features: -- **Fix and update Webpack build / Vendor chunking and overall compilation speed.** ( important ) - 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) diff --git a/Server/Controllers/HomeController.cs b/Server/Controllers/HomeController.cs index 3f19192d..87b41ff2 100644 --- a/Server/Controllers/HomeController.cs +++ b/Server/Controllers/HomeController.cs @@ -43,7 +43,7 @@ public async Task<IActionResult> Index() "/", nodeServices, cancelToken, - new JavaScriptModuleExport(applicationBasePath + "/Client/dist/main-server"), + new JavaScriptModuleExport(applicationBasePath + "/ClientApp/dist/main-server"), unencodedAbsoluteUrl, unencodedPathAndQuery, transferData, // Our simplified Request object & any other CustommData you want to send! diff --git a/Startup.cs b/Startup.cs index 00fc9291..7736f9e9 100644 --- a/Startup.cs +++ b/Startup.cs @@ -73,7 +73,8 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF app.UseDeveloperExceptionPage(); app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions { - HotModuleReplacement = true + HotModuleReplacement = true, + HotModuleReplacementEndpoint = "/dist/__webpack_hmr" }); app.UseSwagger(); app.UseSwaggerUI(c => diff --git a/Views/Home/Index.cshtml b/Views/Home/Index.cshtml index 418bb1fd..b0796562 100644 --- a/Views/Home/Index.cshtml +++ b/Views/Home/Index.cshtml @@ -1,6 +1,7 @@ @Html.Raw(ViewData["SpaHtml"]) +<script src="http://github.com/~/dist/vendor.js" asp-append-version="true"></script> @section scripts { <!-- Our webpack bundle --> - <script src="http://github.com/~/dist/main-browser.js" asp-append-version="true"></script> + <script src="http://github.com/~/dist/main-client.js" asp-append-version="true"></script> } diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 8d8fb071..509c52db 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -1,32 +1,33 @@ <!DOCTYPE html> <html> - <head> - <base href="http://github.com/" /> - <title>@ViewData["Title"] + + + @ViewData["Title"] - - - @Html.Raw(ViewData["Meta"]) - @Html.Raw(ViewData["Links"]) + + + @Html.Raw(ViewData["Meta"]) + @Html.Raw(ViewData["Links"]) - + + - @Html.Raw(ViewData["Styles"]) + @Html.Raw(ViewData["Styles"]) - - - @RenderBody() + + + @RenderBody() - - + + - + - - @Html.Raw(ViewData["TransferData"]) + + @Html.Raw(ViewData["TransferData"]) - @RenderSection("scripts", required: false) - + @RenderSection("scripts", required: false) + diff --git a/package.json b/package.json index 3d0e18c9..f3b00472 100644 --- a/package.json +++ b/package.json @@ -6,40 +6,44 @@ "test:watch": "npm run test -- --watch", "test:ci": "npm run test -- --runInBand", "test:coverage": "npm run test -- --coverage", - "build:dev": "webpack --progress --color", - "build:aot": "webpack --env.aot --env.client & webpack --env.aot --env.server" + "build:dev": "npm run build:vendor && npm run build:webpack", + "build:webpack": "webpack --progress --color", + "build:prod": "npm run build:vendor -- --env.prod && npm run build:dev -- --env.prod", + "build:vendor": "webpack --config webpack.config.vendor.js --progress --color" }, "jest": { "preset": "jest-preset-angular", - "setupTestFrameworkScriptFile": "./Client/test/setupJest.ts", + "setupTestFrameworkScriptFile": "./ClientApp/test/setupJest.ts", "globals": { - "__TS_CONFIG__": "Client/tsconfig.spec.json", + "__TS_CONFIG__": "ClientApp/tsconfig.spec.json", "__TRANSFORM_HTML__": true }, "coveragePathIgnorePatterns": [ "/node_modules/", - "/Client/test/.*.ts" + "/ClientApp/test/.*.ts" ], "coverageDirectory": "coverage" }, "dependencies": { - "@angular/animations": "^4.0.0", - "@angular/common": "^4.0.0", - "@angular/compiler": "^4.0.0", - "@angular/compiler-cli": "^4.0.0", - "@angular/core": "^4.0.0", - "@angular/forms": "^4.0.0", - "@angular/http": "^4.0.0", - "@angular/platform-browser": "^4.0.0", - "@angular/platform-browser-dynamic": "^4.0.0", - "@angular/platform-server": "^4.0.0", - "@angular/router": "^4.0.0", + "@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", "@types/node": "^7.0.12", + "angular2-router-loader": "^0.3.4", "angular2-template-loader": "0.6.0", "aspnet-prerendering": "2.0.3", - "aspnet-webpack": "^1.0.17", + "aspnet-webpack": "^2.0.1", "awesome-typescript-loader": "^3.0.0", "bootstrap": "^3.3.7", "bootstrap-sass": "^3.3.7", @@ -55,7 +59,7 @@ "jquery": "^2.2.1", "json-loader": "^0.5.4", "ng2-signalr": "2.0.4", - "ngx-bootstrap": "^1.7.1", + "ngx-bootstrap": "^2.0.0-beta.2", "node-sass": "^4.5.2", "preboot": "^4.5.2", "raw-loader": "^0.5.1", @@ -78,7 +82,8 @@ "@types/jasmine": "^2.5.37", "@types/jest": "^19.2.3", "chai": "^3.5.0", - "codelyzer": "^3.0.0-beta.4", + "codelyzer": "^3.0.0", + "tslint": "^5.0.0", "jasmine-core": "^2.5.2", "jest": "^20.0.0", "jest-preset-angular": "^2.0.1" diff --git a/tsconfig.json b/tsconfig.json index 8728ffab..0e68aae4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,10 +4,11 @@ "module": "es2015", "target": "es5", "noImplicitAny": false, - "sourceMap": false, + "sourceMap": true, "experimentalDecorators": true, "emitDecoratorMetadata": true, - "noStrictGenericChecks": true, + "skipDefaultLibCheck": true, + "skipLibCheck": true, "lib": [ "es2016", "dom" @@ -15,6 +16,6 @@ "types": [ "node" ] }, "include": [ - "Client" + "ClientApp" ] } diff --git a/webpack.additions.js b/webpack.additions.js new file mode 100644 index 00000000..62bf4bb3 --- /dev/null +++ b/webpack.additions.js @@ -0,0 +1,18 @@ +/* [ Webpack Additions ] + * + * This file contains ADD-ONS we are adding on-top of the traditional JavaScriptServices repo + * We do this so that those already using JavaScriptServices can easily figure out how to combine this repo into it. + */ + +// Shared rules[] we need to add +const sharedModuleRules = [ + // sass + { test: /\.scss$/, loaders: ['to-string-loader', 'css-loader', 'sass-loader'] }, + // font-awesome + { test: /\.(woff2?|ttf|eot|svg)$/, loader: 'url-loader?limit=10000' } +]; + + +module.exports = { + sharedModuleRules +}; diff --git a/webpack.config.js b/webpack.config.js index 76980b9c..06435301 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,46 +1,97 @@ -const path = require('path'); -const webpackMerge = require('webpack-merge'); -const commonPartial = require('./webpack/webpack.common'); -const clientPartial = require('./webpack/webpack.client'); -const serverPartial = require('./webpack/webpack.server'); -const prodPartial = require('./webpack/webpack.prod'); -const { getAotPlugin } = require('./webpack/webpack.aot'); +/* + * Webpack (JavaScriptServices) with a few changes & updates + * - This is to keep us inline with JSServices, and help those using that template to add things from this one + * + * Things updated or changed: + * module -> rules [] + * .ts$ test : Added 'angular2-router-loader' for lazy-loading in development + * added ...sharedModuleRules (for scss & font-awesome loaders) + */ -module.exports = function (options, webpackOptions) { - options = options || {}; - webpackOptions = webpackOptions || {}; +const path = require('path'); +const webpack = require('webpack'); +const merge = require('webpack-merge'); +const AotPlugin = require('@ngtools/webpack').AotPlugin; +const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin; - if (options.aot) { - console.log(`Running build for ${options.client ? 'client' : 'server'} with AoT Compilation`) - } +const { sharedModuleRules } = require('./webpack.additions'); - const serverConfig = webpackMerge({}, commonPartial, serverPartial, { - entry: options.aot ? { 'main-server' : './Client/main.server.aot.ts' } : serverPartial.entry, // Temporary +module.exports = (env) => { + // Configuration in common to both client-side and server-side bundles + const isDevBuild = !(env && env.prod); + const sharedConfig = { + stats: { modules: false }, + context: __dirname, + resolve: { extensions: [ '.js', '.ts' ] }, + output: { + filename: '[name].js', + publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix + }, + module: { + rules: [ + { test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-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' }, + ...sharedModuleRules + ] + }, + plugins: [new CheckerPlugin()] + }; + + // Configuration for client-side bundle suitable for running in browsers + const clientBundleOutputDir = './wwwroot/dist'; + const clientBundleConfig = merge(sharedConfig, { + entry: { 'main-client': './ClientApp/boot.browser.ts' }, + output: { path: path.join(__dirname, clientBundleOutputDir) }, plugins: [ - getAotPlugin('server', !!options.aot) - ] + new webpack.DllReferencePlugin({ + context: __dirname, + manifest: require('./wwwroot/dist/vendor-manifest.json') + }) + ].concat(isDevBuild ? [ + // Plugins that apply in development builds only + new webpack.SourceMapDevToolPlugin({ + filename: '[file].map', // Remove this line if you prefer inline source maps + moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk + }) + ] : [ + // Plugins that apply in production builds only + new webpack.optimize.UglifyJsPlugin(), + new AotPlugin({ + tsConfigPath: './tsconfig.json', + entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), + exclude: ['./**/*.server.ts'] + }) + ]) }); - let clientConfig = webpackMerge({}, commonPartial, clientPartial, { + // 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' }, plugins: [ - getAotPlugin('client', !!options.aot) - ] + new webpack.DllReferencePlugin({ + context: __dirname, + manifest: require('./ClientApp/dist/vendor-manifest.json'), + sourceType: 'commonjs2', + name: './vendor' + }) + ].concat(isDevBuild ? [] : [ + // Plugins that apply in production builds only + new AotPlugin({ + tsConfigPath: './tsconfig.json', + entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'), + exclude: ['./**/*.browser.ts'] + }) + ]), + output: { + libraryTarget: 'commonjs', + path: path.join(__dirname, './ClientApp/dist') + }, + target: 'node', + devtool: 'inline-source-map' }); - if (webpackOptions.prod) { - clientConfig = webpackMerge({}, clientConfig, prodPartial); - } - - const configs = []; - if (!options.aot) { - configs.push(clientConfig, serverConfig); - - } else if (options.client) { - configs.push(clientConfig); - - } else if (options.server) { - configs.push(serverConfig); - } - - return configs; -} + return [clientBundleConfig, serverBundleConfig]; +}; diff --git a/webpack.config.vendor.js b/webpack.config.vendor.js new file mode 100644 index 00000000..7ae8a6d2 --- /dev/null +++ b/webpack.config.vendor.js @@ -0,0 +1,97 @@ +const path = require('path'); +const webpack = require('webpack'); +const ExtractTextPlugin = require('extract-text-webpack-plugin'); +const merge = require('webpack-merge'); +const treeShakableModules = [ + '@angular/animations', + '@angular/common', + '@angular/compiler', + '@angular/core', + '@angular/forms', + '@angular/http', + '@angular/platform-browser', + '@angular/platform-browser-dynamic', + '@angular/router', + 'ngx-bootstrap', + 'zone.js', +]; +const nonTreeShakableModules = [ + 'bootstrap', + 'bootstrap/dist/css/bootstrap.css', + 'core-js', + // 'es6-promise', + // 'es6-shim', + 'event-source-polyfill', + // 'jquery', +]; +const allModules = treeShakableModules.concat(nonTreeShakableModules); + +module.exports = (env) => { + console.log(`env = ${JSON.stringify(env)}`) + const extractCSS = new ExtractTextPlugin('vendor.css'); + const isDevBuild = !(env && env.prod); + const sharedConfig = { + stats: { modules: false }, + resolve: { extensions: [ '.js' ] }, + module: { + rules: [ + { test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, use: 'url-loader?limit=100000' } + ] + }, + output: { + publicPath: 'dist/', + filename: '[name].js', + library: '[name]_[hash]' + }, + 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.IgnorePlugin(/^vertx$/) // Workaround for https://github.com/stefanpenner/es6-promise/issues/100 + ] + }; + + const clientBundleConfig = merge(sharedConfig, { + entry: { + // To keep development builds fast, include all vendor dependencies in the vendor bundle. + // But for production builds, leave the tree-shakable ones out so the AOT compiler can produce a smaller bundle. + vendor: isDevBuild ? allModules : nonTreeShakableModules + }, + output: { path: path.join(__dirname, 'wwwroot', 'dist') }, + module: { + rules: [ + { test: /\.css(\?|$)/, use: extractCSS.extract({ use: isDevBuild ? 'css-loader' : 'css-loader?minimize' }) } + ] + }, + plugins: [ + extractCSS, + new webpack.DllPlugin({ + path: path.join(__dirname, 'wwwroot', 'dist', '[name]-manifest.json'), + name: '[name]_[hash]' + }) + ].concat(isDevBuild ? [] : [ + new webpack.optimize.UglifyJsPlugin() + ]) + }); + + const serverBundleConfig = merge(sharedConfig, { + target: 'node', + resolve: { mainFields: ['main'] }, + entry: { vendor: allModules.concat(['aspnet-prerendering']) }, + output: { + path: path.join(__dirname, 'ClientApp', 'dist'), + libraryTarget: 'commonjs2', + }, + module: { + rules: [ { test: /\.css(\?|$)/, use: ['to-string-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] } ] + }, + plugins: [ + new webpack.DllPlugin({ + path: path.join(__dirname, 'ClientApp', 'dist', '[name]-manifest.json'), + name: '[name]_[hash]' + }) + ] + }); + + return [clientBundleConfig, serverBundleConfig]; +} From c490c6916fabf27e65409a92f863198ef630718a Mon Sep 17 00:00:00 2001 From: Isaac Levin Date: Thu, 24 Aug 2017 10:16:18 -0400 Subject: [PATCH 008/103] update to readme to clean up some things (#384) --- README.md | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 040dc0e0..c900ba32 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,22 @@ -# ASP.NET Core 2.0 & Angular 4 (+) advanced starter - with Server-side prerendering (for Angular SEO)! +# ASP.NET Core 2.0 & Angular 4 (+) advanced starter - with Server-side prerendering (for Angular SEO)!

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

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

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

### What is this repo? Live Demo here: http://aspnetcore-angular2-universal.azurewebsites.net -This repository is maintained by [Angular Universal](https://github.com/angular/universal) and is meant to be an advanced starter +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 -application paints (Note: If you don't need Universal (SSR) [read here](#faq) on how to disable it). +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). @@ -29,7 +29,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual * [Deployment](#deployment) * [Upcoming Features](#upcoming-features) * [Application Structure](#application-structure) -* [Universal Gotchas](#universal-gotchas) +* [Gotchas](#gotchas) * [FAQ](#faq---also-check-out-the-faq-issues-label) * [Special Thanks](#special-thanks) * [License](#license) @@ -46,10 +46,10 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual - RestAPI (WebAPI) integration - SQL Database CRUD demo - Swagger WebAPI documentation when running in development mode - - SignalR Chat demo! (Thanks to [@hakonamatata](https://github.com/hakonamatata) + - SignalR Chat demo! (Thanks to [@hakonamatata](https://github.com/hakonamatata)) - **Angular 4.0.0** : - - Featuring Server-side rendering (Platform-Server (basically Angular Universal, but moved into Angular Core) + - Featuring Server-side rendering (Platform-Server) - Faster initial paints, SEO (Search-engine optimization w Title/Meta/Link tags), social media link-previews, etc - i18n internationalization support (via/ ngx-translate) - Baked in best-practices (follows Angular style guide) @@ -95,7 +95,9 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual # Getting Started? -**Make sure you have at least Node 6.x or higher (w/ npm 3+) installed!** +- **Make sure you have at least Node 6.x or higher (w/ npm 3+) installed!** +- **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)** + ### Visual Studio 2017 @@ -261,7 +263,7 @@ The short-version is that we invoke that Node process, passing in our Request ob A more detailed explanation can be found here: [ng-AspnetCore-Engine Readme](https://github.com/angular/universal/tree/master/modules/ng-aspnetcore-engine) ```csharp -// Prerender / Serialize application (with Universal) +// Prerender / Serialize application var prerenderResult = await Prerenderer.RenderToString( /* all of our parameters / options / boot-server file / customData object goes here */ ); @@ -283,7 +285,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 (+) Universal starter + @ViewData["Title"] - AspNET.Core Angular 4.0.0 (+) starter @@ -320,9 +322,10 @@ Well now, your Client-side Angular will take over, and you'll have a fully funct ---- -# Universal "Gotchas" +# "Gotchas" +- 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 Universal components in Angular 2 there are a few things to keep in mind. +> When building components in Angular 4 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. @@ -364,7 +367,7 @@ constructor(element: ElementRef, renderer: Renderer) { # FAQ - Also check out the [FAQ Issues label](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Afaq) -### How can I disable Universal / SSR (Server-side rendering)? +### 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): ``. @@ -373,16 +376,16 @@ AppComponent tag ("app" in our case): ``. ### How do I have code run only in the Browser? -Check the [Universal Gotchas](#universal-gotchas) on how to use `isPlatformBrowser()`. +Check the [Gotchas](#gotchas) on how to use `isPlatformBrowser()`. ### How do I Material2 with this repo? -You'll either want to remove SSR for now, or wait as support should be coming to handle Universal/platform-server rendering. +You'll either want to remove SSR for now, or wait as support should be coming to handle platform-server rendering. -### How can I use jQuery and/or some jQuery plugins with Angular Universal? +### 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 (2+) such as using the Renderer, etc. +better, more abstract ways of dealing with the DOM in Angular (4+) 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' })` From 8c73209f2f82778b7c8c09ca9f41d9ec8280cfda Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Thu, 24 Aug 2017 10:23:03 -0400 Subject: [PATCH 009/103] docs(readme): update to reflect new naming --- README.md | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index c900ba32..7b53a279 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual - **Webpack build system (Webpack 2)** - HMR : Hot Module Reloading/Replacement - - Production builds + - Production builds w/ AoT Compilation - **Testing frameworks** - Unit testing with Karma/Jasmine @@ -106,7 +106,7 @@ VS2017 will automatically install all the neccessary npm & .NET dependencies whe Simply push F5 to start debugging ! -**Note**: If you get any errors after this such as `module not found: main.server` (or similar), open up command line and run `npm run build:dev` to make sure all the assets have been properly built by Webpack. +**Note**: If you get any errors after this such as `module not found: boot.server` (or similar), open up command line and run `npm run build:dev` to make sure all the assets have been properly built by Webpack. ### Visual Studio Code @@ -177,14 +177,14 @@ Here we have the *usual suspects* found at the root level. - `protractor` - config files (e2e testing) - `tslint` - TypeScript code linting rules -### /Client/ - Everything Angular +### /ClientApp/ - Everything Angular > Let's take a look at how this is structured so we can make some sense of it all! -With Angular Universal, we need to split our applicatoin logic **per platform** so [if we look inside this folder](./Client), +With Angular Universal, we need to split our applicatoin logic **per platform** so [if we look inside this folder](./ClientApp), you'll see the 2 root files, that branch the entire logic for browser & server respectively. -- [**Main.Browser.ts**](./Client/main.browser.ts) - +- [**Boot.Browser.ts**](./ClientApp/main.browser.ts) - This file starts up the entire Angular application for the Client/browser platform. Here we setup a few things, client Angular bootstrapping. @@ -192,24 +192,24 @@ Here we setup a few things, client Angular bootstrapping. You'll barely need to touch this file, but something to note, this is the file where you would import libraries that you **only** want being used in the Browser. (Just know that you'd have to provide a mock implementation for the Server when doing that). -- [**Main-Server.ts**](./Client/main.server.ts) - +- [**Boot.Server.ts**](./ClientApp/boot.server.ts) - This file is where Angular _platform-server_ *serializes* the Angular application itself on the .NET server within a very quick Node process, and renders it a string. This is what causes that initial fast paint of the entire application to the Browser, and helps us get all our _SEO_ goodness :sparkles: --- -Notice the folder structure here in `./Client/` : +Notice the folder structure here in `./ClientApp/` : ```diff -+ /Client/ ++ /ClientApp/ + /app/ App NgModule - our Root NgModule (you'll insert Components/etc here most often) AppComponent / App Routes / global css styles * Notice that we have 2 dividing NgModules: - browser-app.module & server-app.module + app.module.browser & app.module.server You'll almost always be using the common app.module, but these 2 are used to split up platform logic for situations where you need to use Dependency Injection / etc, between platforms. @@ -226,21 +226,21 @@ Note: You could use whatever folder conventions you'd like, I prefer to split up ``` When adding new features/components/etc to your application you'll be commonly adding things to the Root **NgModule** (located -in `/Client/app/app.module.ts`), but why are there **two** other NgModules in this folder? +in `/ClientApp/app/app.module.ts`), but why are there **two** other NgModules in this folder? This is because we want to split our logic **per Platform**, but notice they both share the Common NgModule named `app.module.ts`. When adding most things to your application, this is the only place you'll have to add in your new Component / Directive / Pipe / etc. You'll only occassional need to manually -add in the Platform specific things to either `browser-app.module || server-app.module`. +add in the Platform specific things to either `app.module.browser || app.module.server`. To illustrate this point with an example, you can see how we're using Dependency Injection to inject a `StorageService` that is different for the Browser & Server. ```typescript -// For the Browser (browser-app.module) +// For the Browser (app.module.browser) { provide: StorageService, useClass: BrowserStorage } -// For the Server (server-app.module) +// For the Server (app.module.server) { provide: StorageService, useClass: ServerStorage } ``` @@ -258,14 +258,14 @@ 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! +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) ```csharp // Prerender / Serialize application var prerenderResult = await Prerenderer.RenderToString( - /* all of our parameters / options / boot-server file / customData object goes here */ + /* all of our parameters / options / boot.server file / customData object goes here */ ); ViewData["SpaHtml"] = prerenderResult.Html; @@ -323,6 +323,7 @@ Well now, your Client-side Angular will take over, and you'll have a fully funct ---- # "Gotchas" + - 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. @@ -372,7 +373,7 @@ constructor(element: ElementRef, renderer: Renderer) { Simply comment out the logic within HomeController, and replace `@Html.Raw(ViewData["SpaHtml"])` with just your applications root AppComponent tag ("app" in our case): ``. -> You could also remove any `isPlatformBrowser/etc` logic, and delete the boot-server, browser-app.module & server-app.module files, just make sure your `boot-client` file points to `app.module`. +> 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`. ### How do I have code run only in the Browser? @@ -433,6 +434,8 @@ Nothing's ever perfect, but please let me know by creating an issue (make sure t Copyright (c) 2016-2017 [Mark Pieszak](https://github.com/MarkPieszak) +### Follow me online: + Twitter: [@MarkPieszak](http://twitter.com/MarkPieszak) | Medium: [@MarkPieszak](https://medium.com/@MarkPieszak) ---- From 76108b67a9f664bf09927a1d8b137ce2d86d1c4c Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Thu, 24 Aug 2017 10:24:08 -0400 Subject: [PATCH 010/103] docs(readme): naming fix --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7b53a279..b42ca3b6 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ Here we have the *usual suspects* found at the root level. With Angular Universal, we need to split our applicatoin logic **per platform** so [if we look inside this folder](./ClientApp), you'll see the 2 root files, that branch the entire logic for browser & server respectively. -- [**Boot.Browser.ts**](./ClientApp/main.browser.ts) - +- [**Boot.Browser.ts**](./ClientApp/boot.browser.ts) - This file starts up the entire Angular application for the Client/browser platform. Here we setup a few things, client Angular bootstrapping. @@ -391,7 +391,7 @@ better, more abstract ways of dealing with the DOM in Angular (4+) such as using 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' })` -Now, make sure any "plugins" etc that you have, are only included in your `main.browser.ts` file. (ie: `import 'slick-carousel';`) +Now, make sure any "plugins" etc that you have, are only included in your `boot.browser.ts` file. (ie: `import 'slick-carousel';`) In a Component you want to use jQuery, make sure to import it near the top like so: ```typescript From 265e9a791fbe1b9376d80a49d9a1a2894d620313 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Thu, 24 Aug 2017 16:09:33 -0400 Subject: [PATCH 011/103] fix(csproj): update csproj file to open in vs2017 --- Asp2017.csproj | 54 ++++++++++++++++---------------------------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/Asp2017.csproj b/Asp2017.csproj index e373e9ae..db3c39eb 100644 --- a/Asp2017.csproj +++ b/Asp2017.csproj @@ -1,55 +1,29 @@ - - + - netcoreapp2.0 - TargetFrameworkOverride + netcoreapp2.0 true Latest false - - - - - - - - - - + + - - - + + + + + - - - - - - - - - - - - - - - - - - + @@ -64,5 +38,11 @@
- + + + + + + +
From 94605d604a4fa0b054da4819017764ce5db1e82c Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Thu, 24 Aug 2017 16:27:47 -0400 Subject: [PATCH 012/103] feat(angular-cli): add basic angular-cli support for generators ## Minimal) Angular-CLI integration - This is to be used mainly for Generating Components/Services/etc. - Usage examples: - `ng g c components/example-component` - `ng g s shared/some-service` --- .angular-cli.json | 17 +++++++++++++++++ README.md | 9 +++++++-- package.json | 5 +++-- 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 .angular-cli.json diff --git a/.angular-cli.json b/.angular-cli.json new file mode 100644 index 00000000..3382816f --- /dev/null +++ b/.angular-cli.json @@ -0,0 +1,17 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "project": { + "name": "AspnetCore-Angular-Universal" + }, + "apps": [ + { + "root": "ClientApp" + } + ], + "defaults": { + "styleExt": "scss", + "component": { + "spec": false + } + } +} diff --git a/README.md b/README.md index b42ca3b6..dac4e4d3 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,12 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual - SignalR Chat demo! (Thanks to [@hakonamatata](https://github.com/hakonamatata)) - **Angular 4.0.0** : - - Featuring Server-side rendering (Platform-Server) + - (Minimal) Angular-CLI integration + - This is to be used mainly for Generating Components/Services/etc. + - Usage examples: + - `ng g c components/example-component` + - `ng g s shared/some-service` + - Featuring Server-side rendering (Platform-Server, aka: "Universal") - Faster initial paints, SEO (Search-engine optimization w Title/Meta/Link tags), social media link-previews, etc - i18n internationalization support (via/ ngx-translate) - Baked in best-practices (follows Angular style guide) @@ -62,7 +67,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual - Production builds w/ AoT Compilation - **Testing frameworks** - - Unit testing with Karma/Jasmine + - Unit testing with Jest (Going back to Karma soon) - **Productivity** - Typescript 2 diff --git a/package.json b/package.json index f3b00472..49da51e0 100644 --- a/package.json +++ b/package.json @@ -77,15 +77,16 @@ "zone.js": "^0.8.9" }, "devDependencies": { + "@angular/cli": "^1.3.2", "@ngtools/webpack": "^1.3.0", "@types/chai": "^3.4.34", "@types/jasmine": "^2.5.37", "@types/jest": "^19.2.3", "chai": "^3.5.0", "codelyzer": "^3.0.0", - "tslint": "^5.0.0", "jasmine-core": "^2.5.2", "jest": "^20.0.0", - "jest-preset-angular": "^2.0.1" + "jest-preset-angular": "^2.0.1", + "tslint": "^5.0.0" } } From 469a7a705b8aa8d2f8487c458fb4d625288ffade Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Fri, 25 Aug 2017 10:34:44 -0400 Subject: [PATCH 013/103] fix(signal-r): updated signalr chatroom --- .../components/navmenu/navmenu.component.html | 10 +-- .../app/containers/chat/chat.component.html | 80 ++++++++++--------- .../app/containers/chat/chat.component.scss | 4 +- .../app/containers/chat/chat.component.ts | 26 +++--- Views/Shared/_Layout.cshtml | 6 +- 5 files changed, 68 insertions(+), 58 deletions(-) diff --git a/ClientApp/app/components/navmenu/navmenu.component.html b/ClientApp/app/components/navmenu/navmenu.component.html index b92d8671..a4cffbdc 100644 --- a/ClientApp/app/components/navmenu/navmenu.component.html +++ b/ClientApp/app/components/navmenu/navmenu.component.html @@ -39,11 +39,11 @@ Lazy-loaded demo - +
  • + + Chat + +
  • diff --git a/ClientApp/app/containers/chat/chat.component.html b/ClientApp/app/containers/chat/chat.component.html index e29d109b..d44cc419 100644 --- a/ClientApp/app/containers/chat/chat.component.html +++ b/ClientApp/app/containers/chat/chat.component.html @@ -1,45 +1,51 @@ -

    SignalR chat example

    +

    WebSockets (SignalR) Chatroom Example

    -
    -
    -
    -
    - Chat -
    -
    -
      +
      + Data is stored in Azure here - so even in localhost you might be chatting with other people! +
      -
    • - +
      +
      +
      +
      + Angular Chat +
      +
      +
        -
        -
        - {{message.user}} - x mins ago -
        -

        - {{message.content}} -

        -
        - +
      • + + User Avatar + -
      +
      +
      + {{message.user}} + x mins ago +
      +

      + {{ message.content }} +

      - -
      +
    • + +
    +
    +
    +
    -
    {{chatMessages | json}}
    \ No newline at end of file +
    {{ chatMessages | json }}
    diff --git a/ClientApp/app/containers/chat/chat.component.scss b/ClientApp/app/containers/chat/chat.component.scss index d6fefaad..8e085732 100644 --- a/ClientApp/app/containers/chat/chat.component.scss +++ b/ClientApp/app/containers/chat/chat.component.scss @@ -33,7 +33,7 @@ .panel-body { overflow-y: scroll; - height: 600px; + height: 500px; } ::-webkit-scrollbar-track { @@ -49,4 +49,4 @@ ::-webkit-scrollbar-thumb { -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); background-color: #555; -} \ No newline at end of file +} diff --git a/ClientApp/app/containers/chat/chat.component.ts b/ClientApp/app/containers/chat/chat.component.ts index 8bbd9ed9..78cbdb47 100644 --- a/ClientApp/app/containers/chat/chat.component.ts +++ b/ClientApp/app/containers/chat/chat.component.ts @@ -5,7 +5,7 @@ import { SignalR, BroadcastEventListener, SignalRConnection } from 'ng2-signalr' import { Subscription } from 'rxjs/Subscription'; export class ChatMessage { - constructor(public user: string, public content: string) { } + constructor(public content: string, public user: string) { } } @Component({ @@ -21,23 +21,25 @@ export class ChatComponent implements OnInit { private _subscription: Subscription; constructor(route: ActivatedRoute) { - this._connection = route.snapshot.data['connection']; + this._connection = route.snapshot.data['connection']; } ngOnInit() { - const onMessageSent$ = new BroadcastEventListener('OnMessageSent'); - this._connection.listen(onMessageSent$); - this._subscription = onMessageSent$.subscribe((chatMessage: ChatMessage) => { - this.chatMessages.push(chatMessage); - console.log('chat messages', this.chatMessages); - }); + const onMessageSent$ = new BroadcastEventListener('OnMessageSent'); + this._connection.listen(onMessageSent$); + this._subscription = onMessageSent$.subscribe((chatMessage: ChatMessage) => { + this.chatMessages.push(chatMessage); + console.log('chat messages', this.chatMessages); + }); } // send chat message to server - sendMessage(user, message) { - console.log('send message', user, message); - this._connection.invoke('Chat', new ChatMessage(user, message)) - .catch((err: any) => console.log('Failed to invoke', err)); + sendMessage(user, messageInput) { + console.log('send message', user, messageInput.value); + this._connection.invoke('Chat', new ChatMessage(messageInput.value, user)) + .catch((err: any) => console.log('Failed to invoke', err)); + + messageInput.value = ''; } } diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 509c52db..7fb24bdb 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -18,16 +18,18 @@ @RenderBody() - + - + @Html.Raw(ViewData["TransferData"]) @RenderSection("scripts", required: false) + From 593622f3cbc7cf47047e9109b172334984d6a2d5 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Fri, 25 Aug 2017 10:39:22 -0400 Subject: [PATCH 014/103] fix(signal-r): update resolve --- ClientApp/app/shared/route.resolver.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/ClientApp/app/shared/route.resolver.ts b/ClientApp/app/shared/route.resolver.ts index 9b7e02c0..43b0078c 100644 --- a/ClientApp/app/shared/route.resolver.ts +++ b/ClientApp/app/shared/route.resolver.ts @@ -1,15 +1,21 @@ import { Injectable } from '@angular/core'; -import { Resolve } from '@angular/router'; +import { Resolve, Router } from '@angular/router'; import { SignalR, ISignalRConnection } from 'ng2-signalr'; @Injectable() export class ConnectionResolver implements Resolve { - constructor(private _signalR: SignalR) { } + constructor( + private _signalR: SignalR, + private _router: Router + ) { } - resolve() { - console.log('ConnectionResolver. Resolving...'); - return this._signalR.connect(); + resolve(): Promise { + return this._signalR.connect().then((item) => { + return item; + }).catch(() => { + return this._router.navigate(['/']); + }); } -} +} From 34c67fbf0631a625f8d5a2388f2525cedc1f538e Mon Sep 17 00:00:00 2001 From: David Gnanasekaran Date: Sat, 26 Aug 2017 17:27:03 +0530 Subject: [PATCH 015/103] Modified .csproject to emit the wwwroot/dist folder, if the folder is not created yet (#390) --- Asp2017.csproj | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Asp2017.csproj b/Asp2017.csproj index db3c39eb..1bebcdf2 100644 --- a/Asp2017.csproj +++ b/Asp2017.csproj @@ -23,6 +23,20 @@ + + + + + + + + + + + + + From 85558da2b2a0573629b705548b3dad8e0938df94 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Wed, 30 Aug 2017 12:04:36 -0400 Subject: [PATCH 016/103] chore(webpack): remove old deprecated webpack folder --- webpack/helpers.js | 9 -------- webpack/webpack.aot.js | 48 --------------------------------------- webpack/webpack.client.js | 20 ---------------- webpack/webpack.common.js | 25 -------------------- webpack/webpack.prod.js | 4 ---- webpack/webpack.server.js | 22 ------------------ 6 files changed, 128 deletions(-) delete mode 100644 webpack/helpers.js delete mode 100644 webpack/webpack.aot.js delete mode 100644 webpack/webpack.client.js delete mode 100644 webpack/webpack.common.js delete mode 100644 webpack/webpack.prod.js delete mode 100644 webpack/webpack.server.js diff --git a/webpack/helpers.js b/webpack/helpers.js deleted file mode 100644 index 2b49ccc0..00000000 --- a/webpack/helpers.js +++ /dev/null @@ -1,9 +0,0 @@ -const { resolve } = require('path'); - -function root(path) { - return resolve(__dirname, '..', path); -} - -module.exports = { - root: root -}; diff --git a/webpack/webpack.aot.js b/webpack/webpack.aot.js deleted file mode 100644 index 5af7ca50..00000000 --- a/webpack/webpack.aot.js +++ /dev/null @@ -1,48 +0,0 @@ -const { root } = require('./helpers'); -const { AotPlugin } = require('@ngtools/webpack'); - -const tsconfigs = { - client: root('./Client/tsconfig.browser.json'), - server: root('./Client/tsconfig.server.json') -}; - -const aotTsconfigs = { - client: root('./Client/tsconfig.browser.json'), - server: root('./Client/tsconfig.server.aot.json') -}; - -/** - * Generates a AotPlugin for @ngtools/webpack - * - * @param {string} platform Should either be client or server - * @param {boolean} aot Enables/Disables AoT Compilation - * @returns - */ -function getAotPlugin(platform, aot) { - - var aotPlugin = new AotPlugin({ - tsConfigPath: aot ? aotTsconfigs[platform] : tsconfigs[platform], - skipCodeGeneration: !aot - }); - - // TEMPORARY fix for Windows 10 - will be gone when fixed - aotPlugin._compilerHost._resolve = function (path_to_resolve) { - path_1 = require("path"); - path_to_resolve = aotPlugin._compilerHost._normalizePath(path_to_resolve); - if (path_to_resolve[0] == '.') { - return aotPlugin._compilerHost._normalizePath(path_1.join(aotPlugin._compilerHost.getCurrentDirectory(), path_to_resolve)); - } - else if (path_to_resolve[0] == '/' || path_to_resolve.match(/^\w:\//)) { - return path_to_resolve; - } - else { - return aotPlugin._compilerHost._normalizePath(path_1.join(aotPlugin._compilerHost._basePath, path_to_resolve)); - } - }; - - return aotPlugin; -} - -module.exports = { - getAotPlugin: getAotPlugin -}; diff --git a/webpack/webpack.client.js b/webpack/webpack.client.js deleted file mode 100644 index 1c50c612..00000000 --- a/webpack/webpack.client.js +++ /dev/null @@ -1,20 +0,0 @@ -const { AotPlugin } = require('@ngtools/webpack'); - -const { root } = require('./helpers'); -const clientBundleOutputDir = root('./wwwroot/dist'); - -/** - * This is a client config which should be merged on top of common config - */ -module.exports = { - entry: { - 'main-browser': root('./Client/main.browser.ts') - }, - output: { - path: root('./wwwroot/dist'), - }, - target: 'web', - plugins: [ - - ] -}; diff --git a/webpack/webpack.common.js b/webpack/webpack.common.js deleted file mode 100644 index 254ecf86..00000000 --- a/webpack/webpack.common.js +++ /dev/null @@ -1,25 +0,0 @@ -const { root } = require('./helpers'); - -/** - * This is a common webpack config which is the base for all builds - */ -module.exports = { - devtool: 'source-map', - resolve: { - extensions: ['.ts', '.js'] - }, - output: { - filename: '[name].js', - publicPath: '/dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix - }, - module: { - rules: [ - { test: /\.ts$/, loader: '@ngtools/webpack' }, - { test: /\.css$/, loader: ['to-string-loader', 'css-loader'] }, - { test: /\.html$/, loader: 'html-loader' }, - { test: /\.scss$/, loaders: ['to-string-loader', 'css-loader', 'sass-loader'] }, - { test: /\.(woff2?|ttf|eot|svg)$/, loader: 'url-loader?limit=10000' } - ] - }, - plugins: [] -}; diff --git a/webpack/webpack.prod.js b/webpack/webpack.prod.js deleted file mode 100644 index 658f1cd7..00000000 --- a/webpack/webpack.prod.js +++ /dev/null @@ -1,4 +0,0 @@ -/** - * This is a prod config to be merged with the Client config - */ -module.exports = {}; diff --git a/webpack/webpack.server.js b/webpack/webpack.server.js deleted file mode 100644 index e968400a..00000000 --- a/webpack/webpack.server.js +++ /dev/null @@ -1,22 +0,0 @@ -const { root } = require('./helpers'); -const { AotPlugin } = require('@ngtools/webpack'); - -/** - * This is a server config which should be merged on top of common config - */ -module.exports = { - devtool: 'inline-source-map', - resolve: { - extensions: ['.ts', '.js', '.json'], - // An array of directory names to be resolved to the current directory - modules: [root('Client'), root('node_modules')], - }, - entry: { - 'main-server': root('./Client/main.server.ts') - }, - output: { - libraryTarget: 'commonjs', - path: root('./Client/dist') - }, - target: 'node' -}; From 234f246320f691f1a1956cc0b3cef17c5c7ce2ca Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Fri, 1 Sep 2017 18:32:23 -0400 Subject: [PATCH 017/103] fix(build): fix prod flag --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 49da51e0..66b937c3 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "test:coverage": "npm run test -- --coverage", "build:dev": "npm run build:vendor && npm run build:webpack", "build:webpack": "webpack --progress --color", - "build:prod": "npm run build:vendor -- --env.prod && npm run build:dev -- --env.prod", + "build:prod": "npm run build:vendor -- --env.prod && npm run build:webpack -- --env.prod", "build:vendor": "webpack --config webpack.config.vendor.js --progress --color" }, "jest": { From af574fc67955ea8a1eb487e6e8bc9035c2a303f9 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Sat, 2 Sep 2017 12:41:09 -0400 Subject: [PATCH 018/103] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dac4e4d3..073623ee 100644 --- a/README.md +++ b/README.md @@ -445,7 +445,7 @@ Twitter: [@MarkPieszak](http://twitter.com/MarkPieszak) | Medium: [@MarkPieszak] ---- -# Looking for Angular Consulting / Training / support? +# Looking for Angular & ASP.NET Consulting / Training / support? [Contact me](mpieszak84@gmail.com), and let's talk about your projects needs! From 359623e4c623f1be2f696658f2693e723bda91d9 Mon Sep 17 00:00:00 2001 From: Bill Sheldon <30598595+BillSheldon-HunterIndustries@users.noreply.github.com> Date: Sun, 3 Sep 2017 15:53:19 -0700 Subject: [PATCH 019/103] Minor updates related to the menu when in a mobile size display. When a menu item is selected this update causes the menu to automatically collapse. (#397) --- .../components/navmenu/navmenu.component.html | 18 +++++++++--------- .../components/navmenu/navmenu.component.ts | 6 +++++- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ClientApp/app/components/navmenu/navmenu.component.html b/ClientApp/app/components/navmenu/navmenu.component.html index a4cffbdc..57b9c351 100644 --- a/ClientApp/app/components/navmenu/navmenu.component.html +++ b/ClientApp/app/components/navmenu/navmenu.component.html @@ -14,35 +14,35 @@
    diff --git a/ClientApp/app/components/navmenu/navmenu.component.ts b/ClientApp/app/components/navmenu/navmenu.component.ts index 3287431d..ac36f036 100644 --- a/ClientApp/app/components/navmenu/navmenu.component.ts +++ b/ClientApp/app/components/navmenu/navmenu.component.ts @@ -1,4 +1,4 @@ -import { Component } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'nav-menu', @@ -16,4 +16,8 @@ export class NavMenuComponent { this.collapse = "collapse"; } } + + collapseMenu() { + this.collapse = "collapse" + } } From 9e2583d18d68effa39a6816a0682788778556dab Mon Sep 17 00:00:00 2001 From: David Gnanasekaran Date: Mon, 4 Sep 2017 20:19:13 +0530 Subject: [PATCH 020/103] (Unit testing) using Karma test runner (#399) * Modified .csproject to emit the wwwroot/dist folder, if the folder is not created yet * Remove Jest and added Karma test runner for executing unit test cases --- Asp2017.csproj | 2 +- ClientApp/test/boot-tests.js | 30 +++++++ ClientApp/test/jestGlobalMocks.ts | 15 ---- ClientApp/test/karma.conf.js | 46 +++++++++++ ClientApp/test/setupJest.ts | 2 - ClientApp/test/webpack.config.test.js | 112 ++++++++++++++++++++++++++ package.json | 30 +++---- 7 files changed, 201 insertions(+), 36 deletions(-) create mode 100644 ClientApp/test/boot-tests.js delete mode 100644 ClientApp/test/jestGlobalMocks.ts create mode 100644 ClientApp/test/karma.conf.js delete mode 100644 ClientApp/test/setupJest.ts create mode 100644 ClientApp/test/webpack.config.test.js diff --git a/Asp2017.csproj b/Asp2017.csproj index 1bebcdf2..d944c48d 100644 --- a/Asp2017.csproj +++ b/Asp2017.csproj @@ -54,7 +54,7 @@
    - + diff --git a/ClientApp/test/boot-tests.js b/ClientApp/test/boot-tests.js new file mode 100644 index 00000000..eba839d2 --- /dev/null +++ b/ClientApp/test/boot-tests.js @@ -0,0 +1,30 @@ +Error.stackTraceLimit = Infinity; +// Load required polyfills and testing libraries +require('reflect-metadata'); +require('zone.js'); +require('zone.js/dist/long-stack-trace-zone'); +require('zone.js/dist/proxy.js'); +require('zone.js/dist/sync-test'); +require('zone.js/dist/jasmine-patch'); +require('zone.js/dist/async-test'); +require('zone.js/dist/fake-async-test'); +const testing = require('@angular/core/testing'); +const testingBrowser = require('@angular/platform-browser-dynamic/testing'); + +// Prevent Karma from running prematurely +__karma__.loaded = function () {}; + +// First, initialize the Angular testing environment +testing.getTestBed().initTestEnvironment( + testingBrowser.BrowserDynamicTestingModule, + testingBrowser.platformBrowserDynamicTesting() +); + +// Then we find all the tests +const context = require.context('../', true, /\.spec\.ts$/); + +// And load the modules +context.keys().map(context); + +// Finally, start Karma to run the tests +__karma__.start(); diff --git a/ClientApp/test/jestGlobalMocks.ts b/ClientApp/test/jestGlobalMocks.ts deleted file mode 100644 index e5e90ebc..00000000 --- a/ClientApp/test/jestGlobalMocks.ts +++ /dev/null @@ -1,15 +0,0 @@ -const mock = () => { - let storage = {}; - return { - getItem: key => key in storage ? storage[key] : null, - setItem: (key, value) => storage[key] = value || '', - removeItem: key => delete storage[key], - clear: () => storage = {} - }; -}; - -Object.defineProperty(window, 'localStorage', {value: mock()}); -Object.defineProperty(window, 'sessionStorage', {value: mock()}); -Object.defineProperty(window, 'getComputedStyle', { - value: () => ['-webkit-appearance'] -}); diff --git a/ClientApp/test/karma.conf.js b/ClientApp/test/karma.conf.js new file mode 100644 index 00000000..0ae99871 --- /dev/null +++ b/ClientApp/test/karma.conf.js @@ -0,0 +1,46 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/0.13/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '.', + frameworks: ['jasmine'], + exclude: [], + files: [ + './boot-tests.js' + ], + preprocessors: { + './boot-tests.js': ['coverage', 'webpack', 'sourcemap'] + }, + client: { + captureConsole: false + }, + coverageReporter: { + type: 'in-memory' + }, + remapCoverageReporter: { + 'text-summary': null, + json: './coverage/coverage.json', + html: './coverage/html' + }, + reporters: ['mocha', 'coverage', 'remap-coverage'], + port: 9876, + colors: true, + logLevel: config.LOG_WARN, + autoWatch: false, + browsers: ['Chrome'], + mime: { + 'application/javascript': ['ts', 'tsx'] + }, + singleRun: true, + webpack: require('./webpack.config.test.js')({ + env: 'test' + }), + webpackMiddleware: { + noInfo: true, + stats: { + chunks: false + } + } + }); +}; diff --git a/ClientApp/test/setupJest.ts b/ClientApp/test/setupJest.ts deleted file mode 100644 index 1d3bd024..00000000 --- a/ClientApp/test/setupJest.ts +++ /dev/null @@ -1,2 +0,0 @@ -import 'jest-preset-angular'; -import './jestGlobalMocks'; diff --git a/ClientApp/test/webpack.config.test.js b/ClientApp/test/webpack.config.test.js new file mode 100644 index 00000000..6818b46c --- /dev/null +++ b/ClientApp/test/webpack.config.test.js @@ -0,0 +1,112 @@ +const ContextReplacementPlugin = require('webpack/lib/ContextReplacementPlugin'); +const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin'); + +var path = require('path'); +var rootPath = path.join.bind(path, path.resolve(__dirname, '../../')); + +module.exports = function (options) { + return { + devtool: 'inline-source-map', + resolve: { + extensions: ['.ts', '.js'], + modules: [rootPath('ClientApp'), 'node_modules'] + }, + module: { + rules: [{ + enforce: 'pre', + test: /\.js$/, + loader: 'source-map-loader', + exclude: [ + rootPath('node_modules/rxjs'), + rootPath('node_modules/@angular') + ] + }, + { + test: /\.ts$/, + use: [{ + loader: 'awesome-typescript-loader', + query: { + sourceMap: false, + inlineSourceMap: true, + compilerOptions: { + removeComments: true + } + }, + }, + 'angular2-template-loader' + ], + exclude: [/\.e2e\.ts$/] + }, + { + test: /\.css$/, + loader: ['to-string-loader', 'css-loader'] + }, + { + test: /\.scss$/, + loader: ['raw-loader', 'sass-loader'] + }, + { + test: /\.html$/, + loader: 'raw-loader' + }, + { + enforce: 'post', + test: /\.(js|ts)$/, + loader: 'istanbul-instrumenter-loader', + options: { + esModules: true + }, + include: rootPath('ClientApp'), + exclude: [ + /ClientApp\\test/, + /\.(e2e|spec)\.ts$/, + /node_modules/ + ] + } + + ] + }, + plugins: [ + new ContextReplacementPlugin( + /** + * The (\\|\/) piece accounts for path separators in *nix and Windows + */ + /angular(\\|\/)core(\\|\/)@angular/, + rootPath('ClientApp'), // location of your src + { + /** + * your Angular Async Route paths relative to this root directory + */ + } + ), + new LoaderOptionsPlugin({ + debug: false, + options: { + /** + * legacy options go here + */ + } + }), + + ], + performance: { + hints: false + }, + + /** + * Include polyfills or mocks for various node stuff + * Description: Node configuration + * + * See: https://webpack.github.io/docs/configuration.html#node + */ + node: { + global: true, + process: false, + crypto: 'empty', + module: false, + clearImmediate: false, + setImmediate: false + } + + }; +} diff --git a/package.json b/package.json index 66b937c3..6072e16c 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "angular4-aspnetcore-universal", "version": "1.0.0-rc3", "scripts": { - "test": "jest", - "test:watch": "npm run test -- --watch", + "test": "karma start ClientApp/test/karma.conf.js", + "test:watch": "npm run test -- --auto-watch --no-single-run", "test:ci": "npm run test -- --runInBand", "test:coverage": "npm run test -- --coverage", "build:dev": "npm run build:vendor && npm run build:webpack", @@ -11,19 +11,6 @@ "build:prod": "npm run build:vendor -- --env.prod && npm run build:webpack -- --env.prod", "build:vendor": "webpack --config webpack.config.vendor.js --progress --color" }, - "jest": { - "preset": "jest-preset-angular", - "setupTestFrameworkScriptFile": "./ClientApp/test/setupJest.ts", - "globals": { - "__TS_CONFIG__": "ClientApp/tsconfig.spec.json", - "__TRANSFORM_HTML__": true - }, - "coveragePathIgnorePatterns": [ - "/node_modules/", - "/ClientApp/test/.*.ts" - ], - "coverageDirectory": "coverage" - }, "dependencies": { "@angular/animations": "^4.3.0", "@angular/common": "^4.3.0", @@ -81,12 +68,19 @@ "@ngtools/webpack": "^1.3.0", "@types/chai": "^3.4.34", "@types/jasmine": "^2.5.37", - "@types/jest": "^19.2.3", "chai": "^3.5.0", "codelyzer": "^3.0.0", + "istanbul-instrumenter-loader": "^3.0.0", "jasmine-core": "^2.5.2", - "jest": "^20.0.0", - "jest-preset-angular": "^2.0.1", + "karma": "^1.7.1", + "karma-chai": "^0.1.0", + "karma-chrome-launcher": "^2.2.0", + "karma-coverage": "^1.1.1", + "karma-jasmine": "^1.1.0", + "karma-mocha-reporter": "^2.2.4", + "karma-remap-coverage": "^0.1.4", + "karma-sourcemap-loader": "^0.3.7", + "karma-webpack": "^2.0.3", "tslint": "^5.0.0" } } From 2f11294427ef5da2d6929798c8628e25296aca75 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Tue, 5 Sep 2017 19:02:50 -0400 Subject: [PATCH 021/103] feat(preboot): add preboot functionality & fix aspnetcore-engine (#401) Closes #363 --- ClientApp/app/app.module.browser.ts | 3 +++ ClientApp/app/app.module.server.ts | 3 +++ ClientApp/polyfills/temporary-aspnetcore-engine.ts | 8 ++++++++ Server/Controllers/HomeController.cs | 1 + Views/Shared/_Layout.cshtml | 1 + package.json | 2 +- 6 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ClientApp/app/app.module.browser.ts b/ClientApp/app/app.module.browser.ts index 0af291d4..70918765 100644 --- a/ClientApp/app/app.module.browser.ts +++ b/ClientApp/app/app.module.browser.ts @@ -11,6 +11,8 @@ import { AppComponent } from './app.component'; import { REQUEST } from './shared/constants/request'; import { BrowserTransferStateModule } from '../modules/transfer-state/browser-transfer-state.module'; +import { BrowserPrebootModule } from 'preboot/browser'; + export function createConfig(): SignalRConfiguration { const signalRConfig = new SignalRConfiguration(); @@ -37,6 +39,7 @@ export function getRequest() { BrowserModule.withServerTransition({ appId: 'my-app-id' // make sure this matches with your Server NgModule }), + BrowserPrebootModule.replayEvents(), BrowserAnimationsModule, BrowserTransferStateModule, diff --git a/ClientApp/app/app.module.server.ts b/ClientApp/app/app.module.server.ts index 9ccbfb52..9e22b71e 100644 --- a/ClientApp/app/app.module.server.ts +++ b/ClientApp/app/app.module.server.ts @@ -8,6 +8,8 @@ import { AppComponent } from './app.component'; import { ServerTransferStateModule } from '../modules/transfer-state/server-transfer-state.module'; import { TransferState } from '../modules/transfer-state/transfer-state'; +import { ServerPrebootModule } from 'preboot/server'; + @NgModule({ bootstrap: [AppComponent], imports: [ @@ -15,6 +17,7 @@ import { TransferState } from '../modules/transfer-state/transfer-state'; appId: 'my-app-id' // make sure this matches with your Browser NgModule }), ServerModule, + ServerPrebootModule.recordEvents({ appRoot: 'app' }), NoopAnimationsModule, ServerTransferStateModule, diff --git a/ClientApp/polyfills/temporary-aspnetcore-engine.ts b/ClientApp/polyfills/temporary-aspnetcore-engine.ts index a68986c2..5a2ce9df 100644 --- a/ClientApp/polyfills/temporary-aspnetcore-engine.ts +++ b/ClientApp/polyfills/temporary-aspnetcore-engine.ts @@ -122,6 +122,7 @@ export function ngAspnetCoreEngine( // Strip out Styles / Meta-tags / Title const STYLES = []; + const SCRIPTS = []; const META = []; const LINKS = []; let TITLE = ''; @@ -148,6 +149,12 @@ export function ngAspnetCoreEngine( TITLE = element.children[0].data; } + if (element.name === 'script') { + SCRIPTS.push( + `` + ); + } + // Broken after 4.0 (worked in rc) // if (element.name === 'style') { // let styleTag = '') + 8 - //); - let STYLES_STRING: string = htmlDoc.indexOf('') + 8) : null; - // STYLES_STRING = STYLES_STRING.replace(/\s/g, '').replace(', NgModuleFactory<{}>>(); function getFactory( moduleOrFactory: Type<{}> | NgModuleFactory<{}>, compiler: Compiler ): Promise> { + return new Promise>((resolve, reject) => { // If module has been compiled AoT if (moduleOrFactory instanceof NgModuleFactory) { - console.log('Already AoT?'); resolve(moduleOrFactory); return; } else { @@ -244,7 +237,6 @@ function getFactory( // If module factory is cached if (moduleFactory) { - console.log('\n\n\n WE FOUND ONE!! USE IT!!\n\n\n'); resolve(moduleFactory); return; } @@ -252,7 +244,6 @@ function getFactory( // Compile the module and cache it compiler.compileModuleAsync(moduleOrFactory) .then((factory) => { - console.log('\n\n\n\n MAP THIS THING!!!!\n\n\n '); factoryCacheMap.set(moduleOrFactory, factory); resolve(factory); }, (err => { From 8a02df7d09f3934464684472fa49c31cf8ca209f Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Thu, 21 Sep 2017 17:40:08 -0400 Subject: [PATCH 027/103] bug(ngx-bootstrap): pin to beta.3 for now fixes MouseEvent issue from latest beta release --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b35ac7ab..03efe97c 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "jquery": "^2.2.1", "json-loader": "^0.5.4", "ng2-signalr": "2.0.4", - "ngx-bootstrap": "^2.0.0-beta.2", + "ngx-bootstrap": "2.0.0-beta.3", "node-sass": "^4.5.2", "preboot": "^5.0.0", "raw-loader": "^0.5.1", From 3848e4357d24a04d39d3931d0a36d383c07cc005 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Fri, 22 Sep 2017 17:01:57 -0400 Subject: [PATCH 028/103] docs(readme): renderer2 fix --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f24dfc64..9e30c7a4 100644 --- a/README.md +++ b/README.md @@ -337,7 +337,7 @@ Well now, your Client-side Angular will take over, and you'll have a fully funct - **`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. - ``` + ```typescript import { PLATFORM_ID } from '@angular/core'; import { isPlatformBrowser, isPlatformServer } from '@angular/common'; @@ -358,9 +358,9 @@ Well now, your Client-side Angular will take over, and you'll have a fully funct - Try to *limit or* **avoid** using **`setTimeout`**. It will slow down the server-side rendering process. Make sure to remove them [`ngOnDestroy`](https://angular.io/docs/ts/latest/api/core/index/OnDestroy-class.html) in Components. - Also for RxJs timeouts, make sure to _cancel_ their stream on success, for they can slow down rendering as well. - **Don't manipulate the nativeElement directly**. Use the _Renderer2_. We do this to ensure that in any environment we're able to change our view. -``` -constructor(element: ElementRef, renderer: Renderer) { - renderer.setElementStyle(element.nativeElement, 'font-size', 'x-large'); +```typescript +constructor(element: ElementRef, renderer: Renderer2) { + this.renderer.setStyle(element.nativeElement, 'font-size', 'x-large'); } ``` - The application runs XHR requests on the server & once again on the Client-side (when the application bootstraps) From e627f3ac9bcadf2a7021587d343bdfa1fea9fc3a Mon Sep 17 00:00:00 2001 From: David Gnanasekaran Date: Fri, 29 Sep 2017 23:38:36 +0530 Subject: [PATCH 029/103] fix (AoT - Lazy load) : lazy modules chunks creation on Server bundle (#410) Closes #422 Closes #413 * Modified .csproject to emit the wwwroot/dist folder, if the folder is not created yet * Remove Jest and added Karma test runner for executing unit test cases * Added PhantomJS for running test in CI environments. Removed deprecated tslint rules and amended existing rules. * adding tslint config to angular-cli for the ng lint command (#407) * fix (AoT - Lazy load) : commented code that prevented lazy modules chunks from getting created on PlatformServer * packages updated to fix 1) Zone already loaded error, 2) issue with not-found component template load issue * Update README.md * Update README.md * chore(engine): remove comments * Enable uglifyjs on server bundle to reduce bundle size * Mangling and compress options disabled for Server bundle to fix preboot script issue. Removed duplicated Bootstrap css from vendor bundle --- .../not-found/not-found.component.ts | 1 - ClientApp/boot.server.ts | 2 +- Views/Shared/_Layout.cshtml | 2 +- package.json | 46 ++++++++++--------- webpack.config.js | 10 +++- webpack.config.vendor.js | 8 ++-- 6 files changed, 39 insertions(+), 30 deletions(-) diff --git a/ClientApp/app/containers/not-found/not-found.component.ts b/ClientApp/app/containers/not-found/not-found.component.ts index 0ebd7e90..e39faa05 100644 --- a/ClientApp/app/containers/not-found/not-found.component.ts +++ b/ClientApp/app/containers/not-found/not-found.component.ts @@ -3,7 +3,6 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'not-found', templateUrl: './not-found.component.html' - // styleUrls: ['./not-found.component.css'] }) export class NotFoundComponent implements OnInit { constructor() { } diff --git a/ClientApp/boot.server.ts b/ClientApp/boot.server.ts index d93a4f56..86d65086 100644 --- a/ClientApp/boot.server.ts +++ b/ClientApp/boot.server.ts @@ -13,7 +13,7 @@ import { ngAspnetCoreEngine, IEngineOptions, createTransferScript } from './poly enableProdMode(); -export default createServerRenderer((params: BootFuncParams) => { +export default createServerRenderer((params) => { // Platform-server provider configuration const setupOptions: IEngineOptions = { diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 3f6d8aff..49ecd9b0 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -10,7 +10,7 @@ @Html.Raw(ViewData["Links"]) - + @Html.Raw(ViewData["Styles"]) diff --git a/package.json b/package.json index 03efe97c..f7d886f7 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,9 @@ "test:coverage": "npm run test -- --coverage", "build:dev": "npm run build:vendor && npm run build:webpack", "build:webpack": "webpack --progress --color", - "build:prod": "npm run build:vendor -- --env.prod && npm run build:webpack -- --env.prod", - "build:vendor": "webpack --config webpack.config.vendor.js --progress --color" + "build:prod": "npm run clean && npm run build:vendor -- --env.prod && npm run build:webpack -- --env.prod", + "build:vendor": "webpack --config webpack.config.vendor.js --progress --color", + "clean": "rimraf wwwroot/dist clientapp/dist" }, "dependencies": { "@angular/animations": "^4.3.0", @@ -29,21 +30,21 @@ "@ngx-translate/core": "^6.0.1", "@ngx-translate/http-loader": "0.0.3", "@types/node": "^7.0.12", - "angular2-router-loader": "^0.3.4", - "angular2-template-loader": "0.6.0", - "aspnet-prerendering": "2.0.3", + "angular2-router-loader": "^0.3.5", + "angular2-template-loader": "^0.6.2", + "aspnet-prerendering": "^3.0.1", "aspnet-webpack": "^2.0.1", "awesome-typescript-loader": "^3.0.0", "bootstrap": "^3.3.7", "bootstrap-sass": "^3.3.7", - "core-js": "^2.4.1", + "core-js": "^2.5.1", "css": "^2.2.1", - "css-loader": "^0.25.0", - "event-source-polyfill": "^0.0.7", - "expose-loader": "^0.7.1", - "extract-text-webpack-plugin": "^2.0.0-rc", - "file-loader": "^0.9.0", - "html-loader": "^0.4.4", + "css-loader": "^0.28.7", + "event-source-polyfill": "^0.0.9", + "expose-loader": "^0.7.3", + "extract-text-webpack-plugin": "^3.0.0", + "file-loader": "^0.11.2", + "html-loader": "^0.5.1", "isomorphic-fetch": "^2.2.1", "jquery": "^2.2.1", "json-loader": "^0.5.4", @@ -52,18 +53,18 @@ "node-sass": "^4.5.2", "preboot": "^5.0.0", "raw-loader": "^0.5.1", - "rimraf": "^2.6.1", - "rxjs": "^5.0.1", - "sass-loader": "^6.0.3", + "rimraf": "^2.6.2", + "rxjs": "^5.4.3", + "sass-loader": "^6.0.6", "signalr": "^2.2.1", - "style-loader": "^0.13.1", + "style-loader": "^0.18.2", "to-string-loader": "^1.1.5", - "typescript": "2.3.4", + "typescript": "2.5.2", "url-loader": "^0.5.7", - "webpack": "^2.2.0", - "webpack-hot-middleware": "^2.12.2", - "webpack-merge": "^0.14.1", - "zone.js": "^0.8.9" + "webpack": "^3.6.0", + "webpack-hot-middleware": "^2.19.1", + "webpack-merge": "^4.1.0", + "zone.js": "^0.8.17" }, "devDependencies": { "@angular/cli": "^1.3.2", @@ -84,6 +85,7 @@ "karma-remap-coverage": "^0.1.4", "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^2.0.3", - "tslint": "^5.0.0" + "tslint": "^5.7.0", + "webpack-bundle-analyzer": "^2.9.0" } } diff --git a/webpack.config.js b/webpack.config.js index 06435301..02ff0a01 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -13,6 +13,7 @@ const webpack = require('webpack'); const merge = require('webpack-merge'); const AotPlugin = require('@ngtools/webpack').AotPlugin; const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin; +const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; const { sharedModuleRules } = require('./webpack.additions'); @@ -56,6 +57,7 @@ module.exports = (env) => { moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk }) ] : [ + // new BundleAnalyzerPlugin(), // Plugins that apply in production builds only new webpack.optimize.UglifyJsPlugin(), new AotPlugin({ @@ -68,7 +70,7 @@ module.exports = (env) => { // Configuration for server-side (prerendering) bundle suitable for running in Node const serverBundleConfig = merge(sharedConfig, { - resolve: { mainFields: ['main'] }, + // resolve: { mainFields: ['main'] }, entry: { 'main-server': './ClientApp/boot.server.ts' }, plugins: [ new webpack.DllReferencePlugin({ @@ -78,6 +80,10 @@ module.exports = (env) => { name: './vendor' }) ].concat(isDevBuild ? [] : [ + new webpack.optimize.UglifyJsPlugin({ + compress: false, + mangle: false + }), // Plugins that apply in production builds only new AotPlugin({ tsConfigPath: './tsconfig.json', @@ -90,7 +96,7 @@ module.exports = (env) => { path: path.join(__dirname, './ClientApp/dist') }, target: 'node', - devtool: 'inline-source-map' + devtool: isDevBuild ? 'inline-source-map': false }); return [clientBundleConfig, serverBundleConfig]; diff --git a/webpack.config.vendor.js b/webpack.config.vendor.js index 7ae8a6d2..3e07b78b 100644 --- a/webpack.config.vendor.js +++ b/webpack.config.vendor.js @@ -16,8 +16,8 @@ const treeShakableModules = [ 'zone.js', ]; const nonTreeShakableModules = [ - 'bootstrap', - 'bootstrap/dist/css/bootstrap.css', + // 'bootstrap', + // 'bootstrap/dist/css/bootstrap.css', 'core-js', // 'es6-promise', // 'es6-shim', @@ -90,7 +90,9 @@ module.exports = (env) => { path: path.join(__dirname, 'ClientApp', 'dist', '[name]-manifest.json'), name: '[name]_[hash]' }) - ] + ].concat(isDevBuild ? [] : [ + new webpack.optimize.UglifyJsPlugin() + ]) }); return [clientBundleConfig, serverBundleConfig]; From b288ff49a35acaa116c34f458ff0819608507af0 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Sat, 30 Sep 2017 19:47:46 -0400 Subject: [PATCH 030/103] fix(moment): temp fix adding moment to repo --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index f7d886f7..d6f32bce 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "isomorphic-fetch": "^2.2.1", "jquery": "^2.2.1", "json-loader": "^0.5.4", + "moment": "2.18.1" "ng2-signalr": "2.0.4", "ngx-bootstrap": "2.0.0-beta.3", "node-sass": "^4.5.2", From ec03396a97aa6ff6f583678bca03057b369864a1 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Sun, 1 Oct 2017 14:00:44 -0400 Subject: [PATCH 031/103] fix(moment): add missing coma --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d6f32bce..aaa5af12 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "isomorphic-fetch": "^2.2.1", "jquery": "^2.2.1", "json-loader": "^0.5.4", - "moment": "2.18.1" + "moment": "2.18.1", "ng2-signalr": "2.0.4", "ngx-bootstrap": "2.0.0-beta.3", "node-sass": "^4.5.2", From 9562cf946e39ee73ff78590a0a72bfca1b1c6273 Mon Sep 17 00:00:00 2001 From: Isaac Levin Date: Tue, 3 Oct 2017 15:40:26 -0400 Subject: [PATCH 032/103] Remove SignalR references, added to howto branch instead --- ClientApp/app/app.module.browser.ts | 16 +----- ClientApp/app/app.module.ts | 13 ----- .../app/containers/chat/chat.component.html | 51 ------------------ .../app/containers/chat/chat.component.scss | 52 ------------------- .../app/containers/chat/chat.component.ts | 45 ---------------- ClientApp/app/shared/route.resolver.ts | 21 -------- Views/Shared/_Layout.cshtml | 10 +--- package.json | 2 - 8 files changed, 2 insertions(+), 208 deletions(-) delete mode 100644 ClientApp/app/containers/chat/chat.component.html delete mode 100644 ClientApp/app/containers/chat/chat.component.scss delete mode 100644 ClientApp/app/containers/chat/chat.component.ts delete mode 100644 ClientApp/app/shared/route.resolver.ts diff --git a/ClientApp/app/app.module.browser.ts b/ClientApp/app/app.module.browser.ts index 70918765..ac318d44 100644 --- a/ClientApp/app/app.module.browser.ts +++ b/ClientApp/app/app.module.browser.ts @@ -3,8 +3,6 @@ import { BrowserModule } from '@angular/platform-browser'; import { APP_BASE_HREF } from '@angular/common'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { SignalRModule, SignalRConfiguration } from 'ng2-signalr'; - import { ORIGIN_URL } from './shared/constants/baseurl.constants'; import { AppModuleShared } from './app.module'; import { AppComponent } from './app.component'; @@ -13,17 +11,6 @@ import { BrowserTransferStateModule } from '../modules/transfer-state/browser-tr import { BrowserPrebootModule } from 'preboot/browser'; -export function createConfig(): SignalRConfiguration { - const signalRConfig = new SignalRConfiguration(); - - signalRConfig.hubName = 'Ng2SignalRHub'; - signalRConfig.qs = { user: 'donald' }; - signalRConfig.url = 'http://ng2-signalr-backend.azurewebsites.net/'; - signalRConfig.logging = true; - - return signalRConfig; -} - export function getOriginUrl() { return window.location.origin; } @@ -44,9 +31,8 @@ export function getRequest() { BrowserTransferStateModule, // Our Common AppModule - AppModuleShared, + AppModuleShared - SignalRModule.forRoot(createConfig) ], providers: [ { diff --git a/ClientApp/app/app.module.ts b/ClientApp/app/app.module.ts index 57498bb8..61297b35 100644 --- a/ClientApp/app/app.module.ts +++ b/ClientApp/app/app.module.ts @@ -110,19 +110,6 @@ export function createTranslateLoader(http: Http, baseHref) { ] } }, - { - path: 'chat', component: ChatComponent, - // Wait until the resolve is finished before loading the Route - resolve: { connection: ConnectionResolver }, - data: { - title: 'SignalR chat example', - meta: [{ name: 'description', content: 'This is an Chat page Description!' }], - links: [ - { rel: 'canonical', href: 'http://blogs.example.com/chat/something' }, - { rel: 'alternate', hreflang: 'es', href: 'http://es.example.com/chat' } - ] - } - }, { path: 'ngx-bootstrap', component: NgxBootstrapComponent, data: { diff --git a/ClientApp/app/containers/chat/chat.component.html b/ClientApp/app/containers/chat/chat.component.html deleted file mode 100644 index d44cc419..00000000 --- a/ClientApp/app/containers/chat/chat.component.html +++ /dev/null @@ -1,51 +0,0 @@ -

    WebSockets (SignalR) Chatroom Example

    - -
    - Data is stored in Azure here - so even in localhost you might be chatting with other people! -
    - -
    -
    -
    -
    - Angular Chat -
    -
    -
      - -
    • - - User Avatar - - -
      -
      - {{message.user}} - x mins ago -
      -

      - {{ message.content }} -

      -
      -
    • - -
    -
    - -
    -
    -
    - -
    {{ chatMessages | json }}
    diff --git a/ClientApp/app/containers/chat/chat.component.scss b/ClientApp/app/containers/chat/chat.component.scss deleted file mode 100644 index 8e085732..00000000 --- a/ClientApp/app/containers/chat/chat.component.scss +++ /dev/null @@ -1,52 +0,0 @@ -.chat { - list-style: none; - margin: 0; - padding: 0; -} - -.chat li { - margin-bottom: 10px; - padding-bottom: 5px; - border-bottom: 1px dotted #B3A9A9; -} - - -/* -.chat li.left .chat-body { - margin-left: 60px; -} -*/ - -.chat li.right .chat-body { - margin-right: 60px; -} - -.chat li .chat-body p { - margin: 0; - color: #777777; -} - -.panel .slidedown .glyphicon, -.chat .glyphicon { - margin-right: 5px; -} - -.panel-body { - overflow-y: scroll; - height: 500px; -} - -::-webkit-scrollbar-track { - -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); - background-color: #F5F5F5; -} - -::-webkit-scrollbar { - width: 12px; - background-color: #F5F5F5; -} - -::-webkit-scrollbar-thumb { - -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3); - background-color: #555; -} diff --git a/ClientApp/app/containers/chat/chat.component.ts b/ClientApp/app/containers/chat/chat.component.ts deleted file mode 100644 index 78cbdb47..00000000 --- a/ClientApp/app/containers/chat/chat.component.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Component, OnInit, Inject } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; - -import { SignalR, BroadcastEventListener, SignalRConnection } from 'ng2-signalr'; -import { Subscription } from 'rxjs/Subscription'; - -export class ChatMessage { - constructor(public content: string, public user: string) { } -} - -@Component({ - selector: 'chat', - templateUrl: './chat.component.html', - styleUrls: ['./chat.component.scss'] -}) -export class ChatComponent implements OnInit { - - public chatMessages: ChatMessage[] = []; - - private _connection: SignalRConnection; - private _subscription: Subscription; - - constructor(route: ActivatedRoute) { - this._connection = route.snapshot.data['connection']; - } - - ngOnInit() { - const onMessageSent$ = new BroadcastEventListener('OnMessageSent'); - this._connection.listen(onMessageSent$); - this._subscription = onMessageSent$.subscribe((chatMessage: ChatMessage) => { - this.chatMessages.push(chatMessage); - console.log('chat messages', this.chatMessages); - }); - } - - // send chat message to server - sendMessage(user, messageInput) { - console.log('send message', user, messageInput.value); - this._connection.invoke('Chat', new ChatMessage(messageInput.value, user)) - .catch((err: any) => console.log('Failed to invoke', err)); - - messageInput.value = ''; - } - -} diff --git a/ClientApp/app/shared/route.resolver.ts b/ClientApp/app/shared/route.resolver.ts deleted file mode 100644 index 43b0078c..00000000 --- a/ClientApp/app/shared/route.resolver.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Resolve, Router } from '@angular/router'; - -import { SignalR, ISignalRConnection } from 'ng2-signalr'; - -@Injectable() -export class ConnectionResolver implements Resolve { - - constructor( - private _signalR: SignalR, - private _router: Router - ) { } - - resolve(): Promise { - return this._signalR.connect().then((item) => { - return item; - }).catch(() => { - return this._router.navigate(['/']); - }); - } -} diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 49ecd9b0..993b5133 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -1,4 +1,4 @@ - + @@ -18,14 +18,6 @@ @RenderBody() - - - - - @Html.Raw(ViewData["TransferData"]) @Html.Raw(ViewData["Scripts"]) diff --git a/package.json b/package.json index aaa5af12..9ebbf620 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,6 @@ "jquery": "^2.2.1", "json-loader": "^0.5.4", "moment": "2.18.1", - "ng2-signalr": "2.0.4", "ngx-bootstrap": "2.0.0-beta.3", "node-sass": "^4.5.2", "preboot": "^5.0.0", @@ -57,7 +56,6 @@ "rimraf": "^2.6.2", "rxjs": "^5.4.3", "sass-loader": "^6.0.6", - "signalr": "^2.2.1", "style-loader": "^0.18.2", "to-string-loader": "^1.1.5", "typescript": "2.5.2", From 63792d113e91b6f55780f2df41e1dc6be2adb462 Mon Sep 17 00:00:00 2001 From: Isaac Levin Date: Tue, 3 Oct 2017 15:54:34 -0400 Subject: [PATCH 033/103] refactor HomeController --- Server/Controllers/HomeController.cs | 62 ++----------------------- Server/Helpers/HttpRequestExtensions.cs | 23 +++++++++ Server/Helpers/Prerender.cs | 54 +++++++++++++++++++++ Server/Models/IRequest.cs | 14 ++++++ Server/Models/TransferData.cs | 15 ++++++ 5 files changed, 109 insertions(+), 59 deletions(-) create mode 100644 Server/Helpers/HttpRequestExtensions.cs create mode 100644 Server/Helpers/Prerender.cs create mode 100644 Server/Models/IRequest.cs create mode 100644 Server/Models/TransferData.cs diff --git a/Server/Controllers/HomeController.cs b/Server/Controllers/HomeController.cs index 18899d50..71798dd5 100644 --- a/Server/Controllers/HomeController.cs +++ b/Server/Controllers/HomeController.cs @@ -1,3 +1,4 @@ +using Asp2017.Server.Helpers; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; @@ -9,6 +10,7 @@ using Microsoft.AspNetCore.Http; using System.Diagnostics; using System; +using Asp2017.Server.Models; namespace AspCoreServer.Controllers { @@ -17,39 +19,7 @@ public class HomeController : Controller [HttpGet] public async Task Index() { - var nodeServices = Request.HttpContext.RequestServices.GetRequiredService(); - var hostEnv = Request.HttpContext.RequestServices.GetRequiredService(); - - var applicationBasePath = hostEnv.ContentRootPath; - var requestFeature = Request.HttpContext.Features.Get(); - var unencodedPathAndQuery = requestFeature.RawTarget; - var unencodedAbsoluteUrl = $"{Request.Scheme}://{Request.Host}{unencodedPathAndQuery}"; - - // ** TransferData concept ** - // Here we can pass any Custom Data we want ! - - // By default we're passing down Cookies, Headers, Host from the Request object here - TransferData transferData = new TransferData(); - transferData.request = AbstractHttpContextRequestInfo(Request); - transferData.thisCameFromDotNET = "Hi Angular it's asp.net :)"; - // Add more customData here, add it to the TransferData class - - //Prerender now needs CancellationToken - System.Threading.CancellationTokenSource cancelSource = new System.Threading.CancellationTokenSource(); - System.Threading.CancellationToken cancelToken = cancelSource.Token; - - // Prerender / Serialize application (with Universal) - var prerenderResult = await Prerenderer.RenderToString( - "/", - nodeServices, - cancelToken, - new JavaScriptModuleExport(applicationBasePath + "/ClientApp/dist/main-server"), - unencodedAbsoluteUrl, - unencodedPathAndQuery, - transferData, // Our simplified Request object & any other CustommData you want to send! - 30000, - Request.PathBase.ToString() - ); + var prerenderResult = await Prerender.BuildPrerender(Request); ViewData["SpaHtml"] = prerenderResult.Html; // our from Angular ViewData["Title"] = prerenderResult.Globals["title"]; // set our from Angular @@ -87,31 +57,5 @@ public IActionResult Error() { return View(); } - - private IRequest AbstractHttpContextRequestInfo(HttpRequest request) - { - - IRequest requestSimplified = new IRequest(); - requestSimplified.cookies = request.Cookies; - requestSimplified.headers = request.Headers; - requestSimplified.host = request.Host; - - return requestSimplified; - } - } - - public class IRequest - { - public object cookies { get; set; } - public object headers { get; set; } - public object host { get; set; } - } - - public class TransferData - { - public dynamic request { get; set; } - - // Your data here ? - public object thisCameFromDotNET { get; set; } } } diff --git a/Server/Helpers/HttpRequestExtensions.cs b/Server/Helpers/HttpRequestExtensions.cs new file mode 100644 index 00000000..81663602 --- /dev/null +++ b/Server/Helpers/HttpRequestExtensions.cs @@ -0,0 +1,23 @@ +using Asp2017.Server.Models; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Asp2017.Server.Helpers +{ + public static class HttpRequestExtensions + { + public static IRequest AbstractRequestInfo(this HttpRequest request) + { + + IRequest requestSimplified = new IRequest(); + requestSimplified.cookies = request.Cookies; + requestSimplified.headers = request.Headers; + requestSimplified.host = request.Host; + + return requestSimplified; + } + } +} diff --git a/Server/Helpers/Prerender.cs b/Server/Helpers/Prerender.cs new file mode 100644 index 00000000..13124d3c --- /dev/null +++ b/Server/Helpers/Prerender.cs @@ -0,0 +1,54 @@ +using Asp2017.Server.Models; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.NodeServices; +using Microsoft.AspNetCore.SpaServices.Prerendering; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Asp2017.Server.Helpers +{ + public static class Prerender + { + public static async Task<RenderToStringResult> BuildPrerender(HttpRequest Request) + { + var nodeServices = Request.HttpContext.RequestServices.GetRequiredService<INodeServices>(); + var hostEnv = Request.HttpContext.RequestServices.GetRequiredService<IHostingEnvironment>(); + + var applicationBasePath = hostEnv.ContentRootPath; + var requestFeature = Request.HttpContext.Features.Get<IHttpRequestFeature>(); + var unencodedPathAndQuery = requestFeature.RawTarget; + var unencodedAbsoluteUrl = $"{Request.Scheme}://{Request.Host}{unencodedPathAndQuery}"; + + // ** TransferData concept ** + // Here we can pass any Custom Data we want ! + + // By default we're passing down Cookies, Headers, Host from the Request object here + TransferData transferData = new TransferData(); + transferData.request = Request.AbstractRequestInfo(); + transferData.thisCameFromDotNET = "Hi Angular it's asp.net :)"; + // Add more customData here, add it to the TransferData class + + //Prerender now needs CancellationToken + System.Threading.CancellationTokenSource cancelSource = new System.Threading.CancellationTokenSource(); + System.Threading.CancellationToken cancelToken = cancelSource.Token; + + // Prerender / Serialize application (with Universal) + return await Prerenderer.RenderToString( + "/", + nodeServices, + cancelToken, + new JavaScriptModuleExport(applicationBasePath + "/ClientApp/dist/main-server"), + unencodedAbsoluteUrl, + unencodedPathAndQuery, + transferData, // Our simplified Request object & any other CustommData you want to send! + 30000, + Request.PathBase.ToString() + ); + } + } +} diff --git a/Server/Models/IRequest.cs b/Server/Models/IRequest.cs new file mode 100644 index 00000000..407cf571 --- /dev/null +++ b/Server/Models/IRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Asp2017.Server.Models +{ + public class IRequest + { + public object cookies { get; set; } + public object headers { get; set; } + public object host { get; set; } + } +} diff --git a/Server/Models/TransferData.cs b/Server/Models/TransferData.cs new file mode 100644 index 00000000..a89ab38d --- /dev/null +++ b/Server/Models/TransferData.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Asp2017.Server.Models +{ + public class TransferData + { + public dynamic request { get; set; } + + // Your data here ? + public object thisCameFromDotNET { get; set; } + } +} From e2d0e6e13dc1f531fc2ae3553115c9ac2339be23 Mon Sep 17 00:00:00 2001 From: Isaac Levin <isaac.r.levin@gmail.com> Date: Tue, 3 Oct 2017 16:29:20 -0400 Subject: [PATCH 034/103] make prerender an extension --- Server/Controllers/HomeController.cs | 2 +- Server/Helpers/HttpRequestExtensions.cs | 42 +++++++++++++++++++ Server/Helpers/Prerender.cs | 54 ------------------------- 3 files changed, 43 insertions(+), 55 deletions(-) delete mode 100644 Server/Helpers/Prerender.cs diff --git a/Server/Controllers/HomeController.cs b/Server/Controllers/HomeController.cs index 71798dd5..8a5a77f6 100644 --- a/Server/Controllers/HomeController.cs +++ b/Server/Controllers/HomeController.cs @@ -19,7 +19,7 @@ public class HomeController : Controller [HttpGet] public async Task<IActionResult> Index() { - var prerenderResult = await Prerender.BuildPrerender(Request); + var prerenderResult = await Request.BuildPrerender(); ViewData["SpaHtml"] = prerenderResult.Html; // our <app> from Angular ViewData["Title"] = prerenderResult.Globals["title"]; // set our <title> from Angular diff --git a/Server/Helpers/HttpRequestExtensions.cs b/Server/Helpers/HttpRequestExtensions.cs index 81663602..12648b60 100644 --- a/Server/Helpers/HttpRequestExtensions.cs +++ b/Server/Helpers/HttpRequestExtensions.cs @@ -1,5 +1,10 @@ using Asp2017.Server.Models; +using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Features; +using Microsoft.AspNetCore.NodeServices; +using Microsoft.AspNetCore.SpaServices.Prerendering; +using Microsoft.Extensions.DependencyInjection; using System; using System.Collections.Generic; using System.Linq; @@ -19,5 +24,42 @@ public static IRequest AbstractRequestInfo(this HttpRequest request) return requestSimplified; } + + public static async Task<RenderToStringResult> BuildPrerender(this HttpRequest Request) + { + var nodeServices = Request.HttpContext.RequestServices.GetRequiredService<INodeServices>(); + var hostEnv = Request.HttpContext.RequestServices.GetRequiredService<IHostingEnvironment>(); + + var applicationBasePath = hostEnv.ContentRootPath; + var requestFeature = Request.HttpContext.Features.Get<IHttpRequestFeature>(); + var unencodedPathAndQuery = requestFeature.RawTarget; + var unencodedAbsoluteUrl = $"{Request.Scheme}://{Request.Host}{unencodedPathAndQuery}"; + + // ** TransferData concept ** + // Here we can pass any Custom Data we want ! + + // By default we're passing down Cookies, Headers, Host from the Request object here + TransferData transferData = new TransferData(); + transferData.request = Request.AbstractRequestInfo(); + transferData.thisCameFromDotNET = "Hi Angular it's asp.net :)"; + // Add more customData here, add it to the TransferData class + + //Prerender now needs CancellationToken + System.Threading.CancellationTokenSource cancelSource = new System.Threading.CancellationTokenSource(); + System.Threading.CancellationToken cancelToken = cancelSource.Token; + + // Prerender / Serialize application (with Universal) + return await Prerenderer.RenderToString( + "/", + nodeServices, + cancelToken, + new JavaScriptModuleExport(applicationBasePath + "/ClientApp/dist/main-server"), + unencodedAbsoluteUrl, + unencodedPathAndQuery, + transferData, // Our simplified Request object & any other CustommData you want to send! + 30000, + Request.PathBase.ToString() + ); + } } } diff --git a/Server/Helpers/Prerender.cs b/Server/Helpers/Prerender.cs deleted file mode 100644 index 13124d3c..00000000 --- a/Server/Helpers/Prerender.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Asp2017.Server.Models; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Features; -using Microsoft.AspNetCore.NodeServices; -using Microsoft.AspNetCore.SpaServices.Prerendering; -using Microsoft.Extensions.DependencyInjection; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Asp2017.Server.Helpers -{ - public static class Prerender - { - public static async Task<RenderToStringResult> BuildPrerender(HttpRequest Request) - { - var nodeServices = Request.HttpContext.RequestServices.GetRequiredService<INodeServices>(); - var hostEnv = Request.HttpContext.RequestServices.GetRequiredService<IHostingEnvironment>(); - - var applicationBasePath = hostEnv.ContentRootPath; - var requestFeature = Request.HttpContext.Features.Get<IHttpRequestFeature>(); - var unencodedPathAndQuery = requestFeature.RawTarget; - var unencodedAbsoluteUrl = $"{Request.Scheme}://{Request.Host}{unencodedPathAndQuery}"; - - // ** TransferData concept ** - // Here we can pass any Custom Data we want ! - - // By default we're passing down Cookies, Headers, Host from the Request object here - TransferData transferData = new TransferData(); - transferData.request = Request.AbstractRequestInfo(); - transferData.thisCameFromDotNET = "Hi Angular it's asp.net :)"; - // Add more customData here, add it to the TransferData class - - //Prerender now needs CancellationToken - System.Threading.CancellationTokenSource cancelSource = new System.Threading.CancellationTokenSource(); - System.Threading.CancellationToken cancelToken = cancelSource.Token; - - // Prerender / Serialize application (with Universal) - return await Prerenderer.RenderToString( - "/", - nodeServices, - cancelToken, - new JavaScriptModuleExport(applicationBasePath + "/ClientApp/dist/main-server"), - unencodedAbsoluteUrl, - unencodedPathAndQuery, - transferData, // Our simplified Request object & any other CustommData you want to send! - 30000, - Request.PathBase.ToString() - ); - } - } -} From c0dfc73f2d7179039248638e2dd4f36961f399cc Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Wed, 4 Oct 2017 16:02:02 -0400 Subject: [PATCH 035/103] fix(bug): fix 404 and build issues --- ClientApp/app/app.module.ts | 8 ++++---- ClientApp/app/components/navmenu/navmenu.component.html | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ClientApp/app/app.module.ts b/ClientApp/app/app.module.ts index 61297b35..1c492f1d 100644 --- a/ClientApp/app/app.module.ts +++ b/ClientApp/app/app.module.ts @@ -16,13 +16,13 @@ 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 { 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 { ConnectionResolver } from './shared/route.resolver'; import { ORIGIN_URL } from './shared/constants/baseurl.constants'; import { TransferHttpModule } from '../modules/transfer-http/transfer-http.module'; @@ -43,7 +43,7 @@ export function createTranslateLoader(http: Http, baseHref) { UsersComponent, UserDetailComponent, HomeComponent, - ChatComponent, + // ChatComponent, NotFoundComponent, NgxBootstrapComponent ], @@ -145,7 +145,7 @@ export function createTranslateLoader(http: Http, baseHref) { providers: [ LinkService, UserService, - ConnectionResolver, + // ConnectionResolver, TranslateModule ] }) diff --git a/ClientApp/app/components/navmenu/navmenu.component.html b/ClientApp/app/components/navmenu/navmenu.component.html index 57b9c351..bd6eadda 100644 --- a/ClientApp/app/components/navmenu/navmenu.component.html +++ b/ClientApp/app/components/navmenu/navmenu.component.html @@ -39,11 +39,11 @@ <span class='glyphicon glyphicon-star-empty'></span> Lazy-loaded demo </a> </li> - <li [routerLinkActive]="['link-active']" (click)="collapseMenu()"> + <!-- <li [routerLinkActive]="['link-active']" (click)="collapseMenu()"> <a [routerLink]="['/chat']"> <span class='glyphicon glyphicon-comment'></span> Chat </a> - </li> + </li> --> </ul> </div> </div> From ba9f260384ed107256dd4f6222adb7a1486968bc Mon Sep 17 00:00:00 2001 From: jamescoffman23 <15820584+jamescoffman23@users.noreply.github.com> Date: Sat, 7 Oct 2017 11:30:18 -0500 Subject: [PATCH 036/103] Update _Layout.cshtml (#433) --- Views/Shared/_Layout.cshtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Views/Shared/_Layout.cshtml b/Views/Shared/_Layout.cshtml index 993b5133..bcf5be51 100644 --- a/Views/Shared/_Layout.cshtml +++ b/Views/Shared/_Layout.cshtml @@ -1,7 +1,7 @@ <!DOCTYPE html> <html> <head> - <base href="http://github.com/" /> + <base href="http://github.com/@(Url.Content("~/"))" /> <title>@ViewData["Title"] From 73da5694435cf014218e57194aad0c718dffd168 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Tue, 10 Oct 2017 19:13:31 -0400 Subject: [PATCH 037/103] docs(demo): update to 5.0 branch in readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9e30c7a4..d7ac5277 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # ASP.NET Core 2.0 & Angular 4 (+) 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

    From f31ca8a8d054d11806df13e79d48282ea03f1687 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Sat, 28 Oct 2017 22:16:40 -0400 Subject: [PATCH 038/103] Update README.md --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d7ac5277..60f75520 100644 --- a/README.md +++ b/README.md @@ -444,9 +444,11 @@ Copyright (c) 2016-2017 [Mark Pieszak](https://github.com/MarkPieszak) ---- -# Looking for Angular & ASP.NET Consulting / Training / support? +# DevHelp.Online - Angular & ASP.NET - Consulting | Training | Development -Contact me at , and let's talk about your projects needs! +Check out **[www.DevHelp.Online](http://DevHelp.Online)** for more info! + +Contact us at , and let's talk about your projects needs. ---- From 5e32bf18abda567225b1afdc7c4646a27ee137e9 Mon Sep 17 00:00:00 2001 From: Romoku Date: Tue, 31 Oct 2017 06:40:07 +0200 Subject: [PATCH 039/103] Update Asp2017.csproj (#451) The 'Client' folder does not exist, so the 'ClientApp' folder should be removed instead. --- Asp2017.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Asp2017.csproj b/Asp2017.csproj index d944c48d..46bd2ffa 100644 --- a/Asp2017.csproj +++ b/Asp2017.csproj @@ -57,6 +57,6 @@ - +
    From d2ab9e0bbb63847b6c194ab47436476d26c4ea2b Mon Sep 17 00:00:00 2001 From: electricessence Date: Sat, 16 Dec 2017 08:19:47 -0800 Subject: [PATCH 040/103] Allow for dotnet watch run command. (#524) --- Asp2017.csproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Asp2017.csproj b/Asp2017.csproj index 46bd2ffa..efb619c0 100644 --- a/Asp2017.csproj +++ b/Asp2017.csproj @@ -13,6 +13,9 @@ + + + From d01d2f979e961c2f78d047261f970931eadfc7f3 Mon Sep 17 00:00:00 2001 From: Adam Pine Date: Thu, 21 Dec 2017 17:14:20 -0500 Subject: [PATCH 041/103] Update Read.me to reflect the ability to use Angular Material --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 60f75520..fa942dbf 100644 --- a/README.md +++ b/README.md @@ -389,7 +389,8 @@ Check the [Gotchas](#gotchas) on how to use `isPlatformBrowser()`. ### How do I Material2 with this repo? -You'll either want to remove SSR for now, or wait as support should be coming to handle platform-server rendering. +~~You'll either want to remove SSR for now, or wait as support should be coming to handle platform-server rendering.~~ +This is now possible, with the recently updated Angular Material changes. We do not have a tutorial available for this yet. ### How can I use jQuery and/or some jQuery plugins with this repo? From 26a59053074bc7aa73fde644379058958fa63924 Mon Sep 17 00:00:00 2001 From: Adam Pine Date: Fri, 22 Dec 2017 10:37:09 -0500 Subject: [PATCH 042/103] Fix 5.0 link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa942dbf..10e2f21c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ASP.NET Core 2.0 & Angular 4 (+) 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) +> [(upcoming) Angular 5.0 demo Branch Here](https://github.com/MarkPieszak/aspnetcore-angular2-universal/tree/angular-5.0-WIP)

    ASP.NET Core 2.0 Angular 4+ Starter From 7eafaf86aa92476c47f34a3d5f407a325b9857d7 Mon Sep 17 00:00:00 2001 From: Adam Pine Date: Fri, 22 Dec 2017 11:24:14 -0500 Subject: [PATCH 043/103] Make links to FAQ more visible Added link to the HOW-TO label --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 10e2f21c..e5578667 100644 --- a/README.md +++ b/README.md @@ -374,7 +374,7 @@ constructor(element: ElementRef, renderer: Renderer2) { ---- -# FAQ - Also check out the [FAQ Issues label](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Afaq) +# FAQ - Also check out the [!FAQ Issues label!](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3Afaq) and the [!HOW-TO Issues Label!](https://github.com/MarkPieszak/aspnetcore-angular2-universal/issues?q=is%3Aissue+label%3A%22HOW+TO+-+Guide%22) ### How can I disable SSR (Server-side rendering)? From 40bf6c19d233b713fde87330ee50660ed35fd668 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Tue, 23 Jan 2018 15:02:42 -0500 Subject: [PATCH 044/103] Feature(Angular 5.0): Upgrade to working copy of 5.0 (#538) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This works both in Development & Production. 🎁 (Apologies on the delay) Now dotnet publish won't fail, and you can successfully build Production builds. In the future, boot.server.PRODUCTION.ts probably won't be needed. We'll be working on upgrading this to use the CLI version that Steve Sanderson has been working on the past few months - this will clean-up a lot of the configuration so that it's all handled by the CLI itself. (Aka: no more webpack files for us to deal with here) ✨ This should close out many issues: #535 #482 (others as well, can't find them at the moment) --- 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.PRODUCTION.ts | 38 +++ ClientApp/boot.server.ts | 18 +- .../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 ------------------ ClientApp/tsconfig.app.json | 3 +- README.md | 39 +-- Server/Controllers/HomeController.cs | 2 +- Startup.cs | 4 +- Views/Home/Index.cshtml | 6 +- package.json | 40 +-- tslint.json | 3 +- webpack.config.js | 63 +++-- webpack.config.vendor.js | 2 +- 37 files changed, 232 insertions(+), 704 deletions(-) delete mode 100644 ClientApp/app/shared/constants/baseurl.constants.ts delete mode 100644 ClientApp/app/shared/constants/request.ts create mode 100644 ClientApp/boot.server.PRODUCTION.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 }}

    • ASP.NET Core 2.0 :: ( Visual Studio 2017 )
    • - Angular 4.* front-end UI framework + Angular 5.* front-end UI framework
      • Angular **platform-server** (aka: Universal) - server-side rendering for SEO, deep-linking, and incredible performance.
      • @@ -22,17 +22,10 @@

        {{ 'HOME_FEATURE_LIST_TITLE' | translate }}

      • The latest TypeScript 2.* features -
      • Webpack
          -
        • Hot Module Reloading/Replacement for an amazing development experience.
        • Tree-shaking
        @@ -40,7 +33,6 @@

        {{ 'HOME_FEATURE_LIST_TITLE' | translate }}

      • Bootstrap (ngx-bootstrap) : Bootstrap capable of being rendered even on the server.
      • Unit testing via karma & jasmine.
      • -
      diff --git a/ClientApp/app/containers/home/home.component.ts b/ClientApp/app/containers/home/home.component.ts index 3065c0b1..ff10f2d4 100644 --- a/ClientApp/app/containers/home/home.component.ts +++ b/ClientApp/app/containers/home/home.component.ts @@ -8,7 +8,7 @@ import { TranslateService } from '@ngx-translate/core'; }) export class HomeComponent implements OnInit { - title: string = 'Angular 4.0 Universal & ASP.NET Core 2.0 advanced starter-kit'; + title: string = 'Angular 5.x Universal & ASP.NET Core 2.0 advanced starter-kit'; // Use "constructor"s only for dependency injection constructor( diff --git a/ClientApp/app/containers/lazy/lazy.component.ts b/ClientApp/app/containers/lazy/lazy.component.ts index 25d6d1a4..97d260fd 100644 --- a/ClientApp/app/containers/lazy/lazy.component.ts +++ b/ClientApp/app/containers/lazy/lazy.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'lazy-view', + selector: 'app-lazy-view', template: `

      Lazy-Loaded Component!

      diff --git a/ClientApp/app/containers/not-found/not-found.component.ts b/ClientApp/app/containers/not-found/not-found.component.ts index e39faa05..c59a5f8f 100644 --- a/ClientApp/app/containers/not-found/not-found.component.ts +++ b/ClientApp/app/containers/not-found/not-found.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit } from '@angular/core'; @Component({ - selector: 'not-found', + selector: 'app-not-found', templateUrl: './not-found.component.html' }) export class NotFoundComponent implements OnInit { diff --git a/ClientApp/app/containers/users/users.component.html b/ClientApp/app/containers/users/users.component.html index 5bb77691..1e661476 100644 --- a/ClientApp/app/containers/users/users.component.html +++ b/ClientApp/app/containers/users/users.component.html @@ -26,4 +26,4 @@

      Users

    - + 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.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: '', + 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 serialized + globals: response.globals // all of our styles/scripts/meta-tags/link-tags for aspnet to serve up + }); + }); +}); diff --git a/ClientApp/boot.server.ts b/ClientApp/boot.server.ts index 86d65086..c2c0fb47 100644 --- a/ClientApp/boot.server.ts +++ b/ClientApp/boot.server.ts @@ -1,15 +1,11 @@ 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(); @@ -17,15 +13,17 @@ export default createServerRenderer((params) => { // 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 => { + // Apply your transferData to response.globals response.globals.transferData = createTransferScript({ someData: 'Transfer this to the client on the window.TRANSFER_CACHE {} object', @@ -33,8 +31,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/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/README.md b/README.md index e5578667..9dd99499 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,27 @@ -# 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-WIP) +## By [DevHelp.Online](http://www.DevHelp.Online) + +> Updated to the latest Angular 5.x + +> Note ServerTransferModule still in the works - fix coming soon

    - 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 +55,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: @@ -139,9 +143,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 +271,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 @@ -293,7 +296,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 +337,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 +382,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`. @@ -395,7 +398,7 @@ This is now possible, with the recently updated Angular Material changes. We do ### 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' })` @@ -447,10 +450,14 @@ 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 , and let's talk about your projects needs. +

    + DevHelp.Online - Angular ASPNET JavaScript Consulting Development and Training +

    + ---- ## Follow me online: 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/Views/Home/Index.cshtml b/Views/Home/Index.cshtml index b0796562..8c18039d 100644 --- a/Views/Home/Index.cshtml +++ b/Views/Home/Index.cshtml @@ -1,4 +1,8 @@ -@Html.Raw(ViewData["SpaHtml"]) +<!-- Remove this if you want to remove Server-side rendering --> +@Html.Raw(ViewData["SpaHtml"]) + +<!-- 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 9ebbf620..b86fbe7f 100644 --- a/package.json +++ b/package.json @@ -11,24 +11,25 @@ "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" }, "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/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,16 +50,16 @@ "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", "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.2", + "typescript": "~2.5.0", "url-loader": "^0.5.7", "webpack": "^3.6.0", "webpack-hot-middleware": "^2.19.1", @@ -66,8 +67,9 @@ "zone.js": "^0.8.17" }, "devDependencies": { - "@angular/cli": "^1.3.2", - "@ngtools/webpack": "^1.3.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", "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..02ee879f 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; @@ -59,36 +59,60 @@ module.exports = (env) => { ] : [ // new BundleAnalyzerPlugin(), // Plugins that apply in production builds only - new webpack.optimize.UglifyJsPlugin(), - new AotPlugin({ - tsConfigPath: './tsconfig.json', - entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), - exclude: ['./**/*.server.ts'] - }) - ]) + 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" + } }); // 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, manifest: require('./ClientApp/dist/vendor-manifest.json'), sourceType: 'commonjs2', name: './vendor' - }) - ].concat(isDevBuild ? [] : [ - new webpack.optimize.UglifyJsPlugin({ - compress: false, - mangle: false }), + 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, + // mangle: false + // }), // Plugins that apply in production builds only - new AotPlugin({ - tsConfigPath: './tsconfig.json', - entryModule: path.join(__dirname, 'ClientApp/app/app.module.server#AppModule'), - exclude: ['./**/*.browser.ts'] + new AngularCompilerPlugin({ + 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'] }) ]), output: { @@ -96,7 +120,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 7252a4524bd83a3256883607bbc090cb2280b599 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Tue, 23 Jan 2018 15:24:42 -0500 Subject: [PATCH 045/103] docs(readme): gotchas --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9dd99499..8cffbc2f 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,10 @@ Well now, your Client-side Angular will take over, and you'll have a fully funct > When building components in Angular 5 there are a few things to keep in mind. + - Make sure you provide Absolute URLs when calling any APIs. (The server can't understand relative paths, so `/api/whatever` will fail). + + - API calls will be ran during a server, and once again during the client render, so make sure you're using transfering data that's important to you so that you don't see a flicker. + - **`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. @@ -444,7 +448,7 @@ Nothing's ever perfect, but please let me know by creating an issue (make sure t [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](/LICENSE) -Copyright (c) 2016-2017 [Mark Pieszak](https://github.com/MarkPieszak) +Copyright (c) 2016-2018 [Mark Pieszak](https://github.com/MarkPieszak) ---- From 45d6eaaa1063af25255a7d633524ed06f965471f Mon Sep 17 00:00:00 2001 From: Luiz Machado <machado@odahcam.com> Date: Thu, 25 Jan 2018 13:31:17 -0200 Subject: [PATCH 046/103] fix(webpack): moved context replacement plugin to dev builds only (#545) closes #543 --- webpack.config.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webpack.config.js b/webpack.config.js index 02ee879f..6c348162 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -89,7 +89,8 @@ module.exports = (env) => { manifest: require('./ClientApp/dist/vendor-manifest.json'), sourceType: 'commonjs2', name: './vendor' - }), + }) + ].concat(isDevBuild ? [ new webpack.ContextReplacementPlugin( // fixes WARNING Critical dependency: the request of a dependency is an expression /(.+)?angular(\\|\/)core(.+)?/, @@ -102,7 +103,7 @@ module.exports = (env) => { path.join(__dirname, 'src'), {} ) - ].concat(isDevBuild ? [] : [ + ] : [ // new webpack.optimize.UglifyJsPlugin({ // compress: false, // mangle: false From b7dd580acff001996ded91a13a29aa44a34eb2f0 Mon Sep 17 00:00:00 2001 From: Jan Sviland <jan@sviland.org> Date: Thu, 25 Jan 2018 16:31:52 +0100 Subject: [PATCH 047/103] browser caching (#542) closes #541 --- Startup.cs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Startup.cs b/Startup.cs index b7773ac0..db1d5d8d 100644 --- a/Startup.cs +++ b/Startup.cs @@ -9,6 +9,8 @@ using Microsoft.EntityFrameworkCore; using AspCoreServer.Data; using Swashbuckle.AspNetCore.Swagger; +using Microsoft.AspNetCore.Http; +using Microsoft.Net.Http.Headers; namespace AspCoreServer { @@ -64,7 +66,30 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); - app.UseStaticFiles(); + // app.UseStaticFiles(); + + app.UseStaticFiles(new StaticFileOptions() + { + OnPrepareResponse = c => + { + //Do not add cache to json files. We need to have new versions when we add new translations. + + if (!c.Context.Request.Path.Value.Contains(".json")) + { + c.Context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue() + { + MaxAge = TimeSpan.FromDays(30) // Cache everything except json for 30 days + }; + } + else + { + c.Context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue() + { + MaxAge = TimeSpan.FromMinutes(15) // Cache json for 15 minutes + }; + } + } + }); DbInitializer.Initialize(context); From c8f3a1e5606f2e5115adf2b4dc6fc62d6b625380 Mon Sep 17 00:00:00 2001 From: Eugen Tatuev <eugentatuev@gmail.com> Date: Tue, 30 Jan 2018 08:33:03 +0300 Subject: [PATCH 048/103] fix(webpack): enable uglifyjs for non-vendor bundles --- webpack.config.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/webpack.config.js b/webpack.config.js index 6c348162..a54d3135 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -65,10 +65,11 @@ module.exports = (env) => { entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), exclude: ['./**/*.server.ts'] }), - // new webpack.optimize.UglifyJsPlugin({ - // compress: false, - // mangle: false - // }) + new webpack.optimize.UglifyJsPlugin({ + output: { + ascii_only: true, + } + }), ]), devtool: isDevBuild ? 'cheap-eval-source-map' : false, node: { @@ -104,10 +105,13 @@ module.exports = (env) => { {} ) ] : [ - // new webpack.optimize.UglifyJsPlugin({ - // compress: false, - // mangle: false - // }), + new webpack.optimize.UglifyJsPlugin({ + mangle: false, + compress: false, + output: { + ascii_only: true, + } + }), // Plugins that apply in production builds only new AngularCompilerPlugin({ mainPath: path.join(__dirname, 'ClientApp/boot.server.PRODUCTION.ts'), From 0ad0f60766bc08f3a1e2f36fc2944db874b44b9d Mon Sep 17 00:00:00 2001 From: Isaac Levin <isaac.r.levin@gmail.com> Date: Mon, 5 Feb 2018 12:25:45 -0500 Subject: [PATCH 049/103] Update to REST Api to better handle PUT/DELETE --- .../user-detail/user-detail.component.ts | 7 +- .../app/containers/users/users.component.html | 4 +- .../app/containers/users/users.component.ts | 120 ++++++++++-------- Server/RestAPI/UsersController.cs | 6 +- 4 files changed, 75 insertions(+), 62 deletions(-) diff --git a/ClientApp/app/components/user-detail/user-detail.component.ts b/ClientApp/app/components/user-detail/user-detail.component.ts index d21d3415..75a8369e 100644 --- a/ClientApp/app/components/user-detail/user-detail.component.ts +++ b/ClientApp/app/components/user-detail/user-detail.component.ts @@ -1,4 +1,4 @@ -import { Component, Input } from '@angular/core'; +import { Component, Input, Output, EventEmitter } from '@angular/core'; import { IUser } from '../../models/User'; import { UserService } from '../../shared/user.service'; @@ -8,7 +8,7 @@ import { UserService } from '../../shared/user.service'; }) export class UserDetailComponent { @Input() user: IUser; - + @Output() userUpdate: EventEmitter<any> = new EventEmitter(); constructor(private userService: UserService) { } @@ -17,6 +17,7 @@ export class UserDetailComponent { console.log('Put user result: ', result); }, error => { console.log(`There was an issue. ${error._body}.`); - }); + }); + this.userUpdate.emit(null); } } diff --git a/ClientApp/app/containers/users/users.component.html b/ClientApp/app/containers/users/users.component.html index 1e661476..b90c06aa 100644 --- a/ClientApp/app/containers/users/users.component.html +++ b/ClientApp/app/containers/users/users.component.html @@ -1,4 +1,4 @@ -<h1>This is a RestAPI Example (hitting WebAPI in our case)</h1> +<h1>This is a RestAPI Example (hitting WebAPI in our case)</h1> <blockquote> Let's get some fake users from Rest:<br> @@ -26,4 +26,4 @@ <h2>Users</h2> </button> </li> </ul> -<app-user-detail [user]="selectedUser"></app-user-detail> +<app-user-detail (userUpdate)="onUserUpdate($event)" [user]="selectedUser"></app-user-detail> diff --git a/ClientApp/app/containers/users/users.component.ts b/ClientApp/app/containers/users/users.component.ts index 35cc8517..6bca6a73 100644 --- a/ClientApp/app/containers/users/users.component.ts +++ b/ClientApp/app/containers/users/users.component.ts @@ -1,69 +1,81 @@ -import { - Component, OnInit, - // animation imports - trigger, state, style, transition, animate, Inject +import { + Component, OnInit, + // animation imports + trigger, state, style, transition, animate, Inject } from '@angular/core'; import { IUser } from '../../models/User'; import { UserService } from '../../shared/user.service'; @Component({ - selector: 'app-users', - templateUrl: './users.component.html', - styleUrls: ['./users.component.css'], - animations: [ - // Animation example - // Triggered in the ngFor with [@flyInOut] - trigger('flyInOut', [ - state('in', style({ transform: 'translateY(0)' })), - transition('void => *', [ - style({ transform: 'translateY(-100%)' }), - animate(1000) - ]), - transition('* => void', [ - animate(1000, style({ transform: 'translateY(100%)' })) - ]) - ]) - ] + selector: 'app-users', + templateUrl: './users.component.html', + styleUrls: ['./users.component.css'], + animations: [ + // Animation example + // Triggered in the ngFor with [@flyInOut] + trigger('flyInOut', [ + state('in', style({ transform: 'translateY(0)' })), + transition('void => *', [ + style({ transform: 'translateY(-100%)' }), + animate(1000) + ]), + transition('* => void', [ + animate(1000, style({ transform: 'translateY(100%)' })) + ]) + ]) + ] }) export class UsersComponent implements OnInit { - users: IUser[]; - selectedUser: IUser; + users: IUser[]; + selectedUser: IUser; - // Use "constructor"s only for dependency injection - constructor( - private userService: UserService - ) { } + // Use "constructor"s only for dependency injection + 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('HttpClient [GET] /api/users/allresult', result); - this.users = result; - }); - } + // 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('HttpClient [GET] /api/users/allresult', result); + this.users = result; + }); + } - onSelect(user: IUser): void { - this.selectedUser = user; - } + onSelect(user: IUser): void { + this.selectedUser = user; + } - deleteUser(user) { - this.userService.deleteUser(user).subscribe(result => { - console.log('Delete user result: ', result); - let position = this.users.indexOf(user); - this.users.splice(position, 1); - }, error => { - console.log(`There was an issue. ${error._body}.`); - }); - } + deleteUser(user) { + this.clearUser(); + this.userService.deleteUser(user).subscribe(result => { + console.log('Delete user result: ', result); + let position = this.users.indexOf(user); + this.users.splice(position, 1); + }, error => { + console.log(`There was an issue. ${error._body}.`); + }); + } + + onUserUpdate(event) { + this.clearUser(); + } + + addUser(newUserName) { + this.clearUser(); + this.userService.addUser(newUserName).subscribe(result => { + console.log('Post user result: ', result); + this.users.push(result); + }, error => { + console.log(`There was an issue. ${error._body}.`); + }); + } - addUser(newUserName) { - this.userService.addUser(newUserName).subscribe(result => { - console.log('Post user result: ', result); - this.users.push(result); - }, error => { - console.log(`There was an issue. ${error._body}.`); - }); + clearUser() { + if (this.selectedUser) { + this.selectedUser = null; } + } } diff --git a/Server/RestAPI/UsersController.cs b/Server/RestAPI/UsersController.cs index 2938eb8e..3a7fe3d2 100644 --- a/Server/RestAPI/UsersController.cs +++ b/Server/RestAPI/UsersController.cs @@ -1,4 +1,4 @@ -using AspCoreServer.Data; +using AspCoreServer.Data; using AspCoreServer.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -89,7 +89,7 @@ public async Task<IActionResult> Put(int id, [FromBody]User userUpdateValue) { _context.Update(userUpdateValue); await _context.SaveChangesAsync(); - return Ok("Updated user - " + userUpdateValue.Name); + return Json("Updated user - " + userUpdateValue.Name); } } catch (DbUpdateException) @@ -116,7 +116,7 @@ public async Task<IActionResult> Delete(int id) { _context.User.Remove(userToRemove); await _context.SaveChangesAsync(); - return Ok("Deleted user - " + userToRemove.Name); + return Json("Deleted user - " + userToRemove.Name); } } } From 0f2609c93aaad591d73db99acc7e7957c5051bd8 Mon Sep 17 00:00:00 2001 From: peterdobson <petedobson@gmail.com> Date: Wed, 7 Mar 2018 03:16:04 +1100 Subject: [PATCH 050/103] fix(sitemap): update homecontroller sitemap tags Renamed the "sitemapindex" & "sitemap" SitemapXml tags to "urlset" & "url" to allow Google Search Console to process sitemap.xml without errors closes #562 --- Server/Controllers/HomeController.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Server/Controllers/HomeController.cs b/Server/Controllers/HomeController.cs index 0a674a60..bd9ad008 100644 --- a/Server/Controllers/HomeController.cs +++ b/Server/Controllers/HomeController.cs @@ -38,16 +38,16 @@ 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 += "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9/">"; + xml += "<url>"; xml += "<loc>http://localhost:4251/home</loc>"; xml += "<lastmod>" + DateTime.Now.ToString("yyyy-MM-dd") + "</lastmod>"; - xml += "</sitemap>"; - xml += "<sitemap>"; + xml += "</url>"; + xml += "<url>"; xml += "<loc>http://localhost:4251/counter</loc>"; xml += "<lastmod>" + DateTime.Now.ToString("yyyy-MM-dd") + "</lastmod>"; - xml += "</sitemap>"; - xml += "</sitemapindex>"; + xml += "</url>"; + xml += "</urlset>"; return Content(xml, "text/xml"); From fdef986e352f980bf9091458fd7a1dd2dd8ec0f5 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 22 Mar 2018 15:08:45 -0400 Subject: [PATCH 051/103] fix(nguniversal): pin to beta.5 until new release --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b86fbe7f..d2adcd26 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "@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", + "@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", From dfa802628d895cfbff61ccfb5c4556e50860fb42 Mon Sep 17 00:00:00 2001 From: CaerusKaru <caerus.karu@gmail.com> Date: Fri, 23 Mar 2018 18:40:24 -0400 Subject: [PATCH 052/103] chore: update to latest nguniversal and fix imports (#578) closes #577 --- ClientApp/app/app.component.ts | 2 +- ClientApp/app/app.module.browser.ts | 2 +- ClientApp/app/app.module.ts | 2 +- ClientApp/app/shared/user.service.ts | 2 +- package.json | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ClientApp/app/app.component.ts b/ClientApp/app/app.component.ts index 7a6a75ed..d8b28150 100644 --- a/ClientApp/app/app.component.ts +++ b/ClientApp/app/app.component.ts @@ -7,7 +7,7 @@ import { LinkService } from './shared/link.service'; // i18n support import { TranslateService } from '@ngx-translate/core'; -import { REQUEST } from '@nguniversal/aspnetcore-engine'; +import { REQUEST } from '@nguniversal/aspnetcore-engine/tokens'; @Component({ selector: 'app-root', diff --git a/ClientApp/app/app.module.browser.ts b/ClientApp/app/app.module.browser.ts index 56d1c20c..fa983b67 100644 --- a/ClientApp/app/app.module.browser.ts +++ b/ClientApp/app/app.module.browser.ts @@ -3,7 +3,7 @@ import { BrowserModule } from '@angular/platform-browser'; import { APP_BASE_HREF } from '@angular/common'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { ORIGIN_URL, REQUEST } from '@nguniversal/aspnetcore-engine'; +import { ORIGIN_URL, REQUEST } from '@nguniversal/aspnetcore-engine/tokens'; import { AppModuleShared } from './app.module'; import { AppComponent } from './app.component'; import { BrowserTransferStateModule } from '@angular/platform-browser'; diff --git a/ClientApp/app/app.module.ts b/ClientApp/app/app.module.ts index d31250c4..5394d67d 100644 --- a/ClientApp/app/app.module.ts +++ b/ClientApp/app/app.module.ts @@ -24,7 +24,7 @@ import { NgxBootstrapComponent } from './containers/ngx-bootstrap-demo/ngx-boots import { LinkService } from './shared/link.service'; import { UserService } from './shared/user.service'; -import { ORIGIN_URL } from '@nguniversal/aspnetcore-engine'; +import { ORIGIN_URL } from '@nguniversal/aspnetcore-engine/tokens'; export function createTranslateLoader(http: HttpClient, baseHref) { // Temporary Azure hack diff --git a/ClientApp/app/shared/user.service.ts b/ClientApp/app/shared/user.service.ts index 9489e32f..6a3d7cb7 100644 --- a/ClientApp/app/shared/user.service.ts +++ b/ClientApp/app/shared/user.service.ts @@ -2,7 +2,7 @@ import { HttpClient } from '@angular/common/http'; import { Http, URLSearchParams } from '@angular/http'; import { APP_BASE_HREF } from '@angular/common'; -import { ORIGIN_URL } from '@nguniversal/aspnetcore-engine'; +import { ORIGIN_URL } from '@nguniversal/aspnetcore-engine/tokens'; import { IUser } from '../models/User'; import { Observable } from 'rxjs/Observable'; diff --git a/package.json b/package.json index d2adcd26..86dacd20 100644 --- a/package.json +++ b/package.json @@ -26,8 +26,8 @@ "@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", + "@nguniversal/aspnetcore-engine": "^5.0.0-beta.8", + "@nguniversal/common": "^5.0.0-beta.8", "@ngx-translate/core": "^8.0.0", "@ngx-translate/http-loader": "^2.0.0", "@types/node": "^7.0.12", From 3a8bfe242a31caba034f55162d9f1be972f406ab Mon Sep 17 00:00:00 2001 From: Rune Antonsen <rune.antonsen@gmail.com> Date: Tue, 27 Mar 2018 14:21:40 +0200 Subject: [PATCH 053/103] fix(polyfills): move reflect-metadata to polyfills.ts (#581) No need to have it in both browser.polyfills.ts and server.polyfills.ts when it's the same. Closes #580 --- ClientApp/polyfills/browser.polyfills.ts | 1 - ClientApp/polyfills/polyfills.ts | 3 +++ ClientApp/polyfills/server.polyfills.ts | 1 - 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ClientApp/polyfills/browser.polyfills.ts b/ClientApp/polyfills/browser.polyfills.ts index fa02ffab..dd813a13 100644 --- a/ClientApp/polyfills/browser.polyfills.ts +++ b/ClientApp/polyfills/browser.polyfills.ts @@ -1,4 +1,3 @@ import './polyfills.ts'; import 'zone.js/dist/zone'; -import 'reflect-metadata'; diff --git a/ClientApp/polyfills/polyfills.ts b/ClientApp/polyfills/polyfills.ts index fe3a6bd6..39ccb969 100644 --- a/ClientApp/polyfills/polyfills.ts +++ b/ClientApp/polyfills/polyfills.ts @@ -18,6 +18,9 @@ import 'core-js/es6/map'; import 'core-js/es6/set'; + /** */ + import 'reflect-metadata'; + /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. diff --git a/ClientApp/polyfills/server.polyfills.ts b/ClientApp/polyfills/server.polyfills.ts index 7d3dc3bf..7044895f 100644 --- a/ClientApp/polyfills/server.polyfills.ts +++ b/ClientApp/polyfills/server.polyfills.ts @@ -1,4 +1,3 @@ import './polyfills.ts'; -import 'reflect-metadata'; import 'zone.js'; From 3269cf0ef6bd4b6aad3357cbdb472b1ca07dc4f0 Mon Sep 17 00:00:00 2001 From: Rune Antonsen <rune.antonsen@gmail.com> Date: Tue, 27 Mar 2018 14:46:57 +0200 Subject: [PATCH 054/103] fix(polyfills): web-animations-js should be in browser.polyfills.ts (#582) --- ClientApp/polyfills/browser.polyfills.ts | 2 ++ ClientApp/polyfills/polyfills.ts | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ClientApp/polyfills/browser.polyfills.ts b/ClientApp/polyfills/browser.polyfills.ts index dd813a13..1db98ac8 100644 --- a/ClientApp/polyfills/browser.polyfills.ts +++ b/ClientApp/polyfills/browser.polyfills.ts @@ -1,3 +1,5 @@ import './polyfills.ts'; import 'zone.js/dist/zone'; +import 'reflect-metadata'; +// import 'web-animations-js'; // Run `npm install --save web-animations-js`. diff --git a/ClientApp/polyfills/polyfills.ts b/ClientApp/polyfills/polyfills.ts index 39ccb969..4382a0e1 100644 --- a/ClientApp/polyfills/polyfills.ts +++ b/ClientApp/polyfills/polyfills.ts @@ -24,8 +24,6 @@ /** IE10 and IE11 requires the following for NgClass support on SVG elements */ // import 'classlist.js'; // Run `npm install --save classlist.js`. -// import 'web-animations-js'; // Run `npm install --save web-animations-js`. - /** Evergreen browsers require these. **/ import 'core-js/es6/reflect'; import 'core-js/es7/reflect'; From 82afbb5781165081e6167e4679a89ed1caeba8b6 Mon Sep 17 00:00:00 2001 From: Flood <linusflood@gmail.com> Date: Fri, 6 Apr 2018 15:25:58 +0200 Subject: [PATCH 055/103] fix(cache): add cache busting to js files This fix makes the cache busting work. When using asp-append-version="true" in Index.cshtml like this: <script src="http://github.com/~/dist/vendor.js" asp-append-version="true"></script> It will turn that into: <script src="http://github.com/~/dist/vendor.js?v=37182361827361" ></script> When you publish. --- Views/_ViewImports.cshtml | 1 + 1 file changed, 1 insertion(+) diff --git a/Views/_ViewImports.cshtml b/Views/_ViewImports.cshtml index 8629c125..1872fd6b 100644 --- a/Views/_ViewImports.cshtml +++ b/Views/_ViewImports.cshtml @@ -1,2 +1,3 @@ @using AspCoreServer @addTagHelper "*, Microsoft.AspNetCore.SpaServices" +@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers" From a019c9b9f01c22e66e1b75538bb6f39991ad698c Mon Sep 17 00:00:00 2001 From: Bill <OceansideBill@users.noreply.github.com> Date: Sat, 19 May 2018 09:56:10 -0700 Subject: [PATCH 056/103] feat(rxjs6): added modifications to support updates to ngx-bootstrap and get translation functioning with RXJS 6. --- ClientApp/app/app.component.ts | 20 +++++---- ClientApp/app/app.module.ts | 4 +- ClientApp/app/shared/user.service.ts | 4 +- ClientApp/polyfills/polyfills.ts | 9 +--- ClientApp/polyfills/rx-imports.ts | 30 ------------- package.json | 67 ++++++++++++++-------------- 6 files changed, 50 insertions(+), 84 deletions(-) delete mode 100644 ClientApp/polyfills/rx-imports.ts diff --git a/ClientApp/app/app.component.ts b/ClientApp/app/app.component.ts index d8b28150..614cba3e 100644 --- a/ClientApp/app/app.component.ts +++ b/ClientApp/app/app.component.ts @@ -1,7 +1,9 @@ -import { Component, OnInit, OnDestroy, Inject, ViewEncapsulation, RendererFactory2, PLATFORM_ID, Injector } from '@angular/core'; + +import {mergeMap, map, filter} from 'rxjs/operators'; +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'; +import { Subscription } from 'rxjs'; import { isPlatformServer } from '@angular/common'; import { LinkService } from './shared/link.service'; @@ -60,15 +62,15 @@ export class AppComponent implements OnInit, OnDestroy { private _changeTitleOnNavigation() { - this.routerSub$ = this.router.events - .filter(event => event instanceof NavigationEnd) - .map(() => this.activatedRoute) - .map(route => { + this.routerSub$ = this.router.events.pipe( + filter(event => event instanceof NavigationEnd), + map(() => this.activatedRoute), + map(route => { while (route.firstChild) route = route.firstChild; return route; - }) - .filter(route => route.outlet === 'primary') - .mergeMap(route => route.data) + }), + filter(route => route.outlet === 'primary'), + mergeMap(route => route.data),) .subscribe((event) => { this._setMetaAndLinks(event); }); diff --git a/ClientApp/app/app.module.ts b/ClientApp/app/app.module.ts index 5394d67d..c0fa0985 100644 --- a/ClientApp/app/app.module.ts +++ b/ClientApp/app/app.module.ts @@ -7,7 +7,7 @@ import { FormsModule } from '@angular/forms'; import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser'; import { TransferHttpCacheModule } from '@nguniversal/common'; -import { Ng2BootstrapModule } from 'ngx-bootstrap'; +import { AccordionModule } from 'ngx-bootstrap'; // i18n support import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; @@ -57,7 +57,7 @@ export function createTranslateLoader(http: HttpClient, baseHref) { FormsModule, - Ng2BootstrapModule.forRoot(), // You could also split this up if you don't want the Entire Module imported + AccordionModule.forRoot(), // You could also split this up if you don't want the Entire Module imported // i18n support TranslateModule.forRoot({ diff --git a/ClientApp/app/shared/user.service.ts b/ClientApp/app/shared/user.service.ts index 6a3d7cb7..31110e7e 100644 --- a/ClientApp/app/shared/user.service.ts +++ b/ClientApp/app/shared/user.service.ts @@ -1,10 +1,10 @@ -import { Injectable, Inject, Injector } 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 '@nguniversal/aspnetcore-engine/tokens'; import { IUser } from '../models/User'; -import { Observable } from 'rxjs/Observable'; +import { Observable } from 'rxjs'; @Injectable() diff --git a/ClientApp/polyfills/polyfills.ts b/ClientApp/polyfills/polyfills.ts index 4382a0e1..fd43e294 100644 --- a/ClientApp/polyfills/polyfills.ts +++ b/ClientApp/polyfills/polyfills.ts @@ -1,4 +1,4 @@ - + /*************************************************************************************************** * BROWSER POLYFILLS */ @@ -28,10 +28,3 @@ import 'core-js/es6/reflect'; import 'core-js/es7/reflect'; -/** - * Date, currency, decimal and percent pipes. - * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 - */ -// import 'intl'; // Run `npm install --save intl`. - -import './rx-imports'; diff --git a/ClientApp/polyfills/rx-imports.ts b/ClientApp/polyfills/rx-imports.ts deleted file mode 100644 index 506f102b..00000000 --- a/ClientApp/polyfills/rx-imports.ts +++ /dev/null @@ -1,30 +0,0 @@ - -/* -=- RxJs imports -=- - * - * Here you can place any RxJs imports so you don't have to constantly - * import them throughout your App :) - * - * This file is automatically imported into `polyfills.ts` (which is imported into browser/server modules) - */ - -// General Operators -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/do'; -import 'rxjs/add/operator/throttleTime'; -import 'rxjs/add/operator/distinctUntilChanged'; -import 'rxjs/add/operator/switchMap'; -import 'rxjs/add/operator/take'; -import 'rxjs/add/operator/debounceTime'; -import 'rxjs/add/operator/filter'; -import 'rxjs/add/operator/mergeMap'; -import 'rxjs/add/operator/concat'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/operator/first'; - -// Observable operators -import 'rxjs/add/observable/fromEvent'; -import 'rxjs/add/observable/interval'; -import 'rxjs/add/observable/fromPromise'; -import 'rxjs/add/observable/of'; -import 'rxjs/add/observable/concat'; - diff --git a/package.json b/package.json index 86dacd20..848a12a2 100644 --- a/package.json +++ b/package.json @@ -28,65 +28,66 @@ "@angular/router": "^5.0.0", "@nguniversal/aspnetcore-engine": "^5.0.0-beta.8", "@nguniversal/common": "^5.0.0-beta.8", - "@ngx-translate/core": "^8.0.0", - "@ngx-translate/http-loader": "^2.0.0", + "@ngx-translate/core": "^9.1.1", + "@ngx-translate/http-loader": "^2.0.1", "@types/node": "^7.0.12", "angular2-router-loader": "^0.3.5", "angular2-template-loader": "^0.6.2", "aspnet-prerendering": "^3.0.1", - "aspnet-webpack": "^2.0.1", - "awesome-typescript-loader": "^3.0.0", - "bootstrap": "^3.3.7", + "aspnet-webpack": "^2.0.3", + "awesome-typescript-loader": "^3.2.3", + "bootstrap": "^4.1.1", "bootstrap-sass": "^3.3.7", - "core-js": "^2.5.1", - "css": "^2.2.1", - "css-loader": "^0.28.7", - "event-source-polyfill": "^0.0.9", - "expose-loader": "^0.7.3", - "extract-text-webpack-plugin": "^3.0.0", - "file-loader": "^0.11.2", - "html-loader": "^0.5.1", + "core-js": "^2.5.6", + "css": "^2.2.3", + "css-loader": "^0.28.11", + "event-source-polyfill": "^0.0.12", + "expose-loader": "^0.7.5", + "extract-text-webpack-plugin": "^3.0.2", + "file-loader": "^1.1.11", + "html-loader": "^0.5.5", "isomorphic-fetch": "^2.2.1", - "jquery": "^2.2.1", - "json-loader": "^0.5.4", + "jquery": "^3.3.1", + "json-loader": "^0.5.7", "moment": "2.18.1", - "ngx-bootstrap": "2.0.0-beta.6", - "node-sass": "^4.5.2", + "ngx-bootstrap": "2.0.5", + "node-sass": "^4.9.0", "preboot": "^5.0.0", "raw-loader": "^0.5.1", "rimraf": "^2.6.2", - "rxjs": "^5.5.6", + "rxjs": "^6.1.0", + "rxjs-compat": "^6.1.0", "sass-loader": "^6.0.6", "style-loader": "^0.18.2", "to-string-loader": "^1.1.5", - "typescript": "~2.5.0", - "url-loader": "^0.5.7", + "typescript": "~2.7.2", + "url-loader": "^1.0.1", "webpack": "^3.6.0", - "webpack-hot-middleware": "^2.19.1", + "webpack-hot-middleware": "^2.22.1", "webpack-merge": "^4.1.0", - "zone.js": "^0.8.17" + "zone.js": "^0.8.26" }, "devDependencies": { "@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", - "chai": "^3.5.0", - "codelyzer": "^3.0.0", - "istanbul-instrumenter-loader": "^3.0.0", + "@types/chai": "^4.1.3", + "@types/jasmine": "^2.8.7", + "chai": "^4.1.2", + "codelyzer": "^3.1.2", + "istanbul-instrumenter-loader": "^3.0.1", "jasmine-core": "^2.5.2", "karma": "^1.7.1", "karma-chai": "^0.1.0", "karma-chrome-launcher": "^2.2.0", "karma-coverage": "^1.1.1", - "karma-jasmine": "^1.1.0", - "karma-mocha-reporter": "^2.2.4", + "karma-jasmine": "^1.1.2", + "karma-mocha-reporter": "^2.2.5", "karma-phantomjs-launcher": "^1.0.4", - "karma-remap-coverage": "^0.1.4", + "karma-remap-coverage": "^0.1.5", "karma-sourcemap-loader": "^0.3.7", - "karma-webpack": "^2.0.3", - "tslint": "^5.7.0", - "webpack-bundle-analyzer": "^2.9.0" + "karma-webpack": "^2.0.4", + "tslint": "^5.10.0", + "webpack-bundle-analyzer": "^2.12.0" } } From 0360ad5a8ef1830dd88d6c76aceae4a0f1879bf3 Mon Sep 17 00:00:00 2001 From: Robert Zeni <robert.zeni@mohawkcollege.ca> Date: Mon, 28 May 2018 13:40:45 -0400 Subject: [PATCH 057/103] feat(angular6): upgrade .net core 2.1, bootstrap 4, ngx-bootsrap 3, rxjs 6, etc closes #619 --- .vscode/launch.json | 6 +- Asp2017.csproj | 12 ++-- Asp2017.sln | 25 ++++++++ ClientApp/app/app.module.browser.ts | 4 +- ClientApp/app/app.module.server.ts | 4 +- .../app/containers/home/home.component.html | 2 +- .../app/containers/users/users.component.ts | 11 +++- README.md | 8 +-- package.json | 64 ++++++++++--------- webpack.config.js | 47 ++++++++++---- webpack.config.vendor.js | 40 ++++++++++-- 11 files changed, 152 insertions(+), 71 deletions(-) create mode 100644 Asp2017.sln diff --git a/.vscode/launch.json b/.vscode/launch.json index 08d4edf9..c26ab807 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -20,7 +20,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp2.0/Asp2017.dll", + "program": "${workspaceRoot}/bin/Debug/netcoreapp2.1/Asp2017.dll", "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, @@ -51,7 +51,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp2.0/Asp2017.dll", + "program": "${workspaceRoot}/bin/Debug/netcoreapp2.1/Asp2017.dll", "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, @@ -82,7 +82,7 @@ "type": "coreclr", "request": "launch", "preLaunchTask": "build", - "program": "${workspaceRoot}/bin/Debug/netcoreapp2.0/Asp2017.dll", + "program": "${workspaceRoot}/bin/Debug/netcoreapp2.1/Asp2017.dll", "args": [], "cwd": "${workspaceRoot}", "stopAtEntry": false, diff --git a/Asp2017.csproj b/Asp2017.csproj index efb619c0..fe12d77e 100644 --- a/Asp2017.csproj +++ b/Asp2017.csproj @@ -1,17 +1,17 @@ <Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> - <TargetFramework>netcoreapp2.0</TargetFramework> + <TargetFramework>netcoreapp2.1</TargetFramework> <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion> <IsPackable>false</IsPackable> </PropertyGroup> <ItemGroup> <!-- New Meta Package has SpaServices in It --> - <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> - <PackageReference Include="NETStandard.Library" Version="2.0.0" /> - <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.0.0" /> - <PackageReference Include="Swashbuckle.AspNetCore" Version="1.0.0" /> + <PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.0-rc1-final" /> + <PackageReference Include="NETStandard.Library" Version="2.0.3" /> + <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0-rc1-final" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0-rc1-final" /> + <PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" /> </ItemGroup> <ItemGroup> <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" /> diff --git a/Asp2017.sln b/Asp2017.sln new file mode 100644 index 00000000..56a99822 --- /dev/null +++ b/Asp2017.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27703.2018 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Asp2017", "Asp2017.csproj", "{BC28E9F7-E6EC-447D-AABD-17683BEAD625}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BC28E9F7-E6EC-447D-AABD-17683BEAD625}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BC28E9F7-E6EC-447D-AABD-17683BEAD625}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BC28E9F7-E6EC-447D-AABD-17683BEAD625}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BC28E9F7-E6EC-447D-AABD-17683BEAD625}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DE341460-9041-458F-99D5-43FC7572CFA6} + EndGlobalSection +EndGlobal diff --git a/ClientApp/app/app.module.browser.ts b/ClientApp/app/app.module.browser.ts index fa983b67..f7371e80 100644 --- a/ClientApp/app/app.module.browser.ts +++ b/ClientApp/app/app.module.browser.ts @@ -7,7 +7,7 @@ import { ORIGIN_URL, REQUEST } from '@nguniversal/aspnetcore-engine/tokens'; import { AppModuleShared } from './app.module'; import { AppComponent } from './app.component'; import { BrowserTransferStateModule } from '@angular/platform-browser'; -import { BrowserPrebootModule } from 'preboot/browser'; +import { PrebootModule } from 'preboot'; export function getOriginUrl() { return window.location.origin; @@ -21,7 +21,7 @@ export function getRequest() { @NgModule({ bootstrap: [AppComponent], imports: [ - BrowserPrebootModule.replayEvents(), + PrebootModule.withConfig({ appRoot: 'app-root' }), BrowserAnimationsModule, // Our Common AppModule diff --git a/ClientApp/app/app.module.server.ts b/ClientApp/app/app.module.server.ts index 25711851..642a774c 100644 --- a/ClientApp/app/app.module.server.ts +++ b/ClientApp/app/app.module.server.ts @@ -7,7 +7,7 @@ import { AppModuleShared } from './app.module'; import { AppComponent } from './app.component'; import { ServerTransferStateModule } from '@angular/platform-server'; -import { ServerPrebootModule } from 'preboot/server'; +import { PrebootModule } from 'preboot'; @NgModule({ bootstrap: [AppComponent], @@ -16,7 +16,7 @@ import { ServerPrebootModule } from 'preboot/server'; AppModuleShared, ServerModule, - ServerPrebootModule.recordEvents({ appRoot: 'app-root' }), + PrebootModule.withConfig({ appRoot: 'app-root' }), NoopAnimationsModule, // HttpTransferCacheModule still needs fixes for 5.0 diff --git a/ClientApp/app/containers/home/home.component.html b/ClientApp/app/containers/home/home.component.html index 3a4db63b..3c08c588 100644 --- a/ClientApp/app/containers/home/home.component.html +++ b/ClientApp/app/containers/home/home.component.html @@ -12,7 +12,7 @@ <h2>{{ 'HOME_FEATURE_LIST_TITLE' | translate }} </h2> <ul> <li>ASP.NET Core 2.0 :: ( Visual Studio 2017 )</li> <li> - Angular 5.* front-end UI framework + Angular 6.* front-end UI framework <ul> <li>Angular **platform-server** (aka: Universal) - server-side rendering for SEO, deep-linking, and incredible performance.</li> diff --git a/ClientApp/app/containers/users/users.component.ts b/ClientApp/app/containers/users/users.component.ts index 6bca6a73..f6a0aa2d 100644 --- a/ClientApp/app/containers/users/users.component.ts +++ b/ClientApp/app/containers/users/users.component.ts @@ -1,8 +1,13 @@ import { - Component, OnInit, - // animation imports - trigger, state, style, transition, animate, Inject + Component, OnInit, Inject } from '@angular/core'; +import { + trigger, + state, + style, + animate, + transition +} from '@angular/animations'; import { IUser } from '../../models/User'; import { UserService } from '../../shared/user.service'; diff --git a/README.md b/README.md index 8cffbc2f..d2b1db31 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# ASP.NET Core 2.0 & Angular 5(+) Advanced Starter - with Server-side prerendering (for Angular SEO)! +# ASP.NET Core 2.0 & Angular 6(+) Advanced Starter - with Server-side prerendering (for Angular SEO)! ## By [DevHelp.Online](http://www.DevHelp.Online) -> Updated to the latest Angular 5.x +> Updated to the latest Angular 6.x > Note ServerTransferModule still in the works - fix coming soon @@ -81,7 +81,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual - Codelyzer (for Real-time static code analysis) - VSCode & Atom provide real-time analysis out of the box. -- **ASP.NET Core 2.0** +- **ASP.NET Core 2.1** - Integration with NodeJS to provide pre-rendering, as well as any other Node module asset you want to use. @@ -113,7 +113,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual ### Visual Studio 2017 -Make sure you have .NET Core 2.0 installed and/or VS2017 15.3. +Make sure you have .NET Core 2.1 installed and/or VS2017 15.3. VS2017 will automatically install all the neccessary npm & .NET dependencies when you open the project. Simply push F5 to start debugging ! diff --git a/package.json b/package.json index 848a12a2..9765601e 100644 --- a/package.json +++ b/package.json @@ -16,26 +16,26 @@ "clean": "rimraf wwwroot/dist clientapp/dist" }, "dependencies": { - "@angular/animations": "^5.0.0", - "@angular/common": "^5.0.0", - "@angular/compiler": "^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.8", - "@nguniversal/common": "^5.0.0-beta.8", - "@ngx-translate/core": "^9.1.1", - "@ngx-translate/http-loader": "^2.0.1", - "@types/node": "^7.0.12", + "@angular/animations": "^6.0.3", + "@angular/common": "^6.0.3", + "@angular/compiler": "^6.0.3", + "@angular/core": "^6.0.3", + "@angular/forms": "^6.0.3", + "@angular/http": "^6.0.3", + "@angular/platform-browser": "^6.0.3", + "@angular/platform-browser-dynamic": "^6.0.3", + "@angular/platform-server": "^6.0.3", + "@angular/router": "^6.0.3", + "@nguniversal/aspnetcore-engine": "^6.0.0", + "@nguniversal/common": "^6.0.0", + "@ngx-translate/core": "^10.0.2", + "@ngx-translate/http-loader": "^3.0.1", + "@types/node": "^10.1.2", "angular2-router-loader": "^0.3.5", "angular2-template-loader": "^0.6.2", "aspnet-prerendering": "^3.0.1", "aspnet-webpack": "^2.0.3", - "awesome-typescript-loader": "^3.2.3", + "awesome-typescript-loader": "^5.0.0", "bootstrap": "^4.1.1", "bootstrap-sass": "^3.3.7", "core-js": "^2.5.6", @@ -43,38 +43,38 @@ "css-loader": "^0.28.11", "event-source-polyfill": "^0.0.12", "expose-loader": "^0.7.5", - "extract-text-webpack-plugin": "^3.0.2", "file-loader": "^1.1.11", "html-loader": "^0.5.5", "isomorphic-fetch": "^2.2.1", "jquery": "^3.3.1", "json-loader": "^0.5.7", - "moment": "2.18.1", - "ngx-bootstrap": "2.0.5", + "moment": "2.22.1", + "ngx-bootstrap": "^3.0.0", "node-sass": "^4.9.0", - "preboot": "^5.0.0", + "preboot": "^6.0.0-beta.4", "raw-loader": "^0.5.1", "rimraf": "^2.6.2", - "rxjs": "^6.1.0", - "rxjs-compat": "^6.1.0", - "sass-loader": "^6.0.6", - "style-loader": "^0.18.2", + "rxjs": "^6.2.0", + "rxjs-compat": "^6.2.0", + "sass-loader": "^7.0.1", + "style-loader": "^0.21.0", "to-string-loader": "^1.1.5", "typescript": "~2.7.2", "url-loader": "^1.0.1", - "webpack": "^3.6.0", - "webpack-hot-middleware": "^2.22.1", - "webpack-merge": "^4.1.0", + "webpack": "^4.9.1", + "webpack-hot-middleware": "^2.22.2", + "webpack-merge": "^4.1.2", "zone.js": "^0.8.26" }, "devDependencies": { - "@angular/cli": "^1.7.0-beta.1", - "@angular/compiler-cli": "^5.2.1", - "@ngtools/webpack": "^1.9.0", + "@angular/cli": "^6.0.5", + "@angular/compiler-cli": "6.0.3", + "@ngtools/webpack": "^6.0.5", "@types/chai": "^4.1.3", "@types/jasmine": "^2.8.7", "chai": "^4.1.2", "codelyzer": "^3.1.2", + "extract-text-webpack-plugin": "^4.0.0-beta.0", "istanbul-instrumenter-loader": "^3.0.1", "jasmine-core": "^2.5.2", "karma": "^1.7.1", @@ -88,6 +88,8 @@ "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^2.0.4", "tslint": "^5.10.0", - "webpack-bundle-analyzer": "^2.12.0" + "uglifyjs-webpack-plugin": "^1.2.5", + "webpack-bundle-analyzer": "^2.13.1", + "webpack-cli": "^2.1.4" } } diff --git a/webpack.config.js b/webpack.config.js index a54d3135..d55cb8de 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -21,6 +21,7 @@ module.exports = (env) => { // Configuration in common to both client-side and server-side bundles const isDevBuild = !(env && env.prod); const sharedConfig = { + mode: isDevBuild ? "development" : "production", stats: { modules: false }, context: __dirname, resolve: { extensions: [ '.js', '.ts' ] }, @@ -64,16 +65,26 @@ module.exports = (env) => { tsConfigPath: './tsconfig.json', entryModule: path.join(__dirname, 'ClientApp/app/app.module.browser#AppModule'), exclude: ['./**/*.server.ts'] - }), - new webpack.optimize.UglifyJsPlugin({ - output: { - ascii_only: true, - } - }), + }) ]), devtool: isDevBuild ? 'cheap-eval-source-map' : false, node: { fs: "empty" + }, + optimization: { + minimizer: [].concat(isDevBuild ? [] : [ + // we specify a custom UglifyJsPlugin here to get source maps in production + new UglifyJsPlugin({ + cache: true, + parallel: true, + uglifyOptions: { + compress: false, + ecma: 6, + mangle: true + }, + sourceMap: true + }) + ]) } }); @@ -105,13 +116,6 @@ module.exports = (env) => { {} ) ] : [ - new webpack.optimize.UglifyJsPlugin({ - mangle: false, - compress: false, - output: { - ascii_only: true, - } - }), // Plugins that apply in production builds only new AngularCompilerPlugin({ mainPath: path.join(__dirname, 'ClientApp/boot.server.PRODUCTION.ts'), @@ -126,7 +130,22 @@ module.exports = (env) => { }, target: 'node', // switch to "inline-source-map" if you want to debug the TS during SSR - devtool: isDevBuild ? 'cheap-eval-source-map' : false + devtool: isDevBuild ? 'cheap-eval-source-map' : false, + optimization: { + minimizer: [].concat(isDevBuild ? [] : [ + // we specify a custom UglifyJsPlugin here to get source maps in production + new UglifyJsPlugin({ + cache: true, + parallel: true, + uglifyOptions: { + compress: false, + ecma: 6, + mangle: true + }, + sourceMap: true + }) + ]) + } }); return [clientBundleConfig, serverBundleConfig]; diff --git a/webpack.config.vendor.js b/webpack.config.vendor.js index 6d35d3ba..9a63c583 100644 --- a/webpack.config.vendor.js +++ b/webpack.config.vendor.js @@ -27,10 +27,11 @@ const nonTreeShakableModules = [ const allModules = treeShakableModules.concat(nonTreeShakableModules); module.exports = (env) => { - console.log(`env = ${JSON.stringify(env)}`) + console.log(`env = ${JSON.stringify(env)}`) const extractCSS = new ExtractTextPlugin('vendor.css'); const isDevBuild = !(env && env.prod); const sharedConfig = { + mode: isDevBuild ? "development" : "production", stats: { modules: false }, resolve: { extensions: [ '.js' ] }, module: { @@ -70,8 +71,23 @@ module.exports = (env) => { name: '[name]_[hash]' }) ].concat(isDevBuild ? [] : [ - new webpack.optimize.UglifyJsPlugin() - ]) + + ]), + optimization: { + minimizer: [].concat(isDevBuild ? [] : [ + // we specify a custom UglifyJsPlugin here to get source maps in production + new UglifyJsPlugin({ + cache: true, + parallel: true, + uglifyOptions: { + compress: false, + ecma: 6, + mangle: true + }, + sourceMap: true + }) + ]) + } }); const serverBundleConfig = merge(sharedConfig, { @@ -91,8 +107,22 @@ module.exports = (env) => { name: '[name]_[hash]' }) ].concat(isDevBuild ? [] : [ - new webpack.optimize.UglifyJsPlugin() - ]) + ]), + optimization: { + minimizer: [].concat(isDevBuild ? [] : [ + // we specify a custom UglifyJsPlugin here to get source maps in production + new UglifyJsPlugin({ + cache: true, + parallel: true, + uglifyOptions: { + compress: false, + ecma: 6, + mangle: true + }, + sourceMap: true + }) + ]) + } }); return [clientBundleConfig, serverBundleConfig]; From eff67f28a986be7fb36b16d002649e6ea37622e2 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 31 May 2018 14:56:48 -0400 Subject: [PATCH 058/103] fix(uglify, dotnetcore): update to 2.1, fix uglify issue, prod build fixed closes #632 --- .angular-cli.json | 25 -------------- Asp2017.csproj | 8 ++--- ClientApp/tsconfig.spec.json | 1 + angular.json | 63 ++++++++++++++++++++++++++++++++++++ package.json | 4 ++- webpack.config.js | 1 + webpack.config.vendor.js | 2 ++ 7 files changed, 74 insertions(+), 30 deletions(-) delete mode 100644 .angular-cli.json create mode 100644 angular.json diff --git a/.angular-cli.json b/.angular-cli.json deleted file mode 100644 index 4e8d017d..00000000 --- a/.angular-cli.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "project": { - "name": "AspnetCore-Angular-Universal" - }, - "apps": [ - { - "root": "ClientApp" - } - ], - "defaults": { - "styleExt": "scss", - "component": { - "spec": false - } - }, - "lint":[ - { - "project": "ClientApp/tsconfig.app.json" - }, - { - "project": "ClientApp/tsconfig.spec.json" - } - ] -} diff --git a/Asp2017.csproj b/Asp2017.csproj index fe12d77e..c8975b88 100644 --- a/Asp2017.csproj +++ b/Asp2017.csproj @@ -7,15 +7,15 @@ </PropertyGroup> <ItemGroup> <!-- New Meta Package has SpaServices in It --> - <PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.0-rc1-final" /> + <PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.0" /> <PackageReference Include="NETStandard.Library" Version="2.0.3" /> - <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0-rc1-final" /> - <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0-rc1-final" /> + <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" /> </ItemGroup> <ItemGroup> <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" /> - </ItemGroup> + </ItemGroup> <ItemGroup> <!-- Files not to show in IDE --> <None Remove="yarn.lock" /> diff --git a/ClientApp/tsconfig.spec.json b/ClientApp/tsconfig.spec.json index 584cb0a4..de4e2a75 100644 --- a/ClientApp/tsconfig.spec.json +++ b/ClientApp/tsconfig.spec.json @@ -11,6 +11,7 @@ ] }, "files": [ + "polyfills.ts" ], "include": [ "**/*.spec.ts", diff --git a/angular.json b/angular.json new file mode 100644 index 00000000..42179045 --- /dev/null +++ b/angular.json @@ -0,0 +1,63 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "AspnetCore-Angular-Universal": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/", + "index": "ClientApp/index.html", + "main": "ClientApp/main.ts", + "tsConfig": "ClientApp/tsconfig.app.json", + "assets": [], + "styles": [], + "scripts": [] + }, + "configurations": {} + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "AspnetCore-Angular-Universal:build" + }, + "configurations": {} + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "AspnetCore-Angular-Universal:build" + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "ClientApp/tsconfig.app.json", + "ClientApp/tsconfig.spec.json" + ], + "exclude": [] + } + } + } + }, + "AspnetCore-Angular-Universal-e2e": { + "root": "", + "sourceRoot": "", + "projectType": "application" + } + }, + "defaultProject": "AspnetCore-Angular-Universal", + "schematics": { + "@schematics/angular:component": { + "spec": false, + "styleext": "scss" + }, + "@schematics/angular:directive": {} + } +} \ No newline at end of file diff --git a/package.json b/package.json index 9765601e..61767b74 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "angular4-aspnetcore-universal", "version": "1.0.0-rc3", "scripts": { + "clean:install": "npm run clean && rimraf ./node_modules ./bin ./obj ./package-lock.json && dotnet restore && npm i", "lint": "tslint -p tsconfig.json", "test": "npm run build:vendor && karma start ClientApp/test/karma.conf.js", "test:watch": "npm run test -- --auto-watch --no-single-run", @@ -90,6 +91,7 @@ "tslint": "^5.10.0", "uglifyjs-webpack-plugin": "^1.2.5", "webpack-bundle-analyzer": "^2.13.1", - "webpack-cli": "^2.1.4" + "webpack-cli": "^2.1.4", + "@angular-devkit/build-angular": "~0.6.6" } } diff --git a/webpack.config.js b/webpack.config.js index d55cb8de..029207ac 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -14,6 +14,7 @@ const merge = require('webpack-merge'); const AngularCompilerPlugin = require('@ngtools/webpack').AngularCompilerPlugin; const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin; const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const { sharedModuleRules } = require('./webpack.additions'); diff --git a/webpack.config.vendor.js b/webpack.config.vendor.js index 9a63c583..b335a1f9 100644 --- a/webpack.config.vendor.js +++ b/webpack.config.vendor.js @@ -2,6 +2,7 @@ const path = require('path'); const webpack = require('webpack'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const merge = require('webpack-merge'); +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const treeShakableModules = [ '@angular/animations', '@angular/common', @@ -24,6 +25,7 @@ const nonTreeShakableModules = [ 'event-source-polyfill', // 'jquery', ]; + const allModules = treeShakableModules.concat(nonTreeShakableModules); module.exports = (env) => { From 2e12109b0fe957154edaf2de6a15614b37597f24 Mon Sep 17 00:00:00 2001 From: Mark Pieszak <mpieszak84@gmail.com> Date: Thu, 31 May 2018 15:04:21 -0400 Subject: [PATCH 059/103] docs(readme): update verbiage --- README.md | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index d2b1db31..7006242d 100644 --- a/README.md +++ b/README.md @@ -4,24 +4,22 @@ > Updated to the latest Angular 6.x -> 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"> + <img src="http://github.com/docs/architecture.png" alt="ASP.NET Core 2.0 Angular 6+ Starter" title="ASP.NET Core 2.0 Angular 6+ Starter"> </p> -### Harness the power of Angular 5+, ASP.NET Core 2.0, now with SEO ! +### Harness the power of Angular 6+, ASP.NET Core 2.0, now with SEO ! Angular SEO in action: <p align="center"> - <img src="http://github.com/docs/angular2-seo.png" alt="ASP.NET Core Angular5 SEO" title="ASP.NET Core Angular5 SEO"> + <img src="http://github.com/docs/angular2-seo.png" alt="ASP.NET Core Angular6 SEO" title="ASP.NET Core Angular6 SEO"> </p> ### 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 5.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 6.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). @@ -47,7 +45,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual > These are just some of the features found in this starter! -- ASP.NET 2.0 - VS2017 15.3 support now! +- ASP.NET 2.1 - VS2017 support now! - Azure delpoyment straight from VS2017 - Built in docker support through VS2017 - RestAPI (WebAPI) integration @@ -55,7 +53,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 5.0.0** : +- **Angular 6.0.0** : - (Minimal) Angular-CLI integration - This is to be used mainly for Generating Components/Services/etc. - Usage examples: @@ -69,7 +67,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual - Can be easily replaced with bootstrap4 (3 is provided for browser support) - Bootstrap using SCSS / SASS for easy theming / styling! -- **Webpack build system (Webpack 2)** +- **Webpack build system (Webpack 4)** - HMR : Hot Module Reloading/Replacement - Production builds w/ AoT Compilation @@ -87,7 +85,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual - **Azure** - Microsoft Application Insights setup (for MVC & Web API routing) - - Client-side Angular2 Application Insights integration + - Client-side Angular Application Insights integration - If you're using Azure simply install `npm i -S @markpieszak/ng-application-insights` as a dependencies. - Note: Make sure only the Browser makes these calls ([usage info here](https://github.com/MarkPieszak/angular-application-insights/blob/master/README.md#usage)) - More information here: - https://github.com/MarkPieszak/angular-application-insights @@ -97,9 +95,7 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual instrumentationKey: 'Your-Application-Insights-instrumentationKey' }) ``` - - -> Looking for the older 2.x branch? Go [here](https://github.com/MarkPieszak/aspnetcore-angular2-universal/tree/old-2.x-universal-branch) + ---- @@ -107,8 +103,8 @@ This utilizes all the latest standards, no gulp, no bower, no typings, no manual # Getting Started? -- **Make sure you have at least Node 6.x or higher (w/ npm 3+) installed!** -- **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)** +- **Make sure you have at least Node 8.11.1 or higher (w/ npm 5+) installed!** +- **This repository uses ASP.Net Core 2.1, which has a hard requirement on .NET Core Runtime 2.1 and .NET Core SDK 2.1. Please install these items from [here](https://blogs.msdn.microsoft.com/dotnet/2018/05/30/announcing-net-core-2-1/?WT.mc_id=blog-twitter-timheuer)** ### Visual Studio 2017 @@ -143,8 +139,9 @@ export ASPNETCORE_ENVIRONMENT=Development # Upcoming Features: -- 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)~~ +- Clean API / structure / simplify application +- Refactor to latest RxJs pipeable syntax +- Attempt to integrate with Angular-CLI fully ---- @@ -296,7 +293,7 @@ Take a look at the `_Layout.cshtml` file for example, notice how we let .NET han <head> <base href="http://github.com/" /> <!-- Title will be the one you set in your Angular application --> - <title>@ViewData["Title"] - AspNET.Core Angular 5.0.0 (+) starter + @ViewData["Title"] - AspNET.Core Angular 6.0.0 (+) starter @@ -335,9 +332,9 @@ Well now, your Client-side Angular will take over, and you'll have a fully funct # "Gotchas" -- 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) +- This repository uses ASP.Net Core 2.1, which has a hard requirement on .NET Core Runtime 2.1 and .NET Core SDK 2.1. Please install these items from [here](https://blogs.msdn.microsoft.com/dotnet/2018/05/30/announcing-net-core-2-1/?WT.mc_id=blog-twitter-timheuer) -> When building components in Angular 5 there are a few things to keep in mind. +> When building components in Angular 6 there are a few things to keep in mind. - Make sure you provide Absolute URLs when calling any APIs. (The server can't understand relative paths, so `/api/whatever` will fail). From 8f6356ca35d1164b3c25ce112253e26da5511e39 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Thu, 31 May 2018 15:04:55 -0400 Subject: [PATCH 060/103] docs(readme): update --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7006242d..bdf713cc 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ASP.NET Core 2.0 & Angular 6(+) Advanced Starter - with Server-side prerendering (for Angular SEO)! +# ASP.NET Core 2.1 & Angular 6(+) Advanced Starter - with Server-side prerendering (for Angular SEO)! ## By [DevHelp.Online](http://www.DevHelp.Online) @@ -19,7 +19,7 @@ Angular SEO in action: ### 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 6.0+, not only for the client-side, but to be rendered on the server for instant +for both ASP.NET Core 2.1 using Angular 6.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). From e1b8178d2845e54c584528cd1ea4e235777cd68f Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Thu, 31 May 2018 15:39:02 -0400 Subject: [PATCH 061/103] chore(wording): update 5.0 references in text to 6.0 --- ClientApp/app/containers/home/home.component.html | 6 +++--- Startup.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ClientApp/app/containers/home/home.component.html b/ClientApp/app/containers/home/home.component.html index 3c08c588..7b6799b6 100644 --- a/ClientApp/app/containers/home/home.component.html +++ b/ClientApp/app/containers/home/home.component.html @@ -1,8 +1,8 @@ 

    {{ title }}

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

    @@ -10,7 +10,7 @@

    {{ 'HOME_FEATURE_LIST_TITLE' | translate }}

      -
    • ASP.NET Core 2.0 :: ( Visual Studio 2017 )
    • +
    • ASP.NET Core 2.1 :: ( Visual Studio 2017 )
    • Angular 6.* front-end UI framework
        diff --git a/Startup.cs b/Startup.cs index db1d5d8d..4b07eaed 100644 --- a/Startup.cs +++ b/Startup.cs @@ -56,7 +56,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 5.0 Universal & ASP.NET Core advanced starter-kit web API", Version = "v1" }); + c.SwaggerDoc("v1", new Info { Title = "Angular 6.0 Universal & ASP.NET Core advanced starter-kit web API", Version = "v1" }); }); } From 352fab824aa428079f31a6902c1e95444660f7f8 Mon Sep 17 00:00:00 2001 From: GRIMMR3AP3R Date: Thu, 31 May 2018 14:46:41 -0500 Subject: [PATCH 062/103] feat(bootstrap4): add bootstrap4, docker support, fix bootstrap-sass issues * Real Bootstrap 4 * Real Boostrap 4 * Add docker support --- .dockerignore | 335 ++++++++++++++++++ ClientApp/app/_styles.scss | 45 +++ ClientApp/app/_variables.scss | 6 + ClientApp/app/app.component.html | 8 +- ClientApp/app/app.component.scss | 88 ++--- ClientApp/app/app.module.ts | 5 +- .../components/navmenu/navmenu.component.css | 106 ------ .../components/navmenu/navmenu.component.html | 89 +++-- .../components/navmenu/navmenu.component.scss | 114 ++++++ .../components/navmenu/navmenu.component.ts | 2 +- .../user-detail/user-detail.component.html | 25 +- .../user-detail/user-detail.component.scss | 4 + .../user-detail/user-detail.component.ts | 29 +- .../app/containers/home/home.component.html | 4 +- .../ngx-bootstrap.component.html | 2 +- .../app/containers/users/users.component.css | 64 ---- .../app/containers/users/users.component.html | 55 +-- .../app/containers/users/users.component.scss | 101 ++++++ .../app/containers/users/users.component.ts | 8 +- Dockerfile | 24 ++ Server/Data/DbInitializer.cs | 3 +- Views/Shared/_Layout.cshtml | 3 +- package.json | 1 - 23 files changed, 809 insertions(+), 312 deletions(-) create mode 100644 .dockerignore create mode 100644 ClientApp/app/_styles.scss create mode 100644 ClientApp/app/_variables.scss delete mode 100644 ClientApp/app/components/navmenu/navmenu.component.css create mode 100644 ClientApp/app/components/navmenu/navmenu.component.scss create mode 100644 ClientApp/app/components/user-detail/user-detail.component.scss delete mode 100644 ClientApp/app/containers/users/users.component.css create mode 100644 ClientApp/app/containers/users/users.component.scss create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..230e749b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,335 @@ +.dockerignore +.env +.git +.gitignore +.vs +.vscode +*/bin +*/obj +**/.toolstarget + + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ \ No newline at end of file diff --git a/ClientApp/app/_styles.scss b/ClientApp/app/_styles.scss new file mode 100644 index 00000000..42cf15fe --- /dev/null +++ b/ClientApp/app/_styles.scss @@ -0,0 +1,45 @@ +$body-bg: #f1f1f1; +$body-color: #111; +$theme-colors: ( "primary": #216DAD); +$theme-colors: ( "accent": #669ECD); + + +@import "http://github.com/~bootstrap/scss/bootstrap"; +.panel { + box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12); + height: 100%; + flex: 1; + background-color: rgba(255, 255, 255, .30); + border-radius: .25rem; + .title { + background-color: #86afd0; + color: #FFFFFF; + text-align: center; + border-top-left-radius: .25rem; + border-top-right-radius: .25rem; + } + .body { + display: flex; + } +} + +@include media-breakpoint-down(md) { + .panel { + .body { + flex-direction: column; + padding: 0px; + } + .title { + font-size: 1.5rem; + } + } +} + +@include media-breakpoint-up(md) { + .panel { + .body { + flex-direction: row; + padding: 1.5rem; + } + } +} diff --git a/ClientApp/app/_variables.scss b/ClientApp/app/_variables.scss new file mode 100644 index 00000000..2d34745a --- /dev/null +++ b/ClientApp/app/_variables.scss @@ -0,0 +1,6 @@ +@import "http://github.com/styles"; +$header-height:50px; +$menu-max-width:25%; +$navbar-default-bg: #312312; +$light-orange: #ff8c00; +$navbar-default-color: $light-orange; diff --git a/ClientApp/app/app.component.html b/ClientApp/app/app.component.html index 0345c682..45ca7f89 100644 --- a/ClientApp/app/app.component.html +++ b/ClientApp/app/app.component.html @@ -1,6 +1,6 @@ -
        - -
        -
        +
        + +
        +
        diff --git a/ClientApp/app/app.component.scss b/ClientApp/app/app.component.scss index 481063dc..8705be92 100644 --- a/ClientApp/app/app.component.scss +++ b/ClientApp/app/app.component.scss @@ -1,63 +1,71 @@ -$navbar-default-bg: #312312; -$light-orange: #ff8c00; -$navbar-default-color: $light-orange; +@import "http://github.com/variables"; +/* *** Overall APP Styling can go here *** + -------------------------------------------- + Note: This Component has ViewEncapsulation.None so the styles will bleed out -/* Import Bootstrap & Fonts */ -$icon-font-path: '~bootstrap-sass/assets/fonts/bootstrap/'; -@import "http://github.com/~bootstrap-sass/assets/stylesheets/bootstrap"; +*/ +body { + line-height: 18px; + padding-top: $header-height; +} +.body-content { + margin: auto; +} +h1 { + border-bottom: 3px theme-color("accent") solid; + font-size: 24px; +} -/* *** Overall APP Styling can go here *** - -------------------------------------------- - Note: This Component has ViewEncapsulation.None so the styles will bleed out +h2 { + font-size: 20px; +} -*/ -@media (max-width: 767px) { - body { - background: #f1f1f1; - line-height: 18px; - padding-top: 30px; - } +h1, +h2, +h3 { + padding: 3px 0; +} - h1 { - border-bottom: 3px #4189C7 solid; - font-size: 24px; - } +ul { + padding: 10px 25px; +} - h2 { - font-size: 20px; - } +ul li { + padding: 5px 0; +} - h1, h2, h3 { - padding: 3px 0; - } +blockquote { + margin: 25px 10px; + padding: 10px 35px 10px 10px; + border-left: 10px color("green") solid; + background: $gray-100; +} + +blockquote a, +blockquote a:hover { + color: $green; } -@media (min-width: 768px) { +@include media-breakpoint-up(lg) { body { - background: #f1f1f1; - line-height: 18px; - padding-top: 0px; + padding-top: 30px; + } + .body-content { + margin-left: $menu-max-width; } - h1 { border-bottom: 5px #4189C7 solid; font-size: 36px; } - h2 { font-size: 30px; } - - h1, h2, h3 { + h1, + h2, + h3 { padding: 10px 0; } } - -ul { padding: 10px 25px; } -ul li { padding: 5px 0; } - -blockquote { margin: 25px 10px; padding: 10px 35px 10px 10px; border-left: 10px #158a15 solid; background: #edffed; } -blockquote a, blockquote a:hover { color: #068006; } diff --git a/ClientApp/app/app.module.ts b/ClientApp/app/app.module.ts index c0fa0985..7cc9c4c0 100644 --- a/ClientApp/app/app.module.ts +++ b/ClientApp/app/app.module.ts @@ -3,7 +3,7 @@ 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 { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { BrowserModule, BrowserTransferStateModule } from '@angular/platform-browser'; import { TransferHttpCacheModule } from '@nguniversal/common'; @@ -54,9 +54,8 @@ export function createTranslateLoader(http: HttpClient, baseHref) { HttpClientModule, TransferHttpCacheModule, BrowserTransferStateModule, - - FormsModule, + ReactiveFormsModule, AccordionModule.forRoot(), // You could also split this up if you don't want the Entire Module imported // i18n support diff --git a/ClientApp/app/components/navmenu/navmenu.component.css b/ClientApp/app/components/navmenu/navmenu.component.css deleted file mode 100644 index 8d86aa03..00000000 --- a/ClientApp/app/components/navmenu/navmenu.component.css +++ /dev/null @@ -1,106 +0,0 @@ -li .glyphicon { - margin-right: 10px; -} - -/* Highlighting rules for nav menu items */ -li.link-active a, -li.link-active a:hover, -li.link-active a:focus { - background-color: #4189C7; - color: white; -} - -/* Keep the nav menu independent of scrolling and on top of other items */ -.main-nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1; -} - -.icon-bar { - background-color: #4189C7; -} - - -@media (max-width: 767px) { - /* Apply for small displays */ - .main-nav { - width: 100%; - } - - .navbar-brand { - font-size: 14px; - background-color: #f1f1f1; - } - .navbar-toggle { - padding: 0px 5px; - margin-top: 0px; - height: 26px; - } - - .navbar-link { - margin-top: 4px; - margin-left: 45px; - position: fixed; - } - - .navbar-collapse { - background-color: white; - } - - .navbar a { - /* If a menu item's text is too long, truncate it */ - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - padding-right: 5px; - } -} - -@media (min-width: 768px) { - /* On small screens, convert the nav menu to a vertical sidebar */ - .main-nav { - height: 100%; - max-width: 330px; - width: calc(25% - 20px); - } - .navbar { - border-radius: 0px; - border-width: 0px; - height: 100%; - } - .navbar-brand{ - width: 100%; - } - .navbar-link { - display: block; - width: 100% - } - .navbar-header { - float: none; - } - .navbar-collapse { - border-top: 1px solid #444; - padding: 0px; - } - .navbar ul { - float: none; - } - .navbar li { - float: none; - font-size: 15px; - margin: 6px; - } - .navbar li a { - padding: 10px 16px; - border-radius: 4px; - } - .navbar a { - /* If a menu item's text is too long, truncate it */ - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } -} diff --git a/ClientApp/app/components/navmenu/navmenu.component.html b/ClientApp/app/components/navmenu/navmenu.component.html index 08e1b0fc..36c187ed 100644 --- a/ClientApp/app/components/navmenu/navmenu.component.html +++ b/ClientApp/app/components/navmenu/navmenu.component.html @@ -1,50 +1,41 @@ -
      -

      DevHelp.Online

      +

      Trilon Consulting - Trilon.io

      Consulting | Development | Training | Workshops

      - Get your Team or Application up to speed by working with some of the leading industry experts in JavaScript & ASP.NET!
      + Get your Team or Application up to speed by working with some of the leading industry experts in JavaScript, Node / NestJS, & ASP.NET!

      Follow us on Twitter!

      - @DevHelpOnline | + @trilon_io | @MarkPieszak

      From 83b0301b1db1ed34e1d16d8ef9fa4750c8b970d8 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Sun, 17 Mar 2019 11:55:39 -0400 Subject: [PATCH 096/103] docs: update --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e6ed1417..b0b14e9f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,15 @@ # ASP.NET Core 2.1 & Angular 7(+) Advanced Starter - PWA & Server-side prerendering (for Angular SEO)! -## By [Trilon.io](https://Trilon.io) +## Made with :heart: by [Trilon.io](https://Trilon.io) +

      + + Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training + +

      + +--- -> Updated to the latest Angular 7.x +## High-level architectural diagram

      ASP.NET Core 2.1 Angular 7+ Starter @@ -471,7 +478,9 @@ Check out **[Trilon.io](https://Trilon.io)** for more info! Twitter [@Trilon_io] Contact us at , and let's talk about your projects needs.

      - Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training + + Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training +

      ## Follow Trilon online: From 7e2468a7d01472acf15f430b50ca596a64a62d6b Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Sun, 17 Mar 2019 11:57:52 -0400 Subject: [PATCH 097/103] docs: update --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index b0b14e9f..b6402f4b 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,12 @@ # ASP.NET Core 2.1 & Angular 7(+) Advanced Starter - PWA & Server-side prerendering (for Angular SEO)! -## Made with :heart: by [Trilon.io](https://Trilon.io) +### Made with :heart: by [Trilon.io](https://Trilon.io)

      Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training

      ---- - -## High-level architectural diagram

      ASP.NET Core 2.1 Angular 7+ Starter From 4aa16404f1b1a0dd1b4e70b7dd891b0006eabd9b Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Mon, 18 Mar 2019 12:32:39 -0400 Subject: [PATCH 098/103] fix: rxjs pin to 6.2.2 closes #714 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 99ba5443..01bc52bc 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "preboot": "^7.0.0", "raw-loader": "^1.0.0", "rimraf": "^2.6.3", - "rxjs": "~6.4.0", + "rxjs": "6.2.2", "sass-loader": "^7.1.0", "style-loader": "^0.23.1", "to-string-loader": "^1.1.5", From 9cf8b7ba6ee15c01e2ec02a77421e7ee77eb6254 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Fri, 5 Apr 2019 12:17:42 -0400 Subject: [PATCH 099/103] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6402f4b..8e933ca5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ### Made with :heart: by [Trilon.io](https://Trilon.io)

      - Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training + Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training

      @@ -476,7 +476,7 @@ Contact us at , and let's talk about your projects needs.

      - Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training + Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training

      From 82dc1897c03f9546b613b72e4a72040b85ab54f1 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Fri, 5 Apr 2019 12:45:04 -0400 Subject: [PATCH 100/103] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8e933ca5..ecac2050 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,6 @@

      - -

      - ASP.NET Core 2.1 Angular 7+ Starter -

      - ### Harness the power of Angular 7+, ASP.NET Core 2.1, now with SEO ! Angular SEO in action: @@ -20,6 +15,12 @@ Angular SEO in action: ASP.NET Core Angular7 SEO

      +### Angular Universal Application Architecture + +

      + ASP.NET Core 2.1 Angular 7+ Starter +

      + ### What is this repo? Live Demo here: http://aspnetcore-angular2-universal.azurewebsites.net This repository is maintained by [Trilon.io](https://Trilon.io) and the [Angular](https://github.com/angular/angular) Universal team and is meant to be an advanced starter From b8ec2b0ff276a187e3821797fbd03201842d5311 Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Fri, 5 Apr 2019 12:45:28 -0400 Subject: [PATCH 101/103] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ecac2050..482cc672 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@

      +--- + ### Harness the power of Angular 7+, ASP.NET Core 2.1, now with SEO ! Angular SEO in action: From 55f0105f807946cff515aaa0ef535de1329c2b9f Mon Sep 17 00:00:00 2001 From: Mark Pieszak Date: Sun, 7 Apr 2019 17:56:32 -0400 Subject: [PATCH 102/103] Update README.md --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 482cc672..f52bdf4d 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,17 @@ # ASP.NET Core 2.1 & Angular 7(+) Advanced Starter - PWA & Server-side prerendering (for Angular SEO)! -### Made with :heart: by [Trilon.io](https://Trilon.io) -

      +--- + +
      +

      - Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training + Trilon.io - Angular Universal, NestJS, JavaScript Application Consulting Development and Training

      + +

      Made with :heart: by Trilon.io

      + --- ### Harness the power of Angular 7+, ASP.NET Core 2.1, now with SEO ! From 837b134516631afb3034d40278e2bc9f170acdba Mon Sep 17 00:00:00 2001 From: Detys Date: Mon, 27 May 2019 02:49:07 +0300 Subject: [PATCH 103/103] fix(seeding): seeding now follows .NET Core 2.0 best practices --- Program.cs | 60 ++++++++++++------- Server/Data/CoreEFStartup.cs | 17 ++++++ Server/Data/LoggingEFStartup.cs | 13 ++++ ...itializer.cs => SimpleContentEFStartup.cs} | 24 ++++---- 4 files changed, 80 insertions(+), 34 deletions(-) create mode 100644 Server/Data/CoreEFStartup.cs create mode 100644 Server/Data/LoggingEFStartup.cs rename Server/Data/{DbInitializer.cs => SimpleContentEFStartup.cs} (67%) diff --git a/Program.cs b/Program.cs index 69e56419..fdf46454 100644 --- a/Program.cs +++ b/Program.cs @@ -6,28 +6,42 @@ using Microsoft.Extensions.Logging; using System; using System.IO; +using System.Threading.Tasks; -public class Program { - public static void Main (string[] args) { - var host = BuildWebHost (args); - using (var scope = host.Services.CreateScope ()) { - var services = scope.ServiceProvider; - try { - var context = services.GetRequiredService(); - DbInitializer.Initialize(context); - } catch (Exception ex) { - var logger = services.GetRequiredService> (); - logger.LogError (ex, "An error occurred while seeding the database."); - } - } +public class Program +{ + public static async Task Main(string[] args) + { + var host = BuildWebHost(args); + using (var scope = host.Services.CreateScope()) + { + var services = scope.ServiceProvider; - host.Run (); - } - public static IWebHost BuildWebHost (string[] args) => - WebHost.CreateDefaultBuilder (args) - .UseKestrel () - .UseContentRoot (Directory.GetCurrentDirectory ()) - .UseIISIntegration () - .UseStartup () - .Build (); - } + try + { + await EnsureDataStorageIsReady(services); + + } catch (Exception ex) + { + var logger = services.GetRequiredService>(); + logger.LogError(ex, "An error occurred while seeding the database."); + } + } + + host.Run(); + } + public static IWebHost BuildWebHost(string[] args) => + WebHost.CreateDefaultBuilder(args) + .UseKestrel() + .UseContentRoot(Directory.GetCurrentDirectory()) + .UseIISIntegration() + .UseStartup() + .Build(); + + private static async Task EnsureDataStorageIsReady(IServiceProvider services) + { + await CoreEFStartup.InitializeDatabaseAsync(services); + await SimpleContentEFStartup.InitializeDatabaseAsync(services); + await LoggingEFStartup.InitializeDatabaseAsync(services); + } +} diff --git a/Server/Data/CoreEFStartup.cs b/Server/Data/CoreEFStartup.cs new file mode 100644 index 00000000..d3947ef1 --- /dev/null +++ b/Server/Data/CoreEFStartup.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; + +namespace AspCoreServer.Data +{ + public static class CoreEFStartup + { + public static async Task InitializeDatabaseAsync(IServiceProvider services) + { + var context = services.GetRequiredService(); + + await context.Database.EnsureCreatedAsync(); + } + + } +} diff --git a/Server/Data/LoggingEFStartup.cs b/Server/Data/LoggingEFStartup.cs new file mode 100644 index 00000000..edf33498 --- /dev/null +++ b/Server/Data/LoggingEFStartup.cs @@ -0,0 +1,13 @@ +using System; +using System.Threading.Tasks; + +namespace AspCoreServer.Data +{ + public static class LoggingEFStartup + { + public static async Task InitializeDatabaseAsync(IServiceProvider services) + { + //Implent to your hearts' content + } + } +} diff --git a/Server/Data/DbInitializer.cs b/Server/Data/SimpleContentEFStartup.cs similarity index 67% rename from Server/Data/DbInitializer.cs rename to Server/Data/SimpleContentEFStartup.cs index 919c9282..db160dee 100644 --- a/Server/Data/DbInitializer.cs +++ b/Server/Data/SimpleContentEFStartup.cs @@ -1,16 +1,20 @@ using System; -using System.Linq; -using AspCoreServer; +using System.Threading.Tasks; using AspCoreServer.Models; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; -namespace AspCoreServer.Data { - public static class DbInitializer { - public static void Initialize (SpaDbContext context) { - context.Database.EnsureCreated (); +namespace AspCoreServer.Data +{ + public static class SimpleContentEFStartup + { + public static async Task InitializeDatabaseAsync(IServiceProvider services) + { + var context = services.GetRequiredService(); - if (context.User.Any ()) { + + if (await context.User.AnyAsync()) + { return; // DB has been seeded } var users = new User[] { @@ -27,11 +31,9 @@ public static void Initialize (SpaDbContext context) { new User () { Name = "Gaulomatic" }, new User () { Name = "GRIMMR3AP3R" } }; + await context.User.AddRangeAsync(users); - foreach (var s in users) { - context.User.Add (s); - } - context.SaveChanges (); + await context.SaveChangesAsync(); } } }