Author Archives: admin

React Native Internals

[ Fuente:

https://www.reactnative.guide/3-react-native-internals/3.1-react-native-internals.html

]

React Native Internals

React Native is a framework which allows developers to build native apps using Javascript. Wait! Cordova already does that and it has been around for quite a while. Why would anyone want to use RN?

The primary difference between RN and Cordova based apps is that Cordova based apps run inside a webview while RN apps render using native views. RN apps have direct access to all the Native APIs and views offered by the underlying mobile OS. Thus, RN apps have the same feel and performance as that of a native application.

At first, it is easy to assume that React Native might be compiling JS code into respective native code directly. But this would be really hard to achieve since Java and Objective C are strongly typed languages while Javascript is not! Instead, RN does something much more clever. Essentially, React Native can be considered as a set of React components, where each component represents the corresponding native views and components. For example, a native TextInput will have a corresponding RN component which can be directly imported into the JS code and used like any other React component. Hence, the developer will be writing the code just like for any other React web app but the output will be a native application.

Ok! This looks like black magic 馃檮.

To understand this, let us take a look at the architecture and how React Native works internally.

Architecture 馃

Both iOS and Android have a similar architecture with subtle differences.

If we consider the big picture, there are three parts to the RN platform:

  1. Native Code/Modules: Most of the native code in case of iOS is written in Objective C or Swift, while in the case of Android it is written in Java. But for writing our React Native app, we would hardly ever need to write native code for iOS or Android.

  2. Javascript VM: The JS Virtual Machine that runs all our JavaScript code. On iOS/Android simulators and devices React Native uses JavaScriptCore, which is the JavaScript engine that powers Safari. JavaScriptCore is an open source JavaScript engine originally built for WebKit. In case of iOS, React Native uses the JavaScriptCore provided by the iOS platform. It was first introduced in iOS 7 along with OS X Mavericks.
    https://developer.apple.com/reference/javascriptcore.

    In case of Android, React Native bundles the JavaScriptCore along with the application. This increases the app size. Hence the Hello World application of RN would take around 3 to 4 megabytes for Android.

    In case of Chrome debugging mode, the JavaScript code runs within Chrome itself (instead of the JavaScriptCore on the device) and communicates with native code via WebSocket. Here, it will use the V8 engine. This allows us to see a lot of information on the Chrome debugging tools like network requests, console logs, etc. 馃槑

  3. React Native Bridge: React Native bridge is a C++/Java bridge which is responsible for communication between the native and Javascript thread. A custom protocol is used for message passing.

react native architecture diagram

In most cases, a developer would write the entire React Native application in Javascript. To run the application one of the following commands are issued via the CLI –聽react-native run-ios聽or聽react-native run-android.

At this point, React Native CLI would spawn a node packager/bundler that would bundle the JS code into a single聽main.bundle.js聽file. The packager can be considered as being similar to Webpack.

Now, whenever the React Native app is launched, the first item to be loaded is the native entry point. The Native thread spawns the JS VM thread which runs the bundled JS code. The JS code has all the business logic of the application. The Native thread now sends messages via the RN Bridge to start the JS application.

Now, the spawned Javascript thread starts issuing instructions to the native thread via the RN Bridge. The instructions include what views to load, what information is to be retrieved from the hardware, etc. For example, if the JS thread wants a view and text to be created it will batch the request into a single message and send it across to the Native thread to render them.

[ [2,3,[2,'Text',{...}]] [2,3,[3,'View',{...}]] ]

The native thread will perform these operations and send the result back to the JS assuring that the operations have been performed.

Note: To see the bridge messages on the console, just put the following snippet onto the聽index.<platform>.js聽file

import MessageQueue from 'react-native/Libraries/BatchedBridge/MessageQueue';
MessageQueue.spy(true);

Threading Model 馃毀

When a React Native application is launched, it spawns up the following threading queues.

  1. Main thread(Native Queue)聽– This is the main thread which gets spawned as soon as the application launches. It loads the app and starts the JS thread to execute the Javascript code. The native thread also listens to the UI events like ‘press’, ‘touch’, etc. These events are then passed to the JS thread via the RN Bridge. Once the Javascript loads, the JS thread sends the information on what needs to be rendered onto the screen. This information is used by a聽shadow node thread聽to compute the layouts. The shadow thread is basically like a mathematical engine which finally decides on how to compute the view positions. These instructions are then passed back to the main thread to render the view.

  2. Javascript thread(JS Queue)聽– The Javascript Queue is the thread queue where main bundled JS thread runs. The JS thread runs all the business logic, i.e., the code we write in React Native.

  3. Custom Native Modules聽– Apart from the threads spawned by React Native, we can also spawn threads on the custom native modules we build to speed up the performance of the application. For example – Animations are handled in React Native by a separate native thread to offload the work from the JS thread.

Links:聽https://www.youtube.com/watch?v=0MlT74erp60

Development mode 馃敤

When the app is run in聽DEV聽mode, the Javascript thread is spawned on the development machine. Even though the JS code is running on a more powerful machine as compared to a phone, you will soon notice that the performance is considerably lower as compared to when running in bundled mode or production mode. This is unavoidable because a lot more work is done in DEV mode at runtime to provide good warnings and error messages, such as validating propTypes and various other assertions. Furthermore, the latency of communication between the device and the JS thread also comes into play.

Link:聽https://www.youtube.com/watch?v=8N4f4h6SThc聽– RN android architecture

React native: Expo: How Expo Works

[ Fuente:

https://docs.expo.io/versions/v26.0.0/workflow/how-expo-works

]

How Expo Works

While it’s certainly not necessary to know any of this to use Expo, many engineers like to know how their tools work. We’ll walk through a few key concepts here, including:

  • Local development of your app
  • Publishing/deploying a production version of your app
  • How Expo manages changes to its SDK
  • Opening Expo apps offline

You can also browse the source, fork, hack on and contribute to the Expo tooling on聽github/@expo.

There are two pieces here: the Expo app and the Expo development tool (either XDE or聽exp聽CLI). We’ll just assume XDE here for simplicity of naming. When you open an app up in XDE, it spawns and manages two server processes in the background:

  • the Expo Development Server
  • and the React Native Packager Server.

Note:聽XDE also spawns a tunnel process, which allows devices outside of your LAN to access the the above servers without you needing to change your firewall settings. If you want to learn more, see聽ngrok.

Expo Development Server

This server is the endpoint that you hit first when you type the URL into the Expo app. Its purpose is to serve the聽Expo Manifest聽and provide a communication layer between the XDE UI and the Expo app on your phone or simulator.

The following is an example of a manifest being served through XDE. The first thing that you should notice is there are a lot of identical fields to聽app.json聽(see the聽Configuration with app.json聽section if you haven’t read it yet). These fields are taken directly from that file — this is how the Expo app accesses your configuration.

