Skip to content

Commit cc37710

Browse files
GRIMMR3AP3RMarkPieszak
authored andcommitted
feat(PWA): add progressive web app manifest + PWA to app
* PWA !! * Fixed the published PWA with workaround
1 parent 364d710 commit cc37710

File tree

9 files changed

+127
-127
lines changed

9 files changed

+127
-127
lines changed

Asp2017.csproj

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,16 @@
88
<DockerComposeProjectPath>docker-compose.dcproj</DockerComposeProjectPath>
99
</PropertyGroup>
1010
<ItemGroup>
11-
<!-- New Meta Package has SpaServices in It -->
11+
<!-- New Meta Package has SpaServices in It -->
1212
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.1.0" />
1313
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="0.1.1646902" />
1414
<PackageReference Include="NETStandard.Library" Version="2.0.3" />
1515
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.1.0" />
1616
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.0" />
1717
<PackageReference Include="Swashbuckle.AspNetCore" Version="2.4.0" />
18+
<PackageReference Include="WebEssentials.AspNetCore.PWA" Version="1.0.33" />
1819
</ItemGroup>
19-
<ItemGroup>
20-
<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.0" />
21-
</ItemGroup>
20+
2221
<ItemGroup>
2322
<!-- Files not to show in IDE -->
2423
<None Remove="yarn.lock" />
Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
1-
using Asp2017.Server.Helpers;
1+
using System;
2+
using System.Diagnostics;
23
using System.Threading.Tasks;
4+
using Asp2017.Server.Helpers;
5+
using Asp2017.Server.Models;
6+
using Microsoft.AspNetCore.Hosting;
7+
using Microsoft.AspNetCore.Http;
8+
using Microsoft.AspNetCore.Http.Features;
39
using Microsoft.AspNetCore.Mvc;
4-
5-
using Microsoft.AspNetCore.SpaServices.Prerendering;
610
using Microsoft.AspNetCore.NodeServices;
11+
using Microsoft.AspNetCore.SpaServices.Prerendering;
712
using Microsoft.Extensions.DependencyInjection;
8-
using Microsoft.AspNetCore.Hosting;
9-
using Microsoft.AspNetCore.Http.Features;
10-
using Microsoft.AspNetCore.Http;
11-
using System.Diagnostics;
12-
using System;
13-
using Asp2017.Server.Models;
1413

