Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Folder structure, login design, routes and grunt tasks

I am currently working on a new project and I would like to give it a good start to not mess up with the future iterations.

Description

The application will have 2 sides:
- the client side.
- the admin side.

Each of them have separate APIs, and it seems logical to me to separate them into 2 applications.
Each of them also have their own way to login.

My thoughts

After reading quite a lot of topics on the subject, I was thinking about using this structure:

app/
    admin/
        home/
            home.tpl.html    // admin home template
        admin.html           // admin index, including templates via ng-view
        admin-api.js         // admin api
        admin.js             // admin app
    admin-login/
        home/
            home.tpl.html
        admin-login.html
        admin-login-api.js
        admin-login.js
    client/
        home/
            home.tpl.html
        client.html
        client-api.js
        client.js
    client-login/
        home/
            home.tpl.html
        client-login.html
        client-login-api.js
        client-login.js
css/
fonts/
img/
js/
libs/

Why separating the login from the rest? Because I want the login pages to be lighter (I will not load the same CSS / JS files), and to not be able to access the other files / views if the user is not logged in.

Routing

If we map the routes to this structure, it would give something like this:
/
app/client/client.html

/login
app/client-login/client-login.html

/admin/
app/admin/admin.html

/admin/login
app/admin-login/admin-login.html

Example of authentication conditions:

/
if the user is logged in -> show home page
if the user is NOT logged in -> redirect to /login

Grunt tasks

I will be using grunt-useref mainly to perform automatic concat and uglify on a set of common JS / CSS files.

example:

<!-- build:js js/scripts.<%= pkg.version %>.min.js -->
    <!-- jQuery -->
    <script src="libs/jquery/jquery-1.11.1.js"></script>

    <!-- AngularJS -->
    <script src="libs/angularjs/angular.js"></script>
    <script src="libs/angularjs/angular-route.js"></script>
    <script src="libs/angularjs/angular-resource.js"></script>

    <!-- Our main application -->
    <script src="app/app.js" ></script>
<!-- endbuild -->

The goal is to have a basement, then to add other JS / CSS files on the top of it when the route changes (via lazy loading).

Concerns

First, I am here to learn and to share ideas, so I would like your opinion around what I did.
Secondly, if I keep this structure, I was wondering about how to manage the main routes (/, /login, /admin/, /admin/login) and the user authentication (but for this part there is already quite a lot of threads).

I would like to not handle this server side, would it be possible with an .htaccess or with a top level Angular App?


Update 1

I have finally come to another way to build my folders structure:

app/
    admin/
        home/
            home.html         // admin home view
        login/
            login.html        // admin login view
            login-api.html    // admin login API
            login.js          // admin login module
        admin.html        // admin index, including templates via ng-view
        admin-api.js      // admin api
        admin.js          // admin module

    client/           // same goes for the client
        home/
            home.tpl.html
        login/
            login.html
            login-api.html
            login.js
        client.html
        client-api.js
        client.js
    common/
        common.js         // shared module
    app.js             // main application, routing to the other pages based on Auth
css/
fonts/
img/
js/
libs/
locale/
index.html

the index.html will serve my main application (app.js), which will serve the correct template based on the user login status.

My goal will be to load the css and the js files asynchronously to only have the necessary for the current route.

app/app.js (draft)

/*
 * app/app.js
 * 
 * Our main application, handling routes
 * and lazy loading other modules / scripts
 *
 */
var app = angular.module('app', [
        'ngRoute',
        'ngResource',
        'ngTouch',
        'ngAnimate'
    ]);



/*
 * App configuration
 *
 */
app.config( ['$routeProvider', '$locationProvider',
    function( $routeProvider, $locationProvider ) {

        $locationProvider.hashPrefix('!');

        /*
         * Checks if a user is authorized to access a route
         * 
         * @role (string) minimum role name required
         *
         */
        var requireAuth = function ( role ) {
            return {
                load: function ( $q, $location ) {
                    console.log('Can user access route?');

                    var deferred   = $q.defer(),
                        // TODO: replace isLoggedIn variable value by a function
                        // to check if the user is actually logged in
                        isLoggedIn = true;

                    deferred.resolve();

                    if ( isLoggedIn === true ) { // fire $routeChangeSuccess
                        console.log('authorized');

                        return deferred.promise;
                    }
                    else { // fire $routeChangeError
                        console.log('rejected');

                        $location.path('/login');
                    }
                }
            };
        };

        // Main application routes
        $routeProvider
            .when('/', {
                templateUrl   : 'app/client/home/home.html',
                resolve       : requireAuth()
            })
            .when('/login', {
                templateUrl   : 'app/client/login/login.html',
                resolve       : requireAuth('anonymous')
            })
            .when('/admin/', {
                templateUrl   : 'app/admin/home/home.html',
                resolve       : requireAuth('admin')
            })
            .when('/admin/login', {
                templateUrl   : 'app/admin/login/login.html',
                resolve       : requireAuth('anonymous')
            })
            .otherwise('/', {
                templateUrl   : 'app/client/home/home.html',
                resolve       : requireAuth()
            });
    }]);

Update 2

After more testing and researchs, I guess that I will not be able to do this without a server side to handle the main routes...

Main problems

  • I didn't find a proper way to include an app inside another app
  • When redirecting to the login page, the requested route template was still loaded (ex: if I was redirected from client to client login, it would load both app/client/home/home.html and app/client/login/login.html).

My first conclusion

I absolutely need 4 apps (client, client-login, admin and admin-login) so they each have their own routes, their own main index.html template and therefore, they will be really independant from each other.

Each of them will still have access to the common concat / minified files, but they will also load their own bunch of files.

like image 449
Niflhel Avatar asked Jul 22 '14 21:07

Niflhel


1 Answers

In my opinion your first conclusion is the right way of thinking:) Login pages should not display any AngularJS api. So thay should have only small JS file for handle AJAX postand displaying error messages. Your true business code should be available only after authentication.

In that way your application will have two main files app.js (client, admin) From my experience lazyloading jsFiles is not needed when dealing with AngularJS. Javassript Angular files are quite short. And thanks to AngularJS architecture you can use dependency injection to disable unwanted features.

Your file structure is good, but when your application is getting bigger, you could create in each module subdirs for: controllers, directives, filters, services. I would not advise to keep all controllers in one file (only if they are short), but when your app will develop, keeping clean dir structure can help a lot.

like image 83
Beri Avatar answered Nov 01 '22 15:11

Beri