{
  "name":"My New Project",
  "description":"A starter template",
  "slug":"my-new-project",
  "sdkVersion":"18.0.0",
  "version":"1.0.0",
  "orientation":"portrait",
  "primaryColor":"#cccccc",
  "icon":"https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png",
  "notification":{
    "icon":"https://s3.amazonaws.com/exp-us-standard/placeholder-push-icon.png",
    "color":"#000000"
  },
  "loading":{
    "icon":"https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png"
  },
  "entryPoint": "node_modules/expo/AppEntry.js",
  "packagerOpts":{
    "hostType":"tunnel",
    "dev":false,
    "strict":false,
    "minify":false,
    "urlType":"exp",
    "urlRandomness":"2v-w3z",
    "lanType":"ip"
  },
  "xde":true,
  "developer":{
    "tool":"xde"
  },
  "bundleUrl":"http://packager.2v-w3z.notbrent.internal.exp.direct:80/apps/new-project-template/main.bundle?platform=ios&dev=false&strict=false&minify=false&hot=false&includeAssetFileHashes=true",
  "debuggerHost":"packager.2v-w3z.notbrent.internal.exp.direct:80",
  "mainModuleName":"main",
  "logUrl":"http://2v-w3z.notbrent.internal.exp.direct:80/logs"
}

Every field in the manifest is some configuration option that tells Expo what it needs to know to run your app. The app fetches the manifest first and uses it to show your app’s loading icon that you specified in聽app.json, then proceeds to fetch your app’s JavaScript at the given聽bundleUrl聽— this URL points to the React Native Packager Server.

In order to stream logs to XDE, the Expo SDK intercepts calls to聽console.log,聽console.warn, etc. and posts them to the聽logUrl聽specified in the manifest. This endpoint is on the Expo Development Server.

If you use React Native without Expo, you would start the packager by running聽react-native start聽in your project directory. Expo starts this up for you and pipes聽STDOUT聽to XDE. This server has two purposes.

The first is to serve your app JavaScript compiled into a single file and translating any JavaScript code that you wrote which isn’t compatible with your phone’s JavaScript engine. JSX, for example, is not valid JavaScript — it is a language extension that makes working with React components more pleasant and it compiles down into plain function calls — so聽<HelloWorld />聽would become聽React.createElement(HelloWorld, {}, null)聽(see聽JSX in Depth聽for more information). Other language features like聽async/await聽are not yet available in most engines and so they need to be compiled down into JavaScript code that will run on your phone’s JavaScript engine, JavaScriptCore.

The second purpose is to serve assets. When you include an image in your app, you will use syntax like聽<Image source={require('./assets/example.png')} />, unless you have already cached that asset you will see a request in the XDE logs like:聽<START> processing asset request my-proejct/assets/example@3x.png. Notice that it serves up the correct asset for your screen DPI, assuming that it exists.

 

When you publish an Expo app, we compile it into a JavaScript bundle with production flags enabled. That is, we minify the source and we tell the React Native packager to build in production mode (which in turn sets聽__DEV__聽to聽false聽amongst other things). After compilation, we upload that bundle, along with any assets that it requires (see聽Assets) to CloudFront. We also upload your聽Manifest聽(including most of your聽app.jsonconfiguration) to our server. When publishing is complete, we’ll give you a URL to your app which you can send to anybody who has the Expo client.

Note:聽By default, all Expo projects are聽unlisted, which means that publishing does not make it publicly searchable or discoverable anywhere. It is up to you to share the link. You can change this setting in聽app.json.

As soon as the publish is complete, the new version of your code is available to all your existing users. They’ll download the updated version next time they open the app or refresh it, provided that they have a version of the Expo client that supports the聽sdkVersion聽specified in your聽app.json.

Updates are handled differently on iOS and Android. On Android, updates are downloaded in the background. This means that the first time a user opens your app after an update they will get the old version while the new version is downloaded in the background. The second time they open the app they’ll get the new version. On iOS, updates are downloaded synchronously, so users will get the new version the first time they open your app after an update.

Note:聽To package your app for deployment on the Apple App Store or Google Play Store, see聽Building Standalone Apps. Each time you update the SDK version you will need to rebuild your binary.

 

The聽sdkVersion聽of an Expo app indicates what version of the compiled ObjC/Java/C layer of Expo to use. Each聽sdkVersion聽roughly corresponds to a release of React Native plus the Expo libraries in the SDK section of these docs.

The Expo client app supports many versions of the Expo SDK, but an app can only use one at a time. This allows you to publish your app today and still have it work a year from now without any changes, even if we have completely revamped or removed an API your app depends on in a new version. This is possible because your app will always be running against the same compiled code as the day that you published it.

If you publish an update to your app with a new聽sdkVersion, if a user has yet to update to the latest Expo client then they will still be able to use the previous聽sdkVersion.

Note:聽It’s likely that eventually we will formulate a policy for how long we want to keep around sdkVersions and begin pruning very old versions of the sdk from the client, but until we do that, everything will remain backwards compatible.

 

The process is essentially the same as opening an Expo app in development, only now we hit an Expo server to get the manifest, and manifest points us to CloudFront to retrieve your app’s JavaScript.

 

The Expo client will automatically cache the most recent version of every app it has opened. When you try to open an Expo app, it will always try and fetch the latest version, but if that fails for whatever reason (including being totally offline) then it will load the most recent cached version.

If you build a standalone app with Expo, that standalone binary will also ship with a “pre-cached” version of your JavaScript so that it can cold launch the very first time with no internet. Continue reading for more information about standalone apps.

You can also package your Expo app into a standalone binary for submission to the Apple iTunes Store or Google Play.

Under the hood, it’s a modified version of the Expo client which is designed only to load a single URL (the one for your app) and which will never show the Expo home screen or brand. For more information, see聽Building Standalone Apps.

 

React Native : Building native releases

[Fuente:

https://facebook.github.io/react-native/docs/signed-apk-android.html

https://docs.expo.io/versions/v26.0.0/distribution/building-standalone-apps#content

https://docs.expo.io/versions/v26.0.0/expokit/detach#content

]

Contents

Generating Signed APK

Expo: Building standalone apps

Expo: Detach

Generating Signed APK

Android requires that all apps be digitally signed with a certificate before they can be installed, so to distribute your Android application via聽Google Play store, you’ll need to generate a signed release APK. The聽Signing Your Applications聽page on Android Developers documentation describes the topic in detail. This guide covers the process in brief, as well as lists the steps required to package the JavaScript bundle.

Generating a signing key

You can generate a private signing key using聽keytool. On Windows聽keytool聽must be run from聽C:\Program Files\Java\jdkx.x.x_x\bin.

$ keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000

This command prompts you for passwords for the keystore and key, and to provide the Distinguished Name fields for your key. It then generates the keystore as a file called聽my-release-key.keystore.

The keystore contains a single key, valid for 10000 days. The alias is a name that you will use later when signing your app, so remember to take note of the alias.

Note: Remember to keep your keystore file private and never commit it to version control.

Setting up gradle variables

  1. Place the聽my-release-key.keystore聽file under the聽android/app聽directory in your project folder.
  2. Edit the file聽~/.gradle/gradle.properties聽or聽android/gradle.properties聽and add the following (replace聽*****聽with the correct keystore password, alias and key password),
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****

