-
-
Save htom78/2f46f9e9ad2adea04826 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var join = require('path').join; | |
var DEFAULT_CONFIG = { | |
// spm 源 | |
"registry": "http://private-spm-url", | |
// Rename files | |
// 详见:https://github.com/jeremyruppel/pathmap | |
"pathmap": null, | |
// JS 压缩配置项 | |
// 详见:https://github.com/terinjokes/gulp-uglify/ | |
"uglifyOpts": { | |
"output": { | |
"ascii_only": true | |
} | |
}, | |
// CSS 压缩配置项 | |
// 详见:https://github.com/GoalSmashers/clean-css | |
"cssminOpts": { | |
"noAdvanced": true | |
}, | |
// less 编译配置项 | |
// 详见:https://github.com/plus3network/gulp-less | |
"lessOpts": null, | |
// coffee 预编译配置项 | |
// 详见:https://github.com/wearefractal/gulp-coffee | |
"coffeeOpts": { | |
"bare": true | |
}, | |
// autoprefixer 配置项, 默认关闭 | |
// https://github.com/sindresorhus/gulp-autoprefixer | |
"autoprefixer": false | |
}; | |
////////////////////// | |
// Exports. | |
exports.get = function(cwd) { | |
cwd = cwd || process.cwd(); | |
var userConfig = require(join(cwd, 'package.json')).spm; | |
return extendExist(DEFAULT_CONFIG, userConfig); | |
}; | |
///////////////////// | |
// Helpers. | |
function extendExist(source, obj) { | |
var ret = {}; | |
for (var k in source) { | |
ret[k] = source[k]; | |
if (typeof obj[k] === 'object' && typeof source[k] === 'object') { | |
for (var kk in obj[k]) { | |
ret[k][kk] = obj[k][kk]; | |
} | |
} else if(typeof obj[k] !== 'undefined') { | |
ret[k] = obj[k]; | |
} | |
} | |
return ret; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
require('colorful').colorful(); | |
var fs = require('fs'); | |
var path = require('path'); | |
var umi = require('umi'); | |
var join = require('path').join; | |
var glob = require('glob'); | |
var uniq = require('array-uniq'); | |
var spmrc = require('spmrc'); | |
var log = require('spm-log'); | |
var multipipe = require('multipipe'); | |
var gulp = require('gulp'); | |
var standalonify = require('spm-standalonify'); | |
var through = require('through2'); | |
var extend = require('extend'); | |
var checkonline = require('checkonline'); | |
var install = require('co')(require('spm-client').install); | |
var autoprefixer = require('gulp-autoprefixer'); | |
var cssmin = require('gulp-cssmin'); | |
var transport = require('gulp-transport'); | |
var gulpif = require('gulp-if'); | |
var mirror = require('gulp-mirror'); | |
var pathmap = require('gulp-pathmap'); | |
var clean = require('gulp-clean'); | |
var less = require('gulp-less'); | |
var coffee = require('gulp-coffee'); | |
var uglify = require('gulp-uglify'); | |
var slash = require('gulp-slash'); | |
module.exports = function(opts, cb) { | |
var args = umi.buildArgs(opts); | |
args = extend(require('./config').get(args.cwd), args); | |
logArgs(args); | |
// load spmfile | |
var spmfile = join(args.cwd, 'spmfile.js'); | |
args.spmfile = {}; | |
if (fs.existsSync(spmfile)) { | |
args.spmfile = require(spmfile); | |
} | |
// define task | |
defineCleanTask(args); | |
defineInstallTask(args); | |
defineCustomTasks(args); | |
definePrecompileTasks(args); | |
defineBuildTask(args); | |
defineCheckOnlineTask(args); | |
gulp | |
.on('task_start', function(e) {showLog('start', e);}) | |
.on('task_stop', function(e) {showLog('end', e);}); | |
gulp.start('checkonline', cb); | |
}; | |
////////////////// | |
// Tasks | |
function defineCheckOnlineTask(args) { | |
gulp.task('checkonline', ['endTask'], function(callback) { | |
var isRelative = args.include === 'relative'; | |
var currPkg = args.pkg.name + '/' + args.pkg.version; | |
checkonline({ | |
cwd: args.cwd, | |
server: 'https://a.alipayobjects.com', | |
statusCode: 404, | |
withDeps: isRelative | |
}, function(err, files) { | |
if (err) { | |
return callback(err); | |
} | |
// Check if dependencies pkgs is online | |
if (isRelative) { | |
var pkgs = files | |
// is not online and not current pkg | |
.filter(function(f) {return !f.isOnline && f.filepath.indexOf(currPkg) !== 0;}) | |
// get pkg list in `name@version` | |
.map(function(f) {return f.filepath.split('/').slice(0,2).join('@')}); | |
pkgs = uniq(pkgs); | |
if (pkgs.length) { | |
log.warn('checkonline', 'These deps are not published: ' + pkgs.join(', ').to.yellow.color); | |
} | |
} | |
if (files.filter(isCurrentPkgPublished).length) { | |
var errMsg = 'This version '+(args.pkg.name+'@'+args.pkg.version)+' is already published!'; | |
return callback(new Error(errMsg)); | |
} | |
callback(); | |
function isCurrentPkgPublished(f) { | |
return f.filepath.indexOf(currPkg) === 0 && f.isOnline; | |
} | |
}); | |
}); | |
} | |
function defineCleanTask(args) { | |
gulp.task('clean', function() { | |
return args.force && gulp.src(args.dest) | |
.pipe(clean({force: true})); | |
}); | |
} | |
function defineInstallTask(args) { | |
gulp.task('install', args.install ? function(callback) { | |
var opts = { | |
cwd: args.cwd, | |
registry: args.registry | |
}; | |
install(opts, callback); | |
} : noop); | |
} | |
function defineCustomTasks(args) { | |
gulp.task('startTask', ['clean'], | |
args.spmfile.startTask ? args.spmfile.startTask(args) : function(){}); | |
gulp.task('endTask', ['build'], | |
args.spmfile.endTask ? args.spmfile.endTask(args) : function(){}); | |
} | |
function definePrecompileTasks(args) { | |
var lessFiles = getLessFiles(args); | |
gulp.task('less', ['startTask'], function() { | |
if (!lessFiles.length) return; | |
return pipe( | |
gulp.src(lessFiles, {cwd:args.cwd, base:args.cwd}), | |
less(args.lessOpts || {paths: [args.cwd]}), | |
gulp.dest(args.cwd) | |
); | |
}); | |
var coffeeFiles = getCoffeeFiles(args); | |
gulp.task('coffee', ['startTask'], function() { | |
if (!coffeeFiles.length) return; | |
return pipe( | |
gulp.src(coffeeFiles, {cwd:args.cwd, base:args.cwd}), | |
coffee(args.coffeeOpts), | |
gulp.dest(args.cwd) | |
); | |
}); | |
} | |
function defineBuildTask(args) { | |
gulp.task('build', ['less', 'coffee', 'install'], function(cb) { | |
build(args, cb); | |
}); | |
} | |
function build(args, cb) { | |
try { | |
var pkg = new umi.Package(args.cwd, { | |
skip: args.skip, | |
ignore: args.ignore, | |
moduleDir: spmrc.get('install.path') | |
}); | |
if (!args.noPkgLog) { | |
log.info('package', 'analyse infomation'); | |
log.info('package', 'dependencies: ' + Object.keys(pkg.dependencies)); | |
log.info('package', 'files: ' + Object.keys(pkg.files)); | |
} | |
args.pkg = pkg; | |
} catch(err) { | |
cb(err); | |
} | |
var files = getFiles(pkg); | |
log.info('output', 'files: ' + files); | |
// check duplicatate | |
checkDuplicate(files, pkg); | |
// build package in dependencies | |
var depFiles = {}; | |
if (args.withDeps) { | |
var depPkgs = getAllDependencies(pkg); | |
for (var id in depPkgs) { | |
files = files.concat(getFiles(depPkgs[id]).map(function(f) { | |
var filepath = spmrc.get('install.path') + '/' + id.replace('@','/') + '/' + f; | |
depFiles[filepath] = depPkgs[id].files[f]; | |
return filepath; | |
})); | |
} | |
log.info('withDeps', 'files: ' + files); | |
} | |
// check ext deps and install | |
if (!args.noExtCheck) { | |
var extDeps = getExtDeps(files, pkg, depFiles); | |
if (extDeps.length) { | |
log.info('extDeps', extDeps.join(',')); | |
} | |
if (extDeps.length) { | |
return install({ | |
cwd: args.cwd, | |
save: true, | |
name: extDeps | |
}, function(err) { | |
if (err) { | |
return cb(err); | |
} | |
args.noExtCheck = args.noPkgLog = true; | |
build(args, cb); | |
}); | |
} | |
} | |
var isStandalone; | |
if (args.include === 'standalone') { | |
isStandalone = true; | |
args.include = 'all'; | |
} | |
if (args.include === 'umd') { | |
isStandalone = true; | |
args.include = 'all'; | |
// use package name as global name for umd | |
args.umd = camelCase(args.pkg.name); | |
} | |
// add {{name}} and {{version}} support for pathmap | |
if (args.pathmap) { | |
args.pathmap = template(args.pathmap, pkg); | |
} | |
var opt = umi.util.extendOption(args); | |
var optDebug = umi.util.extendOption(args); | |
optDebug.rename = {'suffix': '-debug'}; | |
return pipe( | |
gulp.src(files, {cwd:opt.cwd, base:opt.cwd}), | |
args.spmfile.startStream ? args.spmfile.startStream(args) : through.obj(), | |
// transport css and js | |
gulpif(isCSSorJS, mirror( | |
// normal | |
pipe( | |
transport(opt), | |
gulpif(isJS, pipe( | |
gulpif(isStandalone, standalonify(args)), | |
uglify(args.uglifyOpts) | |
), pipe( | |
gulpif(args.autoprefixer, autoprefixer(args.autoprefixer)), | |
cssmin(args.cssminOpts) | |
)) | |
), | |
// debug | |
pipe( | |
transport(optDebug), | |
gulpif(isJS, pipe( | |
gulpif(isStandalone, standalonify(args)) | |
), pipe( | |
gulpif(args.autoprefixer, autoprefixer(args.autoprefixer)) | |
)) | |
) | |
)), | |
transport.plugin.dest(opt), | |
slash(), | |
args.pathmap ? pathmap(args.pathmap) : through.obj(), | |
args.spmfile.endStream ? args.spmfile.endStream(args) : through.obj(), | |
gulp.dest(args.dest) | |
).on('end', cb); | |
} | |
////////////////// | |
// Utils | |
function getFiles(pkg) { | |
var files = []; | |
if (fs.existsSync(path.join(pkg.dest, pkg.main))) { | |
files.push(pkg.main); | |
} | |
pkg.output.forEach(function(_glob) { | |
var items = glob.sync(_glob, {cwd: pkg.dest}); | |
files = files.concat(items); | |
}); | |
return uniq(files); | |
} | |
function getLessFiles(args) { | |
var pkg = require(join(args.cwd, 'package.json')); | |
var files = []; | |
if (Array.isArray(pkg.spm.output)) { | |
pkg.spm.output.forEach(function(_glob) { | |
_glob = _glob.replace(/\.css$/, '.less'); | |
var items = glob.sync(_glob, {cwd: args.cwd}); | |
files = files.concat(items); | |
}); | |
} | |
return uniq(files).filter(function(file) { | |
return path.extname(file) === '.less'; | |
}); | |
} | |
function getCoffeeFiles(args) { | |
var pkg = require(join(args.cwd, 'package.json')); | |
var files = []; | |
if (Array.isArray(pkg.spm.output)) { | |
pkg.spm.output.forEach(function(_glob) { | |
_glob = _glob.replace(/\.js/, '.coffee'); | |
var items = glob.sync(_glob, {cwd: args.cwd}); | |
files = files.concat(items); | |
}); | |
} | |
return uniq(files).filter(function(file) { | |
return path.extname(file) === '.coffee'; | |
}); | |
} | |
function pipe() { | |
return multipipe.apply(null, arguments) | |
.on('data', function() {}); | |
} | |
function showLog(type, e) { | |
var info = 'task ' + e.task; | |
if (type === 'end') info = info.to.green.color; | |
log.info(type, info); | |
} | |
function logArgs(args) { | |
Object.keys(args) | |
.forEach(function(key) { | |
var val = args[key]; | |
if (typeof val === 'object') { | |
val = JSON.stringify(val); | |
} | |
log.info('arguments', key + ' = ' + val); | |
}); | |
} | |
function isJS(file) { | |
return path.extname(file.path) === '.js'; | |
} | |
function isCSSorJS(file) { | |
return path.extname(file.path) === '.js' || | |
path.extname(file.path) === '.css'; | |
} | |
function camelCase(str) { | |
return str.replace(/[_.-](\w|$)/g, function (_,x) { | |
return x.toUpperCase(); | |
}); | |
} | |
function template(format, data) { | |
return format.replace(/{{([a-z]*)}}/g, function(all, match) { | |
return data[match] || ''; | |
}); | |
} | |
function noop() {} | |
function getAllDependencies(pkg) { | |
var result = {}; | |
recurseDependencies(pkg); | |
return result; | |
function recurseDependencies(pkg) { | |
Object.keys(pkg.dependencies).forEach(function(key) { | |
var id = pkg.dependencies[key].id; | |
if (!result[id]) { | |
result[id] = pkg.dependencies[key]; | |
recurseDependencies(pkg.dependencies[key]); | |
} | |
}); | |
} | |
} | |
function getExtDeps(files, pkg, depFiles) { | |
var extDeps = {}; | |
files.forEach(function(f) { | |
if (path.extname(f) !== '.js') return; | |
var file = depFiles[f] || pkg.files[f]; | |
if (!file) return; | |
if (!pkg.dependencies['import-style'] && file.hasExt('css')) { | |
extDeps['import-style'] = true; | |
} | |
if (!pkg.dependencies['handlebars-runtime'] && file.hasExt('handlebars')) { | |
extDeps['handlebars-runtime'] = true; | |
} | |
}); | |
return Object.keys(extDeps); | |
} | |
function checkDuplicate(files, pkg) { | |
var rootPkgName = pkg.name; | |
files.forEach(function(f) { | |
var dup = {}; | |
var file = pkg.files[f]; | |
file.lookup(function(fileInfo) { | |
var name = fileInfo.pkg.name; | |
var version = fileInfo.pkg.version; | |
if (name === rootPkgName) return; | |
dup[name] = dup[name] || {}; | |
dup[name][version] = true; | |
}); | |
for (var k in dup) { | |
var versions = Object.keys(dup[k]); | |
if (versions.length > 1) { | |
log.warn('dulplicate', | |
'%s (%s) while building %s'.to.yellow.color, | |
k, | |
versions.join(', '), | |
file.path | |
); | |
} | |
} | |
}); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "spm-build-example", | |
"version": "0.1.0", | |
"description": "SPM build for project.", | |
"main": "index", | |
"author": "chencheng <[email protected]>", | |
"license": "MIT", | |
"scripts": { | |
"test": "make test" | |
}, | |
"dependencies": { | |
"array-uniq": "~1.0.0", | |
"checkonline": "~0.3.0", | |
"co": "~3.1.0", | |
"colorful": "~2.1.0", | |
"extend": "~1.3.0", | |
"glob": "~4.0.5", | |
"gulp": "~3.6.2", | |
"gulp-autoprefixer": "~1.0.0", | |
"gulp-clean": "~0.3.1", | |
"gulp-coffee": "~2.1.2", | |
"gulp-cssmin": "~0.1.6", | |
"gulp-if": "~1.2.4", | |
"gulp-less": "~1.3.5", | |
"gulp-mirror": "~0.3.0", | |
"gulp-pathmap": "~0.1.0", | |
"gulp-slash": "~1.1.3", | |
"gulp-template": "~1.0.0", | |
"gulp-transport": "~0.7.0", | |
"gulp-uglify": "~0.3.2", | |
"multipipe": "~0.1.1", | |
"spm-client": "~0.2.4", | |
"spm-log": "~0.1.1", | |
"spm-standalonify": "~0.1.0", | |
"spmrc": "~1.2.0", | |
"through2": "~0.6.1", | |
"umi": "~0.6.0" | |
}, | |
"devDependencies": { | |
"coveralls": "2", | |
"istanbul": "0", | |
"mocha": "1", | |
"should": "3", | |
"sinon": "~1.10.3" | |
}, | |
"publishConfig": { | |
"registry": "http://registry.npm.alibaba-inc.com" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment