Skip to content

Commit

Permalink
support startup runners
Browse files Browse the repository at this point in the history
  • Loading branch information
Shane Osbourne committed May 17, 2023
1 parent 1f62a9a commit 9ed92de
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 113 deletions.
4 changes: 4 additions & 0 deletions packages/browser-sync/lib/async-tasks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
var async = require("./async");

module.exports = [
{
step: "Execute any startup runners",
fn: async.execStartupRunners
},
{
step: "Finding an empty port",
fn: async.getEmptyPort
Expand Down
25 changes: 24 additions & 1 deletion packages/browser-sync/lib/async.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,31 @@ var utils = require("./utils");
var pluginUtils = require("./plugins");
var connectUtils = require("./connect-utils");
var chalk = require("chalk");
const { toRunnerOption } = require("./types");
const { List } = require("immutable");
const { execRunner } = require("./runner");
const Rx = require("rx");

module.exports = {
execStartupRunners: function(bs, done) {
const runners = bs.options.get("runners", List([])).toJS();

/** @type {import("./types").RunnerOption[]} */
const startupOnlyRunners = runners.filter(r => {
const opt = toRunnerOption(r);
return opt?.at === "startup";
});

if (startupOnlyRunners.length === 0) return done();

Rx.Observable.concat(startupOnlyRunners.map(runner => execRunner(runner)))
.catch(e => {
done(e);
})
.subscribe(() => {
done(null);
});
},
/**
* BrowserSync needs at least 1 free port.
* It will check the one provided in config
Expand Down Expand Up @@ -163,7 +186,7 @@ module.exports = {
* @param {Function} done
*/
setInternalEvents: function(bs, done) {
require("./internal-events")(bs);
require("./internal-events").default(bs);
done();
},
/**
Expand Down
115 changes: 3 additions & 112 deletions packages/browser-sync/lib/internal-events.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// @ts-check
"use strict";

import { execRunner } from "./runner";

var utils = require("./utils");
var fileUtils = require("./file-utils");
var Rx = require("rx");
Expand All @@ -15,7 +17,7 @@ const {
toReloadEvent
} = require("./types");

module.exports = function(bs) {
export default function internalEvents(bs) {
var events = {
/**
* File reloads
Expand Down Expand Up @@ -205,115 +207,4 @@ module.exports = function(bs) {
reloader.dispose();
runnerHandler.dispose();
});
};

/**
* @param {import("./types").RunnerOption} runner
*/
function execRunner(runner) {
return Rx.Observable.concat(
runner.run.map(r => {
if ("bs" in r) {
return bsRunner(r);
}
if ("sh" in r) {
let cmd;
if (typeof r.sh === "string") {
cmd = r.sh;
} else if ("cmd" in r.sh) {
cmd = r.sh.cmd;
} else {
return Rx.Observable.throw(new Error("invalid `sh` config"));
}
return shRunner(r, {
cmd: cmd
});
}
if ("npm" in r) {
return npmRunner(r);
}
throw new Error("unreachable");
})
);
}

/**
* @param {import("./types").Runner} runner
*/
function bsRunner(runner) {
if (!("bs" in runner)) throw new Error("unreachable");
/** @type {import("./types").BsSideEffect[]} */
const effects = [];
if (runner.bs === "inject") {
effects.push({
type: "inject",
files: runner.files.map(f => {
return {
path: f,
event: "bs-runner"
};
})
});
} else if (runner.bs === "reload") {
effects.push({
type: "reload",
files: []
});
}
return Rx.Observable.concat(
Rx.Observable.just(
toRunnerNotification({
status: "start",
effects: [],
runner
})
),
Rx.Observable.just(
toRunnerNotification({
status: "end",
effects: effects,
runner
})
)
);
}

/**
* @param {import("./types").Runner} runner
* @param {object} params
* @param {string} params.cmd
*/
function shRunner(runner, params) {
return Rx.Observable.concat(
Rx.Observable.just(toRunnerNotification({ status: "start", effects: [], runner })),
Rx.Observable.just(toRunnerNotification({ status: "end", effects: [], runner }))
);
}

/**
* @param {import("./types").Runner} runner
*/
function npmRunner(runner) {
if (!("npm" in runner)) throw new Error("unreachble");
return Rx.Observable.just(runner).flatMap(runner => {
try {
const runAll = require("npm-run-all");
const runAllRunner = runAll(runner.npm, {
parallel: false,
stdout: process.stdout,
stdin: process.stdin,
stderr: process.stderr
});
const p = runAllRunner.then(results => {
if (results.some(r => r.code !== 0)) throw new Error("failed");
return results;
});
return Rx.Observable.fromPromise(p).map(results => {
return toRunnerNotification({ status: "end", effects: [], runner });
});
} catch (e) {
console.log("e", e);
return Rx.Observable.throw(e);
}
});
}
113 changes: 113 additions & 0 deletions packages/browser-sync/lib/runner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
const Rx = require("rx");
import { toRunnerNotification } from "./types";

/**
* @param {import("./types").RunnerOption} runner
*/
export function execRunner(runner) {
return Rx.Observable.concat(
runner.run.map(r => {
if ("bs" in r) {
return bsRunner(r);
}
if ("sh" in r) {
let cmd;
if (typeof r.sh === "string") {
cmd = r.sh;
} else if ("cmd" in r.sh) {
cmd = r.sh.cmd;
} else {
return Rx.Observable.throw(new Error("invalid `sh` config"));
}
return shRunner(r, {
cmd: cmd
});
}
if ("npm" in r) {
return npmRunner(r);
}
throw new Error("unreachable");
})
);
}

/**
* @param {import("./types").Runner} runner
*/
export function bsRunner(runner) {
if (!("bs" in runner)) throw new Error("unreachable");
/** @type {import("./types").BsSideEffect[]} */
const effects = [];
if (runner.bs === "inject") {
effects.push({
type: "inject",
files: runner.files.map(f => {
return {
path: f,
event: "bs-runner"
};
})
});
} else if (runner.bs === "reload") {
effects.push({
type: "reload",
files: []
});
}
return Rx.Observable.concat(
Rx.Observable.just(
toRunnerNotification({
status: "start",
effects: [],
runner
})
),
Rx.Observable.just(
toRunnerNotification({
status: "end",
effects: effects,
runner
})
)
);
}

/**
* @param {import("./types").Runner} runner
* @param {object} params
* @param {string} params.cmd
*/
export function shRunner(runner, params) {
return Rx.Observable.concat(
Rx.Observable.just(toRunnerNotification({ status: "start", effects: [], runner })),
Rx.Observable.just(toRunnerNotification({ status: "end", effects: [], runner }))
);
}

/**
* @param {import("./types").Runner} runner
*/
export function npmRunner(runner) {
if (!("npm" in runner)) throw new Error("unreachble");
return Rx.Observable.just(runner).flatMap(runner => {
try {
const runAll = require("npm-run-all");
const runAllRunner = runAll(runner.npm, {
parallel: false,
stdout: process.stdout,
stdin: process.stdin,
stderr: process.stderr
});
const p = runAllRunner.then(results => {
if (results.some(r => r.code !== 0)) throw new Error("failed");
return results;
});
return Rx.Observable.fromPromise(p).map(results => {
return toRunnerNotification({ status: "end", effects: [], runner });
});
} catch (e) {
console.log("e", e);
return Rx.Observable.throw(e);
}
});
}

0 comments on commit 9ed92de

Please sign in to comment.