在ionic1中使用gulp进行项目构建,在ionic2中引入了webpack, 使用ionic2的webpack需要修改相关的配置,而在ionic1中需要自己写gulp任务。其中有一篇特别有帮助的文章, github地址,上面的内容只作为借鉴。这里只叙述下ionic1的,因为比较繁琐。本文只提供一下思路,而非具体步骤。Just a clue, not steps!
相关项目结构
两个环境
- 开发环境
- 生产环境
- 备注:个人感觉没有必要用原文中的staging环境,还有demo中有很多没用的任务, 还有一些是让你
Todo
的。其中有关api-config的可能是做跨域的,也没有用到,本文用的是ionic-cli
注意事项
1) 其中每个模块的写法都是直接挂载到ng-app上的,所以每个模块不需要注入,但必须先引入app.js文件,所以就有了上述boot的任务。
如下一个controller模块 :
(function (angular) { 'use strict'; angular.module('yourNgAppName') .controller('homeCtrl', [ '$scope', function ($scope) { }]);})(angular);
2) 项目结构详细说明:
src中的项目结构:
其中components中是自己的业务代码,比如主页模块,分类模块,tab模块等。
js目录中的项目结构:
其中api提供单纯api模块,app包括项目中的启动文件,通用服务,通用指令,全局变量和app.templates.js文件。settings 文件夹中主要包括设置中通用设置,网络相关设置,匿名ip用户功能,和通用方法组件。third中提供基于cordova的一些第三方功能如QQ,微信,微博登陆功能和极光推送功能等。(备注: 这些设置都是根据自己需求来做的)
3) app.templates.js 文件用法。
angular.module("templates", []);
将templates模块注入到app.js中作为主要依赖。而在名为templates的gulp任务的中将所有的view层写入到缓存模版中。
4) 文件注入, gulp 任务中的inject任务,关键代码:
.pipe(inject(gulp.src(paths.css, {read: false}), {starttag: '{{ext}}', relative: true}))
这种方式使用tag标记和relative:true属性来注入自己的文件。relative表示是否使用相对的路径。
5)跨域相关:
ionic 内部提供了一个跨域工具就是ionic-cli, 官方文档上有说明。这里用的版本是:
"@ionic/cli-plugin-gulp": "1.0.1"
,"@ionic/cli-plugin-ionic1": "2.0.0"
【备注】此处是博客补充,修改时间为:2017年8月26日 22:30:34,在CLI 3.8版本之后将不用这两个插件了,由此这两款插件可以不用安装了,具体提示信息如下:
[WARN] Detected @ionic/cli-plugin-ionic1 in your package.json.As of CLI 3.8, it is no longer needed. You can uninstall it:npm uninstall --save-dev --save-exact @ionic/cli-plugin-ionic1[WARN] Detected @ionic/cli-plugin-gulp in your package.json.As of CLI 3.8, it is no longer needed. You can uninstall it:npm uninstall --save-dev --save-exact @ionic/cli-plugin-gulp
根目录中的ionic.config.json文件中的设置:
{ "name": "your-app-name", "app_id": "your-app-id", "gulpStartupTasks": [ "watch" ], "watchPatterns": [ "www/*" ], "proxies": [ { "path": "/api/user", "proxyUrl": "http://xx.xx.xx.x1:8080/api/user" }, { "path": "/api/sms", "proxyUrl": "http://xx.xx.xx.x1:8080/api/sms" }, { "path": "/api", "proxyUrl": "http://xx.xx.xx.x2:8082/api" } ], "type": "ionic1"}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
可见这里做了三组跨域设置,一个是用户中心,一个是短信接口,一个是提供基本api接口。
在全局变量中的主要设置如下(关键代码):
if (window.cordova) { return { base: 'http://xx.xx.xx.x2:8082/api', user: 'http://xx.xx.xx.x1:8080/api' } } else { return { base: 'http://localhost:8100/api', user: 'http://localhost:8100/api' } }
6) 开发模式:
- 执行$
gulp dev
或者 gulp build --env dev
- 稍后片刻,当打开浏览器后, 在项目目录下新开终端,执行监视拷贝任务 $
gulp watch
- 当在监视任务执行中时, 就可以进行我们的开发了。修改src中的文件,自动同步到www目录,www目录一旦改变,就会通过ionic-cli刷新了浏览器。
- 注意,此处开了两个终端(或命令行),一个用于跨域和刷新,一个用于监视。如果偶尔出现问题,重新运行任务即可。
7) 生产模式:
- 执行:$
gulp pro
或者 gulp build --env pro
- 执行完毕就可以在www目录中得到压缩,混淆合并后的代码了。
8) 其他相关:
- 关于bower第三方管理,可见上述是直接写入gulp文件的,存在局限性,但是有些包的规则并不都是在dist目录中的,所以使用这种方式直接了当。网上很多其他bower管理相关插件,这里没用到。
- 当然其他还有更好的优化这个工作流,比如一些css的进一步优化等。
gulpfile参考代码
var gulp = require('gulp');var gutil = require('gulp-util');var bower = require('bower');var concat = require('gulp-concat');var sass = require('gulp-sass');var rename = require('gulp-rename');var ngAnnotate = require('gulp-ng-annotate');var imagemin = require('gulp-imagemin'); var htmlmin = require('gulp-htmlmin'); var cleanCSS = require('gulp-clean-css');var uglify = require('gulp-uglify'); var _if = require('gulp-if'); var del = require('del'); var stripDebug = require('gulp-strip-debug'); var sh = require('shelljs');var watch = require('gulp-watch');var plumber = require('gulp-plumber');var postcss = require('gulp-postcss');var reporter = require('postcss-reporter');var syntax_scss = require('postcss-scss');var stylelint = require('stylelint');var ngConstant = require('gulp-ng-constant');var extend = require('gulp-extend');var args = require('yargs').argv;var templateCache = require('gulp-angular-templatecache');var inject = require('gulp-inject');var htmlreplace = require('gulp-html-replace');var runSequence = require('run-sequence');var process = require('process');var paths = { html: ['./src/*.html'], css: ['./src/lib/ionic/release/css/ionic.css', './src/css/**/*'], sass: ['./src/css/scss/*.scss'], templates: ['./src/components/**/*.html'], images: ['./src/images/**/*'], fonts: ['./src/fonts/**/*', './src/lib/ionic/release/fonts/**/*'], boot: ['./src/js/app/app.js'], js: ['./src/js/**/*.js', '!./src/js/app/app.js'], components: ['./src/components/**/*.js'], scripts: ['./src/js/**/*.js', './src/components/**/*.js', '!./src/js/app/app.js', '!./src/js/app/app.templates.js'], dist: ['./www'], lib: [ './src/lib/ionic/release/js/ionic.bundle.js', './src/lib/ngCordova/dist/ng-cordova.min.js', './src/lib/ionic-native-transitions/dist/ionic-native-transitions.min.js', './src/lib/angular-cookies/angular-cookies.js', './src/lib/ionic-image-lazy-load/ionic-image-lazy-load.js' ], inject: [ './src/lib/ionic/release/css/ionic.css', './src/css/**/*', './src/js/**/*.js', './src/components/**/*.js' ], watch: ['./src/**/*']};var productionTask = ['index', 'boot', 'scripts', 'minify-third-library-js', 'templates', 'copy-fonts', 'css', 'imagemin'];gulp.task('dev', ['clean', 'inject'], function () { runSequence( 'copy-src-to-www', function () { gutil.log(gutil.colors.yellow('正在为您打开浏览器, 请稍后!')); sh.exec('ionic serve'); });});gulp.task('pro', ['clean'], function () { gutil.log(gutil.colors.yellow('构建开始!')); runSequence(productionTask, function () { gutil.log(gutil.colors.yellow('构建完成!')); });});gulp.task('build', function () { if (!args.env || (args.env === "dev")) { runSequence('dev'); } else if (args.env && args.env === "pro") { runSequence('pro'); } else { gutil.log(gutil.colors.yellow('Wong arguments! Please check again!')); }});gulp.task('clean', function () { return del([ paths.dist + '/**/*' ]);});gulp.task('copy', function () { return gulp.src(paths.watch) .pipe(plumber()) .pipe(gulp.dest(paths.dist + '/'));});function handleWatchType(type) { if (!type) { return; } if (type === 'add' || type === 'unlink') { injectFunc(); } }gulp.task('watch', function () { gulp.src(paths.watch) .pipe(plumber()) .pipe(watch(paths.watch, function (vinyl) { handleWatchType(vinyl.event); })) .pipe(gulp.dest(paths.dist + '/'))});function injectFunc() { return gulp.src('./src/index.html') .pipe(plumber()) .pipe(inject(gulp.src(paths.css, {read: false}), {starttag: '<!-- inject:css:{{ext}} -->', relative: true})) .pipe(inject(gulp.src(paths.lib, {read: false}), {starttag: '<!-- inject:lib:{{ext}} -->', relative: true})) .pipe(inject(gulp.src(paths.boot, {read: false}), {starttag: '<!-- inject:boot:{{ext}} -->', relative: true})) .pipe(inject(gulp.src(paths.js, {read: false}), {starttag: '<!-- inject:js:{{ext}} -->', relative: true})) .pipe(inject(gulp.src(paths.components, {read: false}), { starttag: '<!-- inject:components:{{ext}} -->', relative: true })) .pipe(gulp.dest('./src/'))}gulp.task('inject', injectFunc);gulp.task('index', function () { gulp.src(paths.html) .pipe(plumber()) .pipe(htmlreplace({ 'css': 'css/app.min.css', 'boot': 'js/app.boot.min.js', 'js': 'js/app.bundle.min.js', 'third-library-js': 'js/app.plugin.min.js', 'templates': 'js/app.templates.min.js' })) .pipe(htmlmin({collapseWhitespace: true})) .pipe(gulp.dest(paths.dist + '/.'));});gulp.task('css', function () { gulp.src(paths.css) .pipe(plumber()) .pipe(_if('*.scss', sass.sync())) .pipe(cleanCSS({rebase: false})) .pipe(concat('app.min.css')) .pipe(gulp.dest(paths.dist + '/css'));});gulp.task('imagemin', function () { gulp.src(paths.images) .pipe(plumber()) .pipe(imagemin()) .pipe(gulp.dest(paths.dist + '/images'));});gulp.task('copy-fonts', function () { return gulp.src(paths.fonts) .pipe(plumber()) .pipe(gulp.dest(paths.dist + '/fonts'));});gulp.task('minify-third-library-js', function () { gulp.src(paths.lib) .pipe(plumber()) .pipe(ngAnnotate()) .pipe(uglify()) .pipe(concat('app.plugin.min.js')) .pipe(gulp.dest(paths.dist + '/js'));});gulp.task('boot', function () { gulp.src(paths.boot) .pipe(plumber()) .pipe(stripDebug()) .pipe(ngAnnotate()) .pipe(uglify()) .pipe(concat('app.boot.min.js')) .pipe(gulp.dest(paths.dist + '/js'));});gulp.task('scripts', function () { gulp.src(paths.scripts) .pipe(plumber()) .pipe(stripDebug()) .pipe(ngAnnotate()) .pipe(uglify()) .pipe(concat('app.bundle.min.js')) .pipe(gulp.dest(paths.dist + '/js'));});gulp.task('templates', function () { gulp.src(paths.templates) .pipe(plumber()) .pipe(htmlmin({collapseWhitespace: true})) .pipe(templateCache({ standalone: true, root: 'components' })) .pipe(uglify()) .pipe(concat('app.templates.min.js')) .pipe(gulp.dest(paths.dist + '/js'));});gulp.task('install', ['git-check'], function () { return bower.commands.install() .on('log', function (data) { gutil.log('bower', gutil.colors.cyan(data.id), data.message); });});gulp.task('git-check', function (done) { if (!sh.which('git')) { console.log( ' ' + gutil.colors.red('Git is not installed.'), '\n Git, the version control system, is required to download Ionic.', '\n Download git here:', gutil.colors.cyan('http://git-scm.com/downloads') + '.', '\n Once git is installed, run \'' + gutil.colors.cyan('gulp install') + '\' again.' ); process.exit(1); } done && done();});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
扩展
- 这篇文章确实很有帮助,关于前端架构,模块化不仅仅是为了重用,最重要的是分治
- https://github.com/fouber/blog/issues/10