These are going to be global gradle variables, which we can later use in our gradle config to sign our app.

Note about saving the keystore:聽Once you publish the app on the Play Store, you will need to republish your app under a different package name (losing all downloads and ratings) if you want to change the signing key at any point. So backup your keystore and don’t forget the passwords.

Note about security: If you are not keen on storing your passwords in plaintext and you are running OSX, you can also聽store your credentials in the Keychain Access app. Then you can skip the two last rows in聽~/.gradle/gradle.properties.

Adding signing config to your app’s gradle config

Edit the file聽android/app/build.gradle聽in your project folder and add the signing config,

...
android {
    ...
    defaultConfig { ... }
    signingConfigs {
        release {
            if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
                storeFile file(MYAPP_RELEASE_STORE_FILE)
                storePassword MYAPP_RELEASE_STORE_PASSWORD
                keyAlias MYAPP_RELEASE_KEY_ALIAS
                keyPassword MYAPP_RELEASE_KEY_PASSWORD
            }
        }
    }
    buildTypes {
        release {
            ...
            signingConfig signingConfigs.release
        }
    }
}
...

Generating the release APK

Simply run the following in a terminal:

$ cd android && ./gradlew assembleRelease

Gradle’s聽assembleRelease聽will bundle all the JavaScript needed to run your app into the APK. If you need to change the way the JavaScript bundle and/or drawable resources are bundled (e.g. if you changed the default file/folder names or the general structure of the project), have a look at聽android/app/build.gradle聽to see how you can update it to reflect these changes.

Note: Make sure gradle.properties does not include聽org.gradle.configureondemand=true聽as that will make release build skip bundling JS and assets into the APK.

The generated APK can be found under聽android/app/build/outputs/apk/app-release.apk, and is ready to be distributed.

Testing the release build of your app

Before uploading the release build to the Play Store, make sure you test it thoroughly. First uninstall any previous version of the app you already have installed. Install it on the device using:

$ react-native run-android --variant=release

Note that聽--variant=release聽is only available if you’ve set up signing as described above.

You can kill any running packager instances, all your framework and JavaScript code is bundled in the APK’s assets.

Split APKs by ABI to reduce file size

By default, the generated APK has the native code for both x86 and ARMv7a CPU architectures. This makes it easier to share APKs that run on almost all Android devices. However, this has the downside that there will be some unused native code on any device, leading to unnecessarily bigger APKs.

You can create an APK for each CPU by changing the following line in android/app/build.gradle:

- def enableSeparateBuildPerCPUArchitecture = false
+ def enableSeparateBuildPerCPUArchitecture = true

Upload both these files to markets which support device targetting, such as聽Google Play聽and聽Amazon AppStore聽and the users will automatically get the appropriate APK. If you want to upload to other markets such as聽APKFiles, which do not support multiple APKs for a single app, change the following line as well to create the default universal APK with binaries for both CPUs.

- universalApk false  // If true, also generate a universal APK
+ universalApk true  // If true, also generate a universal APK

Enabling Proguard to reduce the size of the APK (optional)

Proguard is a tool that can slightly reduce the size of the APK. It does this by stripping parts of the React Native Java bytecode (and its dependencies) that your app is not using.

IMPORTANT: Make sure to thoroughly test your app if you’ve enabled Proguard. Proguard often requires configuration specific to each native library you’re using. See聽app/proguard-rules.pro.

To enable Proguard, edit聽android/app/build.gradle:

/**
 * Run Proguard to shrink the Java bytecode in release builds.
 */
def enableProguardInReleaseBuilds = true

React Native: Image snippets

Full width & height

import React, { Component } from 'react';
import { View, Image } from 'react-native';
import splashImage from '../assets/img/Marvel-Comics-Logo.png';

class Splash extends Component {
    render() {
        const { imageStyle, containerStyle } = styles;
        return (
            <View style={containerStyle}>
                    <Image
                        style={imageStyle}
                        source={splashImage}
                    />
            </View>
        );
    }
}

const styles = {
    containerStyle: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'stretch'
    },
    imageStyle: {
        flexGrow: 1,
        height: null,
        width: null,
        alignItems: 'center',
        justifyContent: 'center'
    }
};
export default Splash;

 

 

React Native: Generating Signed APK (Android)

[Fuente: https://facebook.github.io/react-native/docs/signed-apk-android.html]

Android requires that all apps be digitally signed with a certificate before they can be installed, so to distribute your Android application via聽Google Play store, you’ll need to generate a signed release APK. The聽Signing Your Applications聽page on Android Developers documentation describes the topic in detail. This guide covers the process in brief, as well as lists the steps required to package the JavaScript bundle.

Generating a signing key

You can generate a private signing key using聽keytool. On Windows聽keytool聽must be run from聽C:\Program Files\Java\jdkx.x.x_x\bin. In Mac usually is in system path:

$ keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000

This command prompts you for passwords for the keystore and key, and to provide the Distinguished Name fields for your key. It then generates the keystore as a file called聽my-release-key.keystore.

The keystore contains a single key, valid for 10000 days. The alias is a name that you will use later when signing your app, so remember to take note of the alias.

Note: Remember to keep your keystore file private and never commit it to version control.

Setting up gradle variables

  1. Place the聽my-release-key.keystore聽file under the聽android/app聽directory in your project folder.
  2. Edit the file聽~/.gradle/gradle.properties聽or聽android/gradle.properties聽and add the following (replace聽*****聽with the correct keystore password, alias and key password),
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=*****
MYAPP_RELEASE_KEY_PASSWORD=*****

These are going to be global gradle variables, which we can later use in our gradle config to sign our app.

Note about saving the keystore:聽Once you publish the app on the Play Store, you will need to republish your app under a different package name (losing all downloads and ratings) if you want to change the signing key at any point. So backup your keystore and don’t forget the passwords.

Note about security: If you are not keen on storing your passwords in plaintext and you are running OSX, you can also聽store your credentials in the Keychain Access app. Then you can skip the two last rows in聽~/.gradle/gradle.properties.

Adding signing config to your app’s gradle config

Edit the file聽android/app/build.gradle聽in your project folder and add the signing config,

...
android {
    ...
    defaultConfig { ... }
    signingConfigs {
        release {
            if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
                storeFile file(MYAPP_RELEASE_STORE_FILE)
                storePassword MYAPP_RELEASE_STORE_PASSWORD
                keyAlias MYAPP_RELEASE_KEY_ALIAS
                keyPassword MYAPP_RELEASE_KEY_PASSWORD
            }
        }
    }
    buildTypes {
        release {
            ...
            signingConfig signingConfigs.release
        }
    }
}
...

Generating the release APK

Simply run the following in a terminal:

$ cd android && ./gradlew assembleRelease

Gradle’s聽assembleRelease聽will bundle all the JavaScript needed to run your app into the APK. If you need to change the way the JavaScript bundle and/or drawable resources are bundled (e.g. if you changed the default file/folder names or the general structure of the project), have a look at聽android/app/build.gradle聽to see how you can update it to reflect these changes.

The generated APK can be found under聽android/app/build/outputs/apk/app-release.apk, and is ready to be distributed.

