http://www.startersquad.com/blog/AngularJS-requirejs/

While delivering software projects for startups, we’ve come to love angularjs. We’ve also come to struggle with clean modularity, both the parts that Angular does really well, and the parts that are somewhat missing. RequireJS does a great job where Angular leaves some things to be desired, but using them together is not entirely trivial. What follows is our take at the problem.

Why?

Working with Angular you could worry about a good way to organize code. There are already great how-tos on that, check out this mainly theoretical post by Brian Ford and this practical guide by Cliff Meyers if you haven’t already. I’ll share the way I’m managing code in Angular applications with RequireJS.

Continue reading if you want to:

  • stop worrying about including script tags in the right order when building Angular apps;
  • to load your javascript asynchronously;
  • to compile code into single minified js file;

Who?

I assume that you already know what AngularJS is and that you’ve at least heard of AMD and RequireJS. To illustrate the approach I’ll first enable RequireJS for Angular Seed and explain process. Angular Seed structures code by splitting files by type and so will I. It’s also possible to apply this approach if you write modules by entities (you’ll see it from app.controllersmodule implementation).

How?

Angular Seed Project

Let’s check how Angular Seed structures code. Check out the example in your browser or on github (copied from Seed):

  • app.js file to bootstrap and set app config;
  • actual implementation files – controllers, services, directives and filters;
  • index.html with all script tags included in right order;
  • or index-async.html that makes use of angular-loader.js and 3-rd party$script loader library to load dependencies asyncronously.

Let’s start the party.

Add RequireJS

Checkout the example in your browser or on github.

Installing dependencies

I used bower to do this for me. See bower.json file:

{
"name": "AngularJS + RequireJS Example",
"version": "0.1",
"main": "index.html",
"ignore": [
"**/.*",
"libs"
],
"dependencies": {
"angular": "latest",
"requirejs": "latest",
"requirejs-domready": "latest"
}
}

Put the .bowerrc file next to bower.json, run bower install and – poof, we have all we need under libs folder.

index.html

Destruction is a good start. Open Angular Seed’s index.html and remove all the <script> tags. Looks cleaner, doesn’t it? Now switch to creation mode and add single script before closing </body> that will load RequireJS and instruct it to look for config in js/main.js with the data-main attribute:

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My AngularJS AngularJS + RequireJS App</title>
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<ul class="menu">
<li><a href="#/view1">view1</a></li>
<li><a href="#/view2">view2</a></li>
</ul> <div data-ng-view></div> <div>Angular Require seed app: v<span app-version></span></div> <script src="lib/requirejs/require.js" data-main="js/main.js"></script>
</body>
</html>

That’s all there’s to it. You can close index.html now, as there is nothing more we need to add to it.

main.js

Time to setup RequireJS config.

require.config({

  // alias libraries paths
paths: {
'domReady': '../lib/requirejs-domready/domReady',
'angular': '../lib/angular/angular'
}, // angular does not support AMD out of the box, put it in a shim
shim: {
'angular': {
exports: 'angular'
}
}, // kick start application
deps: ['./bootstrap']
});

What just happened? In paths we set aliases for the libraries and plugins used, then we defined that angular should be shimmed and thatbootstrap.js should be loaded to start the application.

bootstrap.js

We’re bootstrapping angular manually now, that’s what bootstrap.js is for. Note that you don’t need ng-app in your html anymore. Also routes.js, which contains angular routes configuration is included into dependencies list.

Note that in this require module we almost have no use of asynchronous loading and we’ll always have chain of angular -> app -> routes, as they depend on each other: angular needs to be present on a page before setting up application module, which is required to exist when defining routes config.

/**
* bootstraps angular onto the window.document node
*/
define([
'require',
'angular',
'app',
'routes'
], function (require, ng) {
'use strict'; require(['domReady!'], function (document) {
ng.bootstrap(document, ['app']);
});
});

We use domReady RequireJS plugin to make sure that DOM is ready when we start the app. Note that before doing so we’re loading the app.jsdependency, in there the main application is defined.

app.js

app.js wraps the definition of the top-level app module and loads the dependencies of its submodules.

define([
'angular',
'./controllers/index',
'./directives/index',
'./filters/index',
'./services/index'
], function (ng) {
'use strict'; return ng.module('app', [
'app.services',
'app.controllers',
'app.filters',
'app.directives'
]);
});

We agreed to have 4 modules by files types: controllers, directives, filters, services – we require these modules to be loaded before defining the main module.

routes.js

Top level routes definition lives here. It is also possible to have modules to set up their own routes (this case is omitted for now in favour of simplicity).

define(['./app'], function (app) {
'use strict';
return app.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/view1', {
templateUrl: 'partials/partial1.html',
controller: 'MyCtrl1'
}); $routeProvider.when('/view2', {
templateUrl: 'partials/partial2.html',
controller: 'MyCtrl2'
}); $routeProvider.otherwise({
redirectTo: '/view1'
});
}]);
});

Module structure

A module consists of 3 parts:

  • definition;
  • component;
  • loader.

Let’s use the app.controllers module as example.

module definition (controllers/module.js)

It’s just like top level app.js: it defines a module.

define(['angular'], function (ng) {
'use strict';
return ng.module('app.controllers', []);
});

This file will be used by the module components to attach themselves to (see next section).

module loader (controllers/index.js)

That’s just an empty define block with all module components included. You don’t need to mention module.js here as it’s already required by components. Loader is included as dependency of top level app module. And that’s actually how RequireJS knows about files to load.

define([
'./my-ctrl-1',
'./my-ctrl-2'
], function () {});

module components (controllers/my-ctrl-1.js)

In the case with the app.controllers module it’ll be controllers. Example of controller wrapped in define is:

