.NET Framework Templates utilize MSBuild’s classic project format which can be developed using either VS.NET or Rider.

All VS.NET Single Page App templates are powered by Webpack which handles the development, testing and production builds of your Web App.

The Angular 5 template built and managed using Angular’s default angular-cli tooling. All other SPA Templates (inc. Angular 4) utilize a modernized Webpack build system, pre-configured with npm scripts to perform all necessary debug, production and live watched builds and testing.

Webpack takes care of all packaging and bundling requirements. Gulp is primarily used to provide a GUI to run the templates npm scripts in VS.NET’s Task Runner Explorer so all templates features can be accessed without leaving VS.NET, or if preferred each npm script can also be run on the command-line with:

$ npm run {script name}

Webpack works natively with npm packages and is used to handle all client assets which can leverage its
vast ecosystem of
loaders and
plugins to handle every kind of web asset, performing the necessary transformations to transpile it into the native formats browsers understand, loading it in browsers and generating source maps so their original source files can be debugged. The Webpack configuration is customized per build type where the optimal configuration is used in development for faster builds and easier debuggability whilst production builds are optimized for performance, size and cacheability.

TypeScript and Sass

All templates are configured with TypeScript which we believe provides the greatest value in enabling a highly-productive and maintainable code-base. TypeScript lets you utilize the latest ES6/7 features including terse ES6 modules and async/await support whilst being able to target down-level browsers. Other benefits include better documented typed APIs, instant compiler feedback, rich intellisense and refactoring support in a graceful superset of JavaScript that scales well to be able develop prototypes quickly then easily go back to harden existing code-bases with optional Type information, catching common errors at compile-time whilst annotating modules with valuable documentation other developers can benefit from.

Whilst CSS is a powerful language for styling Web Apps it lacks many of the DRY and reuse features we take for granted in a general purpose programming language. SASS is designed to close that gap with a number of useful extensions to CSS aimed at enabling a highly-maintainable, modular and configurable css code-base. If you prefer to avoid learning SASS you can continue using vanilla css which has been enhanced with autoprefixer and precss support.

End-to-end Typed APIs

Each template is seamlessly integrated with ServiceStack’s TypeScript Add Reference and generic TypeScript @servicestack/client to provide an end-to-end Typed API to call your Services that can be synced with your Server DTOs by running the npm (or Gulp) dtos script.

The imported client is an instance of JsonServiceClient declared in shared.ts module, configured with the BaseUrl at /:

exportvarclient=newJsonServiceClient(global.BaseUrl||'/');

The global.BaseUrl is defined in package.json and injected by Jest or Karma in order to be able to run end-to-end Integration tests.

Angular 5 HTTP Client

The Angular 5 template is also configured to use Angular’s built-in Rx-enabled HTTP Client with ServiceStack’s ambient TypeScript declarations, as it’s often preferable to utilize Angular’s built-in dependencies when available.

Optimal Dev Workflow with Hot Reloading

The templates include a hot-reload feature which works similar to ServiceStack Templates hot-reloading where in DebugMode it will long poll the server to watch for any modified files in /wwwroot and automatically refresh the page.

Hot Reloading works by leveraging ServiceStack Templates which works seamlessly with Webpack’s generated index.html where it evaluates server Template Expressions when returning the SPA home page. This is leveraged to enable Hot Reloading support by including the expression:

Quick tour of Webpack

Webpack has been pre-configured in all Single Paeege App templates to enable a flexible and feature-rich development model whose defaults in webpack.config.js will be able to support a large number of Web Apps without modification, leaving you free to focus on developing your App.

Although as Webpack is the central hub powering each template you’ll still want to become familiar with its four high-level concepts to understand how it’s new approach to Single Page App development works and how it can handle all your App’s dependencies and resources.

We’ll quickly touch on each of Webpack’s concepts by seeing how the React App’s webpack.config.js is configured to handle its TypeScript sources, sass/css files and their references.

A separate vendor Webpack configuration is maintained for 3rd party Vendor dependencies independent from your App’s code-base so they only need to be compiled once when adding a new dependency instead of each time your App changes. To include another vendor library in the vendor build, add the module name or the resource your App uses in the VENDOR collection, e.g:

Here we can see that our Webpack config supports multiple isProd and isDev configurations, isDev is used for development builds where Webpack bundles our website in the /dist folder whilst isProd is used for production builds which is instead bundled in the /wwwroot/dist folder with each .js bundle including a [chunkhash] cache-breaker in its filename.

It also generates vendor-manifest.json which is referenced in the App’s webpack.config.js to tell it which dependencies are included in the vendor bundles so they don’t need to be compiled with the App:

Loaders are the flexible engine that sets Webpack apart where it’s able to leverage its vast ecosystem where there’s a loader for every kind of web asset typically used when developing Web Apps.

Loaders are configured in the rules section and invoked using node’s require() statement or ES6/TypeScript’s import statement. Rules use the test regex to specify which files they should apply to whilst the loader property tells Webpack which loader to load them with. Each loader is self-contained in a separate npm package that needs to be made available to your project by adding them to your package.json devDependencies.

