Webpack与AngularJS整合之代码逻辑与架构设计

前言

公司项目的前端使用Ionic开发,但是代码的组织方式略显臃肿,代码的书写规范性不佳。一方面造成了严重的性能瓶颈,另一方面也无法应对未来频繁的需求变更,所以准备结合构建工具对前端做设计重构。考察了各个构建工具包括Glup、Grunt、Webpack之后还是决定使用Webpack(最新的主流一般都不会有错的)。查阅了不少资料,大部分是关注的技术细节,对于如何进行代码的组织设计较少,所以本文更多的关注的可能是代码的组织方式,探索一个比较好的组织方案

预备知识

  • AMD/CMD
  • npm
  • AngularJS
  • Webpack

Webpack

Webpack通过一个入口文件(当然可以多入口,不是重点),将所有依赖文件打包到一个文件中,从而减少SAP应用初次加载时http请求到个数。并且可以通过各种loader去处理优化不同的文件,如js、css、svg等。一般一个通行的做法是将webpack构建时的配置信息写入到一个名为 “webpack.config.js”的文件中。这部分的基础知识以及demo一般稍作学习便可掌握。官网文档本身很不错。

所以目录可以这样组织:


Webpack与AngularJS整合之代码逻辑与架构设计_第1张图片
  • app:存放源代码
  • build: 存放webpack构建完成的代码
  • node_modules: npm管理的包库
  • webpack.config.js: webpack构建配置
    这个是webpack视角下大的框架

组织结构

1. Module

关于module,angular的官方Developer Guide是这样写的:

You can think of a module as a container for the different parts of your app – controllers, services, filters, directives, etc.

所以在angular中module是一个层次相对较高的聚合,把相关的controller、service等封装到一个module,以实现一组特定的相对完备的功能。
对一个中大型的项目理想情况下是拆分为几个相对比较独立的module。

以passport模块为例,包含登录注册等功能,组织形式如下:


Webpack与AngularJS整合之代码逻辑与架构设计_第2张图片
  • index.js:将该模块内各个部分联系在一起
angular = require('angular');
uirouter = require('uirouter');

service = require('../services');

//define the app.passport module
module.exports = angular.module('app.passport', [uirouter, service.AuthService, service.Request])
    .config(require('./passport.routes'))
    .controller('SigninController', require('./signin.controller'))
    .controller('SignupController', require('./signup.controller'))
    .service('passportService', require('./passport.service'))
    .name;
  • routes.js:定义该模块的路由
module.exports = ['$stateProvider',
function($stateProvider) {
    $stateProvider
        .state('signup', {
            url: '/signup',
            name: 'signup',
            template: require('./signup.html'),
            controller: 'SignupController'
        })
        .state('signin', {
            url: '/signin',
            name: 'signin',
            template: require('./signin.html'),
            controller: 'SigninController'
        });
}];
  • signin.controller.js: 登录控制器,这里export controller的定义函数,在index中完成最终定义
module.exports = ['$scope','authService','request','$state',
function($scope, authService,request,$state) {

    $scope.user = {
        phone : "",
        password:""
    };

    //执行用户登录操作
    $scope.signin = function() {
        request.post('signin', $scope.user)
            .then(
                function(data) {
                    authService.setToken(data.token, data.expire_in * 1000);
                    $state.go('home');
                },
                function(error) {
                    console.log(error);
                }
            );
    };
}];
  • signin.html 登录页面模版

    
        
用户注册

主要思想就是对于模块内的无论是controller、config也好,将它们的定义放到单独文件中,通过index.js文件,将它们组装定义成目标module

** * 这边的定义都采用数组的方式进行,是为了以后进行代码混淆,函数的参数名即使被替换,依然不影响正常的inject * **

通过这种模式我们就完成了一个模块的定义。

2.项目

完成了一个模块的定义,那么整个项目的integration也就比较明了了。大致结构如下图:


Webpack与AngularJS整合之代码逻辑与架构设计_第3张图片

首先是各个模块的定义,然后将跨模块的复用代码以service的形式提取出来,作为通用模块。这里我是放置在services目录下。整合时,定义app module作为项目的主模块,然后将其他module作为依赖的方式注入到app module中,从而完成整合。

  • app.module.js
angular = require('angular');
uirouter = require('uirouter');
ionic    = require('ionic');

ngCache = require('angular-cache');
config = require('./app.config');
home = require('./home');
passport = require('./passport');

angular.module('app', [ionic,uirouter, ngCache,home,passport])
    .config(config.routing)
    .config(config.providerConfig)
    .constant('ENV', require('./app.env'));
  • app.ENV.js 环境配置
module.exports = {
    version: 1.0,
    api: 'http://xxx.com/v1/',
    appPath: 'http://localhost:8080/'
};
  • app.config.js 配置信息
module.exports.providerConfig = ['$httpProvider', 'CacheFactoryProvider',
    function($httpProvider, CacheFactoryProvider) {

        var param = function(obj) {
            var query = '',
                name, value, fullSubName, subName, subValue, innerObj, i;
            for (name in obj) {
                value = obj[name];
                if (value instanceof Array) {
                    for (i = 0; i < value.length; ++i) {
                        subValue = value[i];
                        fullSubName = name + '[' + i + ']';
                        innerObj = {};
                        innerObj[fullSubName] = subValue;
                        query += param(innerObj) + '&';
                    }
                } else if (value instanceof Object) {
                    for (subName in value) {
                        subValue = value[subName];
                        fullSubName = name + '[' + subName + ']';
                        innerObj = {};
                        innerObj[fullSubName] = subValue;
                        query += param(innerObj) + '&';
                    }
                } else if (value !== undefined && value !== null) query += encodeURIComponent(name) + '=' + encodeURIComponent(value) + '&';
            }
            return query.length ? query.substr(0, query.length - 1) : query;
        };

        $httpProvider.defaults.transformRequest = function(obj) {
            return angular.isObject(obj) && String(obj) !== '[object File]' ? param(obj) : obj;
        };
        $httpProvider.defaults.headers.post = {
            'Content-Type': 'application/x-www-form-urlencoded'
        }
        $httpProvider.defaults.headers.put = {
            'Content-Type': 'application/x-www-form-urlencoded'
        }

        angular.extend(CacheFactoryProvider.defaults, {
            maxAge: 15 * 60 * 1000,

        });
    }
];

module.exports.routing = ['$urlRouterProvider', '$locationProvider',
    function($urlRouterProvider, $locationProvider) {
        $locationProvider.html5Mode(true);

        $urlRouterProvider.otherwise('/signin');
    }
];

More

这篇文章主要讲个大致思路,项目webpack-angular的完整代码已经放到github上面,有需要可以参考。代码的组织方式本身就是仁者见仁,智者见智,没有最好一说,所以还是希望可以一起探讨。

你可能感兴趣的:(Webpack与AngularJS整合之代码逻辑与架构设计)