NOTE: We need to remove node_modules/**/*.bin folders to not to get error

Testing the release build of your app

Before uploading the release build to the Play Store, make sure you test it thoroughly. First uninstall any previous version of the app you already have installed. Install it on the device using:

$ react-native run-android --variant=release

Note that聽--variant=release聽is only available if you’ve set up signing as described above.

You can kill any running packager instances, all your framework and JavaScript code is bundled in the APK’s assets.

Angular 1.5 : A guide to build components

[Source: https://www.sitepoint.com/building-angular-1-5-components/]

In Angular 1, components are the mechanism which allows you to create your own custom HTML elements. This has been possible with Angular directives in the past, but components build on the various improvements that have been made to Angular and enforce best practices in how they are built and designed.

In this article, we鈥檙e going to dig into the design of components and how to put them to use inside of your applications. If you haven鈥檛 already started to use components in Angular 1, you can read about their syntax and design in聽one of our recent tutorials. My goal is to outline some best practices that will improve the quality of your application.

It should also be noted that many of the best practices of Angular 2 are brought into Angular 1 through the new components API, allowing you to build applications that are more easily refactored later. Angular 2 has influenced the way that we think about and design Angular 1 components, but there are still a number of distinct differences. Angular 1 is still a very powerful tool for building applications, so I believe it is worthwhile to invest in improving your applications with components even if you aren鈥檛 planning or ready to migrate to Angular 2.

What Makes a Good Component?

Components should be designed with a number of key characteristics in mind to make them a powerful building block for your application. We鈥檒l dig into each of these in more detail, but here are the primary concepts components should adhere to.

  • Isolated聽鈥 The logic of the component should be encapsulated to remain internal and private. This helps create less coupling between components.
  • Focused聽鈥 Components should act as a single unit for one primary task, which makes them easy to reason about and often more reusable.
  • One-Way Binding聽鈥 When possible, components should leverage one-way binding to reduce the load on the digest cycle.
  • Use Lifecycle Events聽鈥 The lifecycle of a component starts with instanciation and ends with removal from the page. It is to best to hook into these events to maintain the component over time.
  • Well Defined API聽鈥 Components should accept configuration as attributes in a consistent manner, so it is easy to know how to use them.
  • Emit Events聽鈥 In order to communicate with other components, they should emit events with appropriate names and data.

Now let鈥檚 start by looking at why and how components should be isolated and encapsulated from the rest of the application.

Components Should Be Isolated

The evolution of Angular 1 capabilities has been to enable isolated and encapsulated components, and for good reason. Some of the early applications were highly coupled with the use of聽$scope聽and nested controllers. Originally Angular didn鈥檛 provide a solution, but now it does.

Good components do not expose their internal logic. Thanks to the way they are designed, this is pretty easy to accomplish. However, resist any temptation to abuse components by using聽$scope聽unless absolutely necessary, such as emitting/broadcasting events.

Components Should Be Focused

Components should take on a single role. This is important for testability, reusability, and simplicity. It is better to make additional components rather than overload a single one. This doesn鈥檛 mean you won鈥檛 have larger or more complex components, it simply means each component should remain focused on its primary job.

I鈥檝e classified components into four primary groups based on their role in the application to help you think about how you design your components. There is no different syntax to build these different types of components 鈥 it is just important to consider the specific role a component takes.

These types are based on my 5+ years of Angular experience. You may choose to organize slightly differently, but the underlying concept is to ensure your components have a clear role.

App Components

There can be only one app component that acts like the root of your application. You can think of it like having only one component in the body of your web application, and all other logic is loaded through it.

<body>
  <app></app>
</body>

This is recommended primarily for Angular 2 design parity, so it will be easier to migrate some day should you wish. It also helps with testing by moving all of the the root content of your application into a single component, instead of having some of it in the聽index.html聽file. The app component also gives you a place to do app instantiation so you don鈥檛 have to do it in the app聽run聽method, enhancing testability and decreasing reliance upon聽$rootScope.

This component should be as simple as possible. It probably will contain just a template and not contain any bindings or a controller if possible. It does not replace聽ng-app聽or the need to bootstrap your application, however.

Routing Components

In the past, we鈥檝e linked controllers and templates in a ui-router state (or聽ngRoute聽 route). Now it is possible to link a route directly to a component, so the component is still the place in which a controller and template are paired, but with the benefit of being also routable.

For example, with ui-router this is how we would link a template and controller.

$stateProvider.state('mystate', {
  url: '/',
  templateUrl: 'views/mystate.html',
  controller: MyStateController
});

Now, you can link a url directly to a component instead.

$stateProvider.state('mystate', {
  url: '/',
  component: 'mystate'
});

These components can bind data from the route params (such as an item id), and their role is to focus on setting up the route to load the other components needed. This seemingly minor change to defining routes is actually very important for Angular 2 migration capability, but also important in Angular 1.5 to better encapsulate a template and controller at the component level.

Angular 1 actually has two router modules, ngRoute and ngComponentRouter. Only ngComponentRouter supports components, but it is also deprecated. I think the best bet is to go with ui-router.

Stateful Components

Most of the unique components you鈥檒l build for your application are stateful. This is where you鈥檒l actually put your application business logic, make HTTP requests, handle forms, and other stateful tasks. These components are likely unique to your application, and they focus on maintaining data over visual presentation.

Imagine you have a controller that loads a user鈥檚 profile data to display, and has a corresponding template (not shown here) linked together in a directive. This snippet might be the most basic controller to accomplish the job.

.controller('ProfileCtrl', function ($scope, $http) {
  $http.get('/api/profile').then(function (data) {
    $scope.profile = data;
  });
})
.directive('profile', function() {
  return {
    templateUrl: 'views/profile.html',
    controller: 'ProfileCtrl'
  }
})

With components, you can design this better than before. Ideally, you would also use a service instead of聽$http聽directly in the controller.

.component('profile', {
  templateUrl: 'views/profile.html',
  controller: function($http) {
    var vm = this;
    // Called when component is ready, see below
    vm.$onInit = function() {
      $http.get('/api/profile').then(function (data) {
        vm.profile = data;
      });
    };
  }
})

Now you have a component that loads its own data, thus making it stateful. These types of components are similar to routing components, except they might be used without being linked to a single route.

Stateful components will use other (stateless) components to actually render out the UI. Also, you鈥檒l still want to use services instead of putting data access logic directly in the controller.

Stateless Components

Stateless components are focused on rendering without managing business logic, and need not be unique to any particular application. For exampe most components that are used for UI elements (such as form controls, cards, etc) don鈥檛 also handle logic like loading data or saving a form. They are intended to be highly modular, reusable, and isolated.

A stateless component may not need a controller, if it just displays data or controls everything in the template. They will accept input from a stateful component. This example takes a value from the stateful component (the聽profile聽example above) and displays an avatar.

.component('avatar', {
  template: '<img ng-src="http://example.com/images/{{vm.username}}.png" />',
  bindings: {
    username: '<'
  },
  controllerAs: 'vm'
})

To use it, the stateful component would pass the username via the attribute like so聽<avatar username="vm.profile.username">.

Most libraries you use are a collection of stateless components (and perhaps services). They certainly can accept configuration to modify their behavior, but they are not meant to be in charge of logic outside of their own.

Components Should Use One-way Bindings

This is not a new feature with components, but it is often smart to leverage it with components. The intent of one-way bindings is to avoid loading more work into the digest cycle, which is a major factor in application performance. Data now flows into the component without having to look outside of it (which causes some of the coupling problems that exist today), and the component can simply render itself given that input. This design also lends itself to Angular 2, which helps with future migration.

In this example, the聽title聽property is only bound into the component once based on the initial value provided. If the聽title聽changes by some outside actor, it does not get reflected in the component. The syntax to denote a binding as one-way is to use the聽<symbol.

bindings: {
  title: '<'
}

The component will still update when the聽title聽property changes, and we鈥檒l cover how to listen for changes to the聽title聽property. It is recommended to use one-way anytime you can.

Components Should Consider One-time Bindings

Angular also has the ability to bind data one-time, so you can optimize the digest cycle. Essentially, Angular will wait until the first value that is not聽undefined聽is provided into the binding, bind that value, and then (once all bindings have resolved) remove the associated watchers from the digest cycle. This means that particular binding will not add any processing time to the future digest loops.

This is done by putting聽::聽in front of a binding expression. This only makes sense if you know that the input binding will not change over the lifecycle. In this example, if聽title聽is a one-way binding, it will continue to be updated inside of the component but the binding here will not update because we denoted it as one-time.

<h1>{{::title}}</h1>

Components Should Use Lifecycle Events

You probably noticed the $onInit function as a new capability. Components have a lifecycle with corresponding events that you should be using to help manage certain aspects of the component.

$onInit()

The first step in the component lifecycle is initialization. This event runs after the controller and bindings are initialized. You should almost always use this method to do component setup or initialization. It will ensure that all values are available to the component before running. If you were to access binding values in the controller directly there is no guarantee those values will be available to you.

controller: function() {
  var vm = this;
  console.log(vm.title); // May not yet be available!
  vm.$onInit = function() {
    console.log(vm.title); // Guaranteed to be available!
  }
}

The next step is linking any child elements from the template. When the component initializes, there is no guarantee it will have also rendered any children used inside of your template. This is important if you need to manipulate the DOM in any way. One important caveat is that templates that are loaded asynchronously might not have loaded by the time this event fires. You can always use a template caching solution to ensure that templates are always available.

controller: function() {
  var vm = this;
  vm.$postLink = function() {
    // Usually safe to do DOM manipulation
  }
}

$onChanges()

While the component is active, it may need to react to changes in input values. One-way bindings will still update your component, but we have a new聽$onChanges聽event binding to listen for when the inputs change.

For this sample, imagine there is a product title and description provided to a component. You can detect changes as demonstrated below. You are able to look at the object passed to the function, which has an object mapped to the available bindings with both the current and previous values.

bindings: {
  title: '<'
},
controller: function() {
  var vm = this;
  vm.$onChanges = function($event) {
    console.log($event.title.currentValue); // Get updated value
    console.log($event.title.previousValue); // Get previous value
  }
}

$onDestroy()

The final phase is the removal of the component from the page. This event runs right before the controller and its scope are destroyed. It is important to clean up anything that your component might have created or that holds memory, such as event listeners, watchers, or additional DOM elements.

controller: function() {
  var vm = this;
  vm.$onDestroy = function() {
    // Reset or remove any event listeners or watchers
  }
}

Components Should Have a Well Defined API

To configure and initialize a component with a set of data, a component should use bindings to accept these values. This is sometimes thought of as the component API, which is just a different way of describing the way a component accepts inputs.

The challenge here is to give bindings concise but clear names. Sometimes developers try to shorten names to be really succinct, but this is dangerous for the usage of the component. Imagine we have a component that accepts a stock symbol as input, which of these two are better?

bindings: {
  smb: '<',
  symbol: '<'
}

Hopefully you thought聽symbol聽was better. Sometimes developers also like to prefix components and bindings as a way to avoid name collisions. Prefixing the components is sensible, like聽md-toolbar聽is a Material toolbar, but prefixing all of the bindings gets verbose and should be avoided.

Components Should Emit Events

In order to communicate with other components, components should emit custom events. There are many examples of using a service and two-way data binding to sync data between components, but events are a better design choice. Events are far more efficient as a means to communicate with the page (and a foundational part of the JavaScript language and the way it works in Angular 2, which is not a coincidence).

Events in Angular can use either聽$emit聽(up the scope tree) or聽$broadcast聽(down the scope tree). Here is a quick example of events in action.

controller: function($scope, $rootScope) {
  var vm = this;
  vm.$onInit = function() {
    // Emits an event up to parents
    $scope.$emit('componentOnInit');
  };
  vm.$onDestroy = function() {
    // Emits an down child tree, from root
    $rootScope.$broadcast('componentOnDestroy');
  };
}

There are two primary situations where you will need to communicate between components: between components you know about, and components you don鈥檛. To illustrate the difference, let鈥檚 imagine we have a set of components that help manage tabs on the page, and a toolbar that has a link to the corresponding help page.

<my-toolbar></my-toolbar>
<my-tabs>
  <my-tab title="Description"></my-tab>
  <my-tab title="Reviews"></my-tab>
  <my-tab title="Support"></my-tab>
</my-tabs>

In this situation, the聽my-tabs聽and聽my-tab聽components are likely aware of one another, because they work together to create a set of three different tabs. However, the聽my-toolbar聽component is outside of their awareness.

Whenever a different tab is selected (which would be an even on the聽my-tabcomponent instance), the聽my-tabs聽component needs to be aware so it can adjust the display of the tabs to show that instance. The聽my-tab聽component can emit an event up to the parent聽my-tabs聽component. This type of communication is like an internal communication between two components that work together to make a single capability (a tabbed interface).

However, what if聽my-toolbar聽wants to know what tab is currently selected so it can change the help button based on what is visible? The聽my-tab聽event will never reach聽my-toolbar聽because it is not a parent. So another option is to use the聽$rootScopeto emit the event down the entire component tree, which allows any component to listen and react. The potential downfall here is that your event now reaches every controller, and if another component uses the same event name you could trigger unintended effects.

Decide which of these approaches make sense for your use case, but anytime another component might need to know about an event you鈥檒l likely want to use the second option to emit to the entire component tree.

Summary

Angular 1 applications can now be written with components, which changes the best practices and nature of how we write applications. This is for the better, but just simply using a component doesn鈥檛 necessarily make it better than what you had before. Here are the key things to keep in mind as you build your Angular 1 components.

  • Isolate your logic.聽Keep as much of the component logic internal and away from other aspects of the application to ensure consistency and quality.
  • Keep components simple and focused on a single role.聽They might be complex components, but the various tasks of a single component should be logically connected as a unit.
  • Use the lifecycle events.聽By hooking into the component lifecycle, you can ensure that data is ready at the right time and that you can clean up.
  • Use one-way and one-time bindings.聽When possible, one-way bindings are more efficient and promote good design, while one-time bindings can speed up your application. You can always use聽$onChanges聽lifecycle event to watch changes.
  • Use events for communication.聽Components can communicate using custom events, which is in line with how Angular 2 functions and a better design.
  • Have a well defined API.聽Ensure that your components are clearly named and easy to understand

 

Angular2 – Typescript

Introduction

TypeScript is a superset to JavaScript, which means, that it compiles into pure JavaScript in the end.

Why do we use it then? First, it provides 鈥strong typing鈥 (that鈥檚 where the name comes from). This means that we can (and should) assign types to our variables and class members. These types won鈥檛 compile to JavaScript (as JS does not know types) but we will get compilation errors if we assign wrong types or make any other type-related errors. This is a HUGE help in the daily development work and should not be underestimated!

Second, TypeScript introduces some nice features, JS does not have out of the box (at least in the ES5 specification). This includes classes (鈥榗lass鈥 keyword), interfaces, generics and modules. Being able to use these constructs makes our code cleaner, easier to read and helps us avoid nasty errors. Especially in combination with the strong typing we are really able to write high quality code and track down errors quickly.

Where can I learn all the TypeScript fundamentals?

There are a lot of great resources out there which will get you started very quickly. The official documentation is not too bad to be honest, so you may give it a try: http://www.typescriptlang.org/Handbook

There鈥檚 also a course here on Udemy, though I have not tested it! https://www.udemy.com/typescript/

Can we mix TypeScript and JavaScript?

Yes, we can. No one is preventing us from not setting types, using 鈥榲ar鈥 instead of 鈥榣et鈥 or using pure JavaScript libraries (i.e. libraries which don鈥檛 offer a TypeScript version/ implementation).

Can鈥檛 I use 鈥榥ormal鈥 JavaScript to write Angular 2 applications?

You can absolutely do that. But currently finding good documentation and examples on Angular 2 using plain JavaScript is extremely hard. And to be honest: TypeScript will be the standard 鈥榣anguage鈥 to be used when developing Angular 2 applications. So I definitely recommend using TypeScript.

Using types

  • We can define type for variables. Example:

01-typing/typing.ts

// Declaring a variable with a type
// Using the 'let' keyword to create a variable ('const' would define an immutable constant)
let myString: string;
myString = 'This is a string';
  • If we try to assign a different type will get an error on the typescript compiler
// Declaring a variable with a type
// Using the 'let' keyword to create a variable ('const' would define an immutable constant)
let myString: string;
myString = 'This is a string';

// Try to assign a number to a string => Error
myString = 4;
> tsc typing
typing.ts(10,1): error TS2322: Type '4' is not assignable to type 'string'
  • Typescript can also infer types. So in this example will also get an error:
// TypeScript can also infer types
let anotherString = 'This is a string without :string'; // => Type 'string' was inferred from the assigned value

// This will still resolve in a compilation error
anotherString = 4;
  • WARNING: Infering the type doesnt work if we not assign a value in declaration
// TypeScript may only infer values when those values are assigned at the declaration
// This does not work:
let yetAnotherString;
yetAnotherString = 'This is a string';

// TypeScript does not know the type, therefore we don't get an error ... but no we're also ignoring TypeScripts strength: Typing
yetAnotherString = 5;
  • By default if we dont聽specify type in the declaration will get the type any.
let yetAnotherString: any;
  • Other basic types:
// Other basic types

let aString: string;
let aNumber: number;
let aBoolean: boolean;
let anArray: Array<string>; // This is a generic type => May only hold 'strings' in this case
let anything: any; // Any can be used if we don't know the actual type => Use it rarely!
// We also got void (=> nothing) and enums (a set of numeric values)
  • We can also create custom types.
  • Summary : Strong types your variables: prevent errors.

 

Classes

// Classes allow us to create 'blueprints' for objects
// In Angular 2 we use classes a lot. For example to create Components, Services, Directives, Pipes, ...

// How to create a class

class Car {
    engineName: string;
    gears: number;
    private speed: number;

    constructor(speed: number) {
        this.speed = speed || 0;
    }

    accelerate(): void {
        this.speed++;
    }

    throttle():void {
        this.speed--;
    }

    getSpeed():void {
        console.log(this.speed);
    }

    static numberOfWheels(): number {
        return 4;
    }
}

// Instantiate (create) an object from a class

let car = new Car(5);
car.accelerate();
car.getSpeed();

console.log(Car.numberOfWheels());

* In old Javascript we already got class聽but now with TS use of classes is easier.

  • We can define private properties accessible from outside. By default are public
  • Static methods for been called for the class not for the instance. Yo dont need to create an object to call it:
    console.log(Car.numberOfWheels());

 

Interfaces

// Interfaces allow us to create contracts other classes/ objects have to implement
// We can use them to define custom types without creating classes
// Interfaces ARE NOT compiled to JavaScript! It's just for checking/ validation done by our TypeScript compiler

// Example interface

interface User {
    username: string;
    password: string;
    confirmPassword?: string; // Optional property => Does not have to be implemented
}

let user:User;

// This value does not satisfy the interface => Compilation error
// user = { anything: 'anything', anynumber: 5};

// This value does satisfy the interface
user = {username: 'max', password: 'supersecret'};

// Interfaces can also contain functions (without the function body - as it only is a blueprint/ requirement)

interface CanDrive {
    accelerate(speed:number): void;
}

let car:CanDrive = {
    accelerate: function (speed:number) {
        // ...
    }
};

Generics

  • Generic types allow us to be flexible with typing.
// Generics are types which can hold/ use several types
// We're only touching the very basics here - you can go MUCH more into detail

// Consider the Array object

let numberArray: Array<number>; // This array will only accept numbers

// Try to initialize it with strings

// numberArray = ['test']; // => Error
numberArray = [1,2,3];

 

 

Wrap up & modules

// TypeScript is modular, we can divide our code up over several files
// In Angular 2 we then use  "import {} from ''" to access the code in these files

// We export a class, interface, variable, ... by adding 'export' keyword in front of it

export class ExportedClass {
    // This class is exported
}

Deep dive into TypeScript

How to learn TypeScript

Throughout this course we鈥檙e always using TypeScript and I am convinced that you鈥檒l be able to learn it 鈥榦n the fly鈥. But a little head start is never wrong.

What is TypeScript?

TypeScript is a superset to JavaScript, which means, that it compiles into pure JavaScript in the end. Why do we use it then?

First, it provides 鈥榮trong typing鈥 (that鈥檚 where the name comes from). This means that we can (and should) assign types to our variables and class members. These types won鈥檛 compile to JavaScript (as JS does not know types) but we will get compilation errors if we assign wrong types or make any other type-related errors. This is a HUGE help in the daily development work and should not be underestimated!

Second, TypeScript introduces some nice features, JS does not have out of the box (at least in the ES5 specification). This includes classes (鈥榗lass鈥 keyword), interfaces, generics and modules. Being able to use these constructs makes our code cleaner, easier to read and helps us avoid nasty errors. Especially in combination with the strong typing we are really able to write high quality code and track down errors quickly.

Where can I learn all the TypeScript fundamentals?

There are a lot of great resources out there which will get you started very quickly.

The official documentation is not too bad to be honest, so you may give it a try:聽http://www.typescriptlang.org/Handbook

There鈥檚 also a course here on Udemy, though I have not tested it!聽https://www.udemy.com/typescript/

Can we mix TypeScript and JavaScript?

Yes, we can. No one is preventing us from not setting types, using 鈥榲ar鈥 instead of 鈥榣et鈥 or using pure JavaScript libraries (i.e. libraries which don鈥檛 offer a TypeScript version/ implementation).

Can鈥檛 I use 鈥榥ormal鈥 JavaScript to write Angular 2 applications?

You can absolutely do that. But currently finding good documentation and examples on Angular 2 using plain JavaScript is extremely hard. And to be honest: TypeScript will be the standard 鈥榣anguage鈥 to be used when developing Angular 2 applications. So I definitely recommend using TypeScript

 

 

Angular2 – Custom project & Workflow setup

An alternative to create the project with the Angular CLI. A custom way.

Create Angular applications with a Webpack based tooling.

Official doc:聽https://angular.io/docs/ts/latest/guide/webpack.html

Initializing the project

  • We run
    npm init

to create聽a package.json.

Setting up the basic project files

  • Lets make the folder structure and blank files:
    • src folder
    • src/app folder
    • src/app/main.ts:聽Compiles the application with the JIT compiler and bootstraps the application’s main module (AppModule) to run in the browser. The JIT compiler is a reasonable choice during the development of most projects and it’s the only viable choice for a sample running in a live-coding environment like Plunker.
    • src/app/home.component.ts
    • src/app/app.module.ts: 聽Defines AppModule, the root module that tells Angular how to assemble the application. Right now it declares only the AppComponent. Soon there will be more components to declare.
    • src/app/app-routing.module.ts
    • src/app/app.component.ts:聽聽It is the root聽component of what will become a tree of nested components聽as the application evolves.
    • src/app/app.component.html
    • src/app/app.component.css
    • src/index.html
    • src/pollyfills.js
    • src/app/users/users.module.ts
    • src/app/users/users,component.ts
    • src/app/users/users.component.html
    • src/app/users/users.component.css
    • src/app/users/users-routing.module.ts

Installing the core dependencies

Lets install all the packages needed with npm install:

npm install --save @angular/core @angular/compiler @angular/common @angular/compiler-cli @angular/forms @angular/http @angular/platform-browser @angular/platform-browser-dynamic @angular/platform-server @angular/router @angular/upgrade @angular/animations
typescript rxjs zone.js core-js

Filling the Project Files with some life

  • We create some basic content for all the components.

index.html & pollyfills

./polyfills.js:聽

You’ll need polyfills to run an Angular application in most browsers as explained in the Browser Support guide. Polyfills should be bundled separately from the application and vendor bundles. Add a polyfills.ts like this one to the src/folder.

import 'core-js/es6';
import 'core-js/es7/reflect';
require('zone.js/dist/zone');

./index.html

<!doctype html>
<html class="no-js" lang="">
    <head>
        <base href="/">
        <meta charset="utf-8">
        <meta http-equiv="x-ua-compatible" content="ie=edge">
        <title>Angular seed</title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <link rel="apple-touch-icon" href="apple-touch-icon.png">
        <!-- Place favicon.ico in the root directory -->

        <link rel="stylesheet" href="css/normalize.css">
        <link rel="stylesheet" href="css/main.css">
    </head>
    <body>
      <app-root>Loading...</app-root>
    </body>
</html>

Installing development dependencies

sudo npm install --save-dev webpack webpack-dev-server angular-router-loader angular2-template-loader awesome-typescript-loader html-loader raw-loader del-cli

Setting up a development workflow: Typescript configuration

TypeScript is a primary language for Angular application development. It is a superset of JavaScript with design-time support for type safety and tooling.Browsers can’t execute TypeScript directly. Typescript must be “transpiled” into JavaScript using the tsc compiler, which requires some configuration.

Typescript wiki: http://www.typescriptlang.org/docs/handbook/tsconfig-json.html

Typescript compiler options:聽http://www.typescriptlang.org/docs/handbook/compiler-options.html

./tsconfig.json:TypeScript compiler configuration

{
  "compilerOptions": {
    "moduleResolution": "node",  
    "emitDecoratorMetadata": true,  
    "experimentalDecorators": true,
    "target":"es5",
    "lib": [
      "es5",
      "dom"
    ]
  }
}
  • emitDecoratorMetadata: true and experimentalDecorators:true because we are using decorators.
  • target:es5 to run in all browsers

Setting up a development workflow:Webpack

Webpack is a powerful module bundler. A bundle is a JavaScript file that incorporates assets that belong together and should be served to the client in a response to a single file request. A bundle can include JavaScript, CSS styles, HTML, and almost any other kind of file.

Webpack roams over your application source code, looking for import statements, building a dependency graph, and emitting one or more bundles. With plugins and rules, Webpack can preprocess and minify different non-JavaScript files such as TypeScript, SASS, and LESS files.

You determine what Webpack does and how it does it with a JavaScript configuration file, webpack.config.js.

  • And we create three different webpack config files: webpack.config.common.js , webpack.config.dev.js and webpack.config.prod.js
  • For merging webpack config files we need to install a new npm package:
sudo npm install --save-dev webpack-merge
  • we also need to install

    HtmlWebpackPlugin

    Webpack generates a number of js and CSS files. You could insert them into the index.html manually. That would be tedious and error-prone. Webpack can inject those scripts and links for you with the HtmlWebpackPlugin.

sudo npm install --save-dev html-webpack-plugin

./webpack.config.common.js:

The webpack.common.js configuration file does most of the heavy lifting. Create separate, environment-specific configuration files that build on webpack.common by merging into it the peculiarities particular to the target environments.

These files tend to be short and simple.

module.exports = {
  entry: './src/app/main.ts',

  resolve: {
    extensions: ['.js', '.ts']
  },

  module: {
    rules: [
      {
        test: /\.html$/,
        loaders: ['html-loader']
      },
      {
        test: /\.css$/,
        loaders: ['raw-loader']
      }
    ],
    exprContextCritical: false
  },
 plugins: [
   new HtmlWebpackPlugin({
   template: 'src/index.html'
 })
 ]
};

./webpack.config.dev.js

var webpackMerge = require('webpack-merge');
const path = require('path');

var commonConfig = require('./webpack.config.common');

module.exports = webpackMerge(commonConfig, {
  devtool: 'cheap-module-eval-source-map',
  output: {
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
    filename: 'bundle.js',
    chunkFilename: '[id].chunk.js'
  },

  module: {
    rules: [
      {
        test: /.ts$/,
        use: [
          {loader: 'awesome-typescript-loader', options: {
            transpileOnly: true
          }},
          {loader: 'angular2-template-loader'},
          {loader: 'angular-router-loader'}
        ]

      }
    ]
  },

  devServer: {
    historyApiFallback: true,
    stats: 'minimal'
  }
});

Webpack config: Entries and outputs

You supply Webpack with one or more entry files and let it find and incorporate the dependencies that radiate from those entries. The one entry point file in this example is the application’s root file, src/main.ts:

entry: {
  'app': './src/main.ts'
},

Webpack inspects that file and traverses its import dependencies recursively.

Webpack config: Loaders

Webpack can bundle any kind of file: JavaScript, TypeScript, CSS, SASS, LESS, images, HTML, fonts, whatever. Webpack itself only understands JavaScript files. Teach it to transform non-JavaScript file into their JavaScript equivalents with loaders. Configure loaders for TypeScript and CSS as follows.

rules: [
  {
    test: /\.ts$/,
    loader: 'awesome-typescript-loader'
  },
  {
    test: /\.css$/,
    loaders: 'style-loader!css-loader'
  }
]

Webpack config: Plugins

Webpack has a build pipeline with well-defined phases. Tap into that pipeline with plugins such as the uglify minification plugin:

plugins: [
  new webpack.optimize.UglifyJsPlugin()
]

Finishing and using the development workflow

  • Lets modify our package.json to run the local development server:

package.json

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack-dev-server --inline --progress --port 8080 --config webpack.config.dev.js"
  },
  • Now we can run
    npm run build

and hit localhost:8080 in the browser

Setting up a production workflow

  • For make a build for production we want to add AoT (Ahead of time compilation) to optimize loading of the app.
  • Let first create聽versions of the config files implementing AoT.
  • ./src/app/main.aot.ts聽
import '../polyfills';

import {platformBrowser} from '@angular/platform-browser';
import {enableProdMode} from '@angular/core';

import {AppModuleNgFactory} from './app.module.ngfactory';

enableProdMode();
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

NOTE 1:app.module.ngfactory will be generated in the time of building for production with aot.

NOTE 2: For bootstrapping angular this time we are using platform-browser instead of platform-browser-dynamic. The difference between platform-browser-dynamic and platform-browser is the way your angular app will be compiled.
Using the dynamic platform makes angular sending the Just-in-Time compiler to the front-end as well as your application. Which means your application is being compiled on client-side.
On the other hand, using platform-browser leads to an Ahead-of-Time pre-compiled version of your applicatiion being sent to the browser. Which usually means a significantally smaller package being sent to the browser.
The angular2-documentation for bootstrapping at https://angular.io/docs/ts/latest/guide/ngmodule.html#!#bootstrap explains it in more detail.

./tsconfig.aot.json

{
  "compilerOptions": {
    "module": "es2015",
    "outDir":"./dist",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target":"es5",
    "lib": [
      "es5",
      "dom"
    ]
  },
  "angularCompilerOptions": {
    "skipMetadataEmit":true
  }
}