This configuration instructs Webpack to load any .ts or .tsx files using the TypeScript loader for webpack which is then responsible for compiling the source files with TypeScript’s compiler.

Loaders are also chainable as seen in the .css and .scss rules which starts from right-to-left where the output of the rightmost loader is passed into the next loader on its left and so on.

{test:/\.css$/,use:['style-loader','css-loader',postcssLoader]},

Here the .css contents are first processed with postcssLoader which uses precss to let you use basic sass-like features in vanilla .css files and autoprefixer which lets you write clean standard css rules like:

a{display:flex;}

Which autoprefixer will expand to include vendor prefixes, maximizing support for older browser versions:

The output of postcssLoader then gets passed into css-loader which processes any css @import() and @url() rules and loads them with Webpack’s require() to ensure its references are also processed by Webpack.

The output of css-loader then gets passed into style-loader who injects the resulting css fragments within <style></style> tags in the browser’s DOM which is how Web App styles in development builds are still visible despite their being no .css files written. Sass.scss files are handled similarly to .css files except they’re initially loaded with sass-loader which converts them into .css. Both these rules together let you use your preferred choice of .scss or .css files to style your Web App.

There’s a separate configuration needed for Production builds which is configured to minify the css and write their contents out into separate .css bundles as defined in the plugins section below:

/wwwroot WebRoot Path for .NET Framework Templates

To simplify migration efforts of ServiceStack projects between .NET Core and .NET Framework, all SPA and Website Templates are configured to use .NET Core’s convention of /wwwroot for its public WebRoot Path. The 2 adjustments needed to support this was configuring ServiceStack to use the /wwwroot path in AppHost:

Deployments

When your App is ready to deploy, run the publish npm (or Gulp) script to package your App for deployment:

npm run publish

Which creates a production build of your App where the .css files are written using ExtractTextPlugin and the resulting .js files minified with UglifyJS. The full production build is generated in in /wwwroot/dist folder where it’s ready for an XCOPY, rsync or MSDeploy deployment.

In .NET Core 2.0 projects the publish npm script runs dotnet publish -c Release to Publish a Release build of your App in the /bin/netcoreapp2.0/publish folder which can then copied to remote server or an included in a Docker container to deploy your App.

Loading Dependencies

Now that we’ve covered how Webpack is configured, the next step is showing how to make use of it, by loading your App’s resources using node’s require() or TypeScript’s import statement.

This can be seen in the App’s main.ts starting point where it imports bootstrap.css and font-awesome.css directly from the installed bootstrap and font-awesome npm packages as well as a local ./app.scss SASS file which lives side-by-side next to TypeScript source files:

Importing bootstrap and font-awesome also imports their references, including any images, fonts, svg and other .css files. These are all transparently added to the webpack build and bundled with the rest of your app.

In production builds the file-loader copies their references to the output folder, embedding its sha512 hash in each file name. url-loader works similarly but also has the option of embedding file contents below the configured 10000 byte limit inline inside a Data URI to reduce network requests in production builds.

require() can also be used to load resources in other files which is how images can be imported in the index.template.ejs home page template:

<imgsrc="<%=require('./src/assets/img/logo.png')%>"/>

Or inside App components, both of which returns the image url after it has been processed by Webpack’s loaders, e.g:

constructor(){this.logoUrl=require("./assets/img/logo.png");}

In production builds this returns a relative url to the output image, e.g: img/logo.36166adfacf0c8cc11d493f2161164fd.png.

Webpack builds

By importing all your WebApp resources into Webpack it’s able to maintain a knowledgeable graph of all your Web Apps dependencies where it lets you define how they’re handled at a macro level making it easy to incorporate design-time features like TypeScript and Sass whilst also taking care of generating optimal builds for development, testing and production.

Development builds

You’ll use development builds when developing your app locally which you can run with either the webpack-build Gulp task in VS.NET’s Task Runner Explorer GUI or by running the build npm script on the command-line:

The lack of .css files or source-maps are due to being embedded in the .js bundles and injected in the browser’s DOM within <style></style> tags.

After the Webpack development build has completed you can just run or refresh your ASP.NET Web App to view the latest changes.

Production builds

When your App is ready to deploy you can run a production build using the webpack-build-prod Gulp task or the build-prod npm script:

$ npm run build-prod

This will bundle and generate your WebApp in the /wwwroot/dist folder with css and source maps extracted and written into separate files, css and js minified and all assets emitted with cache-breaking hashes, similar to:

Development workflow

Executing a development build of Webpack is all that’s required to be able to see our changes but it can take a while to run a full dev build which negatively impacts our fast iterative dev workflow. It’s instead recommended to leave webpack running in the background and have it watch for changes so it only needs to rebuild assets that have changed, which it’s able to do very quickly.

Whilst we recommend running the dev Gulp or npm script during development to run a live watched development, you can instead run the npm run dev-server npm script to run a development build of your app through Webpack’s dev-server which has it’s own built-in hot reloading for when your Client Apps source code changes.