15-
namespace AspCoreServer.Controllers
16-
{
17-
public class HomeController : Controller
18-
{
14+
namespace AspCoreServer.Controllers {
15+
public class HomeController : Controller {
16+
protected readonly IHostingEnvironment HostingEnvironment;
17+
public HomeController (IHostingEnvironment hostingEnv) {
18+
this.HostingEnvironment = hostingEnv;
19+
}
20+
1921
[HttpGet]
20-
public async Task<IActionResult> Index()
21-
{
22-
var prerenderResult = await Request.BuildPrerender();
22+
public async Task<IActionResult> Index () {
23+
var prerenderResult = await Request.BuildPrerender ();
2324

2425
ViewData["SpaHtml"] = prerenderResult.Html; // our <app-root /> from Angular
2526
ViewData["Title"] = prerenderResult.Globals["title"]; // set our <title> from Angular
@@ -28,34 +29,35 @@ public async Task<IActionResult> Index()
2829
ViewData["Meta"] = prerenderResult.Globals["meta"]; // set our <meta> SEO tags
2930
ViewData["Links"] = prerenderResult.Globals["links"]; // set our <link rel="canonical"> etc SEO tags
3031
ViewData["TransferData"] = prerenderResult.Globals["transferData"]; // our transfer data set to window.TRANSFER_CACHE = {};
32+
if (!HostingEnvironment.IsDevelopment ()) {
33+
ViewData["ServiceWorker"] = "<script>'serviceWorker'in navigator&&navigator.serviceWorker.register('/serviceworker')</script>";
34+
}
3135

32-
return View();
36+
return View ();
3337
}
3438

3539
[HttpGet]
36-
[Route("sitemap.xml")]
37-
public async Task<IActionResult> SitemapXml()
38-
{
40+
[Route ("sitemap.xml")]
41+
public IActionResult SitemapXml () {
3942
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>";
4043

4144
xml += "<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">";
4245
xml += "<url>";
4346
xml += "<loc>http://localhost:4251/home</loc>";
44-
xml += "<lastmod>" + DateTime.Now.ToString("yyyy-MM-dd") + "</lastmod>";
47+
xml += "<lastmod>" + DateTime.Now.ToString ("yyyy-MM-dd") + "</lastmod>";
4548
xml += "</url>";
4649
xml += "<url>";
4750
xml += "<loc>http://localhost:4251/counter</loc>";
48-
xml += "<lastmod>" + DateTime.Now.ToString("yyyy-MM-dd") + "</lastmod>";
51+
xml += "<lastmod>" + DateTime.Now.ToString ("yyyy-MM-dd") + "</lastmod>";
4952
xml += "</url>";
5053
xml += "</urlset>";
5154

52-
return Content(xml, "text/xml");
55+
return Content (xml, "text/xml");
5356

5457
}
5558

56-
public IActionResult Error()
57-
{
58-
return View();
59+
public IActionResult Error () {
60+
return View ();
5961
}
6062
}
61-
}
63+
}

Startup.cs

Lines changed: 73 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,125 @@
11
using System;
22
using System.IO;
3+
using AspCoreServer.Data;
34
using Microsoft.AspNetCore.Builder;
45
using Microsoft.AspNetCore.Hosting;
6+
using Microsoft.AspNetCore.Http;
57
using Microsoft.AspNetCore.SpaServices.Webpack;
8+
using Microsoft.EntityFrameworkCore;
69
using Microsoft.Extensions.Configuration;
710
using Microsoft.Extensions.DependencyInjection;
811
using Microsoft.Extensions.Logging;
9-
using Microsoft.EntityFrameworkCore;
10-
using AspCoreServer.Data;
11-
using Swashbuckle.AspNetCore.Swagger;
12-
using Microsoft.AspNetCore.Http;
1312
using Microsoft.Net.Http.Headers;
13+
using Swashbuckle.AspNetCore.Swagger;
14+
using WebEssentials.AspNetCore.Pwa;
15+
16+
namespace AspCoreServer {
17+
public class Startup {
18+
19+
public static void Main (string[] args) {
20+
var host = new WebHostBuilder ()
21+
.UseKestrel ()
22+
.UseContentRoot (Directory.GetCurrentDirectory ())
23+
.UseIISIntegration ()
24+
.UseStartup<Startup> ()
25+
.Build ();
1426

15-
namespace AspCoreServer
16-
{
17-
public class Startup
18-
{
19-
20-
public static void Main(string[] args)
21-
{
22-
var host = new WebHostBuilder()
23-
.UseKestrel()
24-
.UseContentRoot(Directory.GetCurrentDirectory())
25-
.UseIISIntegration()
26-
.UseStartup<Startup>()
27-
.Build();
28-
29-
host.Run();
27+
host.Run ();
3028
}
31-
public Startup(IHostingEnvironment env)
32-
{
33-
var builder = new ConfigurationBuilder()
34-
.SetBasePath(env.ContentRootPath)
35-
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
36-
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
37-
.AddEnvironmentVariables();
38-
Configuration = builder.Build();
29+
public Startup (IHostingEnvironment env) {
30+
var builder = new ConfigurationBuilder ()
31+
.SetBasePath (env.ContentRootPath)
32+
.AddJsonFile ("appsettings.json", optional : true, reloadOnChange : true)
33+
.AddJsonFile ($"appsettings.{env.EnvironmentName}.json", optional : true)
34+
.AddEnvironmentVariables ();
35+
Configuration = builder.Build ();
3936
}
4037

4138
public IConfigurationRoot Configuration { get; }
4239

4340
// This method gets called by the runtime. Use this method to add services to the container.
44-
public void ConfigureServices(IServiceCollection services)
45-
{
41+
public void ConfigureServices (IServiceCollection services) {
4642
// Add framework services.
47-
services.AddMvc();
48-
services.AddNodeServices();
43+
services.AddMvc ();
44+
services.AddNodeServices ();
45+
services.AddHttpContextAccessor ();
46+
services.AddProgressiveWebApp (new PwaOptions { Strategy = ServiceWorkerStrategy.CacheFirst, RegisterServiceWorker = true, RegisterWebmanifest = true }, "manifest.json");
4947

5048
var connectionStringBuilder = new Microsoft.Data.Sqlite.SqliteConnectionStringBuilder { DataSource = "spa.db" };
51-
var connectionString = connectionStringBuilder.ToString();
49+
var connectionString = connectionStringBuilder.ToString ();
5250

53-
services.AddDbContext<SpaDbContext>(options =>
54-
options.UseSqlite(connectionString));
51+
services.AddDbContext<SpaDbContext> (options =>
52+
options.UseSqlite (connectionString));
5553

5654
// Register the Swagger generator, defining one or more Swagger documents
57-
services.AddSwaggerGen(c =>
58-
{
59-
c.SwaggerDoc("v1", new Info { Title = "Angular 6.0 Universal & ASP.NET Core advanced starter-kit web API", Version = "v1" });
55+
services.AddSwaggerGen (c => {
56+
c.SwaggerDoc ("v1", new Info { Title = "Angular 6.0 Universal & ASP.NET Core advanced starter-kit web API", Version = "v1" });
6057
});
6158
}
6259

6360
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
64-
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, SpaDbContext context)
65-
{
66-
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
67-
loggerFactory.AddDebug();
61+
public void Configure (IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, SpaDbContext context) {
62+
loggerFactory.AddConsole (Configuration.GetSection ("Logging"));
63+
loggerFactory.AddDebug ();
6864

6965
// app.UseStaticFiles();
7066

71-
app.UseStaticFiles(new StaticFileOptions()
72-
{
73-
OnPrepareResponse = c =>
74-
{
67+
app.UseStaticFiles (new StaticFileOptions () {
68+
OnPrepareResponse = c => {
7569
//Do not add cache to json files. We need to have new versions when we add new translations.
7670

77-
if (!c.Context.Request.Path.Value.Contains(".json"))
78-
{
79-
c.Context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue()
80-
{
81-
MaxAge = TimeSpan.FromDays(30) // Cache everything except json for 30 days
71+
if (!c.Context.Request.Path.Value.Contains (".json")) {
72+
c.Context.Response.GetTypedHeaders ().CacheControl = new CacheControlHeaderValue () {
73+
MaxAge = TimeSpan.FromDays (30) // Cache everything except json for 30 days
8274
};
83-
}
84-
else
85-
{
86-
c.Context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue()
87-
{
88-
MaxAge = TimeSpan.FromMinutes(15) // Cache json for 15 minutes
75+
} else {
76+
c.Context.Response.GetTypedHeaders ().CacheControl = new CacheControlHeaderValue () {
77+
MaxAge = TimeSpan.FromMinutes (15) // Cache json for 15 minutes
8978
};
9079
}
9180
}
9281
});
9382

94-
DbInitializer.Initialize(context);
83+
DbInitializer.Initialize (context);
9584

96-
if (env.IsDevelopment())
97-
{
98-
app.UseDeveloperExceptionPage();
99-
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
100-
{
85+
if (env.IsDevelopment ()) {
86+
app.UseDeveloperExceptionPage ();
87+
app.UseWebpackDevMiddleware (new WebpackDevMiddlewareOptions {
10188
HotModuleReplacement = true,
102-
HotModuleReplacementEndpoint = "/dist/"
89+
HotModuleReplacementEndpoint = "/dist/"
10390
});
104-
app.UseSwagger();
105-
app.UseSwaggerUI(c =>
106-
{
107-
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
91+
app.UseSwagger ();
92+
app.UseSwaggerUI (c => {
93+
c.SwaggerEndpoint ("/swagger/v1/swagger.json", "My API V1");
10894
});
10995

11096
// Enable middleware to serve swagger-ui (HTML, JS, CSS etc.), specifying the Swagger JSON endpoint.
11197

112-
113-
app.MapWhen(x => !x.Request.Path.Value.StartsWith("/swagger", StringComparison.OrdinalIgnoreCase), builder =>
114-
{
115-
builder.UseMvc(routes =>
116-
{
117-
routes.MapSpaFallbackRoute(
118-
name: "spa-fallback",
119-
defaults: new { controller = "Home", action = "Index" });
98+
app.MapWhen (x => !x.Request.Path.Value.StartsWith ("/swagger", StringComparison.OrdinalIgnoreCase), builder => {
99+
builder.UseMvc (routes => {
100+
routes.MapSpaFallbackRoute (
101+
name: "spa-fallback",
102+
defaults : new { controller = "Home", action = "Index" });
120103
});
121104
});
122-
}
123-
else
124-
{
125-
app.UseMvc(routes =>
126-
{
127-
routes.MapRoute(
128-
name: "default",
129-
template: "{controller=Home}/{action=Index}/{id?}");
130-
131-
routes.MapRoute(
132-
"Sitemap",
133-
"sitemap.xml",
134-
new { controller = "Home", action = "SitemapXml" });
135-
136-
routes.MapSpaFallbackRoute(
105+
} else {
106+
app.UseMvc (routes => {
107+
routes.MapRoute (
108+
name: "default",
109+
template: "{controller=Home}/{action=Index}/{id?}");
110+
111+
routes.MapRoute (
112+
"Sitemap",
113+
"sitemap.xml",
114+
new { controller = "Home", action = "SitemapXml" });
115+
116+
routes.MapSpaFallbackRoute (
137117
name: "spa-fallback",
138-
defaults: new { controller = "Home", action = "Index" });
118+
defaults : new { controller = "Home", action = "Index" });
139119

140120
});
141-
app.UseExceptionHandler("/Home/Error");
121+
app.UseExceptionHandler ("/Home/Error");
142122
}
143123
}
144124
}
145-
}
125+
}

Views/Home/Index.cshtml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@
99
<!-- Our webpack bundle -->
1010
<script src="~/dist/main-client.js" asp-append-version="true"></script>
1111
}
12+
@Html.Raw(ViewData["ServiceWorker"])

Views/Shared/_Layout.cshtml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<script defer src="https://use.fontawesome.com/releases/v5.0.13/js/all.js" integrity="sha384-xymdQtn1n3lH2wcu0qhcdaOpQwyoarkgLVxC/wZ5q7h9gHtxICrpcaSUfygqZGOe" crossorigin="anonymous"></script>
1313

1414
@Html.Raw(ViewData["Styles"])
15-
15+
<link rel="manifest" href="/manifest.json">
1616
</head>
1717
<body>
1818
@RenderBody()
@@ -21,7 +21,6 @@
2121
@Html.Raw(ViewData["TransferData"])
2222
@Html.Raw(ViewData["Scripts"])
2323

24-
@RenderSection("scripts", required: false)
25-
24+
@RenderSection("scripts", required: false)
2625
</body>
2726
</html>

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"moment": "2.22.1",
5252
"ngx-bootstrap": "^3.0.0",
5353
"node-sass": "^4.9.0",
54+
"npm": "^6.1.0",
5455
"preboot": "^6.0.0-beta.4",
5556
"raw-loader": "^0.5.1",
5657
"rimraf": "^2.6.2",

wwwroot/images/icon192x192.png

9.59 KB
Loading

wwwroot/images/icon512x512.png

28.4 KB
Loading

wwwroot/manifest.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "ASP.NET Core 2.1 & Angular 6(+) Advanced Starter",
3+
"short_name": "aspnetcore-angular2-universal",
4+
"description": "ASP.NET Core 2.1 & Angular 6(+) Advanced Starter - with Server-side prerendering (for Angular SEO)!",
5+
"icons": [{
6+
"src": "/images/icon192x192.png",
7+
"sizes": "192x192"
8+
},
9+
{
10+
"src": "/images/icon512x512.png",
11+
"sizes": "512x512"
12+
}
13+
],
14+
"background_color": "#3E4EB8",
15+
"theme_color": "#2F3BA2",
16+
"display": "standalone",
17+
"start_url": "/"
18+
}

0 commit comments

Comments
 (0)