Deploy Angular 2 ‘Quick Start’ Example On Azure

Where We Start

You can refer to my last blog to understand how I came along. What happened after that is:

  1. Deployed the empty ASP.NET project with Quick Start example to Azure through Visual Studio 2015Screen Shot 07-22-17 at 09.46 PM.PNG
  2. run npm install in the console of Azureinstall-packages-on-azure.png
    If you see the node_modules folder, then it works, even you might receive Bad Request error.

Of course, it does not work, or why else am I writing this blog. It seems that all the requests of the .js files under /node_module/.. folder are rejected, and the server just return the default file under the dir, which is the /src/index.html itself:

forbiddn.png

Yeah….it is an official boilerplate app, but not cloud-platform-deployable.

200.gif

Solution

Step 1: change the index.html, removing the base tag:

remove-base.png

Step 2: change the file structure, the dir structure of the example is:

  root
	|--node_modules
	|   |--...	
	|	
	|---src
		|--app
		|   |--app.component.html 
		|   |--...
		|
		|--index.html
		|--favicon.ico
		|--main.js
		|--main.js
		|--styles.css

All you need to do is change it to be:

  root
	|
	|--app
	|   |--app.component.html 
	|   |--...
	|
	|--node_modules
	|   |--...
	|
	|--index.html
	|--favicon.ico
	|--main.js
	|--main.js
	|--styles.css

Pretty simple and straightforward, move the file and folders under /src/ to the root folder.

The only problem is, how do you do that on Azure, I used a tool called Kudu. Open the tool by navigating to:

https://yourservicename.scm.azurewebsites.net

And you can manage the files from there:

Kudu.png

Here is a good tutorial talking about Kudu.

Step 3: not really necessary, delete the useless files/folders, there are quite a lot

Reference

My question on stackoverflow.

Advertisements

Run Unit Tests On Angular 2 Quick-Start Example With Jasmine & Karma

What I have done beforehand

  1. Followed the instructions to set up my Visual Studio 2015;
  2. Checked out the Quick Start Example, and after solving some unexpected issues, I can run it;
  3. I walked through the instructions for running unit tests with Karma.

That is the starting point of this blog.

The Problem

I run the command

npm test

run-test.png

It launches the Karma tab in Chrome, but it does not work, and I got errors from the cmd prompt:

error-in-karma.png

It says:

[1] 21 07 2017 16:10:13.532:WARN [web-server]: 404: /node_modules/@angular/core/bundles/core-testing.umd.js
[1] 21 07 2017 16:10:13.548:WARN [web-server]: 404: /node_modules/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic-testing.umd.js
[1] Chrome 59.0.3071 (Windows 7 0.0.0) ERROR: 'Unhandled Promise rejection:', '(SystemJS) XHR error (404 Not Found) loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js
[1]     Error: XHR error (404 Not Found) loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js
[1]     Error loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js', '; Zone:', 'root', '; Task:', 'Promise.then', '; Value:', Error{originalErr: Error{__zone_symbol__currentTask: ZoneTask{_zone: ..., runCount: ..., _zoneDelegates: ..., _state: ..., type: ..., source: ..., data: ..., scheduleFn: ..., cancelFn: ..., callback: ..., invoke: ...}}, __zone_symbol__currentTask: ZoneTask{_zone: Zone{_properties: ..., _parent: ..., _name: ..., _zoneDelegate: ...}, runCount: 0, _zoneDelegates: null, _state: 'notScheduled', type:'microTask', source: 'Promise.then', data: undefined, scheduleFn: undefined, cancelFn: null, callback: function () { ... }, invoke: function () { ... }}}, '(SystemJS) XHR error (404 Not Found) loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js
[1]     Error: XHR error (404 Not Found) loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js
[1]     Error loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js'
[1]
[1] Chrome 59.0.3071 (Windows 7 0.0.0) ERROR: 'Unhandled Promise rejection:', '(SystemJS) XHR error (404 Not Found) loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js
[1]     Error: XHR error (404 Not Found) loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js
[1]     Error loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js', '; Zone:', 'root', '; Task:', 'Promise.then', '; Value:', Error{originalErr: Error{__zone_symbol__currentTask: ZoneTask{_zone: ..., runCount: ..., _zoneDelegates: ..., _state: ..., type: ..., source: ..., data: ..., scheduleFn: ..., cancelFn: ..., callback: ..., invoke: ...}}, __zone_symbol__currentTask: ZoneTask{_zone: Zone{_properties: ..., _parent: ..., _name: ..., _zoneDelegate: ...}, runCount: 0, _zoneDelegates: null, _state: 'notScheduled', type:'microTask', source: 'Promise.then', data: undefined, scheduleFn: undefined, cancelFn: null, callback: function () { ... }, invoke: function () { ... }}}, '(SystemJS) XHR error (404 Not Found) loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js
[1]     Error: XHR error (404 Not Found) loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js
[1]     Error loading http://localhost:9876/node_modules/@angular/core/bundles/core-testing.umd.js'
[1] 21 07 2017 16:10:23.557:WARN [Chrome 59.0.3071 (Windows 7 0.0.0)]: Disconnected (1 times), because no message in 10000 ms.
[1] Chrome 59.0.3071 (Windows 7 0.0.0) ERROR
[1]   Disconnected, because no message in 10000 ms.
[1]
[1] Chrome 59.0.3071 (Windows 7 0.0.0) ERROR
[1]   Disconnected, because no message in 10000 ms.
[1]
[1] 21 07 2017 16:15:29.135:WARN [web-server]: 404: /node_modules/@angular/core/bundles/core-testing.umd.js

