src/tasks/defineTasks.js
// ====================
// Packages and modules
// ====================
// native packages
import path from 'path';
import fs from 'fs';
import { exec } from 'child_process';
// vendor packages
import gulp from 'gulp';
import gutil from 'gulp-util';
import changed from 'gulp-changed';
import rimraf from 'rimraf';
import babel from 'gulp-babel';
import webpack from 'webpack';
import sourcemaps from 'gulp-sourcemaps';
import gulpif from 'gulp-if';
import notify from 'gulp-notify';
import nodemon from 'gulp-nodemon';
import mocha from 'gulp-mocha';
// local modules
import defaultBabelConfig from '../configs/babel.default';
import { outputFormatOptions } from '../utils/';
export default function defineTasks(opts) {
// file wildcards relative to the project root
// const options = {
// src: {
// base: opts.dir.src,
// },
// dest: {
// cwd: opts.dir.target,
// },
// };
const files = {
scripts: [
path.join(opts.dir.src, '**/*.js'),
'!' + path.join(opts.dir.src, '*/flux/**/*.js'),
'!' + path.join(opts.dir.src, '*/public/**/*.js'),
],
reacts: [
path.join(opts.dir.src, '*/flux/**/*.js'),
],
statics: [
path.join(opts.dir.src, '*/public/**/*'),
],
nodemonWatchIgnore: [
'gulpfile.js',
'node_modules/**/*',
path.join(opts.dir.src, '**/*'),
path.join(opts.dir.target, '*/public/js/bundle.js'),
path.join(opts.dir.target, 'public/js/common.js'),
path.join(opts.dir.target, '*/flux/**/*'),
],
};
// clean build files
gulp.task('clean', (done) => {
try {
rimraf.sync(opts.dir.target);
done();
} catch (e) {
return gutil.log(
'Cannot clean build directory. Please shutdown the server first.');
}
});
// output formated options
gulp.task('output:options', ['clean'], (done) => {
outputFormatOptions(opts, done);
});
// build nodejs source files
gulp.task('build:nodejs', () => {
return gulp
.src(files.scripts)
.pipe(gulpif(opts.watch, changed(opts.dir.target)))
.pipe(gulpif(opts.env.development, sourcemaps.init()))
.pipe(babel(defaultBabelConfig))
.on('error', notify.onError({
title: 'babel fail',
message: '<%= error.message %>',
}))
.pipe(gulpif(opts.env.development, sourcemaps.write({
includeContent: false,
sourceRoot: (file) => path.join(process.cwd(), opts.dir.src),
})))
.pipe(gulp.dest(opts.dir.target));
});
// build reactjs source files
gulp.task('build:reactjs', ['build:nodejs'], () => {
const settings = require(path.join(opts.dir.target, 'settings.js')).default;
const { installedApps } = settings;
defaultBabelConfig.resolveModuleSource = (source, filename) => {
if (filename.match(/flux/)) {
installedApps.forEach((appPath) => {
const appTargetPath = path.join(opts.dir.target, appPath);
const appSettings = require(path.join(appTargetPath, 'settings.js')).default;
source = source.replace(
`@${appSettings.name}`, path.join(appTargetPath, 'flux'));
});
}
return source;
};
return gulp
.src(files.reacts)
.pipe(gulpif(opts.watch, changed(opts.dir.target)))
.pipe(gulpif(opts.env.development, sourcemaps.init()))
.pipe(babel(defaultBabelConfig))
.on('error', notify.onError({
title: 'babel fail',
message: '<%= error.message %>',
}))
.pipe(gulpif(opts.env.development, sourcemaps.write({
includeContent: false,
sourceRoot: (file) => path.join(process.cwd(), opts.dir.src),
})))
.pipe(gulp.dest(opts.dir.target));
});
// bundle react components
gulp.task('webpack', ['build:reactjs'], (cb) => {
const webpackConfig = require(`../configs/webpack.${opts.env.NODE_ENV}`).default;
const settings = require(path.join(opts.dir.target, 'settings.js')).default;
const { installedApps } = settings;
const appAliasArray = installedApps
.map((appPath) => {
const appSrcPath = path.join(opts.dir.src, appPath);
const appTargetPath = path.join(opts.dir.target, appPath);
const entryPath = path.join(appSrcPath, 'flux/boot.js');
const appSettings = require(path.join(appTargetPath, 'settings.js')).default;
// insert resolve alias
webpackConfig.resolve.alias[`@${appSettings.name}`] =
path.join(opts.dir.src, appPath, 'flux');
// insert entries
if (fs.existsSync(entryPath)) {
const appDirName = path.parse(appSrcPath).base;
const appAlias = appSettings.name;
webpackConfig.entry[appDirName] = [ entryPath, ];
return appAlias;
}
return false;
})
.filter((appAlias) => appAlias);
// insert output path
webpackConfig.output.path = opts.dir.target;
// insert common plugin
webpackConfig.plugins.push(
new webpack.optimize.CommonsChunkPlugin(
'public/js/common.js', appAliasArray)
);
// insert resolve paths of loaders
webpackConfig.resolveLoader = {
modulesDirectories: [
// the default value
// see https://webpack.github.io/docs/configuration.html#resolveloader
'web_loaders',
'web_modules',
'node_loaders',
'node_modules',
// use loaders (like babel-loader) installed in exseed-cli
path.join(opts.dir.cliRoot, 'node_modules'),
],
};
webpack(webpackConfig, (err, stats) => {
if (err) {
return cb(err);
}
const jsonStats = stats.toJson();
if (jsonStats.errors.length > 0) {
return cb(jsonStats.errors);
}
if (jsonStats.warnings.length > 0) {
gutil.warn(jsonStats.warnings);
}
cb();
});
});
// copy static files
gulp.task('copy', function() {
return gulp
.src(files.statics/*, {
read: false,
}*/)
.pipe(gulpif(opts.watch, changed(opts.dir.target)))
.pipe(gulp.dest(opts.dir.target));
});
gulp.task('init', (cb) => {
const entryPath = path.join(opts.dir.target, 'server.js');
const child = exec(`node ${entryPath}`, {
env: {
EXSEED_OPTIONS: JSON.stringify({
init: true,
name: opts.app,
}),
},
});
child.stdout.on('data', (data) => {
gutil.log(data);
});
child.stderr.on('data', (data) => {
gutil.log(data);
});
child.on('close', (code) => {
cb();
});
});
gulp.task('serve', (cb) => {
let started = false;
const entryPath = path.join(opts.dir.target, 'server.js');
return nodemon({
script: entryPath,
watch: [`${opts.dir.target}/**/*.js`],
ext: 'js',
env: {
NODE_ENV: opts.env.NODE_ENV,
},
ignore: files.nodemonWatchIgnore,
})
.on('start', () => {
if (!started) {
cb();
started = true;
}
})
.on('restart', () => {
});
});
// watching source files
gulp.task('watch', [
'build:nodejs', 'build:reactjs', 'webpack', 'copy',
], () => {
if (opts.watch) {
gulp.watch(files.scripts, ['build:nodejs']);
gulp.watch(files.reacts, ['build:reactjs', 'webpack']);
gulp.watch(files.statics, ['copy']);
}
});
return gulp;
}