./webpack.config.prod.js

var webpackMerge = require('webpack-merge');
const path = require('path');
var webpack = require('webpack');

var commonConfig = require('./webpack.config.common');

module.exports = webpackMerge(commonConfig, {
  entry: './src/app/main.aot.ts',
  devtool: 'cheap-module-eval-source-map',
  output: {
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/',
    filename: '[hash].js',
    chunkFilename: '[id].[hash].chunk.js'
  },

  module: {
    rules: [
      {
        test: /.ts$/,
        use: [
          {loader: 'awesome-typescript-loader'},
          {loader: 'angular2-template-loader'},
          {loader: 'angular-router-loader?aot=true'}
        ]

      }
    ]
  },

  plugins: [
    new webpack.optimize.UglifyJsPlugin()
  ]
});

package.json

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack-dev-server --inline --progress --port 8080 --config webpack.config.dev.js",
    "build:prod":"del-cli dist && ngc -p tsconfig.aot.json && ngc -p tsconfig.aot.json && webpack --config webpack.config.prod.js --progress --profile --bail && del-cli 'src/app/**/*.js' 'src/app/**/*.ngfactory.ts' 'src/app/**/*.js.map' 'src/app/**/*.shim.ts' 'src/app/**/*.ngsummary.json'"
  },
  • In the build:prod script , we first clean the dist folder , then we compiler typescripts files with angular offline compiler (ngc), then we make the bundle with webpack and finally we clean files not needed.