The files it fails in loading are just right there, as I have ran the npm command to install the packages:

file.png

The Solution

Open the config file: /src/systemjs.config.js, change the value of path to be:

paths: {
  'npm:': '/base/node_modules/'
},

The whole file reads as:

/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function (global) {
  System.config({
    paths: {
      // paths serve as alias
      'npm:': '/base/node_modules/'
    },
    // map tells the System loader where to look for things
    map: {
      // our app is within the app folder
      'app': 'app',

      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',

      // other libraries
      'rxjs':                      'npm:rxjs',
      'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
    },
    // packages tells the System loader how to load when no filename and/or no extension
    packages: {
      app: {
        defaultExtension: 'js',
        meta: {
          './*.js': {
            loader: 'systemjs-angular-loader.js'
          }
        }
      },
      rxjs: {
        defaultExtension: 'js'
      }
    }
  });
})(this);

Re-start the Karma service, and I can run sample unit test: true is true, as well as other tests of my service classes, keep in mind that you will need to undo the change to be able to build & run the app.

However, I got errors running the test of my component, as it uses an external html as template and a css file for styling, these files are all under /src/app/.

My component class looks like:

// imports...

@Component({
    selector: 'my-app',
    templateUrl: 'app/app.component.html',
    styleUrls: ['app/app.component.css'],
    providers: [RuntimeSettingsService]
})
export class AppComponent implements OnInit {
	//...
}

This works fine when building the app, but it causes the problem when running the tests. A better way is use relative path, as the official sample shows:

// imports...

@Component({
    selector: 'my-app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    providers: [RuntimeSettingsService]
})
export class AppComponent implements OnInit {
	//...
}

In the case of unit test, its path should be base/src/app/app.component.html. The relative path works for both building and testing, otherwise you would have to keep changing the paths forth and back as you switch between develop and unit test.

You need to re-start Karma, and even reboot your pc sometimes to get it to work.

Reference

My question on stackoverflow.

 

Get Started With Expo

After playing with React Native for two weeks, I realized that the development tools are not stable yet — particularly on Windows — in that, I keep receiving platform-level errors and compatibility issues. I reckon that is because there are too many layers in the stack. But anyway, as a result, I cannot focus on the development of my project.

I recently start trying this tool, called Expo, in hope that it can remove the obstacles in my way. If you pey attention, you would have already found it from React Native’s official site, it is used to host and demo the snippets of React Naive code in the pages of documents.

expo-on-rn--doc-page.png

Here is its website:

expo.png

It does support online compiliation and building, and you can run the project in the wrapper app of Expo on your mobile device.

Before you can start, you really need to sign up.
signup.png

I signed with Github account.

After installation, the first start-up of the XDE looks like:

startup-XDE.png

Log in, create a new project:

new-proj.png

template.png

run-new-pro.png

The left pane is called packager console, sort of the counterpart of the cmd window where you run React Native CLI.

Launch Genymotion, and afterward the option of Open on Android will be available:

run-android.png

Run on Android, for the first time, you would see:

1st-run-011st-run-02

Now you can play with the app in the Android emulator:

right-pane.png

The right pane is a console to display device logs. The messages are displayed after I navigate to another tab, and they look like the data kept in the store of Redux.

The new project’s path is under the installation directory of Expo

pro-dir.png

Open the root folder in VS Code, and change the content of the home screen:

 

 

change-content.png

And saving the changes will automatically trigger rebuilding:

saving.png

You can also download Expo app on your mobile phone, and run this project from it, which I will go over shortly.

Setup React-Native For Android App Development On Windows – Part 3

Debugging React Native

Connect To Chrome DevTool

Unfortunately, I have not figured out how to use the standalone React Developer Tool. And I have not found out the correct way to inspect React Native components in Chrome DevTool.

All I can do now, is output some debug information in the console of Chrome browser. I followed the official instructions.

Beforehand, I changed the source code of the sample app created by react-native init. Open index.android.js, add one line:

add-line-console.png

Open the developer menu by pressing CTRL+M in the emulator, choose Debug JS Remotely, that will open a tab in Chrome:

debug-remotely

Press F12 to open up the DevTool of Chrome:

console-chrome.PNG

Yeah, we can see the log information we wrote, plus the reddish warnings, splendid.

Bring that Developer Menu again, choose Toggle Inspector,

toggle-inspector.png

You would see:

click-secret-area.png

And click the area slightly right above the inspector (but not on text) will change the view as (not sure if it works for everyone the same way, have not found any official docs on that):

moretabs.png

Connect To React DevTool

According to its official doc, we can install it locally, so I run npm install –save-dev react-devtools on the project root directory.

install-react-devtool.png

And update the package.json, adding react-devtools, it now looks like (displayed in a visualized json viewer):

packages.png

 

Setup React-Native For Android App Development On Windows – Part 2

Android_Studio_icon

In the last blog, we have already setup Android Studio 2.3.3 and Reactive Native dev tools, and successfully run the startup project in the emulator of Android Studio.

Setup Genymotion For Emulation

The default emulator which comes with Android Studio is laggy and slow, and even Google recommends Genymotion as the emulator for Android app development. Before you start, you really need to sign up (and activate your account) on its official website:

genymotion-website

Otherwise, you won’t be able to finish this setup. Since its home page changed, the download link of the free version seems to be a secret path now, anyway, it’s here.

Basically, I took some video tutorials on youtube as the reference, but none of them covers everything:

 

 

 

 

 

 

You can find a lot out there, but most of them are exactly the same as the first one.

Let’s go through the steps.

Step 1: Install & configure Genymotion

If you have never installed Genymotion or Oracle VM VirtualBox before, you can refer to any of the tutorials on youtube, and skip the rest of step 1, jumping to step 2 straightway. Just keep in mind that you should choose the installation file with VirtualBox – the bigger one.

However, if you have installed Genymotion, like me, and it does not work with the updated Android Studio. In that case, if you don’t want to wipe everything and re-install them, you can follow my instructions at the end of the blog.

Step 2: Configure Android Studio & Genymotion

Open up AS, go to menu: File->Settings…

setting.png

In the panel, go to ‘Plugins’, and click ‘Browse repositories’

plugins.png

Type in ‘genym…’ to search the plugin for it, and install it:

genymotion-in-plugins

After installation, restart Android Studio, and you would see the button of Genymotion, besides, you can also press CTRL+SHIFT+A and type in genymotion to launch Genymotion device manager:

geny-device-mger.png

As I said above, I installed Genymotion before, and I just re-installed AS, so AS is not aware of Genymotion anymore, therefore in my case, after opening up the Genymotion Device Manager, I saw this dialog:

genymotion-path

It asks me to provide the installation path of Genymotion:

geny-path-sel.png

