在开发Angular.js应用程序时,经常面临如何组织和管理代码的问题。本文将探讨一种简化的构建方法,这种方法避免了复杂的模块系统,转而采用直接合并文件的方式。
在Angular.js开发中,可能会遇到各种模块加载器,如RequireJS。虽然这些工具在某些情况下很有用,但它们往往会增加项目的复杂性,而没有带来相应的好处。例如,RequireJS与AngularJS的结合可能会导致难以调试的问题,因为AngularJS并不完全兼容AMD规范。
使用这些工具就像是用锤子敲自己的脸,虽然有些夸张,但那些使用过这两种工具结合的人可能会深有同感。
Browserify是另一种模块打包工具,它的语法更清晰,但使用起来仍然有些麻烦。理想情况下,希望能够使用ECMA6模块语法,然后通过Traceur等工具进行编译。然而,这需要大量的工具支持,会减慢构建流程,而且实际上并没有真正使用模块。
Jeff Dicky在他的文章《Best Practices for Building Angular.js Apps》中提出了一种最佳实践,即忘记所有的模块系统,只进行文件合并。以下是推荐的项目结构:
myproject
- app/
- css/
- vendor/
- index.html
然后在app文件夹中放置主文件:
myproject
- app/
- app.js
- css/
- vendor/
- index.html
app.js文件应该定义主Angular模块:
angular.module('app', []);
接下来,可以将app文件夹中的所有内容合并。可以按照自己的方式组织结构:
myproject
- app/
- components/
- home/
- profile/
- app.js
- css/
- vendor/
- index.html
合并操作会将所有内容放在顶级文件夹中(即app.js)。只要不在顶级文件夹中放置任何其他文件(按字母顺序在'a'之前),那么可以随意放置其他文件,只要在定义它们时不引用任何全局变量。例如:
angular.module('app').controller('SomeController', function() {
// something
});
这种方法简单明了,不需要复杂的模块系统。不需要强制在Angular上使用另一个模块系统,因为这样做的好处并不多。耐心等待ECMA6更广泛地被接受,就可以开始使用原生模块了。
如果是Gulp用户,以下是如何构建一个合并JavaScript的流水线:
var gulp = require('gulp');
var jshint = require('gulp-jshint');
var stylish = require('jshint-stylish');
var uglify = require('gulp-uglify');
var rename = require('gulp-rename');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
var ngAnnotate = require('gulp-ng-annotate');
// Hints and builds all JavaScript.
gulp.task('js', function() {
return gulp.src(['./client/app/**/*.js'])
.pipe(jshint())
.pipe(jshint.reporter(stylish))
.pipe(jshint.reporter('fail'))
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(concat('app.js'))
.pipe(gulp.dest('./client/dist'))
.pipe(ngAnnotate())
.pipe(uglify())
.pipe(rename({suffix: '.min'}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./client/dist'));
});
这样,当app JavaScript文件夹发生变化时,它会自动进行提示,合并到一个单独的分发文件夹中,进行注释和压缩,同时构建完整的源代码映射。
对于供应商代码(如jQuery、Bootstrap等),不要试图聪明地使用require或import。只需在应用程序中使用script标签包含它。不建议在一种实际上不支持它的语言上强制使用某种智能模块系统——如果可以避免这样做,那就去做吧。