Browsed by
Category: JavaScript exposed

Znacznie szybsze debugowanie JS w VS Code

Znacznie szybsze debugowanie JS w VS Code

Ostatnio odkryłem nową funkcjonalność środowiska Visual Studio Code. Używając wtyczki VS Code – Debugger for Chrome można umożliwić debugowanie JS. Kod aplikacji uruchomiony w przeglądarce może być śledzony w edytorze. Visual Studio Code zawiera kilka wbudowanych debuggerów w tym np. dla Node.js. Aby doinstalować powyższy dodatek wystarczy nacisnąć F1 a następnie install extension. Gdy z otwartej listy wybierzemy pozycję Debugger for Chrome, będziemy mogli już przystąpić do konfiguracji naszego rozszerzenia.

Konfiguracja

Podstawową kwestią jest zmiana konfiguracji Chrome, aby upewnić się, że udostępnia on usługę zdalnego debugowania kodu na określonym porcie. Aby to zrobić wystarczy uruchomić przeglądarkę z parametrem

chrome.exe --remote-debugging-port=9222

W ten sposób Chrome udostępnia usługę do zdalnej inspekcji kodu stron otwieranych w przeglądarce. Można to przetestować wpisując adres:

http://localhost:9222

Następnie wystarczy skonfigurować taski debugujące w Visual Studio Code.

Jeżeli jeszcze nie posiadamy pliku launch.json wystarczy nacisnąć przycisk F5 odpowiadający za rozpoczęcie debugowania, aby plik został wygenerowany. Wewnątrz niego w sekcji configurations możemy dodać wiele rodzajów debuggerów począwszy od .NET do Node.js. Jednak my skupimy się jedynie na połączeniu z Chrome.

Interesują nas trzy konfiguracje dla debugowania:

  1. Debugowanie JS w lokalnym pliku
    {
        "name": "Launch index.html",
        "type": "chrome",
        "request": "launch",
        "file": "${workspaceRoot}/src/index.html"
    }
    
  2. Debug hostowanego projektu
    {
        "name": "Launch localhost with sourcemaps",
        "type": "chrome",
        "request": "launch",
        "url": "http://localhost/mypage.html",
        "sourceMaps": true,
        "webRoot": "wwwroot"
    }
    
  3. Podłączenie się do już uruchomionej strony
    {
        "name": "Attach",
        "type": "chrome",
        "request": "attach",
        "port": 9222,
            "sourceMaps": true
    }
    

Co to zmienia?

Jak dotąd istniał stały podział: backend debugowało się w konkretnych IDE, a frontend w narzędziach developerskich przeglądarki. Połączenie przeglądarki i edytora na czas debugowania aplikacji zbliża nas do połączenia tych dwóch ekosystemów i zwalnia z przełączania się pomiędzy środowiskami gdzie edytujemy kod i gdzie go testujemy. Według mnie to zwiększa komfort pracy i pozwala lepiej skoncentrować się na rozwiązywanym problemie, zamiast na próbach synchronizowania przeglądarki z kodem nad którym pracujemy.

Przykłady

Mechanizm ten jest skonfigurowany dla mojego projektu na GitHub – InvestDashboard. Można pobrać najnowszą wersję tego projektu i po odpaleniu go w Visual Studio Code nacisnąć przycisk F5 i debugowanie będzie już działało poprawnie. Trzeba jednak pamiętać o odpowiedniej konfiguracji Chrome

Konfiguracja TypeScript – kompilacja

Konfiguracja TypeScript – kompilacja

Co to jest TypeScript?

TypeScript to język, który jest nakładką na JavaScript. Udostępnia on silne typowanie dla tego dynamicznego języka. Dodatkowo wprowadza on klasy, moduły i interfejsy, które pomagają w organizacji kodu aplikacji. Jest to szczególnie użyteczne w dużych projektach z wydzielonymi wieloma częściami aplikacji. Dzięki użyciu mechanizmów obiektowych możemy porządkować kod, a dzięki silnemu typowaniu każdy błąd składniowy zostanie wykryty już podczas kompilacji lub, w niektórych edytorach, nawet podczas pisania. Dobra konfiguracja TypeScript pozwoli nam w dużej mierze zautomatyzować ten proces.