If you install Genymotion after AS, you won’t see that and don’t need to bother with that. We have done with AS settings, and now go to the setting of Genymotion, we also need to update the Android Studio SDK path in Genymotion’s setting panel:

AS-sdk-path-in-geny

Now, we can create and start device from Genymotion Device Manager, to test it, I just pick one from the previously created devices, and srart it:

start-device-in-geny

It starts successfully:

running-htc

And if we run the Android native app from Andriod Studio (remember I created one when first time opening up AS), we can choose the running device now, which means AS are connected to the virtual devices:

select-running-device

Go ahead and run the native sample app:

buggy-sample.png

Oops, too buggy.

However, the HTC One device runs Android 4.4.4, which seems not to support React Native, remember from the last blog that we have installed Android 6 particularly for React Native support.

So, we need to create a new device with Android 6. Let’s put the details of that in the next step.

Step 3: Create virtual device

I did that in Genymotion its own window, rather than the manager launched from AS. Hit ‘Add’ in the panel:

add-device.png

That brings up the setting panel:

select-devices.png

This is where your account comes into play, you need to log in an activated account to be able to see the of the available devices shown in the above screenshot. I chose Google Nexus 5, which runs Android 6.0.0:

name-devicefinished

Now change its settings as:

google-nex-setting.png

At least in my case, it is necessary to change the Network mode to Bridge. I also reduced the number of CPU processors and memory as my computer is sort of lame.

Step 4: Run React Native in Genymotion

Let’s launch Genymotion Device Manager from Android Studio, and start the newly created Google Nexus, after few minutes, it is all setup. With those things in place, let’s run the React Native project in the same way as I described in my last blog, and what happened was:

run-rn-fail.png

WHAT????

65613242.jpg

OK, the solution for me was pointed out here, thanks to Daniel Masarin, he has the credits.

Press CTRL+M, in the panel, click ‘Dev Settings’:

dev-swtting.png

And you will see:

server-host.png

Look for ‘Debug Server Host & Port for device’, click on it, and type in localhost:8081:

host-port.png

If you are wondering where this port number comes from, remember from the last setup blog that, when running react-native start, you would see:

┌───────────────────────────────────────────────┐

│ Running packager on port 8081.                                                                                          │

│                                                                                                                                                      │

│ Keep this packager running while developing on any JS projects. Feel    │

│ free to close this tab and run your own packager instance if you             │

│ prefer.                                                                                                                     │

│                                                                                                                                   │

https://github.com/facebook/react-native                                                   

│                                                                                                                               │

└───────────────────────────────────────────────┘

You need to stop the React Native building service, and run the commands react-native start and react-native run-android again in the two command prompts respectively to make it work:

succed.png

Setup VS Code For React Native

Nothing much in this section, just some handy plugins.

menuUntitled

Appendix: Fix previously created virtual devices in Genymotion

I have a previous version installed on my Windows, it is a little bit old.

Open it up:

first-openup-genymotion

Try to start the HTC One device, it fails:

fail-to-run-htc-one.png

According to the second video, you can just reinstall VirtualBox to fix it. I didn’t do that, because it used to work, and it probably has something to do with the settings as I have re-installed my Android Studio two days ago.

Open up VirtualBox:

virtual-box-startup

Start the HTC device:

error-in-vb.png

The problem is the Network setting, open up the setting panel, go to network tab, the below screenshot shows my settings for Adapter 1:

network-adpt1.png

And Adapter 2, it is very important to select the wifi adapter on your computer so that the virtual device can access the Internet:

network-adpt2

Start the device again from VB:

re-start-htc.png

This command line thing kept going for over 10 minutes at least, and finally displayed nothing but a blank black screen, so I just closed it.

Re-start the device from Genymotion:

htc-setting-geny.png

I can run it now, and I can access the internet as well:

run-htc-successfully-in-geny.png

Yeah, there you go.

As for the adapters and adapter types in the Network setting panel, you can refer to the links for details:

https://www.virtualbox.org/manual/ch06.html

https://askubuntu.com/questions/95022/which-type-of-virtualbox-networking-should-i-use

https://www.thomas-krenn.com/en/wiki/Network_Configuration_in_VirtualBox

Setup React-Native For Android App Development On Windows – Part 1

windows-android-react-native

