Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
ittechhunter committed Jun 3, 2024
1 parent 45d3384 commit b5f8902
Show file tree
Hide file tree
Showing 6 changed files with 7,924 additions and 243 deletions.
197 changes: 101 additions & 96 deletions lib/dev.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
import { readJson, writeJson } from "fs-extra";
import path from "path";
import { Server as IoServer } from "socket.io";
import { Gaze } from "gaze";
import { buildApp } from "./build";
import { BaseConfig, loadConfig, readConfig } from "./config";
import { startDevServer } from "./server";
import { startSocket } from "./socket";
import { Network } from "./types";
import { loopThroughFiles, readFile } from "./utils/fs";
import { mergeDeep } from "./utils/objects";
import { mergeDeep, substractDeep } from "./utils/objects";
import { startFileWatcher } from "./watcher";
import { optional } from "joi";

const DEV_DIST_FOLDER = "build";

var appSrcs = [], appDists = [];
var appDevJsons = [];
var appDevJsonPath = "bos-loader.json";
var appDevOptions: null | DevOptions = null;
let io: null | IoServer = null;
let fileWatcher: null | Gaze = null;

export type DevOptions = {
port?: number; // port to run dev server
NoGateway?: boolean; // disable local gateway
Expand All @@ -29,15 +38,12 @@ export type DevOptions = {
* @param opts DevOptions
*/
export async function dev(src: string, opts: DevOptions) {
let io: null | IoServer = null;

let config = await loadConfig(src, opts.network);
const dist = path.join(src, DEV_DIST_FOLDER);
const devJsonPath = path.join(dist, "bos-loader.json");
const hotReloadEnabled = !opts.NoHot;


// Build the app for the first time
let devJson = await generateApp(src, dist, config, opts, devJsonPath);
const config = await loadConfig(src, opts.network);
let devJson = await generateApp(src, dist, config, opts);
await writeJson(devJsonPath, devJson);

// set index widget (temp, this can be done better)
Expand All @@ -46,10 +52,15 @@ export async function dev(src: string, opts: DevOptions) {
}

// Start the dev server
const server = startDevServer([src], [dist], devJsonPath, opts);
appSrcs = [src];
appDists = [dist];
appDevJsons = [devJson];
appDevJsonPath = devJsonPath;
appDevOptions = opts;
const server = startDevServer(appSrcs, appDists, appDevJsonPath, appDevOptions);

// Start the socket server if hot reload is enabled
if (hotReloadEnabled) {
if (!opts.NoHot) {
io = startSocket(server, (io: IoServer) => {
readJson(devJsonPath).then((devJson: DevJson) => {
io?.emit("fileChange", devJson);
Expand All @@ -61,24 +72,15 @@ export async function dev(src: string, opts: DevOptions) {
}

// Watch for changes in the src folder and rebuild the app on changes
startFileWatcher([
path.join(src, "widget/**/*"),
path.join(src, "module/**/*"),
path.join(src, "ipfs/**/*"),
path.join(src, "bos.config.json"),
path.join(src, "aliases.json")
], async (_: string, file: string) => {
if (file.includes("bos.config.json")) {
config = await loadConfig(src, opts.network);
}
log.info(`[${path.relative(src, file)}] changed: rebuilding app...`, LogLevels.DEV);
devJson = await generateApp(src, dist, config, opts, devJsonPath);
await writeJson(devJsonPath, devJson);

if (hotReloadEnabled && io) {
io.emit("fileChange", devJson);
}
});
fileWatcher = startFileWatcher([
path.join(src, "widget/**/*"),
path.join(src, "module/**/*"),
path.join(src, "ipfs/**/*"),
path.join(src, "bos.config.json"),
path.join(src, "aliases.json")
],
fileWatcherCallback
);
}

/**
Expand All @@ -89,28 +91,26 @@ export async function dev(src: string, opts: DevOptions) {
* @param opts DevOptions
*/
export async function devMulti(root: string, srcs: string[], opts: DevOptions) {
let io: null | IoServer = null;
const dist = path.join(root, DEV_DIST_FOLDER);
const devJsonPath = path.join(dist, "bos-loader.json");
let devJson = { components: {}, data: {} };


// Build all apps for the first time and merge devJson
let dists = [];
let appDevJson = { components: {}, data: {} };

for (const src of srcs) {
dists.push(path.join(dist, path.relative(root, src)));

const appDevJson = await generateApp(
src,
path.join(dist, path.relative(root, src)),
await loadConfig(src, opts.network),
opts,
devJsonPath
);
await writeJson(devJsonPath, mergeDeep(devJson, appDevJson))
const config = await loadConfig(src, opts.network);
const devJson = await generateApp(src, path.join(dist, path.relative(root, src)), config, opts);
await writeJson(devJsonPath, mergeDeep(appDevJson, devJson));

appSrcs.push(src);
appDists.push(path.join(dist, path.relative(root, src)));
appDevJsons.push(devJson);
}

// Start the dev server
const server = startDevServer(srcs, dists, devJsonPath, opts);
appDevJsonPath = devJsonPath;
appDevOptions = opts;
const server = startDevServer(appSrcs, appDists, appDevJsonPath, appDevOptions);

// Start the socket server if hot reload is enabled
if (!opts.NoHot) {
Expand All @@ -125,72 +125,77 @@ export async function devMulti(root: string, srcs: string[], opts: DevOptions) {
}

// Watch for changes in the mutliple srcs folder and rebuild apps on changes
startFileWatcher(srcs.map((src) => [path.join(src, "widget/**/*"), path.join(src, "module/**/*"), path.join(src, "ipfs/**/*"), path.join(src, "bos.config.json"), path.join(src, "aliases.json")]).flat(), async (_: string, file: string) => {
// find which app this file belongs to
const src = srcs.find((src) => file.includes(src));
if (!src) {
return;
}
log.info(`[${path.relative(src, file)}] changed: rebuilding app...`, LogLevels.DEV);
// rebuild app
const appDevJson = await generateApp(
src,
path.join(dist, path.relative(root, src)),
await loadConfig(src, opts.network),
opts,
devJsonPath
);
// write to redirect map
await writeJson(devJsonPath, mergeDeep(devJson, appDevJson))
if (io) {
io.emit("fileChange", devJson);
}
});
fileWatcher = startFileWatcher(
srcs.map((src) => [
path.join(src, "widget/**/*"),
path.join(src, "module/**/*"),
path.join(src, "ipfs/**/*"),
path.join(src, "bos.config.json"),
path.join(src, "aliases.json")
]).flat(),
fileWatcherCallback
);
}

export async function addApps(srcs: string[], dists: string[], devJsonPath: string, opts: DevOptions) {
let devJson = await readJson(devJsonPath, { throws: false });
export async function addApps(srcs: string[], dists: string[]) {
let appDevJson = await readJson(appDevJsonPath, { throws: false });

for (let i = 0; i < srcs.length; i ++) {
const src = srcs[i];
const dist = dists[i];

const appDevJson = await generateApp(
src,
dist,
await loadConfig(src, opts.network),
opts,
devJsonPath
);
await writeJson(devJsonPath, mergeDeep(devJson, appDevJson))
const config = await loadConfig(src, appDevOptions.network);
const devJson = await generateApp(src, dist, config, appDevOptions);
await writeJson(appDevJsonPath, mergeDeep(appDevJson, devJson));

appSrcs.push(src);
appDists.push(dist);
appDevJsons.push(devJson);
}

startFileWatcher(srcs.map((src) => [path.join(src, "widget/**/*"), path.join(src, "module/**/*"), path.join(src, "ipfs/**/*"), path.join(src, "bos.config.json"), path.join(src, "aliases.json")]).flat(), async (_: string, file: string) => {
// find which app this file belongs to
const index = srcs.findIndex((src) => file.includes(src));
if (index == -1) {
return;
}
if (io) {
io.emit("fileChange", appDevJson);
}

const src = srcs[index];
const dist = dists[index];

log.info(`[${file}] changed: rebuilding app...`, LogLevels.DEV);
// rebuild app
const appDevJson = await generateApp(
src,
dist,
await loadConfig(src, opts.network),
opts,
devJsonPath
);

// write to redirect map
await writeJson(devJsonPath, mergeDeep(devJson, appDevJson))
});
fileWatcher.add(srcs.map((src) => [
path.join(src, "widget/**/*"),
path.join(src, "module/**/*"),
path.join(src, "ipfs/**/*"),
path.join(src, "bos.config.json"),
path.join(src, "aliases.json")
]).flat()
);
}

async function fileWatcherCallback(action: string, file: string) {
let appDevJson = await readJson(appDevJsonPath, { throws: false });

// find which app this file belongs to
const index = appSrcs.findIndex((src) => file.includes(src));
if (index == -1) {
return;
}

const src = appSrcs[index];
const dist = appDists[index];

let devJson = appDevJsons[index];
substractDeep(appDevJson, devJson);

// rebuild app
log.info(`[${path.relative(src, file)}] changed: rebuilding app...`, LogLevels.DEV);
const config = await loadConfig(src, appDevOptions.network);
devJson = await generateApp(src, dist, config, appDevOptions);

// write to redirect map
await writeJson(appDevJsonPath, mergeDeep(appDevJson, devJson));
appDevJsons[index] = devJson;
if (io) {
io.emit("fileChange", appDevJson);
}
}

async function generateApp(src: string, appDist: string, config: BaseConfig, opts: DevOptions, distDevJson: string): Promise<DevJson> {
async function generateApp(src: string, appDist: string, config: BaseConfig, opts: DevOptions): Promise<DevJson> {
await buildApp(src, appDist, opts.network);
return await generateDevJson(appDist, config);
};
Expand Down
3 changes: 1 addition & 2 deletions lib/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import http from 'http';
import path from "path";
import { handleReplacements } from './gateway';
import { readFile } from "./utils/fs";
import { mergeDeep } from "./utils/objects";

// the gateway dist path in node_modules
const GATEWAY_PATH = path.join(__dirname, "../..", "gateway", "dist");
Expand Down Expand Up @@ -127,7 +126,7 @@ export function createApp(devJsonPath: string, opts: DevOptions): Express.Applic
const srcs = req.body.srcs;
const dists = req.body.dists;

addApps(srcs, dists, devJsonPath, opts).then(() => {
addApps(srcs, dists).then(() => {
res.status(200).send("Success");
}).catch((err: Error) => {
log.error(err.stack || err.message);
Expand Down
33 changes: 33 additions & 0 deletions lib/utils/objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,36 @@ export function mergeDeep(target: any, ...sources: any[]): object {
return mergeDeep(target, ...sources);
}

/**
* Deep substract two objects.
* @param target The target object to substract by.
* @param sources The source objects to substract.
* @returns {object} Returns the substracted object.
*/
export function substractDeep(target: any, ...sources: any[]): object {
if (!sources.length) return target;

const source = sources.shift();

if (isObject(target) && isObject(source)) {
for (const key in source) {
if (!target[key])
continue;

if (isObject(source[key])) {
if (isObject(target[key])) {
substractDeep(target[key], source[key]);
// If target[key] is now an empty object, delete it
if (Object.keys(target[key]).length === 0)
delete target[key];
}
} else {
if (target[key] === source[key])
delete target[key];
}
}
}

// Recursively merge remaining sources
return substractDeep(target, ...sources);
}
6 changes: 4 additions & 2 deletions lib/watcher.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { Gaze } from "gaze";

export function startFileWatcher(watchPaths: string[], callback: Function) {
const gaze = new Gaze(watchPaths, { debounceDelay: 100 });
export function startFileWatcher(watchPaths: string[], callback: Function): Gaze {
let gaze = new Gaze(watchPaths, { debounceDelay: 100 });
// @ts-ignore
gaze.on("all", callback);

return gaze;
}
Loading

0 comments on commit b5f8902

Please sign in to comment.