builder-isv
Version:
ISV 模块本地预览与云构建器
302 lines (254 loc) • 9.43 kB
JavaScript
var co = require('co');
var fs = require('fs');
var path = require('path');
var gulp = require('gulp');
var gutil = require('gulp-util');
var clean = require('gulp-clean');
var cakeCssTask = require('isv-gulp-cake-css');
var abcOptions = require('./lib/getabc.js');
var webpack = require('webpack');
var Base = require('./models/base');
var uglify = require('gulp-uglify');
var through = require('through2');
var rename = require('gulp-rename');
var copy2 = require('gulp-contrib-copy');
var uglify_parallel = require('isv-uglify-parallel');
var _ = require('lodash');
// var babel = require('gulp-babel');
var util = require('./lib/util');
var rimraf = require('rimraf');
var Debug = require('debug');
var debug = Debug('mod');
var debugMini = Debug('mod:mini');
var debugError = Debug('mod:error');
// 在 shell 中执行一个命令
var exec = require('child_process').exec;
var SRC_BASE = abcOptions.SRC_BASE;
var BUILD_BASE = abcOptions.BUILD_BASE;
var CACHE_DIR = '.cachefile';
var config = require('./config');
var utils = require('./lib/utils');
var rendererFactory = new (require('./models/rendererFactory'))(Base.INVOKE_TYPE_BUILD);
config.defOptions = {
base: SRC_BASE,
verbose: process.env.DEF_LOG_LEVEL === 'verbose'
};
process.utils = utils;
try {
abcOptions.packageJSON = JSON.parse(fs.readFileSync(SRC_BASE + '/package.json'));
} catch (e) {
utils.log.info("\n**注意:本目录不存在package.json文件,不能使用 builder-mod 进行打包,故略过**\n");
gulp.task('default', function() {});
return;
}
// 创建缓存文件夹
try {
var cacheDir = path.join(SRC_BASE, CACHE_DIR);
fs.mkdirSync(cacheDir);
debugMini('=====> 创建文件夹成功:' + cacheDir);
} catch (e) {
if (e.code == 'EEXIST') {
debugMini('=====> 文件夹已存在不需要创建');
} else { // 如果不是文件已存在的案例,则直接抛出错误
debugError('=====> 创建文件夹失败:', e);
console.log('文件夹:', cacheDir, '创建失败');
return;
}
}
// 是否是新模块打包方式,根据guideName进行判断
var guideName = abcOptions.packageJSON && abcOptions.packageJSON.upx && abcOptions.packageJSON.upx.guideName;
var isBaseUpx = !!guideName;
abcOptions.isNewModule = isBaseUpx;
abcOptions.options.entry = {};
var isWeex = abcOptions.info && abcOptions.info.extraLib === 'weex';
var isVue2 = abcOptions.info && abcOptions.info.extraLib === 'vue2';
var isRax = abcOptions.info && abcOptions.info.extraLib === 'rax';
var customeName = isBaseUpx ? ['upx', abcOptions.group, abcOptions.name].join(';') : abcOptions.name; // 自定义模块名
var suffix = isWeex ? '.we?customeName=' + customeName : '.js';
if (isVue2) {
suffix = '.vue?customeName=' + customeName;
}
abcOptions.options.entry['index'] = SRC_BASE + '/index' + suffix;
abcOptions.modBuild = true;
//补充配置信息,支持rx、kimi 调试
var info = abcOptions.info;
if (!info.project) {
abcOptions.info.project = 'mod';
}
// 强制删除define 声明中的 deps 的标志位
// info.extraLib 还有可能是 'null',此时一般是pc或者kimi模块
var shouldRemoveDeps = false;
if (info.extraLib === 'reactjs') {
abcOptions.info.extraLib = 'rx';
shouldRemoveDeps = true;
}
abcOptions.options.ignore = _.merge({
"@ali/rx": "kg/rx/index",
"@ali/rx-components": "kg/rx-components/index",
"@ali/pi/mod-base": "kg/pi/mod-base",
"@ali/rx-mounter": "kg/rx-mounter/index"
}, abcOptions.options.ignore || {});
// 为了解决 weex 模块找不到 babel-runtime 的问题,需要手动指定 alias
var WEEX_LOADER_PATH = path.join(__dirname, './node_modules/@ali/cake-webpack-config/node_modules/@ali/weex-mod-loader');
abcOptions.options.resolve = {
alias: {
'babel-runtime': path.join(WEEX_LOADER_PATH, './node_modules/babel-runtime')
}
};
// 打包的时候,需要强制删除缓存文件
// 这样就能强制生成deps.json文件了
function emptyCacheDeps(base) {
// 要清理的文件,包含缓存文件、原始的 deps.json 文件
var fileRule = isRax ? [] : [path.join(base, CACHE_DIR, '*.json')];
fileRule.push(path.join(base, 'deps.json'));
// 删除缓存文件夹中 版本 文件
return gulp.src(fileRule, {read: false}).pipe(clean());
}
/* ----------------------------------------------------
从 upx 查询有注册过的组件,供动态 external 使用
----------------------------------------------------- */
gulp.task('get-external', function() {
return util.getVersionFromUpx(abcOptions.packageJSON.dependencies).then(function(result) {
// 过滤结果,给出提示
_.forOwn(result, function(v, k) {
if (typeof v === 'undefined' || v === null) {
console.log(' ****** 组件 ' + k + ' 未在 upx 中注册,若引用该组件将打包进最终bundle,请斟酌使用 *****\n');
}
});
// console.log('44444', result);
abcOptions.componentsInUpx = result;
}).catch(function(err) {
console.log('尝试从 upx 获取 组件信息失败', err);
});
});
gulp.task('clean-cache', function() {
return emptyCacheDeps(SRC_BASE);
});
gulp.task('clean', ['clean-cache'], function() {
return gulp
.src(BUILD_BASE, {
read: false
})
.pipe(clean());
});
gulp.task("webpack", ['clean', 'get-external'], function(callback) {
co(function*() {
let renderer = yield rendererFactory.getRenderer(null, 'index', path.isAbsolute(SRC_BASE) ? SRC_BASE : path.join(process.cwd(), SRC_BASE), BUILD_BASE);
renderer.addListener('compileSucceed', () => {
callback();
});
//var compiler = webpack(webpackConfig, function(err, stats) {
// if (err) {
// throw new gutil.PluginError("webpack", err);
// }
// //如果编译出错,直接退出进程
// if (stats.hasErrors()) {
// gutil.log("[webpack]", stats.toString({
// chunks: false,
// colors: true,
// children: false
// }));
// //打印报错信息
// console.log(stats.toJson('errors-only'));
// process.exit(1);
// }
//
// gutil.log("[webpack]", stats.toString({
// chunks: false,
// colors: true,
// children: false
// }));
// callback();
//});
//
//if (compiler.compilers) {
// compiler.compilers.forEach(function(compiler) {
// // 注入变量
// compiler.plugin('should-emit', function(compilation) {
// compiler.shouldRemoveDeps = shouldRemoveDeps;
// });
// });
//
// compiler.plugin("done", function(stats) {
// // vue2.0 deps 尝试读取三端的缓存deps进行合并
// if (
// Options && abcOptions.info && abcOptions.info.extraLib === 'vue2') {
// var nativeDeps = util.parseOrFalse(util.readFileOrEmpty(path.join(SRC_BASE, '.cachefile', 'deps.native.json')));
// var webDeps = util.parseOrFalse(util.readFileOrEmpty(path.join(SRC_BASE, '.cachefile', 'deps.web.json')));
// var originDeps = util.parseOrFalse(util.readFileOrEmpty(path.join(SRC_BASE, '.cachefile', 'deps.origin.json')));
//
// var finalDeps = _.assign(nativeDeps, webDeps, originDeps);
// util.writeFileOrNone(path.join(modPath, 'deps.json'), JSON.stringify(finalDeps));
// }
// });
//} else {
// // 注入变量
// compiler.plugin('should-emit', function(compilation) {
// compiler.shouldRemoveDeps = shouldRemoveDeps;
// });
//}
}).catch(function(err) {
utils.log.error(err.stack);
});
var webpackConfigOptions = {
entryDir: SRC_BASE,
outputDir: BUILD_BASE,
abcOptions: abcOptions,
callback: function(err, webpackConfig) {
}
};
});
gulp.task('uglify-parallel', ['webpack'], function() {
return new Promise(function(resolve) {
uglify_parallel({
pattern: '**/*.js',
src: BUILD_BASE,
dest: BUILD_BASE,
// https://github.com/mishoo/UglifyJS2/issues/490
params: ['--compress', 'pure_getters=true,unused=false', '--beautify', 'beautify=false,ascii-only=true']
}, function() {
resolve();
})
});
});
gulp.task('minify-js', ['webpack'], function() {
var isSouce = false;
// if(abcOptions.options.build){
// isSouce = abcOptions.options.build.minifyJS === false;
// }
console.log('=== minify-js阶段 ===');
if (process.env.BUILD_DEBUG === 'debug') {
// 用户添加 --debug 参数,则不代码压缩等处理
console.log('=== 源代码不进行压缩处理 ===');
isSouce = true;
}
//todo pure_getters 参数防止 xtpl 生成的代码在 IE8下无法运行
return gulp.src('**/*.js', {
cwd: BUILD_BASE,
base: BUILD_BASE
}).pipe(isSouce && gutil.noop() || uglify({output: {"ascii_only": true}, "pure_getters": true}))
.pipe(gulp.dest(BUILD_BASE));
});
gulp.task('copy-js', ['minify-js'], function() {
return gulp.src('**/*.js', {
cwd: BUILD_BASE,
base: BUILD_BASE
})
.pipe(copy2())
.pipe(rename({
extname: '-min.js'
}))
.pipe(gulp.dest(BUILD_BASE));
});
gulp.task('copy-json', ['copy-js'], function() {
return gulp
.src([SRC_BASE + '/deps.json'])
.pipe(copy2())
.pipe(gulp.dest(BUILD_BASE));
});
gulp.task('build-js', ['copy-json']);
//css编译任务
cakeCssTask(gulp, abcOptions);
gulp.task('default', ['build-js', 'build-css'], function() {
return emptyCacheDeps(SRC_BASE); // 清空缓存
});