Templates for building React.js in ASP.NET Core and MVC5

Posted 大内老A

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Templates for building React.js in ASP.NET Core and MVC5相关的知识,希望对你有一定的参考价值。

I have been interested in React, Facebook’s libraries for building front-end User Interface, for some time. Having worked on a Single Page Application (SPA) some years ago that used Backbone I was very aware of the pain point React is aimed at, i.e. the problem of building and debugging complex views with lots of interactions (see Why React?).


Recently I got some spare time and I decided to create some samples ASP.NET MVC applications that used React so that I was clear on how I could use it in the future. Well, it turned out WAY more complex than I thought but I learnt a lot!


Note: While my solution is aimed at ASP.NET MVC all React code and build/test files would work in any system supporting Node.js. You can try all the code using Visual Studio Code, which is a free tool that runs on multiple platforms.


What this article is all about


My aim was to produce sample applications that I could use as a basis for building real-world ASP.NET MVC applications that used React to help build the UI. As such they needed to have:


  • Good development environment.

  • Good Unit Test setup.

  • Good production building setup.

  • Examples in both flavours of ASP.NET, e.g. the existing MVC5 and the new ASP.NET Core MVC.

I ended up making a number of projects which I have made available as an open-source Visual Studio solution, AspNetReactSamples, on GitHub. This currently contains four projects:


  • ReactJsNet.MVC5, which uses the ReactJS.Net NuGet package.

  • ReactWebPack.CoreRC2, which used WebPack and the new ASP.NET Core (version 1.0.0, RC2) MVC app.

  • ReactWebPack.MVC5,  which used WebPack and the existing ASP.NET MVC5 app.

  • ReactTests, which is an example of how to Unit Test React components/libraries.

The bulk of this article goes though the decisions I made when putting these examples together. Having ‘cut-and-pasted’ other people’s examples and got lost, I think knowing why I built something that way is as important as knowing how.


I’m going to assume you at least know what React is and that it has lots of associated libraries. If you don’t then there are plenty of articles out there on React [1, 2, 3] but I would also really recommend the book “Pro React”, which helped me a lot.


NOTE: In my review of the book on Amazon I said that the only down side of the Pro React book was it used Flux instead of the newer Redux library to implement stores. Well the author, Cássio de Sousa Antonio, saw my review and has made available an alternative version of Chapter 6 using Redux. How about that for good service!


UPDATE: I have recently taken Cássio’s new chapter on using Redux to heart and converted the ReactWebPack.CoreRC2 project over to using Redux. You can read about my experience of doing that in my article Using a Redux store in your React.js application.


OK, let’s start with the first example of how to use React in an ASP.NET application. This is the simplest to use, so makes a good starting point for anyone looking at React for the first time.


1. For simple applications try ReactJS.Net


If you want a simple place to start with React on ASP.NET then try the ReactJS.Net NuGet package from Facebook. This allows you to write JSX code which it turns into javascript on the fly. I have an example in my sample application called ReactJsNet.MVC5. (React.Net is also available for ASP.NET core RC1, but with a few limitations. See Nuget package ReactJS.NET MVC6).


Note: JSX is a source format that combines html and JavaScript. Sounds horrible, but it works, although you can write regular JavaScript if you prefer. Read this for an opinion on why it’s better to use JSX. More on the impact of using JSX later, but here is an example of some JSX.


var Comment = React.createClass({

    rawMarkup: function() {

        var rawMarkup = marked(

            this.props.children.toString(), {sanitize: true});

        return { __html: rawMarkup };

    }, 

    render: function() {

        return ( 

<div className="comment">  

<h2 className="commentAuthor">

              {this.props.author}

            </h2> 

            <span dangerouslySetInnerHTML={this.rawMarkup()} />

          </div> 

      );

    }

});


If this React class Comment was called with the following JXS code:


<Comment author={'Jon Smith'}>

   {'This is a **bold** comment'}

</Comment> 


then the rendered HTML would be as shown below. Note that the method ‘marked’ is a library call that turns markdown into HTML, so “**bold**” gets turned into “<strong>bold</strong>”


<div class="comment">  

<h2 class="commentAuthor">Jon Smith</h2>  

<span>

      This is a <strong>bold</strong> comment

   </span>

</div>


My verdict on ReactJS.Net

