diff --git a/.gitignore b/.gitignore index f86fa8e..23bb45c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ # https://git-scm.com/docs/gitignore # https://help.github.com/articles/ignoring-files -# Example .gitignore files: https://github.com/github/gitignore \ No newline at end of file +# Example .gitignore files: https://github.com/github/gitignore +/node_modules/ +/old/ \ No newline at end of file diff --git a/app.es5.js b/app.es5.js new file mode 100644 index 0000000..dc48811 --- /dev/null +++ b/app.es5.js @@ -0,0 +1,31 @@ +'use strict'; + +var Promise = require("bluebird"); +var rfr = require("rfr"); +var electron = require("electron"); +var path = require("path"); + +var awaitReady = rfr("lib/electron/await-ready"); +var windowManagerCreator = rfr("lib/electron/window-manager"); +var viewUrlCreator = rfr("lib/electron/view-url"); + +var windowManager = windowManagerCreator(); + +var viewUrl = viewUrlCreator(path.join(__dirname, "lib/views"), { + extension: "html" +}); + +var useLiveReload = process.env.NODE_ENV === "development"; + +var windows = {}; + +Promise.try(function () { + return awaitReady(electron.app); +}).then(function () { + windowManager.create({ + width: 800, + height: 600, + url: viewUrl("index"), + liveReload: useLiveReload + }); +}); diff --git a/app.js b/app.js new file mode 100644 index 0000000..802a6d5 --- /dev/null +++ b/app.js @@ -0,0 +1,31 @@ +'use strict'; + +const Promise = require("bluebird"); +const rfr = require("rfr"); +const electron = require("electron"); +const path = require("path"); + +const awaitReady = rfr("lib/electron/await-ready"); +const windowManagerCreator = rfr("lib/electron/window-manager"); +const viewUrlCreator = rfr("lib/electron/view-url"); + +const windowManager = windowManagerCreator(); + +const viewUrl = viewUrlCreator(path.join(__dirname, "lib/views"), { + extension: "html" +}); + +let useLiveReload = (process.env.NODE_ENV === "development"); + +let windows = {}; + +Promise.try(() => { + return awaitReady(electron.app); +}).then(() => { + windowManager.create({ + width: 800, + height: 600, + url: viewUrl("index"), + liveReload: useLiveReload + }); +}); diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..dbf6dc7 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,88 @@ +var gulp = require("gulp"); +var fileUrl = require("file-url"); +var path = require("path"); +var xtend = require("xtend"); +var rfr = require("rfr"); + +var jade = require("gulp-jade"); +var babel = require("gulp-babel"); +var livereload = require("gulp-livereload"); +var cache = require("gulp-cached"); +var remember = require("gulp-remember"); +var plumber = require("gulp-plumber"); +var rename = require("gulp-rename"); +var namedLog = require("gulp-named-log"); + +var runProcess = rfr("lib/gulp/run-process"); +var patchLivereloadLogger = rfr("lib/gulp/patch-livereload-logger"); + +var babelLogger = namedLog("babel"); +var jadeLogger = namedLog("jade"); +var electronLogger = namedLog("electron"); +var livereloadLogger = namedLog("livereload"); + +patchLivereloadLogger(livereload, livereloadLogger); + +var sources = { + "babel-main": "app.js", + "babel-lib": "src/**/*.js", + "jade-views": "src/views/**/*.jade" +} + +function getLiveReloadStream() { + var lr = livereload({ + quiet: true + }); + + return lr; +} + +gulp.task("electron", function() { + var electronProcess = runProcess(path.join(__dirname, "node_modules/.bin/electron"), [__dirname], { + logger: electronLogger, + env: xtend(process.env, { + NODE_ENV: "development" + }) + }); +}); + +gulp.task('babel-main', function() { + return gulp.src(sources["babel-main"]) + .pipe(plumber()) + .pipe(cache("babel-main")) + .pipe(babel({presets: ["es2015"]}).on('error', babelLogger.error)).on('data', babelLogger.log) + .pipe(getLiveReloadStream()) + .pipe(remember("babel-main")) + .pipe(rename("app.es5.js")) + .pipe(gulp.dest("./")); +}); + +gulp.task('babel-lib', function() { + return gulp.src(sources["babel-lib"]) + .pipe(plumber()) + .pipe(cache("babel-lib")) + .pipe(babel({presets: ["es2015"]}).on('error', babelLogger.error)).on('data', babelLogger.log) + .pipe(getLiveReloadStream()) + .pipe(remember("babel-lib")) + .pipe(gulp.dest("lib/")); +}); + +gulp.task("jade-views", function() { + return gulp.src(sources["jade-views"]) + .pipe(plumber()) + .pipe(cache("jade-views")) + .pipe(jade().on('error', jadeLogger.error)).on('data', jadeLogger.log) + .pipe(getLiveReloadStream()) + .pipe(remember("jade-views")) + .pipe(gulp.dest("lib/views/")); +}); + +gulp.task('watch', function () { + livereload.listen(); + + gulp.watch(sources["babel-lib"], ["babel-lib"]); + gulp.watch(sources["babel-main"], ["babel-main"]); + gulp.watch(sources["jade-views"], ["jade-views"]); +}); + +gulp.task('default', ['babel-lib', 'babel-main', 'jade-views', 'watch', 'electron']); diff --git a/lib/electron/await-ready.js b/lib/electron/await-ready.js new file mode 100644 index 0000000..77bb8f0 --- /dev/null +++ b/lib/electron/await-ready.js @@ -0,0 +1,11 @@ +'use strict'; + +var Promise = require("bluebird"); + +module.exports = function (app) { + return new Promise(function (resolve, reject) { + app.on("ready", function () { + resolve(); + }); + }); +}; diff --git a/lib/electron/create-window.js b/lib/electron/create-window.js new file mode 100644 index 0000000..3918c74 --- /dev/null +++ b/lib/electron/create-window.js @@ -0,0 +1 @@ +"use strict"; diff --git a/lib/electron/spawn-window.js b/lib/electron/spawn-window.js new file mode 100644 index 0000000..5847675 --- /dev/null +++ b/lib/electron/spawn-window.js @@ -0,0 +1,3 @@ +"use strict"; + +module.exports = function (options) {}; diff --git a/lib/electron/view-url.js b/lib/electron/view-url.js new file mode 100644 index 0000000..557bab3 --- /dev/null +++ b/lib/electron/view-url.js @@ -0,0 +1,16 @@ +"use strict"; + +var path = require("path"); +var fileUrl = require("file-url"); + +module.exports = function (viewDirectory, options) { + return function (viewPath) { + var fullPath = path.join(viewDirectory, viewPath); + + if (options.extension != null) { + fullPath += "." + options.extension; + } + + return fileUrl(fullPath); + }; +}; diff --git a/lib/electron/window-manager.js b/lib/electron/window-manager.js new file mode 100644 index 0000000..27a2898 --- /dev/null +++ b/lib/electron/window-manager.js @@ -0,0 +1,50 @@ +"use strict"; + +var electron = require("electron"); +var uuid = require("uuid"); + +module.exports = function () { + var windows = {}; + + function packFunction(func) { + return ";" + func.toString() + ";" + func.name + "();"; + } + + function loadLiveReload() { + var scriptTag = document.createElement("script"); + scriptTag.src = "http://127.0.0.1:35729/livereload.js"; + document.querySelector("head").appendChild(scriptTag); + } + + return { + create: function create(options) { + var id = uuid.v4(); + var window = new electron.BrowserWindow(options); + + if (options.url != null) { + window.loadURL(options.url); + } + + if (options.loadDeveloperTools) { + window.webContents.openDevTools(); + } + + if (options.liveReload) { + window.webContents.on("dom-ready", function () { + window.webContents.executeJavaScript(packFunction(loadLiveReload)); + }); + } + + windows[id] = window; + + window.on("closed", function () { + delete windows[id]; + }); + + return window; + }, + get: function get(id) { + return windows[id]; + } + }; +}; diff --git a/lib/gulp/log-stream.js b/lib/gulp/log-stream.js new file mode 100644 index 0000000..7baa2cb --- /dev/null +++ b/lib/gulp/log-stream.js @@ -0,0 +1,11 @@ +'use strict'; + +var split = require("split"); + +module.exports = function logStream(stream, logger) { + stream.pipe(split()).on("data", function (data) { + if (data.trim() !== "") { + logger(data); + } + }); +}; diff --git a/lib/gulp/patch-livereload-logger.js b/lib/gulp/patch-livereload-logger.js new file mode 100644 index 0000000..63bafc9 --- /dev/null +++ b/lib/gulp/patch-livereload-logger.js @@ -0,0 +1,11 @@ +'use strict'; + +var chalk = require("chalk"); + +module.exports = function (livereload, logger) { + var _oldChanged = livereload.changed.bind(livereload); + livereload.changed = function (filePath) { + logger.log(chalk.magenta(filePath) + " reloaded."); + _oldChanged.apply(null, arguments); + }; +}; diff --git a/lib/gulp/run-process.js b/lib/gulp/run-process.js new file mode 100644 index 0000000..201c6c3 --- /dev/null +++ b/lib/gulp/run-process.js @@ -0,0 +1,30 @@ +'use strict'; + +var childProcess = require("child_process"); +var rfr = require("rfr"); +var logStream = rfr("lib/gulp/log-stream"); + +module.exports = function runProcess(path, args) { + var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2]; + + if (options.logger != null) { + options.logger.info("Starting " + path + "..."); + } + + var proc = childProcess.spawn(path, args, options); + + if (options.logger != null) { + logStream(proc.stdout, options.logger.log); + logStream(proc.stderr, options.logger.error); + } + + proc.on("error", function (err) { + if (options.logger != null) { + options.logger.error(err.stack); + } + }); + + proc.on("close", function (code) { + options.logger.info("Exited with code " + code.toString() + ": " + path + "."); + }); +}; diff --git a/lib/views/index.html b/lib/views/index.html new file mode 100644 index 0000000..c24418b --- /dev/null +++ b/lib/views/index.html @@ -0,0 +1 @@ +Sample application

Sample header 2

Some sample content

diff --git a/package.json b/package.json new file mode 100644 index 0000000..2620c9b --- /dev/null +++ b/package.json @@ -0,0 +1,42 @@ +{ + "name": "archivist", + "version": "1.0.0", + "description": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://git.cryto.net/joepie91/archivist.git" + }, + "keywords": [ + "archival", + "internet archive" + ], + "author": "Sven Slootweg", + "license": "WTFPL", + "main": "app.js", + "dependencies": { + "bhttp": "^1.2.1", + "bluebird": "^3.3.4", + "chalk": "^1.1.3", + "electron-prebuilt": "^0.37.5", + "file-url": "^1.1.0", + "ia-headers": "^1.0.0", + "rfr": "^1.2.3", + "uuid": "^2.0.1", + "xtend": "^4.0.1" + }, + "devDependencies": { + "babel-preset-es2015": "^6.6.0", + "gulp": "^3.9.1", + "gulp-babel": "^6.1.2", + "gulp-cached": "^1.1.0", + "gulp-jade": "^1.1.0", + "gulp-livereload": "^3.8.1", + "gulp-plumber": "^1.1.0", + "gulp-remember": "^0.3.1", + "gulp-rename": "^1.2.2", + "split": "^1.0.0" + } +} diff --git a/src/electron/await-ready.js b/src/electron/await-ready.js new file mode 100644 index 0000000..034a7ed --- /dev/null +++ b/src/electron/await-ready.js @@ -0,0 +1,11 @@ +'use strict'; + +const Promise = require("bluebird"); + +module.exports = function(app) { + return new Promise((resolve, reject) => { + app.on("ready", () => { + resolve(); + }); + }) +} diff --git a/src/electron/view-url.js b/src/electron/view-url.js new file mode 100644 index 0000000..6c67485 --- /dev/null +++ b/src/electron/view-url.js @@ -0,0 +1,14 @@ +const path = require("path"); +const fileUrl = require("file-url"); + +module.exports = function(viewDirectory, options) { + return function(viewPath) { + let fullPath = path.join(viewDirectory, viewPath); + + if (options.extension != null) { + fullPath += `.${options.extension}`; + } + + return fileUrl(fullPath); + } +} diff --git a/src/electron/window-manager.js b/src/electron/window-manager.js new file mode 100644 index 0000000..e00c39a --- /dev/null +++ b/src/electron/window-manager.js @@ -0,0 +1,48 @@ +const electron = require("electron"); +const uuid = require("uuid"); + +module.exports = function() { + let windows = {}; + + function packFunction(func) { + return `;${func.toString()};${func.name}();`; + } + + function loadLiveReload() { + let scriptTag = document.createElement("script"); + scriptTag.src = "http://127.0.0.1:35729/livereload.js"; + document.querySelector("head").appendChild(scriptTag); + } + + return { + create: function(options) { + let id = uuid.v4(); + let window = new electron.BrowserWindow(options); + + if (options.url != null) { + window.loadURL(options.url); + } + + if (options.loadDeveloperTools) { + window.webContents.openDevTools(); + } + + if (options.liveReload) { + window.webContents.on("dom-ready", () => { + window.webContents.executeJavaScript(packFunction(loadLiveReload)); + }); + } + + windows[id] = window; + + window.on("closed", () => { + delete windows[id]; + }); + + return window; + }, + get: function(id) { + return windows[id]; + } + } +} diff --git a/src/gulp/log-stream.js b/src/gulp/log-stream.js new file mode 100644 index 0000000..85d84a2 --- /dev/null +++ b/src/gulp/log-stream.js @@ -0,0 +1,11 @@ +'use strict'; + +const split = require("split"); + +module.exports = function logStream(stream, logger) { + stream.pipe(split()).on("data", function(data) { + if (data.trim() !== "") { + logger(data); + } + }) +} diff --git a/src/gulp/patch-livereload-logger.js b/src/gulp/patch-livereload-logger.js new file mode 100644 index 0000000..67aa127 --- /dev/null +++ b/src/gulp/patch-livereload-logger.js @@ -0,0 +1,11 @@ +'use strict'; + +const chalk = require("chalk"); + +module.exports = function(livereload, logger) { + var _oldChanged = livereload.changed.bind(livereload); + livereload.changed = function(filePath) { + logger.log(chalk.magenta(filePath) + " reloaded."); + _oldChanged.apply(null, arguments); + } +} diff --git a/src/gulp/run-process.js b/src/gulp/run-process.js new file mode 100644 index 0000000..d7a2406 --- /dev/null +++ b/src/gulp/run-process.js @@ -0,0 +1,28 @@ +'use strict'; + +const childProcess = require("child_process"); +const rfr = require("rfr"); +const logStream = rfr("lib/gulp/log-stream"); + +module.exports = function runProcess(path, args, options = {}) { + if (options.logger != null) { + options.logger.info(`Starting ${path}...`); + } + + let proc = childProcess.spawn(path, args, options); + + if (options.logger != null) { + logStream(proc.stdout, options.logger.log); + logStream(proc.stderr, options.logger.error); + } + + proc.on("error", (err) => { + if (options.logger != null) { + options.logger.error(err.stack); + } + }); + + proc.on("close", (code) => { + options.logger.info(`Exited with code ${code.toString()}: ${path}.`); + }) +} diff --git a/src/views/index.jade b/src/views/index.jade new file mode 100644 index 0000000..adcc492 --- /dev/null +++ b/src/views/index.jade @@ -0,0 +1,7 @@ +html + head + meta(charset="UTF-8") + title Sample application + body + h1 Sample header 2 + p Some sample content