My Environment

Windows 7 Pro 64-bit

Node.js & npm

Java (jdk1.8.0_102)

My Setup Procedure

I found quite a few useful tutorials, below are the latest ones:

Android SDK & AVD Setup For React Native

React Native Crash Course

But unfortunately, none of them is up to date, some instructions are outdated, as things are constantly changing fast, that’s the reason I now am writing this blog. The date of writing is 6/July/2017, so if you came across this blog later than the date, you may find that things have changed again.

Step 1: Install Android Studio

I have Android Studio 2.1.x installed previously, but the latest version is 2.3.3. In order to update, you have to uninstall the previous one, and if you want to re-install the new version into the same directory, you have to clean up the directory, to make sure it is empty.

There is not much of Android Studio installation, you can refer to its official instruction.

android-01android-02android-03

After the initial launch, I created a new Android project, btw.

For those who re-install Android Studio like me, there is one thing to take note. If you specify another location for Andriod SDK installation other than the default one, like me:

path.png

In case the folder is not empty, the installation wizard will ignore that and install the SDK into the default path without telling you, which is:

C:\Users\YourName\AppData\Local\Android\Sdk

That’s what happened in my case, not so nice:(

Step 2: Download the SDK

As for which packages we should download, we just need to reference to React Native’s official doc. If you come here a long time after the date of writing, check it first.

doc-01.png

You can boost the SDK manager from the menu of AS:

setup-SDK-mgmer.png

For those who have experience with previous versions of Android Studio, you may expect a standalone manager for this, like:

not-any-more.png

But it has been removed recently, from now on, you won’t see it anymore. Instead, you can tick the option of ‘Show Package Details’ in the new manager:

setup-SDK-mgmer01setup-SDK-mgmer02setup-SDK-mgmer03

Select all the items as requested by React Native online doc, and install them.

setup-SDK-mgmer04

Step 3: Add environment variables

This is required by any development environment setup with Java technology, quite simple and straightforward.

sysvar-01sysvar-02
I added two paths to PATH in User variable section:

C:\Users\YourName\AppData\Local\Android\Sdk\platform-tools
C:\Users\YourName\AppData\Local\Android\Sdk\tools

sysvar-03
And two variables to System variable section:

ANDROID_HOME - C:\Users\YourName\AppData\Local\Android\Sdk
ANDROID_SDK_HOME - C:\Users\YourName

sysvar-04

First thing, practically speaking, you don’t have to set variable ANDROID_SDK_HOME, you can just leave it out. The default value will work unless you make some strange setting.

Secondly, please note that the value of ANDROID_SDK_HOME in my case is different from the one as shown in the video I mentioned above, which is exactly the same as ANDROID_HOME. That doesn’t seem to make sense to have two variables with same values, and as a matter of fact, you will get a warning if you do that when you start up your Android Studio after reboot, as shown:

sdk-val-error

And as a result, you won’t be able to activate the AVD manager after rebooting your computer, if you have your ANDROID_SDK_HOME pointing to …\…\Local\Android\sdk.

Step 4: Configure Virtual Device

avd-01

avd-02

avd-03

In the below dialog, make sure you select Android 6.0 (again, this is up to the official doc of React Native, it may change later), and the correct version for your computer.

avd-04

Start the virtual device:

avd-05

After some sort of initialization like this (it took quite a few minutes in my case, depends on your hardware spec):

avd-06

There we go!

avd-07

The default VD which comes with AS is quite slow, so Google recommends Genymotion, I which will go over in the next blog.

Step 5: Install the packages/tools for React Native

Open the command line prompt of Windows, navigate to the directory where you would like to start your React Native journey. Run npm commands to install the packages that React Native has dependencies on (refer to docs):

  • react-native-cli
  • yarn
  • watchman
  • flow
npm install -g react-native-cli
npm install -g yarn
npm install -g watchman
npm install -g flow

I chose to install them globally, and they are installed into:

C:\Users\YourName\AppData\Roaming\npm

flow-01.png

Step 6: Initiate a React Native project

With the virtual device running, run command:

react-native init yourProjectName

rn-init-01.png

That takes a few minutes, and will create a folder with the name you specify:

root-folder.png

Now, we are ready to compile and pack the sample project, in the prompt, navigate to the project folder, run command:

react-native start

start-rn.png

That seems to start a service, and btw, you can press CTRL+C to stop it.

Keep it running right there, open another command prompt, navigate to the project directory, run:

react-native run-android

run-android.png

A few minutes later, you should see the sample app loaded and running on the virtual device:

succed.png

Conclusion

It is actually a boilerplate repo on Git, with the practice that Facebook recommends for React Native development, you can take it as a project template. I reckon it is not the only way to start up a React Native project. Let’s open up the project in VS Code:

myFirstRNApp.png

Now, you can start working on your own functionalities by modifying this project template.

The export/import Syntax Supported by Webpack 2

es6-webpack-module

I am writing this blog to discuss the problem I mentioned at the end of another blog: First Taste Of Webpack 2. I have solved it now.

The Problem

We have four .js files, and their dependencies are illustrated by Curran in his slides:

depend.png

I left out ‘default’ keyword in add.js, so it read like:

export function add(a, b){
  return a + b;
}

Actually I didn’t make the mistake accidentally. I thought I could leave it as I had named the function, that is compliant with ES6 syntax, according to Nicholas’s new book Understanding ES6. What I did here is perfect ES6 code, but in fact, that causes webpack giving a warn during compiling the code.

error.png

Anyway I solved it by adding ‘default’ keyword:

export default function add(a, b){
  return a + b;
}

And let’s compare the webpack-generated code before and after I made this change in WinMerge:

diff1.png

diff2.png

Conclusion

It seems that the export/import syntax which webpack 2 supports doesn’t comply with ES6.

Webpack 2 Recipe

Serve web pages with HTTP

Go to the project directory in command prompt, and run the following command to initialize it:

npm init

Run the command to install http-server package:

npm install http-server --save-dev

install-http-server

In the created package.json file, add one line:

"start": "http-server -a localhost -p 8000"

So, it now reads:

{
  "name": "currans-example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "http-server -a localhost -p 8000"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "http-server": "^0.10.0"
  }
}

