📜 ⬆️ ⬇️

Angular boilerplate. Simplicity - the trend of youth

Any physical system tends to the state with the lowest potential energy. And programmers are no exception. Therefore, we will discuss how to simplify your life when developing on angular.js, while using services that are now in trend. Mainly, I will unobtrusively promote my angular-boilerplate architectural solution, and for a snack I will offer to share my experience and ideas in the comments.

Motivation


Reduce routine to a minimum, create an intuitive architecture and bring together what is called the best practices.

Immediately, I ’ll make a reservation that angular-boilerplate is the result of creating several projects of varying degrees of complexity from scratch, in the process of working on which I tried my best to get rid of unnecessary complications, first of all, my own workflow. Therefore, in some ways my decisions are caused by a subjective view of the development, but nevertheless they all passed the test of time and showed practical benefits.

Special features


')

Grunt


To begin with, we need grunt.js. Grunt will need, first of all, to collect and compress code and style files. The project already has two tasks in Gruntfile.js : grunt install and grunt build - the first allows you to perform various operations during the installation and in the initial version installs the necessary libraries through bower , the second, as I wrote above, collects and minifitsirut files using require. js .

Bower


In order not to run on the githabs once again, libraries are easier to load via bower. Here I will mark the .bowerrc file, in which you can simply define the path and name of the module folder.

Require.js


Practice, when libraries and code are included in the html page, personally causes cognitive dissonance in me. And I always wanted to have in javascipt the usual opportunity for other languages ​​to programmatically connect code and define dependencies. Therefore, I am very enthusiastic about Require.js and using it as a framework for an application. In this place, I will probably omit the detailed introduction to Require.js, but simply point out how it is used in the project.

So, the main thing that require.js gives us, besides modularity, is the ability to merge the entire application into one file and then compress. But, of course, I would like to deal with the development of a normal version of the files, so the index has two options for connecting logic and styles:
<!--Development--> <link rel="stylesheet" href="app/styles/styles.css"> <!--Production--> <link rel="stylesheet" href="app/styles/styles.min.css"> <!--Development--> <script data-main="app/js/app" src="app/lib/requirejs/require.js"></script> <!--Production--> <script src="app/js/app.min.js"></script> 

Which allow you to switch between development and production.

All libraries, modules, etc. are connected at the same time when the application is initialized, and their settings are defined in the app.js file:
 require.config({ baseUrl: 'app', paths: { 'jquery': 'lib/jquery/dist/jquery', 'angular': 'lib/angular/angular', 'text': 'lib/requirejs-text/text' }, shim: { 'jquery': { exports: 'jQuery' }, 'angular': { exports: 'angular', 'deps': ['jquery'] }, 'lib/angular-route/angular-route': { 'deps': ['angular'] } }, config: { 'js/services': { apiUrl: 'http://localhost/api' } } }); 

Next, go through the files.

Files


 /app /js app.js app.min.js controllers.js directives.js filters.js services.js /styles styles.js styles.min.js /templates someone-template.html index.html bower.json package.json .bowerrc Gruntfile.js 

The overall structure of the project should not cause any special questions. Services, directives, controllers, filters are set in the appropriate files, which are then automatically connected when the application is loaded:
 var angular = require('angular'), controllers = require('js/controllers'), services = require('js/services'), directives = require('js/directives'), filters = require('js/filters'); ... angular.forEach(services, function (service, name) { $provide.factory(name, service); }); ... angular.forEach(directives, function (directive, name) { app.directive(name, directive); }); angular.forEach(filters, function (filter, name) { app.filter(name, filter); }); angular.forEach(controllers, function (controller, name) { app.controller(name, controller); }); 


I think that many people, and I myself, at first wondered how to properly form logic that is not tied to a specific display, but is executed globally. Often the answer to this question is the controller, which is called somewhere in index.html using the ng-controller . Of course, this is not fatal, but I personally consider this option more correct:
 app.run(controllers.GlobalCtrl); 

That is, this controller is called once when the application is started and is not formally associated with any template.

One of the nice additions of requirejs is the text module, which allows loading through require () not only AMD modules, but also plain text files, for example, html, which can then be included when compiling. This allows us to add template files to the shared build .

 ... .when('/', { controller: controllers.MainCtrl, template: require('text!templates/main.html') }); ... 


And finally, with regard to:
 $httpProvider.interceptors.push(['$q', '$error', function ($q, $error) { return { 'request': function (config) { return config; }, 'response': function (response) { return response; }, 'responseError': function (rejection) { $error('Connection error!'); return $q.reject(rejection); } } }]); 

In my opinion, the intermediary in the processing of requests is an integral part of the client-server interaction, which allows you to format the response or, in a particular case, implement centralized processing of all errors.

I do not want to say more than necessary, so that's all. As promised, I invite in the comments to share my practice, thoughts and suggestions.

Source: https://habr.com/ru/post/214063/


All Articles