Dużym plusem języka TypeScript jest jego pełna kompatybilność z JavaScript. Każdy plik napisany w JS po zmianie rozszerzenia na .ts jest od razu poprawnym plikiem TypeScriptowym. Pozwala to na stosunkowo łatwą migrację projektu napisanego w JS. Jednak warto też wspomnieć o minusach TypeScriptu. Kłopoty zaczynają się, gdy chcemy skorzystać z biblioteki, do której nie są dostępne pliki typowań (definicje typów dla mechanizmu silnego typowania). Typowania dla wielu bibliotek jesteśmy w stanie znaleźć na https://github.com/DefinitelyTyped/DefinitelyTyped. Niestety, gdy chcemy skorzystać z mniej popularnych bibliotek lub choćby z najnowszych wersji, możemy nie znaleźć odpowiednich definicji. Ponieważ typowania są nam potrzebne głównie do sprawdzania poprawności użytych typów danych, możemy skompilować nasze pliki do JS, licząc się z tym, że będą one generować błędy lub ostrzeżenia kompilacji.

Dalej pokażę jak skonfigurować kompilację TypeScript w różnych środowiskach.

Konsola

Podstawowym miejscem obsługi kompilatora TypeScript jest konsola. Zacznijmy od instalacji, którą najlepiej przeprowadzić za pomocą npm

npm install -g typescript

Następnie potrzebny jest plik konfigurujący dla kompilatora. Definiujemy w nim parametry, mówiące o dialekcie, do którego chcemy skompilować kod (ES4, ES5 lub ES6), kompilowanych plikach lub też generowaniu sourceMap. Dokładny opis parametrów znajduje się w dokumentacji https://github.com/Microsoft/TypeScript/wiki/tsconfig.json. Podstawowym ustawieniem może być:

{
    "compilerOptions": {
        "module": "commonjs",
        "noImplicitAny": true,
        "removeComments": true,
        "preserveConstEnums": true,
        "sourceMap": true
    },
    "exclude": [
        "node_modules",
        "dist"
    ]
}

Powoduje ono kompilacje wszystkich dostępnych plików .ts do plików .js oraz do sourceMap z katalogu bieżącego i katalogów w nim zawartych. Dodatkowo czyści wynikowe pliki z nadliczbowych komentarzy i definicji.

Teraz wystarczy wywołać komendę

tsc

Pozwala ona na kompilowanie wszystkich plików w naszym projekcie. Pliki .ts zostaną przetworzone do plików .js w tym samym folderze. Można skorzystać z ułatwienia kompilacji i założyć czujkę na plikach do kompilacji. To pozwoli na kompilowanie plików w tle przy każdym zapisie.

tsc -w

Gulp

Gdybyśmy chcieli włączyć proces kompilacji do procesu przetwarzania naszego projektu np. przy pomocy Gulp, musimy skorzystać z odpowiedniej biblioteki

npm install gulp-typescript --save-dev

następnie możemy dodać poniższe kroki budowania do naszego pliku konfiguracyjnego gulpfile.js

var gulp = require('gulp');
var ts = require('gulp-typescript');
var tsProject = ts.createProject('tsconfig.json');

gulp.task('scripts', function () {   
    var tsResult = tsProject.src().pipe(ts(tsProject));
    return tsResult.js.pipe(gulp.dest('.'));
});

Dokładniejszy opis można znaleźć w http://blah.winsmarts.com/2015-7-Setting_up_TypeScript_with_Visual_Studio_Code.aspx

VisualStudio Code

Używając Visual Studio Code do edycji projektów w TypeScript, można skonfigurować sposób budowania aplikacji, który wykorzystuje kompilator TypeScript. W tym celu wystarczy dodać w pliku tasks.json, znajdującym się w klatalogu .vscode, odpowiednią konfigurację dla kompilacji

{
    "version": "0.1.0",
    "command": "tsc",
    "isShellCommand": true,
    "showOutput": "silent",
    "problemMatcher": "$tsc"
}

https://code.visualstudio.com/Docs/languages/typescript
https://cmatskas.com/typescript-and-vs-code/

W codziennej pracy pomocne jest uporządkowanie naszego projektu tak, aby nie wyświetlał generowanych plików. Aby to zrobić, należy edytować ustawienia workspace (File | Preferences | Workspace Settings), a następnie dodać ukrycie plików sourcemap i warunkowe ukrycie plików js

"files.exclude": {
    ...
    "**/*.js": { "when": "$(basename).ts"},
    "**/*.js.map": true
} 

https://code.visualstudio.com/Docs/languages/typescript#_hiding-derived-javascript-files

Przykładowe kody źródłowe można znaleźć na GitHub:

https://github.com/suvroc/InvestDashboard/releases/tag/v0.0.1

Interceptor in Angular

Interceptor in Angular

$http service