Now, run the command as below:

npm start

start.png

Access http://localhost:8000

server.png

First Taste Of Webpack 2: Module Bundling

es6-webpack-module

Environment

Windows 7 Pro 64-bit

NodeJS & NPM

WAMP (I am using it as my server instead of Node, even though I have Node installed)

Task Description

What I am going to do is use webpack to load JavaScript modules (with ES6 syntax) and generate one single .js file. Mainly I will follow the instructions from this video tutorial, but I am building  the example code from Curran Kelleher’s tutorial: JavaScript Modules & Build Tools. However, I will use a simplified version of the code, as the app built with the original code ran into an error, and I haven’t solved it yet, which I will discuss at the end of this blog.

Instruction

OK, let’s go.

Step 1: create the sample project

Its structure is (btw, I am using Sublime Text 3 as my editor, and the whole folder is under C:\wamp\www, as I am going to use Apache to serve the pages):

project-directory

index.html:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Example</title>
  </head>
  <body>

    <h1 id="output"></h1>
    <script src="bundle.js"></script>
      
  </body>
</html>

Please note that the index.html imports a bundle.js file which does not exist yet, we will create it with webpack.

add.js (please note that you cannot leave ‘default’ out here, but you can use export {} syntax otherwise):

export default function add(a, b) {
  return a + b;
}

main.js:

import add from './add';

var result = add(1, 2);

var outputElement = document.getElementById("output")
outputElement.innerHTML = result;

Step 2: initialize the project with npm

Open up the command prompt in Windows, I am used to running it as admin, it might be optional in your case:

hit-cmd.png

In the command line, navigate to the project directory, an run command:

npm init

init.png

That will create a file named package.json, its content is:

{
  "name": "1st-webpack-test",
  "version": "1.0.0",
  "description": "vincents first try on webpack",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

Step 3: install webpack

Run command:

npm install webpack --save-dev

It will take a while to install all the packages that webpack has dependencies on:

install-webpack

That will create a new folder under the directory called node_modules, and update the package.json file, it now reads like:

{
  "name": "1st-webpack-test",
  "version": "1.0.0",
  "description": "vincents first try on webpack",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.0.0"
  }
}