Adding types and fixing bugs

  • For resolving a bug in the compilation we need to install two more packages: @types/core-js and @types/node. NOTE : be sure to fit to these versions:
    "@types/core-js": "^0.9.36",
    "@types/node": "^6.0.45",

and modify tsconfig.aot.json to :

    "target":"es5",
    "typeRoots": [
      "node_modules/@types"
    ],
  • Now we are ready to run
    npm run build:prod

this will generate a dist folder with a build release for production.

Finishing touches

  • Let finally create a lite server for testing our build release for production.
  • Lets install npm package lite-server
npm install --save-dev lite-server
  • And create a config file for that server:

bs-config.js

module.exports = {
  server: {
    baseDir: './dist',
    middleWare: {
      1: require('connect-history-api-fallback')({ index:'/index.html', verbose:true })
    }
  }
};

and a new script “serve” in the package.json:

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack-dev-server --inline --progress --port 8080 --config webpack.config.dev.js",
    "build:prod": "del-cli dist && ngc -p tsconfig.aot.json && ngc -p tsconfig.aot.json && webpack --config webpack.config.prod.js --progress --profile --bail && del-cli 'src/app/**/*.js' 'src/app/**/*.ngfactory.ts' 'src/app/**/*.js.map' 'src/app/**/*.shim.ts' 'src/app/**/*.ngsummary.json' 'src/app/**/*.ngstyle.ts' 'dist/app'",
    "serve": "lite-server"
  },