ReactJS.Net makes starting using React really easy, but by default it uses the simple module linking of each library, i.e. using a global variable that other packages use, for example the way we often use JQuery in ASP.NET. In any substantial front-end system this style of module linking has its limits, and that is especially true with React as there are lots of libraries to include.


Therefore ReactJS.Net is a great solution if you want to add some simple React views to an existing ASP.NET project, or you just want to play with React. In my samples the ReactJsNet.MVC5 project implements the React Quick Start Tutorial of a simple chat.


However for bigger applications, or applications that needs more React features such as stores and routing, we need to handle the finding and linking of JavaScript module and libraries in a better way.


Note: You can use a system of linking modules on top of using ReactJS.Net, but then you need to use the more complex build process I describe in the next section.


However before we leave ReactJS.Net there is one feature that is very important – that of server-side rendering of React. This is really important as you can pre-render some React on the server and then tell the client-side React that the html has been pre-initialised and it will work with it. These sorts of application are called “Isomorphic Apps” (not a very helpful name in my opinion) but I don’t have the space to cover this. Have a look at these articles [1, 2, 3] and chapter 8 of the “Pro React” book I recommended to find out more about “Isomorphic Apps”.


2. Building React applications with JavaScript modules


For larger, more complex React applications then you are going to have lots of separate files (React components are normally small) and lots of libraries that you want to link to. Linking by loading them in sequence is not a viable option. So you need two things: a) a package manager to get the libraries and b) a way to link your code and the libraries together.


2.a. Library package manager


In the JavaScript world there are a number of package managers, the biggest two being NPM and Bower. While I am a fan of Bower it soon became very clear that React uses NPM extensively.  In the end it was obvious I needed to use ASP.NET’s package.json file and NPM, as using Bower would not have given me the access to all the libraries I needed.


2.b. Linking code and libraries.


This one was more complicated and it felt like I had fallen down Alice in Wonderland’s rabbit hole! The build of a normal React goes like this:


  • Transpile the JSX: Because I have chosen to use the JSX format then I need this translated that format into ordinary JavaScript (ES5). This needs a Transpiler. I used Babel, which is well respected, but there are others, like Traceur from Google.

  • Extract ES6 Modules: Because I am using the Babel Transpiler it understands the new ES6 module format which everyone in the React camp seems to use. Babel currently converts ES6 modules to a number of formats such as Common.js, AMD/Require etc. (Note: the ES6 module feature is at the time of writing not supported by any browsers natively, but is coming soon to Microsoft Edge).

  • Load & link the references: React libraries have lots of links to other libraries and it would be a real pain to have to hand-locate each library. There are a few ways to do this, but WebPack seems to be the way that most React developers use. There are a number of alternatives to WebPack.


Other Benefits of this process – ES6 JavaScript

If you are using a Transpiler then it makes sense to make the most of it. What most people do is swap over to using the new ES6 JavaScript standard which has a number of very useful enhancements. You have already heard about modules, but there are things like let & const and classes. Also many of the functions I used from the JavaScript underscore / lodash libraries like _.map() are built into ES6. The benefits are cleaner, more rigorous code and you are somewhat future-proofing your code. Have a look at “Top 10 ES6 Features every busy JavaScript Developer must know”.


Babel converts all the ES6 commands to regular JavaScript (ES5), plus has a babel-polyfill library so that the code will run on all the modern browsers. Babel can output code for older (ES3) browsers but you need to add some more settings and libraries (see this useful note about that).


The down side of this process – JavaScript ‘build’


The down side is that you have to ‘build’ the JavaScript, even in development mode. For anyone used to using JavaScript with ASP.NET MVC you know that it’s great to be able to debug JavaScript by simply editing the JavaScript, hit F5 in the browser and you are away. Now you need to run the build process on every change.


However there is one saving grace. WebPack has a “watch” mode and if you start this it will rebuild when you save a JavaScript/JSX file. A normal build takes some time, 6 seconds for my simple sample, but because WebPack caches the build then changing a single file normally takes ½ second.


2a. Setting up a build process


I would say that setting up the build process was the hardest and most frustrating part of the project. There are lots of different ways to set it up, each with its own pros/cons. The main problem, especially with WebPack is if it didn’t work it was really hard to find out why. Let me tell you some of the decisions I made so you know where I am coming from:


Big decisions


  • I used Babel for my Transpiler. That is what everybody is using and it worked well.

  • I used WebPack for my module bundler because everybody else seem to use it. I found WebPack really hard work to configure but it works now. I have since heard about systemJs and jspm, which follow the ES6 module approach. I am definitely going to look into those!

  • I chose WebPack as the command to call to build as it has a ‘watch’ facility to recompile on changes to a file. I think that is best, but you can call Babel, which then calls WebPack.

  • I chose to write NPM “scripts” to call WebPack. These scripts live in the package.json file. I quite like this, and it works for Unit Testing too (see later).

  • I chose to use the NPM Task Runner extension to call these scripts in Visual Studio, and the VSCode npm Scripts extension to run them in Visual Studio Code (more on that later). I tried other approaches such as the WebPack Task Runner, but NPM definitely worked the best.


Small decisions


  • I chose to use the extension ‘.js’ for my JSX code rather than ‘.jsx’. A lot of people do that and the tools handle either. Not much in it, but if you use .jsx then when you use the module import you have to add ‘.jsx’ on the end of the filename. (note: the build files in the sample applications are set to ONLY look at .js files).

  • This is a bit deep so ignore until you understand WebPack, but I didn’t use WebPack’s dev server to deliver the bundles files in the development build. This was partly because I had problems with setting up sourcemaps but I also liked having the Bundled JavaScript file around to look at. However I did use WebPack’s dev server in the Unit Testing, for no better reason than it worked that way by default.

To see other people’s approaches to the React build process, some of which I learnt from myself,  especially the first one, then do look at:


  • Develop React + ASP.NET Web API apps in Visual Studio 2015

  • Setting up Webpack for ES6, React, SASS and Bootstrap

  • Using React, Typescript, and Webpack with Visual Studio 2015

  • WebPack For Visual Studio Developers

  • Beginner’s guide to Webpack

  • Webpack — The Confusing Parts


2b. How to run the build process

The best way to study my build process is to download the AspNetReactSamples and run a build. There are two versions which build and run the same React application, but for the two current version of ASP.NET MVC:


  • ReactWebPack.CoreRC2, which is built on the new ASP.NET Core MVC app.

  • ReactWebPack.MVC5, which is built on the existing ASP.NET MVC5 app.


The full information on how to do this is in the Readme.md file in the AspNetReactSamples solution so I won’t repeat it here.


Note: One nice trick is to use Visual Studio Code (VSCode) alongside Visual Studio. If you aren’t aware of VSCode it’s a free, lightweight IDE which is especially good with JavaScript etc. In fact I found that VSCode understand JSX format better that Visual Studio 2015. Details in the Readme file.


3. Unit Testing

One of the plus points of React is that it is easy to Unit Test for two reasons. Firstly it is easier because React uses what is called a ‘Virtual Dom’, which is an in-memory DOM. The Virtual Dom means that the Unit Tests tools can check the virtual Dom rather than the actual DOM, which can be slow and troublesome. The second reason is that Facebook, and other React library suppliers like Redux, have thought about Unit Testing from the start and made sure their components/libraries are easy to test.


Even so, setting up a sensible Unit Testing environment still took quite a bit of research and trials. Let me tell share with you the choices and decisions I made so you can understand why I went this way:


Big decisions

  • I chose Mocha as my test framework. Facebook recommend Jest for Unit Testing React, but a number of posts [1, 2, 3] said Jest was slow and Mocha was better. I have also used Mocha successfully in the past, which gave me confidence in this approach.

  • I used Karma as my test runner. Most people do and I have used it before. Specifically it has a ‘watch’ facility and can interface with WebPack, which means it does a recompile and test when a test file is changed. That feature makes a big difference to the test/fix cycle.

  • I run my Unit Tests inside a real browser, Chrome, rather than a phantom browser. This adds a bit of start-up time but it does mean I can debug my Unit Tests (I talk about that later).

  • I used AirBnB’s enzyme React testing utility. I had lots of trouble with my early tests, mainly because The “Pro React” book I mentioned used a very old version of React, and things had change. However even when I was looking at the correct code was still quite complex, with extra libraries and different approaches. The React Test Utilities page suggested Enzyme which I found simpler than the standard React Test Utilities, and Enzyme has good documentation.

  • I used mJackson’s expect assertions rather than the older expect.js library I used before. mJackson’s expect has shorter test names and has its own event spy part. The spy part is significant because it turns out that Sinon, the normal package for doing spying on events, has some problems with WebPack.

  • I placed my Unit Tests in another Visual Studio project, mainly because I want to keep my test code separate. However others normally have the tests in the same project, which has the advantage of only one package.json to keep up to date. You can decide which you like.

  • I created NPM scripts in the ReactTests’s json file so that the tests could be run in same way as the build. That way I can call them for Visual Studio or VSCode. I tried other ways but this was certainly the best.


