Webpack與AngularJS整合之代碼邏輯與架構(gòu)設(shè)計

前言

公司項目的前端使用Ionic開發(fā)舆吮,但是代碼的組織方式略顯臃腫,代碼的書寫規(guī)范性不佳队贱。一方面造成了嚴(yán)重的性能瓶頸色冀,另一方面也無法應(yīng)對未來頻繁的需求變更,所以準(zhǔn)備結(jié)合構(gòu)建工具對前端做設(shè)計重構(gòu)柱嫌》嫣瘢考察了各個構(gòu)建工具包括Glup、Grunt编丘、Webpack之后還是決定使用Webpack(最新的主流一般都不會有錯的)与学。查閱了不少資料,大部分是關(guān)注的技術(shù)細(xì)節(jié)嘉抓,對于如何進(jìn)行代碼的組織設(shè)計較少索守,所以本文更多的關(guān)注的可能是代碼的組織方式,探索一個比較好的組織方案

預(yù)備知識

  • AMD/CMD
  • npm
  • AngularJS
  • Webpack

Webpack

Webpack通過一個入口文件(當(dāng)然可以多入口抑片,不是重點)卵佛,將所有依賴文件打包到一個文件中,從而減少SAP應(yīng)用初次加載時http請求到個數(shù)敞斋。并且可以通過各種loader去處理優(yōu)化不同的文件截汪,如js、css植捎、svg等衙解。一般一個通行的做法是將webpack構(gòu)建時的配置信息寫入到一個名為 “webpack.config.js”的文件中。這部分的基礎(chǔ)知識以及demo一般稍作學(xué)習(xí)便可掌握鸥跟。官網(wǎng)文檔本身很不錯丢郊。

所以目錄可以這樣組織:


  • app:存放源代碼
  • build: 存放webpack構(gòu)建完成的代碼
  • node_modules: npm管理的包庫
  • webpack.config.js: webpack構(gòu)建配置
    這個是webpack視角下大的框架

組織結(jié)構(gòu)

1. Module

關(guān)于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是一個層次相對較高的聚合医咨,把相關(guān)的controller枫匾、service等封裝到一個module,以實現(xiàn)一組特定的相對完備的功能拟淮。
對一個中大型的項目理想情況下是拆分為幾個相對比較獨立的module干茉。

以passport模塊為例,包含登錄注冊等功能很泊,組織形式如下:


  • index.js:將該模塊內(nèi)各個部分聯(lián)系在一起
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的定義函數(shù)沾谓,在index中完成最終定義
module.exports = ['$scope','authService','request','$state',
function($scope, authService,request,$state) {

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

    //執(zhí)行用戶登錄操作
    $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 登錄頁面模版
<ion-view>
    <ion-content class="padding">
        <div style="margin-top: 120px;">
            <form name="myForm" novalidate="">
                <div class="list list-inset" style="background-color:transparent;">
                    <label class="item item-input">
                        <input name="phone" ng-maxlength="11" ng-minlength="11" ng-model="user.phone" ng-pattern="/^(((1[0-9]{2})|159|153)+\d{8})$/" placeholder="輸入手機(jī)號" required="" type="number"/>
                    </label>
                    <label class="item item-input">
                        <input name="password" ng-maxlength="32" ng-minlength="6" ng-model="user.password" placeholder="6-32位字母數(shù)字組合" required="" type="password">
                        </input>
                    </label>
                    <input class="button button-block button-small button-positive" ng-click="signin()" ng-disabled="myForm.$invalid" type="submit" value="登錄" />
                    <div class="row">
                        <div class="col button button-clear button-positive" ui-sref="register" style="color:#7b7b7b;">
                            用戶注冊
                        </div>
                        <button class="col button button-clear button-positive" style="color:#7b7b7b;">
                            重置密碼
                        </button>
                    </div>
                </div>
            </form>
        </div>
    </ion-content>
</ion-view>

主要思想就是對于模塊內(nèi)的無論是controller、config也好戳鹅,將它們的定義放到單獨文件中均驶,通過index.js文件,將它們組裝定義成目標(biāo)module

** * 這邊的定義都采用數(shù)組的方式進(jìn)行枫虏,是為了以后進(jìn)行代碼混淆妇穴,函數(shù)的參數(shù)名即使被替換,依然不影響正常的inject * **

通過這種模式我們就完成了一個模塊的定義隶债。

2.項目

完成了一個模塊的定義腾它,那么整個項目的integration也就比較明了了。大致結(jié)構(gòu)如下圖:



首先是各個模塊的定義死讹,然后將跨模塊的復(fù)用代碼以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 環(huán)境配置
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的完整代碼已經(jīng)放到github上面忘瓦,有需要可以參考。代碼的組織方式本身就是仁者見仁引颈,智者見智耕皮,沒有最好一說,所以還是希望可以一起探討蝙场。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凌停,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子售滤,更是在濱河造成了極大的恐慌罚拟,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件完箩,死亡現(xiàn)場離奇詭異赐俗,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)弊知,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門阻逮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人秩彤,你說我怎么就攤上這事叔扼∈驴蓿” “怎么了?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵瓜富,是天一觀的道長鳍咱。 經(jīng)常有香客問我,道長与柑,這世上最難降的妖魔是什么流炕? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮仅胞,結(jié)果婚禮上每辟,老公的妹妹穿的比我還像新娘。我一直安慰自己干旧,他們只是感情好渠欺,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著椎眯,像睡著了一般挠将。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上编整,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天舔稀,我揣著相機(jī)與錄音,去河邊找鬼掌测。 笑死内贮,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的汞斧。 我是一名探鬼主播夜郁,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粘勒!你這毒婦竟也來了竞端?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤庙睡,失蹤者是張志新(化名)和其女友劉穎事富,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乘陪,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡统台,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了暂刘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饺谬。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出募寨,到底是詐尸還是另有隱情族展,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布拔鹰,位于F島的核電站仪缸,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏列肢。R本人自食惡果不足惜恰画,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瓷马。 院中可真熱鬧拴还,春花似錦、人聲如沸欧聘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怀骤。三九已至费封,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蒋伦,已是汗流浹背弓摘。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓竣贪,卻偏偏與公主長得像,于是被迫代替她去往敵國和親势决。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 無意中看到zhangwnag大佬分享的webpack教程感覺受益匪淺蓝撇,特此分享以備自己日后查看,也希望更多的人看到...
    小小字符閱讀 8,164評論 7 35
  • 在現(xiàn)在的前端開發(fā)中陈莽,前后端分離渤昌、模塊化開發(fā)、版本控制走搁、文件合并與壓縮独柑、mock數(shù)據(jù)等等一些原本后端的思想開始...
    Charlot閱讀 5,439評論 1 32
  • 最近在學(xué)習(xí) Webpack,網(wǎng)上大多數(shù)入門教程都是基于 Webpack 1.x 版本的,我學(xué)習(xí) Webpack 的...
    My_Oh_My閱讀 8,184評論 40 247
  • GitChat技術(shù)雜談 前言 本文較長,為了節(jié)省你的閱讀時間私植,在文前列寫作思路如下: 什么是 webpack忌栅,它要...
    蕭玄辭閱讀 12,693評論 7 110
  • 《新余志不約》 余良天日在東方, 絕路不悔吾愁棱。 志悔無醋幻物虧索绪, 傲氣凜然固畫國湖员。 2017年11月10日作
    春城怡景閱讀 163評論 4 8