A new property ‘devDependencies’ is added.

Step 4: build the project

Modify the package.json file, adding build property to scripts:
“build”: “webpack main.js bundle.js”

it now reads:

{
  "name": "1st-webpack-test",
  "version": "1.0.0",
  "description": "vincents first try on webpack",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack main.js bundle.js"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.0.0"
  }
}

We are now ready to run the build command:

npm run build

It will create the bundle.js file:

run-build.png

Now we can see the newly created bundle.js file, it reads like:

/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, {
/******/ 				configurable: false,
/******/ 				enumerable: true,
/******/ 				get: getter
/******/ 			});
/******/ 		}
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__add__ = __webpack_require__(1);


var result = __WEBPACK_IMPORTED_MODULE_0__add__["a" /* default */](1, 2);

var outputElement = document.getElementById("output")
outputElement.innerHTML = result;

/***/ }),
/* 1 */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
/* harmony export (immutable) */ __webpack_exports__["a"] = add;
function add(a, b) {
  return a + b;
}

/***/ })
/******/ ]);

If we now run the index.html from Apache server (again, I am using WAMP):

built.png

Step 5: minify the bundle.js

Add one line to package.json:
“build:prod”: “webpack main.js bundle.js -p”

so it now reads as:

{
  "name": "1st-webpack-test",
  "version": "1.0.0",
  "description": "vincents first try on webpack",
  "main": "main.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack main.js bundle.js",
    "build:prod": "webpack main.js bundle.js -p"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^3.0.0"
  }
}

And run the command:

npm run build:prod

mini

it will compress the bundle.js, and it looks like:

minify.png

Conclusion

It looks like that webpack 2 now supports ES6 syntax as well as AMD and ConnomJS.

Problem With Original Example Code

I can build it, but when running the page, I got a TypeError, which says:

error-with-original.png

This issue is very typical to such transpiling techniques, in the beginning we have our code working fine, but it runs into errors after processed with those tools, and we cannot debug the generated code.

How does Anonymous Type in C# Work?

Recently I encountered a question about this topic in a test. Below is the question.

var person = new { FirstName = "Jon", LastName= "Doe" };

What class is generated to present person by the compiler when running the above code?

  1. <>f__AnonymousType0’2[System.String,System.String]
  2. AnonymousType[String,String]
  3. <>f__AnonymousType0’2[string,string]
  4. <>f__AnonymousType0’2[System.Char[],System.Char[]]
  5. AnonymousType0’2[System.String,System.String]

At first glance, I can rule out choice 2 and 5, the internal notation should not be that simple, and then I exclude the choice 3, as I think full qualification of type name should include namespace. I was struggling between 1 and 4, I though Char[] would save more space as the length of the string was determined at compiling time, but that turned wrong in the end.

Let’s walk through the investigation. First thing first, create a project of Windows Console, and my Program.cs reads like:

using System;

namespace AnonymousType
{
    class Program
    {
        static void Main(string[] args)
        {
            var person = new
            {
                FirstName = "Jon",
                LastName= "Doe"
            };
            ReflectOverAnonymousType(person);
            Console.ReadKey();
        }

        static void ReflectOverAnonymousType(object obj)
        {
            Console.WriteLine("obj is an instance of: {0}", obj.GetType().Name);
            Console.WriteLine("Base class of {0} is {1}", obj.GetType().Name, obj.GetType().BaseType);
            Console.WriteLine("obj.ToString() == {0}", obj.ToString());
            Console.WriteLine("obj.GetHashCode() == {0}", obj.GetHashCode());
            Console.WriteLine();
        }
    }
}

Here I am reusing the function ReflectOverAnonymousType from Andrew’s [C# 6.0 and The .NET 4.6 Framework].

The output displays only the name of the generated class type:

reflection

The rest is to figure out the type of the properties: FirstName and LastName. I thought Ildasm would give me some useful information, but as a matter of fact, it does not:

ildasm

Have no idea about ‘<FirstName>j_Tpar’.

 

Finally, I found an easy way to work it out, which is to execute GetType() on person object in Immediate Window:

immediate-window

So, the correct answer is choice 1.