define(['./module'], function (controllers) {
'use strict';
controllers.controller('MyCtrl1', [function ($scope) {}]);
});

Note that we used reference to ./module.js to attach component to its module.

Conclusion

That’s it. Now you have working Angular application powered by RequireJS. You can enjoy the power of not tracking the order of your scripts anymore and you get some powerful minification tooling to boot.

In next articles I’ll show you how to test this application properly, how to compile it into single file and automate workflows with grunt. All this is already enabled in StarterSquad Angular + Require Seed check it out if you can’t wait (I’m a slow typist).

About StarterSquad

StarterSquad is a community of distributed development teams consisting of freelance developers. We specialize in startups and lean innovation. If you want to know more, read more about how we work and if you need any help with Angular, checkout my team.

AngularJS + RequireJS的更多相关文章

  1. 前端angularjs+requirejs+dhtmlx 后端asp.net webapi

    享一个前后端分离方案源码-前端angularjs+requirejs+dhtmlx 后端asp.net webapi   一.前言 半年前左右折腾了一个前后端分离的架子,这几天才想起来翻出来分享给大家 ...

  2. AngularJS+requireJS项目的目录结构设想

    AngularJS+requireJS项目的目录结构设想 准备用AngularJS + require.js 作为新项目的底层框架,以下目录结果只是一个初步设想: /default    放页面,不过 ...

  3. angularjs+requirejs整合

    通过requirejs的配置让angularJS可以正常运行.以下是配置的步骤: 环境需求 require.js angular.js 有了这两文件,就可以进行下一步了,具体将文件放到哪个目录,可以跟 ...

  4. 新建一个angularjs+requirejs+bootstrap+typescript+gulp+vscode+git的项目

    环境 windows 10 准备工具 Visual Studio Code Node.js Git 需求 必须支持IE8 步骤开始: 执行命令行工具 mkdir Demo && cd ...

  5. 【开源】分享一个前后端分离方案-前端angularjs+requirejs+dhtmlx 后端asp.net webapi

    一.前言 半年前左右折腾了一个前后端分离的架子,这几天才想起来翻出来分享给大家.关于前后端分离这个话题大家也谈了很久了,希望我这个实践能对大家有点点帮助,演示和源码都贴在后面. 二.技术架构 这两年a ...

  6. angularJS+requireJS并集成karma测试实践

    最近在为下一个项目做前端技术选型,Angular是必须要用的(BOSS指定,个人感觉也不错,开发效率会很高).由于需要加载的JS很多,所以打算看看angular和requirejs一起用会怎么样.在g ...

  7. AngularJS+RequireJs实现动态加载JS和页面的方案研究【上】

    1.入口页面 存放地址:src/main/webapp/WEB-INF/view/workflow/workflow.jsp [html] view plain copy 在CODE上查看代码片派生到 ...

  8. angularJS+requireJS实现controller及directive的按需加载

    最近因为项目的比较大,需要加载的js文件较多,为了提高首屏页面的加载速度,需要对js文件进行按需加载,然后网上参考了一些资料,自己也深入研究一番之后,实现了按需加载控制器js文件及指令js文件的效果: ...

  9. AngularJS+RequireJs实现动态加载JS和页面的方案研究【下】

    about.js: [html] view plain copy 在CODE上查看代码片派生到我的代码片 define(['app'], function(app) { app.controller( ...

随机推荐

  1. Cocos2D将v1.0的tileMap游戏转换到v3.4中一例(二)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 首先在CatMazeV3中新建CatSprite类,继承于Spr ...

  2. J2EE学习从菜鸟变大鸟之五 JDBC(Java Data Base Connectivity)

    JDBC刚开始学习这个的时候看到了,以为是ODBC呢,很是相似啊,总的来说还是基本上一类的东东,但是还有一些细微的区别,下面和大家一起分享学习. JDBC(Java Data Base Connect ...

  3. redis3.0.5在linux上安装与配置

    redis3.0.5在linux上安装与配置 rhel6/ubuntu14 1 下载 # wget http://download.redis.io/releases/redis-3.0.5.tar. ...

  4. (NO.00003)iOS游戏简单的机器人投射游戏成形记(五)

    上一篇我们建立了机器人物理对象,下面我们来看看对应的逻辑代码. 进入Xcode,新建Robot和Arm类,分别继承于CCNode和CCSprite类.代码全部留空,后面再实现. 我们再看一下这个机器人 ...

  5. iOS-导航头像缩放,支持点击回调

    在很多App中,经常存在一种需求就是,界面上下滚动时用户的头像也会跟着滚动,而用户头像在视图向上滚动一定范围时停留并在导航栏的位置 基本用法如下:1.单纯的实现这一效果: - (LEOHeaderVi ...

  6. [Java]数组排序-选择排序 冒泡排序 插入排序

    1 选择排序  原理:a 将数组中的每个元素,与第一个元素比较          如果这个元素小于第一个元素, 就将这个         两个元素交换.       b 每轮使用a的规则, 可以选择出 ...

  7. EBS 信用检查(一)

    信用逻辑 This post will more focus on Technical part of credit check Functionality. You can check the fu ...

  8. ISLR系列:(4.3)模型选择 PCR & PLS

    Linear Model Selection and Regularization 此博文是 An Introduction to Statistical Learning with Applicat ...

  9. volatile和synchronized的区别和联系

    volatile 它所修饰的变量不保留拷贝,直接访问主内存中的.   在Java内存模型中,有main memory,每个线程也有自己的memory (例如寄存器).为了性能,一个线程会在自己的mem ...

  10. UML之状态图

    状态图,英文名曰-Statechart Diagram,她是系统的动态方面建模的五种图之一,一个状态图显示了一个状态机,在为对象的生命期建模中,她发挥着重要的作用,展示了单个对象内从状态到状态的控制流 ...