{"id":9176,"date":"2017-02-14T12:11:50","date_gmt":"2017-02-14T20:11:50","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=9176"},"modified":"2017-02-14T12:11:50","modified_gmt":"2017-02-14T20:11:50","slug":"building-single-page-applications-on-asp-net-core-with-javascriptservices","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/building-single-page-applications-on-asp-net-core-with-javascriptservices\/","title":{"rendered":"Building Single Page Applications on ASP.NET Core with JavaScriptServices"},"content":{"rendered":"<p><em>This is a guest post by <a href=\"http:\/\/blog.stevensanderson.com\/\">Steve Sanderson<\/a><\/em><\/p>\n<p class=\"code-line\">\n  These days, many developers are building Single-Page Applications (SPAs) using frameworks such as Angular or React. These are powerful frameworks that produce a great end-user experience, but we often hear that building these applications is complicated. It can be a challenge to integrate server-side and client-side code well, or even just to choose a productive project setup in the first place.<!--more-->\n<\/p>\n<p class=\"code-line\">\n  Our goal is to make ASP.NET Core the best server-side platform for these kinds of projects. So, we recently shipped three new NuGet packages that are intended to simplify SPA development and add powerful, useful features:\n<\/p>\n<p><li class=\"code-line\">\n  <code>Microsoft.AspNetCore.SpaTemplates<\/code> plugs into <code>dotnet new<\/code>, providing project templates for Angular 2, Aurelia, Knockout, React, and React+Redux applications.\n<\/li>\n<li class=\"code-line\">\n  <code>Microsoft.AspNetCore.SpaServices<\/code> is how <code>SpaTemplates<\/code>-produced projects work internally. It provides useful features for SPA applications, such as server-side rendering for Angular and React applications, plus integration with Webpack build middleware.\n<\/li>\n<li class=\"code-line\">\n  <code>Microsoft.AspNetCore.NodeServices<\/code> is how <code>SpaServices<\/code> works internally. It&#8217;s a low-level library that gives a fast, robust way for ASP.NET Core applications to run arbitrary JavaScript code on the server.\n<\/li>\n<\/p>\n<p class=\"code-line\">\n  Collectively, these features go by the name <em>JavaScriptServices<\/em>. You&#8217;ll find the source code, issue tracker, and documentation on <a href=\"https:\/\/github.com\/aspnet\/JavaScriptServices\">the JavaScriptServices GitHub repository<\/a>.\n<\/p>\n<h2 class=\"code-line\" id=\"prerequistes\">\n  Prerequistes\n<\/h2>\n<p class=\"code-line\">\n  To work with these technologies, first make sure you&#8217;ve installed the following:\n<\/p>\n<p><li class=\"code-line\">\n  <a href=\"https:\/\/github.com\/dotnet\/core\/tree\/master\/release-notes\">.NET Core SDK 1.0 RC4<\/a> (or later) for Windows, Mac, or Linux<\/p>\n<ul>\n<li>\n      Or, if you&#8217;re on Windows, you can install the latest <a href=\"https:\/\/www.visualstudio.com\/vs\/visual-studio-2017-rc\/\">Visual Studio 2017 RC<\/a>, which includes it. Be sure you have VS2017 build 26206 or later &#8211; older versions won&#8217;t work.\n    <\/li>\n<\/ul>\n<\/li>\n<p><li class=\"code-line\">\n  <a href=\"https:\/\/nodejs.org\/en\/\">Node.js<\/a>, version 6 or later\n<\/li>\n<\/p>\n<h2 class=\"code-line\" id=\"getting-started\">\n  Getting started\n<\/h2>\n<p class=\"code-line\">\n  The easiest way to get started is by using one of the project templates we&#8217;ve made available. These plug into the standard <code>dotnet new<\/code> command, and work on Windows, Mac, and Linux.\n<\/p>\n<p class=\"code-line\">\n  To install the Single Page Application (SPA) templates, run the following command:\n<\/p>\n<pre>dotnet new --install Microsoft.AspNetCore.SpaTemplates::*<\/pre>\n<p class=\"code-line\">\n  One this is installed, you&#8217;ll see that <code>dotnet new<\/code> now can produce projects based on <code>angular<\/code>, <code>aurelia<\/code>, <code>knockout<\/code>, <code>react<\/code>, and <code>reactredux<\/code>:\n<\/p>\n<p><figure id=\"attachment_9185\" aria-labelledby=\"figcaption_attachment_9185\" class=\"wp-caption aligncenter\" ><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/02\/dotnet-new-templates-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/02\/dotnet-new-templates-1-1024x563-1.png\" alt=\"Template list for the &quot;dotnet new&quot; command\" class=\"size-large wp-image-9185\" width=\"879\" height=\"483\" \/><\/a><figcaption id=\"figcaption_attachment_9185\" class=\"wp-caption-text\">Template list for the &#8220;dotnet new&#8221; command<\/figcaption><\/figure><\/p>\n<p class=\"code-line\">\n  To actually generate a new project, first create an empty directory for it to go into, <code>cd<\/code> to that directory, and then use <code>dotnet new<\/code> to create your project. For example:\n<\/p>\n<pre>dotnet new angular<\/pre>\n<p class=\"code-line\">\n  There are two ways to run your new project: via the command line, or via Visual Studio (Windows only).\n<\/p>\n<p class=\"code-line\">\n  <strong>Option 1: Running via the Command Line<\/strong>\n<\/p>\n<p class=\"code-line\">\n  To run your project on the command line, you must first restore both the .NET and NPM dependencies. Execute the following commands:\n<\/p>\n<pre>dotnet restore \nnpm install<\/pre>\n<p class=\"code-line\">\n  Then, set an environment variable to tell ASP.NET to run in development mode:\n<\/p>\n<p><li class=\"code-line\">\n  If you&#8217;re using PowerShell in Windows, execute <code>$Env:ASPNETCORE_ENVIRONMENT = \"Development\"<\/code>\n<\/li>\n<li class=\"code-line\">\n  If you&#8217;re using <code>cmd.exe<\/code> in Windows, execute <code>setx ASPNETCORE_ENVIRONMENT \"Development\"<\/code>, and then restart your command prompt to make the change take effect\n<\/li>\n<li class=\"code-line\">\n  If you&#8217;re using Mac\/Linux, execute <code>export ASPNETCORE_ENVIRONMENT=Development<\/code>\n<\/li>\n<\/p>\n<p class=\"code-line\">\n  Finally, you can start your new app by running <code>dotnet run<\/code>. It will listen on port 5000, so point your browser to <code>http:\/\/localhost:5000<\/code> to see it.\n<\/p>\n<p class=\"code-line\">\n  <strong>Option 2: Running in Visual Studio 2017 RC<\/strong>\n<\/p>\n<p class=\"code-line\">\n  If you&#8217;re on Windows and want to use Visual Studio 2017 RC, you can simply open your newly-generated <code>.csproj<\/code> file in Visual Studio. It will take care of restoring the .NET and NPM dependencies for you (though it can take a few minutes).\n<\/p>\n<p class=\"code-line\">\n  When your dependencies are restored, just press Ctrl+F5 to launch the application in a browser as usual.\n<\/p>\n<p class=\"code-line\">\n  <strong>Alternative: Creating a SPA project via Yeoman<\/strong>\n<\/p>\n<p class=\"code-line\">\n  If for some reason you&#8217;re stuck on older (pre-RC4) versions of .NET Core tooling, or if you need to use Visual Studio 2015, then instead of using the <code>dotnet new<\/code> command, you can use <a href=\"http:\/\/yeoman.io\/\">Yeoman<\/a> to create your new project. You&#8217;ll need <a href=\"https:\/\/www.microsoft.com\/net\/download\/core#\/current\">.NET Core SDK 1.1<\/a> and <a href=\"https:\/\/nodejs.org\/en\/\">Node.js<\/a> version 6 or later.\n<\/p>\n<p class=\"code-line\">\n  To install Yeoman and these templates, open a command prompt, and then run the following:\n<\/p>\n<pre>npm install -g yo generator-aspnetcore-spa<\/pre>\n<p class=\"code-line\">\n  Then, <code>cd<\/code> to an empty directory where you want your project to go, and then run Yeoman as follows:\n<\/p>\n<pre>yo aspnetcore-spa<\/pre>\n<p class=\"code-line\">\n  Once your new project is created, Yeoman will automatically fetch its .NET and NPM dependencies. You can then set the <code>ASPNETCORE_ENVIRONMENT<\/code> variable as described above, then run your project by executing <code>dotnet run<\/code>.\n<\/p>\n<h2 class=\"code-line\" id=\"your-new-single-page-application-project\">\n  Your new Single-Page Application project\n<\/h2>\n<p class=\"code-line\">\n  Whichever way you choose to create and run your project, here&#8217;s how it will initially look:\n<\/p>\n<p><figure id=\"attachment_9206\" aria-labelledby=\"figcaption_attachment_9206\" class=\"wp-caption aligncenter\" ><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/02\/angular-app-home.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/02\/angular-app-home-1024x590-1.png\" alt=\"Generated Angular application homepage\" class=\"wp-image-9206 size-large\" width=\"879\" height=\"506\" \/><\/a><figcaption id=\"figcaption_attachment_9206\" class=\"wp-caption-text\">Generated Angular application homepage<\/figcaption><\/figure><\/p>\n<p class=\"code-line\">\n  Let&#8217;s now look at some of the features in the templates.\n<\/p>\n<h3 class=\"code-line\" id=\"server-side-prerendering\">\n  Server-side prerendering\n<\/h3>\n<p class=\"code-line\">\n  If you&#8217;re using the Angular or React+Redux template, then you will have <em>server-side prerendering<\/em>. This makes your application&#8217;s initial UI appear much more quickly, because users don&#8217;t have to wait for their browser to download, evaluate, and execute large JavaScript libraries before the application appears. This works by executing Angular\/React\/etc components on the server as well as on the client. To a limited extent, it means your SPA can even work with JavaScript disabled in the browser, which is great for ensuring your app is accessible to all search engine crawlers.\n<\/p>\n<p class=\"code-line\">\n  As a quick (but artificial) demo to prove this is working, just try disabling JavaScript in your browser. You&#8217;ll still be able to load the page and navigate around. Bear in mind that <em>only<\/em> navigation works without JavaScript, not any other user actions that are meant to execute JavaScript.\n<\/p>\n<p class=\"code-line\">\n  The primary use case for server-side prerendering is to make your page appear extremely quickly, even if the user has a slow network connection or a slow mobile device, and even if your SPA codebase is very large. The client-side code will download in the background, and then takes over execution as soon as it&#8217;s loaded. This feature solves what is otherwise a significant drawback of large SPA frameworks.\n<\/p>\n<h3 class=\"code-line\" id=\"webpack-dev-middleware\">\n  Webpack dev middleware\n<\/h3>\n<p class=\"code-line\">\n  These projects all use Webpack as a front-end build system, because it&#8217;s the dominant system used by Angular\/React\/etc developers. One of its powerful features is the ability, during development, to keep running in the background and incrementally recompile any modified code extremely quickly.\n<\/p>\n<p class=\"code-line\">\n  Webpack dev middleware is integrated into these projects via <code>SpaServices<\/code>. As long as your application is running in the <code>Development<\/code> environment, you can modify your client-side code (e.g., the TypeScript, or in Angular, the <code>html<\/code> files that are compiled into your components), and the updated version is almost immediately available to the browser. You don&#8217;t have to run any build commands manually.\n<\/p>\n<h3 class=\"code-line\" id=\"hot-module-replacement\">\n  Hot Module Replacement\n<\/h3>\n<p class=\"code-line\">\n  Hot Module Replacement (HMR) takes the dev middleware feature a step further. It sets up a live link between the Webpack dev middleware service and your application running in your local browser. Whenever your source files change and the dev middleware provides an incremental update, HMR pushes it to your local browser immediately. It does this<em>without<\/em> causing a full page reload (because that might wipe out useful state, such as any debugging session you have in progress). It directly updates the affected modules in your running application.\n<\/p>\n<p class=\"code-line\">\n  The purpose of this is to give you a faster, more productive development experience. To see it working, just edit one of the TypeScript or HTML files in your <code>\/ClientApp<\/code> directory. You&#8217;ll see the corresponding update appear in your browser right away.\n<\/p>\n<p class=\"code-line\">\n  If you&#8217;re using React or React+Redux, your application state will br preserved through the update. If you cause a compiler error, its details will appear as an overlay in your browser. Once you fix the compiler error, your application will resume, still preserving its previous in-memory state.\n<\/p>\n<p class=\"code-line\">\n  <em>Note: HMR is currently available in all the templates except for the Aurelia one. We aim to add it to the Aurelia template soon.<\/em>\n<\/p>\n<h3 class=\"code-line\" id=\"efficient-production-builds\">\n  Efficient production builds\n<\/h3>\n<p class=\"code-line\">\n  These project templates are set up to build your client-side assets (TypeScript, bundled HTML, CSS, etc.) in two different modes:\n<\/p>\n<p><li class=\"code-line\">\n  <em>Development<\/em>, which includes source maps for easy debugging\n<\/li>\n<li class=\"code-line\">\n  <em>Production<\/em>, which tightly minifies your code and does not include source maps\n<\/li>\n<\/p>\n<p class=\"code-line\">\n  Since this is achieved using Webpack 2, you can easily edit the Webpack configration files to set up whatever combination of build options you require, or to enable support for compiling LESS\/SASS or other popular front-end file types and languages. See the <code>webpack.config.js<\/code> file at the root of the project, and <a href=\"https:\/\/webpack.js.org\/configuration\/\">Webpack 2 documentation<\/a> for details of the available options. There&#8217;s a <a href=\"https:\/\/github.com\/aspnet\/JavaScriptServices\/tree\/dev\/src\/Microsoft.AspNetCore.SpaServices#example-a-simple-webpack-setup-that-builds-less\">guide to enabling LESS support<\/a> in the <code>SpaServices<\/code> documentation.\n<\/p>\n<h4 class=\"code-line\" id=\"invoking-webpack-manually\">\n  Invoking Webpack manually\n<\/h4>\n<p class=\"code-line\">\n  The dev middleware feature means you don&#8217;t normally need to invoke Webpack manually. But if you do want to run Webpack manually on the command line, you can run the following:\n<\/p>\n<pre>webpack --config webpack.config.vendor.js \nwebpack<\/pre>\n<p class=\"code-line\">\n  The first line repackages all of your <em>vendor<\/em> dependencies, i.e., third party libraries such as Angular or React and all their dependencies. You only need to run this if you modify your third-party dependencies, such as if you update to a newer version of your chosen SPA framework.\n<\/p>\n<p class=\"code-line\">\n  The second line (running <code>webpack<\/code> with no parameters) rebuilds your own application code. Separating your own application code from your vendor dependencies makes your builds much faster.\n<\/p>\n<p class=\"code-line\">\n  These commands will produce development-mode builds. If you want to produce production-mode builds, then also pass the flag <code>--env.prod<\/code> when invoking Webpack.\n<\/p>\n<h4 class=\"code-line\" id=\"publishing-for-deployment\">\n  Publishing for deployment\n<\/h4>\n<p class=\"code-line\">\n  To deploy your application to production, you can use the <em>publish<\/em> feature which is built into <code>dotnet<\/code> command line tooling and Visual Studio. For example, on the command line, run:\n<\/p>\n<pre>dotnet publish -c Release<\/pre>\n<p class=\"code-line\">\n  This will produce a ready-to-deploy production build of your application. It includes .NET code compiled in <em>Release<\/em> mode, and invokes Webpack with the <code>--env.prod<\/code> flag to produce a production build of front-end assets. Equivalently, you can use the <em>Publish<\/em> option from Visual Studio&#8217;s <em>Build<\/em> menu.\n<\/p>\n<h3 class=\"code-line\" id=\"learn-more\">\n  Learn more\n<\/h3>\n<p class=\"code-line\">\n  Learn more about <code>SpaServices<\/code> and see other usage examples at the <a href=\"https:\/\/github.com\/aspnet\/JavaScriptServices\/tree\/dev\/src\/Microsoft.AspNetCore.SpaServices#microsoftaspnetcorespaservices\">SpaServices online documentation.<\/a>\n<\/p>\n<h2 class=\"code-line\" id=\"using-nodeservices-directly\">\n  Using NodeServices directly\n<\/h2>\n<p class=\"code-line\">\n  Even if you&#8217;re not building a single-page application, it can be extremely useful to be able to run JavaScript on the server in certain cases. Why would you want to do this? Primarily, because a huge number of useful, high-quality Web-related open source packages are in the form of Node Package Manager (NPM) modules. NPM is the largest repository of open-source software packages in the world, and the <code>Microsoft.AspNetCore.NodeServices<\/code> package means that you can use any of them in your ASP.NET Core application.\n<\/p>\n<p class=\"code-line\">\n  Of course, this is how <code>SpaServices<\/code> works behind the scenes. For example, to prerender Angular or React components on the server, it needs to execute your JavaScript on the server. It does this via <code>NodeServices<\/code>, which starts up a hidden Node.js instance and provides a fast and robust way of making calls into it from .NET.\n<\/p>\n<h2 class=\"code-line\" id=\"walkthrough-using-nodeservices\">\n  Walkthrough: Using NodeServices\n<\/h2>\n<p class=\"code-line\">\n  For this walkthrough, first create a new application with ASP.NET Core 1.1.0 or later.\n<\/p>\n<p class=\"code-line\">\n  Next, add a reference to <code>Microsoft.AspNetCore.NodeServices<\/code> using one of these techniques:\n<\/p>\n<p><li class=\"code-line\">\n  If you use Visual Studio, use its <em>NuGet Package Manager<\/em> dialog\n<\/li>\n<li class=\"code-line\">\n  Or, if you have .NET Core RC 4 (or later) tools, you can execute <code>dotnet add package Microsoft.AspNetCore.NodeServices<\/code>\n<\/li>\n<li class=\"code-line\">\n  Or, if you have a <code>project.json<\/code>-based project, you can edit your <code>project.json<\/code> file to add a reference to <code>Microsoft.AspNetCore.NodeServices<\/code> and then run <code>dotnet restore<\/code>\n<\/li>\n<\/p>\n<p class=\"code-line\">\n  Next, configure ASP.NET&#8217;s dependency injection (DI) system to make it aware of NodeServices. In your <code>Startup.cs<\/code> file, in the <code>ConfigureServices<\/code> method, add the following line:\n<\/p>\n<pre>services.AddNodeServices();<\/pre>\n<p class=\"code-line\">\n  You&#8217;re now ready to receive instances of <code>INodeServices<\/code> in your application. <code>INodeServices<\/code> is the API through which .NET code can make calls into JavaScript that runs in a Node environment. Let&#8217;s start just by getting back a string from JavaScript.\n<\/p>\n<p class=\"code-line\">\n  In <code>HomeController.cs<\/code>, at the top, add the line <code>using Microsoft.AspNetCore.NodeServices;<\/code>. Now amend its <code>About<\/code> method as follows, so that it makes a call into Node.js and awaits the result:\n<\/p>\n<p class=\"code-line\">\n  If you run your application now and try to browse to the <em>about<\/em> page, you&#8217;ll get an error saying <em>Cannot find module &#8216;myNodeModule.js&#8217;<\/em>. This is because NodeServices tried to invoke your JavaScript code, but no such code was found. Of course, you need to create a file with that name.\n<\/p>\n<p class=\"code-line\">\n  At the root directory of your project, add a file called <code>myNodeModule.js<\/code>, containing the following:\n<\/p>\n<p class=\"code-line\">\n  Finally, display the result by editing your <code>Views\/Home\/About.cshtml<\/code> view so it emits the <code>ResultFromNode<\/code> value:\n<\/p>\n<p class=\"code-line\">\n  Now you&#8217;ll see your JavaScript code was executed on the server, the result went back to your .NET code, and is displayed to the visitor:\n<\/p>\n<p><figure id=\"attachment_9205\" aria-labelledby=\"figcaption_attachment_9205\" class=\"wp-caption aligncenter\" ><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/02\/hello-from-node-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/02\/hello-from-node-1-1024x576-1.png\" alt=\"Screenshot displaying value returned from Node.js\" class=\"size-large wp-image-9205\" width=\"879\" height=\"494\" \/><\/a><figcaption id=\"figcaption_attachment_9205\" class=\"wp-caption-text\">Screenshot displaying value returned from Node.js<\/figcaption><\/figure><\/p>\n<p class=\"code-line\">\n  Since you can now run arbitrary server-side JavaScript in your application, you have access to the entire NPM ecosystem. This provides new ways of solving many problems, including dynamic transpilation of TypeScript\/SASS\/ES2017, image\/audio manipulation, or running on the server many libraries that would otherwise run in the browser.\n<\/p>\n<h3 class=\"code-line\" id=\"example-rendering-chartsgraphs-on-the-server\">\n  Example: Rendering charts\/graphs on the server\n<\/h3>\n<p class=\"code-line\">\n  Imagine you want to display some charts and graphs in your web pages. These need to be constructed dynamically using data from some backend database or web service.\n<\/p>\n<p class=\"code-line\">\n  There are various ways to approach this. One popular choice today is to have the server send raw data values to the browser, and then use a client-side library to actually draw the charts. For example, you could use the extremely popular <a href=\"https:\/\/gionkunz.github.io\/chartist-js\/\">chartist.js<\/a> library.\n<\/p>\n<p class=\"code-line\">\n  This works well, but there may be cases where you don&#8217;t want to depend on executing client-side code for this (you might want to avoid that overhead for the browser, or can&#8217;t rely on JavaScript being enabled and not blocked on all your customers&#8217; devices).\n<\/p>\n<p class=\"code-line\">\n  <code>NodeServices<\/code> lets you continue using Chartist, but run it on the server, so that browsers don&#8217;t need to run any JavaScript code to get the graphs. To do this, following on from the previous example, add the Chartist library to your project by running the following in a command line:\n<\/p>\n<pre>npm install --save node-chartist<\/pre>\n<p class=\"code-line\">\n  Next, you can amend your <code>About<\/code> method to pass some data and options from .NET code into your Node.js module:\n<\/p>\n<p class=\"code-line\">\n  The <code>options<\/code> and <code>data<\/code> objects, when JSON-serialized, will be in exactly the correct format for Chartist. You can learn more about the available chart types and option in <a href=\"https:\/\/gionkunz.github.io\/chartist-js\/\">Chartist&#8217;s documentation<\/a>.\n<\/p>\n<p class=\"code-line\">\n  The next job is to update <code>myNodeModule.js<\/code> so that it receives the <code>options<\/code> and <code>data<\/code> parameters, and passes them through to Chartist. When it gets back the rendered chart, it can return it to the .NET code::\n<\/p>\n<p class=\"code-line\">\n  If you know JavaScript, you&#8217;ll recognize that Chartist&#8217;s <code>generate<\/code> function returns a <code>Promise<\/code> object. This code uses the <code>then<\/code> method to pass the result &#8211; which in this case is a string of SVG markup &#8211; back to .NET via the supplied <code>callback<\/code> parameter. In effect, the Node.js module you&#8217;re writing here is a simple adapter between .NET code and (in this case) the Chartist library.\n<\/p>\n<p class=\"code-line\">\n  There are two final things you need to do to see the graph in your page:\n<\/p>\n<p><li class=\"code-line\">\n  In your <code>About.cshtml<\/code>, replace <code>@ViewData[\"ResultFromNode\"]<\/code> with <code>@Html.Raw(ViewData[\"ChartMarkup\"])<\/code>. You need to use <code>Html.Raw<\/code> because Chartist will return SVG markup.\n<\/li>\n<li class=\"code-line\">\n  In your <code>Views\/Shared\/_Layout.cshtml<\/code> file, in the <code>&lt;head&gt;<\/code> element, add a reference to a suitable stylesheet for the Chartist charts. This is how you control the color scheme and visual style. For example, use the default Chartist CSS file available via CDN: <code>&lt;link rel=\"stylesheet\" href=\"http:\/\/cdn.jsdelivr.net\/chartist.js\/latest\/chartist.min.css\"&gt;<\/code>\n<\/li>\n<\/p>\n<p class=\"code-line\">\n  Now when you run your application and visit the <em>About<\/em> page, you&#8217;ll see your chart:\n<\/p>\n<p><figure id=\"attachment_9195\" aria-labelledby=\"figcaption_attachment_9195\" class=\"wp-caption aligncenter\" ><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/02\/chartist-chart-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/02\/chartist-chart-1-1024x801-1.png\" alt=\"Screenshot displaying server-rendered chart\" class=\"size-large wp-image-9195\" width=\"879\" height=\"688\" \/><\/a><figcaption id=\"figcaption_attachment_9195\" class=\"wp-caption-text\">Screenshot displaying server-rendered chart<\/figcaption><\/figure><\/p>\n<p class=\"code-line\">\n  This looks identical to how Chartist would render the same data on the client, except now it involves no client-side code for the browser to execute. Chartist is relatively simple. If it turns out that your requirements are too sophisticated for it, you could switch to the incredibly powerful <a href=\"https:\/\/d3js.org\/\">D3.js<\/a>, because that also supports running in Node and therefore works with <code>NodeServices<\/code>.\n<\/p>\n<p class=\"code-line\">\n  <strong>Summary<\/strong>\n<\/p>\n<p class=\"code-line\">\n  Of course, rendering charts is just one example. <code>NodeServices<\/code> allows ASP.NET Core developers to make use of the entire NPM ecosystem, which gives rise to a huge range of possibilities.\n<\/p>\n<p class=\"code-line\">\n  You can read more about the APIs in <code>NodeServices<\/code> (for invoking Node.js code from .NET) <a href=\"https:\/\/github.com\/aspnet\/JavaScriptServices\/tree\/dev\/src\/Microsoft.AspNetCore.NodeServices#microsoftaspnetcorenodeservices\">at the NodeServices project on GitHub<\/a>. Similarly, you can read more about the APIs in <code>SpaServices<\/code> (a package of SPA-specific helpers, e.g., for server-side prerendering) <a href=\"https:\/\/github.com\/aspnet\/JavaScriptServices\/tree\/dev\/src\/Microsoft.AspNetCore.SpaServices#microsoftaspnetcorespaservices\">at the SpaServicesProject on GitHub<\/a>.\n<\/p>\n<h2 class=\"code-line\" id=\"try-it-out\">\n  Try it out\n<\/h2>\n<p class=\"code-line\">\n  We hope these new features will make it easier for you to build sophisticated, modern web applications that combine .NET and JavaScript code.\n<\/p>\n<p class=\"code-line\">\n  Please let us know if you have feedback on the features, or encounter any problems when using them, by posting to the issues list on the <a href=\"https:\/\/github.com\/aspnet\/JavaScriptServices\">JavaScriptServices GitHub repo<\/a>.\n<\/p>\n<p>\u00a0 \u00a0<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This is a guest post by Steve Sanderson These days, many developers are building Single-Page Applications (SPAs) using frameworks such as Angular or React. These are powerful frameworks that produce a great end-user experience, but we often hear that building these applications is complicated. It can be a challenge to integrate server-side and client-side code [&hellip;]<\/p>\n","protected":false},"author":405,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197,7509],"tags":[7372,7526,7527],"class_list":["post-9176","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-aspnetcore","tag-javascript","tag-javascriptservices","tag-node"],"acf":[],"blog_post_summary":"<p>This is a guest post by Steve Sanderson These days, many developers are building Single-Page Applications (SPAs) using frameworks such as Angular or React. These are powerful frameworks that produce a great end-user experience, but we often hear that building these applications is complicated. It can be a challenge to integrate server-side and client-side code [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/9176","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/405"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=9176"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/9176\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=9176"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=9176"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=9176"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}