Sunday, February 26, 2017

Configuring React in Visual Studio 2015 / ASP.NET Core with Webpack and NodeJs/Typescript tools

So I haven't blogged in a while...or much ever to be honest...but it looks like it's been 6 years...yikes! Guess its time for a new post.

I'm working on a side project and decided to use React for the front end. My project is an ASP.NET Core Web Application running against .NET framework. It wasn't too hard to get react working initially. First I added it as a Bower package, referenced the react.js files in my Layout view, added a couple of NPM packages for Babel and React and configured a gulp task to transpile my JSX files into javascript.  Took and hour or two to figure it all out but it worked. Not too bad to get a Hello World up and running.

BUT BUT BUT then I tried to split up my React components and import/export them as modules and this is where everything went to hell. My code still compiled with Gulp, but i got an error in the browser.

require is not defined

OK. I realized I needed to use a module loader to get this thing working the way I want and split up my components. Now let me preface this post by saying I don't have a lot of experience with Gulp or Babel or Webpack or Node or Browserify or Grunt or any of the other 5,000 front end Javascript precompilation/bundling/task running programs. But it wasn't to hard to get React up and running, it shouldn't be too hard to get the modules working either, right? Wrong.

It took me about 2 days of absolute frustration to get the JSX files working in Visual Studio the way I wanted. My hope here is to save someone else the time, as there seems to be little on the web about getting React working correctly in Visual Studio.

First let me tell you what didn't work. I tried to get the modules working using Gulp since that is what is already running by default in my project. There may be a way to do this...but I couldn't figure it out. I tried using some Browserify and Rollup plug-ins and some other stuff in my Gulp script to no avail. The documentation on this stuff is sparse and there are 500 npm packages and plugins that might or might not work or are deprecated, and for most of them I couldn't find a good recipe that worked how I wanted with my project.

I also tried using Typescript TSX files. I wasn't too keen on this as the tsx syntax is a little different like forcing you to use a generic version of React.Component with a Typescript interface. Frankly I just wanted to use the vanilla syntax, and even though it kind-of worked for a simple file i was still getting strange errors on the import statements in the text editor. I tried every possible combination of settings in the typescript config file to no avail. So, this is how I finally got everything playing nicely.

Step 1

Make sure you have the following two Visual Studio extensions installed. These packages will give you better intellisense and tooling for your javascript coding.  I'm not entirely sure both are required to make this work, but I couldn't get some of the module errors to go away until I had them installed and started using the respective editors.

Node JS Tools for Visual Studio

Typescript for Visual Studio 2015

Step 2

Next go to Tools -> Options -> Text Editor -> File Extension and set .jsx files to use the TypeScript editor. This is the only way I could get the module import/export errors to disappear in the text editor. I also set my js files to use the Node editor.



Step 3

Were going to use Webpack to build the JSX files and do the module loading. The thing is...there is no webpack support in the default Core Web App project so we have to add everything manually. The wonderful article below helped me get over the hump, although its not specific to .NET so I had to tweak a couple of things.

Setting up React with Babel and Webpack

I installed Webpack with

npm install -g webpack@2.1.0-beta21

Why not use the latest version? Well...I tried that initially and maybe it will work with the configuration in the tutorial link above, but it did NOT work with some other examples I found such as this one. Apparently there are breaking changes in the latest version of Webpack that conflict with several of the configs I found online. So feel free to try the latest version at your own risk, but 2.1.0-beta21 worked for me so I'm sticking with that for now.

Step 4

Add the following npm packages to your package.json file. Also "path" if its not already there. These will be used by Webpack. (I just add these in my package.json but you can use the command line as well.)

npm i babel-loader babel-preset-es2015 babel-preset-react -S

Step 5

Create a webpack config in your root project directory. This file is called

webpack.config.js

I configured mine as follows. In my root web project directory I added a folder called "app" and one below that called "components" for my React components. I also added an "app" folder in wwwroot. This configuration will build "./app/index.jsx" to ".'wwwroot/app/bundle.js".

var path = require('path');
 
var BUILD_DIR = path.resolve(__dirname, 'wwwroot/app');
var APP_DIR = path.resolve(__dirname, 'app');
 
var config = {
    entry: APP_DIR + '/index.jsx',
    output: {
        path: BUILD_DIR,
        filename: 'bundle.js'
    },
    module : {
        loaders : [
            {
                test : /\.jsx?/,
                include : APP_DIR,
                loader : 'babel'
            }
        ]
    }
};
 
module.exports = config;

Step 6

Add a file called .babelrc in the root projectd directory. This is the babel configuration. I used the following code from the tutorial linked above.

{
  "presets" : ["es2015""react"]
}

Step 7

Create your JSX files. At this point you have a couple of options since module loading is now set up. One is you can just add script references to React to your HTML from the wwwroot/lib folder from a Bower install. Then you just have to import other React components to your JSX files.  Make sure you give a relative path to your other JSX components as they aren't NPM installs and otherwise Webpack will not know where to look.




The other option is to install the React NPM packages and then import the React and ReactDOM modules into your JSX files. The libraries will be compiled out to your bundle.js files and then you don't need the react script references or the Bower install.



Step 8

Open a command prompt and navigate to your project directory. Run the Webpack command below. This will build your JSX to a bundle.js file in wwwroot.

>webpack -d

Step 9

Add the bundle.js file to your HTML.

@section Scripts
{
    
    
    <script src="~/app/bundle.js"></script>
   
}

Step 10

Run your project. Boom! Your React app should be up and running!

Conclusion

At this point you would have to run the webpack build every time you change a JSX file which is a little annoying. However the React tutorial shows how to set up a watch with NPM to get it to auto-build on file changes.

Let me know if this doesn't work for you or if you have any other suggestions. I'm still not getting any JSX intellisense, but at least I'm not getting build errors. I would love to know how to get this working with Gulp so that I only have to deal with one task runner. Below is a screenshot of my package.json to show the versions I am using in my project. If this setup doesn't work for anyone happy to edit the post or see if I can help diagnose the issue.