在ionic1中使用gulp进行项目构建,在ionic2中引入了webpack, 使用ionic2的webpack需要修改相关的配置,而在ionic1中需要自己写gulp任务。其中有一篇特别有帮助的文章, github地址,上面的内容只作为借鉴。这里只叙述下ionic1的,因为比较繁琐。本文只提供一下思路,而非具体步骤。Just a clue, not steps!
相关项目结构
- 源码src目录
- 拷贝或编译后的代码www目录
两个环境
- 开发环境
- 生产环境
- 备注:个人感觉没有必要用原文中的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) {
// your business logic
}]);
})(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: '<!-- inject:css:{{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"
}
可见这里做了三组跨域设置,一个是用户中心,一个是短信接口,一个是提供基本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'); // 压缩html
var cleanCSS = require('gulp-clean-css');
var uglify = require('gulp-uglify'); // 压缩js
var _if = require('gulp-if'); // 引用判断
var del = require('del'); // 清空文件和文件夹
var stripDebug = require('gulp-strip-debug'); // Strip console, alert, and debugger statements
var sh = require('shelljs');
var watch = require('gulp-watch');
var plumber = require('gulp-plumber');
// Linting Sass stylesheets with Stylelint
// http://www.creativenightly.com/2016/02/How-to-lint-your-css-with-stylelint/
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');
// This is intended to be a temporary solution until the release of gulp 4.0 which has support
// for defining task dependencies in series or in parallel.
var runSequence = require('run-sequence');
var process = require('process');
// === PATHS ===
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/**/*']
};
// ============ TOP LEVEL TASKS (invoke with "gulp <task-name>") ============
// production task
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');
// 本想打开一个新终端窗口去watch, 在同一目录下 ionic serve 和 watch 冲突。
// 所以现在解决方案是:手动打开新窗口切换到项目目录下执行 `gulp watch`
});
});
// 生产模式
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!'));
}
});
// ==================================== children TASKS ====================================
// clean task
gulp.task('clean', function () {
return del([
paths.dist + '/**/*'
]);
});
// copy src to www
gulp.task('copy', function () {
return gulp.src(paths.watch)
.pipe(plumber())
.pipe(gulp.dest(paths.dist + '/'));
});
// 监视src文件中的变化
function handleWatchType(type) {
if (!type) {
return;
}
if (type === 'add' || type === 'unlink') {
injectFunc(); // 添加新文件 或 删除文件
}
// 备注 change 不做处理
}
gulp.task('watch', function () {
gulp.src(paths.watch)
.pipe(plumber())
.pipe(watch(paths.watch, function (vinyl) {
handleWatchType(vinyl.event);
}))
.pipe(gulp.dest(paths.dist + '/'))
});
// automatic injection third library script in the index file
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);
// prepare Index.html for dist - ie. using min files
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 + '/.'));
});
// css task including sass
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'));
});
// imagemin images and output them in dist
gulp.task('imagemin', function () {
gulp.src(paths.images)
.pipe(plumber())
.pipe(imagemin())
.pipe(gulp.dest(paths.dist + '/images'));
});
// copy fonts task
gulp.task('copy-fonts', function () {
return gulp.src(paths.fonts)
.pipe(plumber())
.pipe(gulp.dest(paths.dist + '/fonts'));
});
// minify third library script 第三方不用去 stripDebug
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'));
});
// boot task
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'));
});
// scripts task
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'));
});
// templatesCache task
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'));
});
// === OTHER TASKS (used by Ionic CLI default) ===
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();
});