I have only done a limited amount of Unit Tests (only 5 Unit Tests at the moment) so I can’t be sure this is a perfect setup, but it looks good. Only a real application will tell me whether I have the right setup (my Backbone SPA had over 700 Unit Tests).


However there is stacks of information on Unit Testing React because lot of people, like Facebook and Airbnb, use Unit Tests. Try:


  • Testing React Web Apps with Mocha, Hammer Lab

  • UI Testing with React Components

  • Testing ReactJS Components with Karma and Webpack

  • Codementor Testing React with Mocha


3b. Running the React Unit Tests

Again, if you want to look at the Unit Tests, I recommend you download the AspNetReactSamples solution and look at ReactTests project. The Readme.md file in the AspNetReactSamples solution has all the information for running the Unit Tests, so I won’t repeat that. However here are some thoughts on Unit Testing React.


Debugging with Unit Tests


You can run the Unit Tests once by calling the command test-run. It will tell you what passed or failed. However when you do have a failing bug it is very useful to be able to debug it by inspecting the code and live variables, change the code and retest. Therefore I have added a test-watch that a) runs the tests, but leaves the browser open and b) will rebundle and rerun the tests if a .js file is changed.


Because the test-watch command leaves the browser open then you can use Developer Mode (F12) to place breakpoints in the code and rerun the tests by pressing F5 in the browser. Then you can inspect the code and the live variables to see where the problem is.


However because we are working with JSX and a Transpiler there is a wrinkle!


The issue of transpiled code


By default Chrome will find the source maps and show you the original JavaScript/JSX file. This is really helpful, but can be misleading as you aren’t looking at the actual code that is running. Mostly it’s fine, but imported methods/variables will have different names in the Chrome ‘scope’ window from what you see in your original code.


If you want to see the underlying ES5 code then the only way I have found to do that is to turn off ‘Enable JavaScript source maps’ in Chrome’s developer setting and press F5 again. Then you see the real code, which shows the correct variable names.


Once you get used to it it’s fine, but I got very confused at the start.


Note: Mocha has some useful commands when you are working on a large set of tests. The most important is the .only() method which, if added to a test/sub test, will only run that test. Also the .skip() method can be added to a test/sub test and causes it to be skipped.


Another useful feature is adding the line debugger; to your JavaScript which will cause a breakpoint when it is executed if the developer tools (F12) is open.


Conclusion

I started this project by cut-and-pasting solutions I found on the web and got terribly lost, especially because some things like WebPack can ‘fail silently’, e.g. does not do what I wanted it to do, but did not produce any error messages. Therefore when I wrote this article I took the time to include the decisions I made and why. I hope that helps you to decide what you want to do, and more importantly help you understand what is wrong when it doesn’t work.


This has been quite a long research project for me, but at the end I have what I consider a really good example setup that I could use in a real project. My final solution ticks almost all the points I needed apart from having multiple React apps (but I know how to do that).


My journey with React had only just begun and there is much more to learn. If I have time I plan to look at systemJs and jspm as an alternative to WebPack (have a look at this video on HTTP/2 and systemJs to see why this looks like a good way to go).


Happy coding!




请扫描此二维码或者搜索“大内老A”关注蒋金楠(Artech)微信公众帐号,你将会得到及时的高质量技术文章推送信息。

以上是关于Templates for building React.js in ASP.NET Core and MVC5的主要内容,如果未能解决你的问题,请参考以下文章

Django templates 模板的语法

File Templates for web.xml & web-fragment.xml (Servlet 2.3, 2.4, 2.5 + 3.0)

(转)Three challenges you’re going to face when building a chatbot

sourceTree git 空目录从远程仓库克隆代码出现warning: templates not found

Django的templates(模板)

D02 TED Elon Mulsk The future we're building — and boring