and we are ready to run

 npm run serve

and see our prod release live!

Angular 2 – What changed with Angular 4?

Backward compatibility

Angular 4 is NOT a complete re-write of Angular 2, indeed, it shouldn鈥檛 introduce any breaking changes. Some features will be deprecated (i.e. they still work but will get replaced with the next major Angular version), some new features were added.

Regarding your old code all will continue to work.

聽Changes

  • ng-if with else

// Syntax for ngIf/Else
<div *ngIf=鈥漜ondition; else elseBlock鈥>Truthy condition</div>
<template #elseBlock>Falsy condition</template>
  • A new Renderer: Renderer2

Just make sure to check import and dependency injections with Rendere2 instead of Renderer

  • Email validator with email directive

Angular 4 has a built-in “email” validation tag that can be added within the input. E.g.:

<input type="email" id="contactemail" email>

Under the hood improvements:

  • Typecript 2.2

Check聽https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html

  • Flat ES Modules (Flat ESM / FESM)

    We now ship flattened versions of our modules (“rolled up” version of our code in the EcmaScript Module format, see example file). This format should help tree-shaking, help reduce the size of your generated bundles, and speed up build, transpilation, and loading in the browser in certain scenarios.
    Read more about the importance of Flat ES Modules in “The cost of small modules”.

Deprecations

  • Renderer v1
  • Angular animation package from core –> now will import from angular/animations