2019-10-07 11:48:01 +00:00
|
|
|
import browserify = require("browserify");
|
|
|
|
import log = require("fancy-log");
|
2019-10-07 15:50:06 +00:00
|
|
|
import FileSystem = require("fs-extra");
|
2019-10-07 11:48:01 +00:00
|
|
|
import { TaskFunction } from "gulp";
|
2019-10-07 15:50:06 +00:00
|
|
|
import gulp = require("gulp");
|
2019-10-07 11:48:01 +00:00
|
|
|
import gulpIf = require("gulp-if");
|
2019-10-07 16:59:23 +00:00
|
|
|
import rename = require("gulp-rename");
|
|
|
|
import sass = require("gulp-sass");
|
2019-10-07 11:48:01 +00:00
|
|
|
import terser = require("gulp-terser");
|
|
|
|
import merge = require("merge-stream");
|
|
|
|
import minimist = require("minimist");
|
|
|
|
import { Server, Socket } from "net";
|
|
|
|
import PromiseQueue = require("promise-queue");
|
|
|
|
import { parseArgsStringToArgv } from "string-argv";
|
|
|
|
import Path = require("upath");
|
|
|
|
import buffer = require("vinyl-buffer");
|
|
|
|
import vinylSourceStream = require("vinyl-source-stream");
|
|
|
|
import Watchify = require("watchify");
|
|
|
|
import { Settings } from "./.gulp/Settings";
|
2019-10-05 21:35:56 +00:00
|
|
|
import "./.gulp/TaskFunction";
|
|
|
|
|
2019-10-07 11:48:01 +00:00
|
|
|
/**
|
|
|
|
* The port to listen for stop-requests.
|
|
|
|
*/
|
|
|
|
const watchConnectorPort = 50958;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The message that is printed when starting the compilation in watch mode.
|
|
|
|
*/
|
|
|
|
const watchStartMessage = "Starting compilation in watch mode...";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The message that is printed when starting an incremental compilation.
|
|
|
|
*/
|
|
|
|
const incrementalMessage = "File change detected. Starting incremental compilation...";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates the message that is printed after finishing a compilation in watch mode.
|
|
|
|
*
|
|
|
|
* @param errorCount
|
|
|
|
* The number of errors which occurred.
|
|
|
|
*/
|
|
|
|
const watchFinishMessage = (errorCount: number) =>
|
|
|
|
{
|
|
|
|
return `Found ${errorCount} errors. Watching for file changes.`;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The arguments passed by the user.
|
|
|
|
*/
|
|
|
|
let options = ParseArgs(process.argv.slice(2));
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses the specified arguments.
|
|
|
|
*
|
|
|
|
* @param args
|
|
|
|
* The arguments to parse.
|
|
|
|
*/
|
|
|
|
function ParseArgs(args: string[])
|
|
|
|
{
|
|
|
|
return minimist(
|
|
|
|
args,
|
|
|
|
{
|
|
|
|
string: [
|
|
|
|
"target"
|
|
|
|
],
|
|
|
|
alias: {
|
|
|
|
target: "t"
|
|
|
|
},
|
|
|
|
default: {
|
|
|
|
target: "Debug"
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The settings for building the project.
|
|
|
|
*/
|
|
|
|
let settings = new Settings(options["target"]);
|
|
|
|
|
2019-10-05 21:35:56 +00:00
|
|
|
/**
|
|
|
|
* Initializes the project.
|
|
|
|
*/
|
2019-10-07 15:50:06 +00:00
|
|
|
export async function Initialize()
|
2019-10-05 21:35:56 +00:00
|
|
|
{
|
2019-10-07 15:50:06 +00:00
|
|
|
let directories = [
|
|
|
|
"javascript",
|
|
|
|
"css",
|
|
|
|
"templates",
|
|
|
|
"assets"
|
|
|
|
];
|
|
|
|
|
|
|
|
for (let directory of directories)
|
|
|
|
{
|
|
|
|
await FileSystem.emptyDir(settings.RootPath(directory));
|
|
|
|
}
|
|
|
|
|
2019-10-07 20:03:44 +00:00
|
|
|
if (await FileSystem.pathExists(settings.TestThemePath()))
|
2019-10-07 15:50:06 +00:00
|
|
|
{
|
2019-10-07 20:03:44 +00:00
|
|
|
await FileSystem.remove(settings.TestThemePath());
|
2019-10-07 15:50:06 +00:00
|
|
|
}
|
|
|
|
|
2019-10-07 20:03:44 +00:00
|
|
|
await require("create-symlink")(settings.RootPath(), settings.TestThemePath(), { type: "junction" });
|
2019-10-05 21:35:56 +00:00
|
|
|
}
|
|
|
|
|
2019-10-07 11:48:01 +00:00
|
|
|
Initialize.description = "Initializes the project.";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds the project in watched mode.
|
|
|
|
*/
|
|
|
|
export let Watch: TaskFunction = (done) =>
|
|
|
|
{
|
|
|
|
settings.Watch = true;
|
|
|
|
Build();
|
|
|
|
|
|
|
|
let server = new Server(
|
|
|
|
(socket) =>
|
|
|
|
{
|
|
|
|
socket.on(
|
|
|
|
"data",
|
|
|
|
(data) =>
|
|
|
|
{
|
|
|
|
let args = parseArgsStringToArgv(data.toString());
|
|
|
|
socket.destroy();
|
|
|
|
|
|
|
|
if (args[0] === "stop")
|
|
|
|
{
|
|
|
|
let options = ParseArgs(args.slice(1));
|
|
|
|
|
|
|
|
if (options["target"] === settings.Target)
|
|
|
|
{
|
|
|
|
server.close();
|
|
|
|
done();
|
|
|
|
process.exit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
server.listen(watchConnectorPort);
|
|
|
|
};
|
|
|
|
|
|
|
|
Watch.description = "Builds the project in watched mode.";
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds the project.
|
|
|
|
*/
|
|
|
|
export async function Build()
|
|
|
|
{
|
|
|
|
if (settings.Watch)
|
|
|
|
{
|
|
|
|
log.info(watchStartMessage);
|
2019-10-07 18:44:32 +00:00
|
|
|
gulp.watch(settings.ThemeSource("**"), Theme);
|
|
|
|
gulp.watch(settings.TemplateSource("**"), Templates);
|
2019-10-07 11:48:01 +00:00
|
|
|
}
|
|
|
|
|
2019-10-07 16:59:23 +00:00
|
|
|
await Promise.all(
|
|
|
|
[
|
|
|
|
Library(),
|
2019-10-07 17:09:35 +00:00
|
|
|
Theme(),
|
|
|
|
Templates()
|
2019-10-07 16:59:23 +00:00
|
|
|
]);
|
2019-10-07 11:48:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds the TypeScript- and JavaScript-library.
|
|
|
|
*/
|
|
|
|
export async function Library()
|
|
|
|
{
|
|
|
|
let streams: Array<Promise<NodeJS.ReadWriteStream>> = [];
|
|
|
|
let queue = new PromiseQueue();
|
|
|
|
let tsConfigFile = settings.TypeScriptProjectRoot("tsconfig.json");
|
|
|
|
let tsConfig = require(tsConfigFile);
|
|
|
|
|
|
|
|
let optionBase: browserify.Options = {
|
|
|
|
...Watchify.args,
|
|
|
|
node: true,
|
|
|
|
ignoreMissing: true,
|
|
|
|
debug: settings.Debug
|
|
|
|
};
|
|
|
|
|
|
|
|
{
|
|
|
|
let errorMessages: string[] = [];
|
|
|
|
let files = (tsConfig.files as string[]).map(
|
|
|
|
(file) => Path.relative(settings.TypeScriptSourceRoot(), settings.TypeScriptProjectRoot(file)));
|
|
|
|
|
|
|
|
for (let file of files)
|
|
|
|
{
|
|
|
|
let bundler = browserify(
|
|
|
|
{
|
|
|
|
...optionBase,
|
|
|
|
basedir: settings.LibraryPath(Path.dirname(file)),
|
|
|
|
entries: [
|
|
|
|
settings.TypeScriptSourceRoot(file)
|
|
|
|
],
|
|
|
|
standalone: Path.join(Path.dirname(file), Path.parse(file).name)
|
|
|
|
});
|
|
|
|
|
|
|
|
if (settings.Watch)
|
|
|
|
{
|
|
|
|
bundler = Watchify(bundler);
|
|
|
|
}
|
|
|
|
|
|
|
|
bundler.plugin(
|
|
|
|
require("tsify"),
|
|
|
|
{
|
|
|
|
project: tsConfigFile
|
|
|
|
});
|
|
|
|
|
|
|
|
let bundle = async () =>
|
|
|
|
{
|
|
|
|
return new Promise<NodeJS.ReadWriteStream>(
|
|
|
|
(resolve) =>
|
|
|
|
{
|
|
|
|
let stream = bundler.bundle().on(
|
|
|
|
"error",
|
|
|
|
(error) =>
|
|
|
|
{
|
|
|
|
let message: string = error.message;
|
|
|
|
|
|
|
|
if (!errorMessages.includes(message))
|
|
|
|
{
|
|
|
|
errorMessages.push(message);
|
|
|
|
log.error(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
).pipe(
|
|
|
|
vinylSourceStream(Path.changeExt(file, "js"))
|
|
|
|
).pipe(
|
|
|
|
buffer()
|
|
|
|
).pipe(
|
|
|
|
gulpIf(
|
2019-10-07 18:44:32 +00:00
|
|
|
!settings.Debug,
|
2019-10-07 11:48:01 +00:00
|
|
|
terser()
|
|
|
|
)
|
|
|
|
).pipe(
|
|
|
|
gulp.dest(settings.LibraryPath())
|
|
|
|
);
|
|
|
|
|
|
|
|
stream.on(
|
|
|
|
"end",
|
|
|
|
() =>
|
|
|
|
{
|
|
|
|
if (settings.Watch && ((queue.getQueueLength() + queue.getPendingLength()) === 1))
|
|
|
|
{
|
|
|
|
log.info(watchFinishMessage(errorMessages.length));
|
|
|
|
}
|
|
|
|
|
|
|
|
errorMessages.splice(0, errorMessages.length);
|
|
|
|
resolve(stream);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
if (settings.Watch)
|
|
|
|
{
|
|
|
|
bundler.on(
|
|
|
|
"update",
|
|
|
|
() =>
|
|
|
|
{
|
|
|
|
if ((queue.getQueueLength() + queue.getPendingLength()) === 0)
|
|
|
|
{
|
|
|
|
log.info(incrementalMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
queue.add(
|
|
|
|
async () =>
|
|
|
|
{
|
|
|
|
return bundle();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
let build = () => queue.add(bundle);
|
|
|
|
build.displayName = Build.displayName;
|
|
|
|
build.description = Build.description;
|
|
|
|
streams.push(build());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return merge(await Promise.all(streams)) as NodeJS.ReadWriteStream;
|
|
|
|
}
|
|
|
|
|
|
|
|
Library.description = "Builds the TypeScript- and JavaScript-library.";
|
|
|
|
|
2019-10-07 16:59:23 +00:00
|
|
|
/**
|
|
|
|
* Builds the theme.
|
|
|
|
*/
|
|
|
|
export async function Theme()
|
|
|
|
{
|
|
|
|
return gulp.src(
|
|
|
|
settings.ThemeSource("main.scss"),
|
|
|
|
{
|
|
|
|
sourcemaps: settings.Debug,
|
|
|
|
base: settings.StylePath()
|
|
|
|
}).pipe(
|
2019-10-07 18:53:26 +00:00
|
|
|
sass(
|
|
|
|
{
|
|
|
|
importer: require("node-sass-tilde-importer"),
|
|
|
|
outputStyle: settings.Debug ? "expanded" : "compressed"
|
|
|
|
})
|
2019-10-07 16:59:23 +00:00
|
|
|
).pipe(
|
|
|
|
rename(
|
|
|
|
(parsedPath) =>
|
|
|
|
{
|
|
|
|
parsedPath.dirname = "";
|
|
|
|
parsedPath.basename = "mantra";
|
|
|
|
})
|
|
|
|
).pipe(
|
|
|
|
gulp.dest(
|
|
|
|
settings.StylePath(),
|
|
|
|
settings.Debug ?
|
|
|
|
{
|
|
|
|
sourcemaps: true
|
|
|
|
}
|
|
|
|
:
|
|
|
|
undefined)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Theme.description = "Builds the theme.";
|
|
|
|
|
2019-10-07 17:09:35 +00:00
|
|
|
/**
|
|
|
|
* Builds the templates.
|
|
|
|
*/
|
|
|
|
export function Templates()
|
|
|
|
{
|
|
|
|
return gulp.src(
|
|
|
|
settings.TemplateSource("**")).pipe(
|
|
|
|
gulp.dest(settings.TemplatePath()));
|
|
|
|
}
|
|
|
|
|
|
|
|
Templates.description = "Builds the templates.";
|
|
|
|
|
2019-10-07 11:48:01 +00:00
|
|
|
/**
|
|
|
|
* Stops a watch-task.
|
|
|
|
*/
|
|
|
|
export async function Stop()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
await new Promise(
|
|
|
|
(resolve, reject) =>
|
|
|
|
{
|
|
|
|
let client = new Socket();
|
|
|
|
|
|
|
|
client.connect(
|
|
|
|
watchConnectorPort,
|
|
|
|
"localhost",
|
|
|
|
async () =>
|
|
|
|
{
|
|
|
|
client.write(`stop -t ${settings.Target}`);
|
|
|
|
});
|
|
|
|
|
|
|
|
client.on("close", resolve);
|
|
|
|
client.on("error", reject);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
|
|
|
log.info("The specified task is not running.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Stop.description = "Stops a watch-task";
|