#1 Quick Start
Friday, May 18, 2018
In this article we will begin by creating a new project using the web application template provided in Visual Studio. Once the project is created we will remove the unnecessary parts that are included in the template, modify the existing shared layout and home pages and finally set our project up to use the hot module replacement capabilities of webpack.
Parts
- Part 29: Offset Pager Urls
- Part 28: Offset Pager Start
- Part 27: Mock Context Builder
- Part 26: Mock Repository
- Part 25: Mock Async
- Part 24: Picture Tag Helper
- Part 23: Img DPR Tag Helper
- Part 22: Img Responsive Tag Helper
- Part 21: Img Optimized Display
- Part 20: Img Optimization
- Part 19: Img Lazy Loading
- Part 18: Img Responsive
- Part 17: Bottom Nav
- Part 16: Main Nav Cookie
- Part 15: Main Nav Mobile
- Part 14: Main Nav Search
- Part 13: Main Nav Auth
- Part 12: Main Nav Anchors
- Part 11: Main Nav Logo
- Part 10: Search Results
- Part 9: Search Manager
- Part 8: Search Start
- Part 7: Seeding the Database
- Part 6: Domain Database
- Part 5: Emailing Exceptions
- Part 4: Mailkit
- Part 3: View Renderer
- Part 2: Upgrade to 2.1
- Part 1: Quick Start
Project Creation
This project begins as they all do using File -> New -> Project in Visual Studio. You are of course free to use any IDE/Text editor that you prefer but we will be using Visual Studio and Visual Studio Code throughout this series. Both are available for free at Visual Studio Community and Visual Studio Code. When starting a new project I more likely than not begin with creating a blank solution (a), which at the time of the writing of this article will be targeting version 4.6.1 of the .Net Framework which I will name AspNetCoreAngularWebpack. Next we need to add a new project in our blank solution again using File -> New -> Project but this time we are going to create an ASP.NET Core Web Application (b), which I have named WebUi. After clicking ok we are presented with another dialog which we use to select the specific template that we want to start with. After making sure that the selection box at the top of the dialog says 'ASP.NET Core 2.0' we will select the 'Web Application' option with no authentication (c) and click ok.
-
WebUi
- WebUi.csproj
If you are using Visual Studio we need to disable its built in behaviour for dealing with typescript files since we will be using webpack to
transpile all of them. To do this we need to add an entry to our WebUi.csproj
file by simply right clicking on the project in the solution explorer
and selecting 'Edit WebUi.csproj' option which will open the file for us. Once it is open we need to add the property group
(d) to it. This will prevent the transpiling of the typescript code when our solution is built.
WebUi.csproj (1)
<PropertyGroup>
<TypeScriptCompileBlocked>True</TypeScriptCompileBlocked>
</PropertyGroup>
Time to lighten the load
-
WebUi
-
wwwroot
-
css
- site.css
- site.min.css
-
images
- banner1.svg
- banner2.svg
- banner3.svg
- banner4.svg
-
js
- site.js
- site.min.js
-
lib
- bootstrap
- jquery
- jquery-validation
- jquery-validation-unobtrusive
-
css
-
Pages
- _Layout.cshtml
- Index.cshtml
-
wwwroot
Now it is time for us to remove some files that were included by the project creation template. As shown in the folder structure we want
to remove all of the files contained in the various sub-folders of the wwwroot folder. Once that is completed we will modify the
_Layout.cshtml
(e) and
Index.cshtml
(f) files contained in our Pages
folder.
The _Layout.cshtml
references both css and javascript files that we will define in the next section.
_Layout.cshtml (1)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"]</title>
<environment include="Development">
<link rel="stylesheet" href="~/css/main.bundle.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="~/css/main.bundle.min.css" asp-append-version="true" />
</environment>
@RenderSection("Styles", required: false)
</head>
<body>
@RenderBody()
<environment include="Development">
<script src="~/js/common.bundle.js"></script>
<script src="~/js/main.bundle.js"></script>
</environment>
<environment exclude="Development">
<script src="~/js/common.bundle.min.js" asp-append-version="true"></script>
<script src="~/js/main.bundle.min.js" asp-append-version="true"></script>
</environment>
@RenderSection("Scripts", required: false)
</body>
</html>
Index.cshtml (1)
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<h1>Index</h1>
How about some scss and typescript
-
WebUi
-
Source
- main.site.scss
- main.site.ts
-
Source
As mentioned in the previous section we need to add the site wide scss and typescript files for our project. We do this by creating a
Source
folder at the root of our project. Inside the source folder we will create a
main.site.scss
(g) file and a
main.site.ts
(h) file. The contents of the files are of course just temporary
and are being used to make sure that our project is set up correctly. Now that we have scss and typescript files included in our project we need to be
able to convert them to css and javascript respectively. Luckily there exists another quick start article for webpack
quick start article for webpack.
main.site.scss (1)
body {
font-size: 96px;
}
main.site.ts (1)
document.body
.appendChild(document
.createElement("div")
.appendChild(document
.createTextNode("Hello World!")));
If all has gone well with the setup of webpack once we run the npm run build
command, at the root of our project, and
start the server by using the Debug -> Start Without Debugging
command located in the toolbar of Visual Studio we should
be greeted with the home page shown in (i).
That's nice but you promised I wouldn't need to use the refresh button
-
WebUi
- Startup.cs
The first thing we need to do start the process of enabling the hot module replacement capability of webpack is to install the
Microsoft.AspNetCore.SpaServices
package using NuGet. Simply right-click on the dependencies node in
our project explorer and select Manage NuGet Packages...
. Once that package is installed we need to
modify our Startup.cs
file to enable the hot module replacement (j).
Startup.cs (1)
...
using Microsoft.AspNetCore.SpaServices.Webpack;
...
namespace WebUi
{
public class Startup
{
...
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
...
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions
{
HotModuleReplacement = true
});
}
...
}
}
}
Returning to the browser and pressing refresh, for we are sure the last time, we are presented with an error which tells us that we a missing a couple of npm packages (k).
To fix this error we just need to install the packages shown in (l). Once the packages are added you will probably need to rebuild the project in order to make it work.
npm install (1)
npm install --save-dev
aspnet-webpack
webpack-hot-middleware
Does it work?
-
WebUi
-
Source
- main.site.ts
-
Source
After rebuilding the project and refreshing the browser if we make a change to our main.site.ts
file
(m) and save it we are presented with the output in our browser console shown in (n).
This output is telling us that the update that we were just attempting to make have been ignored. This is due to the fact the updates are an opt in
and we have not opted in for our module.
main.site.ts (2)
document.body
.appendChild(document
.createElement("div")
.appendChild(document
.createTextNode("Hello World! Does this work?")));
Opting in to HMR
-
WebUi
-
Source
- main.site.ts
-
Source
Before we make the last change to our main typescript file we need to include the node types if we have not already
done it previously as well as the types for the webpack module API (o). With that done we will return to our
main.site.ts
file and update it (p). As you can
see in (p) we have modified the appending to add a css class to the div so that we can
first remove it and then reappened it when a change is made.
npm install (2)
npm install --save-dev
@types/node
@types/webpack-env
main.site.ts (4)
if (process.env.NODE_ENV === "development" && module.hot) {
module.hot.accept();
const oldApp = document.getElementsByClassName("app")[0];
if (typeof oldApp !== "undefined" && oldApp !== null) {
oldApp.remove();
}
}
const app = document.createElement("div");
app.classList.add("app");
const child = document.createTextNode("Now it works");
app.appendChild(child);
document.body.appendChild(app);
With that done, and refreshing the browser one last time, changes that we make are now picked up automatically without the need for us to precess the refresh button.