在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中的项目结构:

      
  • ios15跨域携带cookie失败 ionic 跨域_跨域

  •  
      
      其中components中是自己的业务代码,比如主页模块,分类模块,tab模块等。
  • js目录中的项目结构:

      
  • ios15跨域携带cookie失败 ionic 跨域_gulp_02

  •   
    其中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();
});