This service is an Angular method for making HTTP request for external resources. All HTTP requests has an asynchronous nature. Because of that, all operations return promises. Generally, this service could be used by defining parameters directly, like below

$http({
  method: 'GET',
  url: '/someUrl'
}).then(function successCallback(response) {
    // this callback will be called asynchronously
    // when the response is available
  }, function errorCallback(response) {
    // called asynchronously if an error occurs
    // or server returns response with an error status.
  });

or by using shortcut methods

$http.get('/someUrl', config).then(successCallback, errorCallback);

Interceptor in Angular

The same as in previous post about interceptor in Angular you can also setup global mechanism to intercept each HTTP request. It can be useful for error handling, logging or authentication. You can use 4 types of additional configurations:

  • before sending request (request function)
  • after response retrieve (response function)
  • on error during sending request (requestError function)
  • on error during retrieving response (responseError function)

Implementation

To setup interceptor, you should only define service factory with declaring at least one of function mentioned in list above. Below you can see an example from the Angular documentation

// register the interceptor as a service 
$provide.factory('myHttpInterceptor', function($q) 
{ 
    return { 
        'request': function(config) { 
            // do something on success 
            return config || $q.when(config);
        }, 
        'requestError': function(rejection) { 
            // do something on error 
            if (canRecover(rejection)) { 
                return responseOrNewPromise 
            } 
            return $q.reject(rejection); 
        }, 
        'response': function(response) { 
            // do something on success 
            return response || $q.when(response); 
        }, 
        'responseError': function(rejection) { 
            // do something on error 
            if (canRecover(rejection)) { 
                return responseOrNewPromise 
            } 
            return $q.reject(rejection); 
        } 
    }; 
}); 
$httpProvider.interceptors.push('myHttpInterceptor');

Into this handlers you can also use asynchronous operations, because you can return promises from them.

As can be seen, it is very simple, but powerful functionality to add common behaviours to your data operations.

References:

https://docs.angularjs.org/api/ng/service/$http

http://www.webdeveasy.com/interceptors-in-angularjs-and-useful-examples/

http://www.bennadel.com/blog/2777-monitoring-http-activity-with-http-interceptors-in-angularjs.htm

http://thecodebarbarian.com/2015/01/24/angularjs-interceptors

Intercept HTTP requests – AJAX/jQuery

Intercept HTTP requests – AJAX/jQuery

Working in JavaScript we often need to make some HTTP requests to server. Requests could pass some information or try to get some of it. This is a typical functionality in client-server architecture. However, there are some cases that could be useful to do some action for each HTTP request. For example, we may want to add custom headers to all our requests or add authentication code to login into system. We can also capture every response from server to validate something or handle errors globally. This requirements could be met using interceptors. They give us an opportunity to handle HTTP request before sending and after answer receiving.

In this post I will show you how useful interceptors can be in few simple situations with few different technologies.

JavaScript (XMLHttpRequest)

Let’s imagine that we have an application written in vanilla JS. You have implemented authentication system based on token that is passed with every request. It is generated on server and send back in Authorization header to server to confirm user identification for each HTTP request. This functionality is similar to OAuth (http://oauth.net/articles/authentication/). Therefore you want to add this header to your HTTP mechanism globally. It can be easily modifying XMLHttpRequest prototype. Also you want to log each response status

(function(open) {
    XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
        this.addEventListener("readystatechange", function() {
			if (this.readyState == 4) 
            { 
				console.log(this.status);
			}
        }, false);
        open.call(this, method, url, async, user, pass);
		this.setRequestHeader("Authorization", "Token 123")
    };
})(XMLHttpRequest.prototype.open);

In this example you can see two important things. In line 10 you can add your actions before request will be sent. While line 6 is the place where you can get response data and modify it.

Then you can execute some HTTP request and all magic will be done automatically.

var oReq = new XMLHttpRequest();
oReq.open("get", "www.example.com", true);
oReq.send();

JQuery

Now let’s imagine that you have the same problem as recently, but you should do this in jQuery. This will be much easier, because this library encapsulate each HTTP mechanism using special objects.

To intercept before sending a request you can use $.ajaxSetup function

$.ajaxSetup({
    beforeSend: function (xhr) {
        xhr.setRequestHeader('Authorization', 'Token 123')
    }
});

But to capture responses you should use global callback functions (http://api.jquery.com/ajaxSuccess/, http://api.jquery.com/ajaxError/) as it’s showed below

$( document ).ajaxSuccess(function( event, request, settings ) {
	console.log(request.status);
});

$( document ).ajaxError(function( event, request, settings ) {
	console.log(request.status);
});