Webpack watch

Our recommendation during development is to run the dev Gulp task and leave it running in the background, or if preferred, run the dev npm script on the command-line with:

$ npm run dev

Webpack dev initially generates a full development build of your Web App then stays running in the background to process files as they’re changed. This enables the normal dev workflow of running your ASP.NET Web App from VS.NET, saving changes locally which are then reloaded using ServiceStack’s built-in hot reloading. Alternatively hitting F5 will refresh the page and view the latest changes.

Each change updates the output dev resources so even if you stop the dev task your Web App remains in a working state that’s viewable when running the ASP.NET Web App.

Live reload with Webpack Dev Server

The alternative dev workflow is to run the dev-server npm script to run the Webpack dev server:

$ npm run dev-server

This launches the Webpack dev server listening at http://localhost:3000/ and configured to proxy all non-Webpack HTTP requests to the ASP.NET Web App where it handles all Server API requests. The benefit of viewing your App through the Webpack dev server is its built-in Live Reload feature where it will automatically reload the page as resources are updated. We’ve found the Webpack dev server ideal when developing UI’s where your Web App is running side-by-side VS.NET, where every change saved triggers the dev server to reload the current page so changes are visible immediately.

The disadvantage of the dev server is that all transformations are kept in memory so when the dev server is stopped, the Web Apps resources are lost, so it requires a webpack-build in order to generate a current build. There’s also a slight lag in API requests resulting from each server request being handled by both Webpack’s Dev Server and ASP.NET’s IIS Express.

Watched .NET Core builds

.NET Core projects can also benefit from Live Coding using dotnet watch which performs a “watched build” where it automatically stops, recompiles and restarts your .NET Core App when it detects source file changes. You can start a watched build from the command-line with:

$ dotnet watch run

Single Page App Features

Our goals with the Single Page Templates is to provide a highly productive base that’s ideal for developing small to medium-sized JavaScript Web Apps including just the core essentials that pack the most productive punch whilst adding minimal complexity and required configuration, whilst still remaining open-ended to easily plug-in other tools into your Webpack configuration you believe will improve your development workflow.

With these goals in mind we’ve hand-picked and integrated a number of simple best-of-breed technologies so you’ll be immediately productive:

Updating Server TypeScript DTOs

To get the latest Server DTOs, build the ASP.NET Web App then either right-click on dtos.ts and select Update ServiceStack Reference from the Context Menu:

Or alternatively you can run the dtos Gulp task in Task Runner Explorer GUI, or if preferred, run the script on the command-line with:

$ npm run dtos

Routing Enabled, Multi-page Layout

All templates have multiple views with Routing enabled so they’re all setup to develop multi-page navigable Single Page Apps out-of-the-gate. All templates are designed to be functionally equivalent utilizing a 3 page tabbed layout but implemented using their own idiomatic style so you’ll be able to easily inspect and compare the structure and ergonomics of each JavaScript framework to evaluate the one you like best.

Deep linkable Pretty URLs

All Single Page Apps are configured to use Pretty URLs (i.e. without #!) and are deep-linkable so they behave similarly to server-generated websites in that they support the back button and full-page reloads to refresh the current page. This works behind the scenes using a [FallbackRoute] to have all unknown routes return the home page so the route can be handled on the client to load the appropriate view.

Angular and Vue are configured to use the Karma test runner with the headless phantomjs WebKit browser so the behavior of Components are tested in a real browser.

Tests can be run with the tests-run gulp task, or on the command-line using any of npm’s testing conventions:

$ npm test
$ npm t

Live Testing

Each template also includes support for Live Testing which can be run in the background by clicking the tests-watch Gulp task or on the command-line with:

$ npm run test-watch

Live testing automatically re-runs JavaScript tests after each change to provide instant feedback to detect when changes causes existing tests to fail.

Test Coverage

Angular, Aurelia and React are also pre-configured to be able to show test coverage, viewable by running the tests-coverage Gulp task or on the command-line with:

$ npm run test-coverage

Multi-Project Solution Layout

All templates follow our Recommended Physical Project Structure ensuring ServiceStack projects starts off from an optimal logical project layout, laying the foundation for growing into a more maintainable, cohesive and reusable code-base.

Track progress whilst templates are being created

The Single Page App templates sources their client dependencies from npm which can take up to few minutes to finish downloading and installing. You’ll be able to see its progress by looking at the Bower/npm Output Window in VS.NET:

You’ll be able to detect when it’s finished by waiting for the original contents of wwwroot/index.html:

Keep Desktop node and VS.NET in sync

Unfortunately VS.NET 2017 ships with an outdated version of node.exe which can be problematic when trying to run scripts from the command-line with a locally installed version of node as native module packages like node-sass are coupled to the specific node version and platform they were installed with. This can easily be resolved by configuring VS.NET to use your Desktop version of node instead by adding its the C:\Program Files\nodejs folder as the first path in: