Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions config/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,17 @@ const createConfig = (data, configDirPath, radiusSlug = null) => {
};

const writeConfigurations = () => {
const organizationsFile = path.join(clientDir, "organizations.json");
const previousSlugs = fs.existsSync(organizationsFile)
? JSON.parse(fs.readFileSync(organizationsFile, "utf-8")).map((o) => o.slug)
: [];

// Reset arrays so re-running this function (e.g. on file-watch re-run) does
// not accumulate duplicate entries from previous invocations.
clientConfigs.length = 0;
serverConfigs.length = 0;
organizations.length = 0;
Comment thread
PRoIISHAAN marked this conversation as resolved.

// loop through all the config files
fs.readdirSync(organizationsDir).forEach((file) => {
const configDirPath = path.join(organizationsDir, file);
Expand Down Expand Up @@ -228,6 +239,20 @@ const writeConfigurations = () => {
}
});

const currentSlugs = new Set(organizations.map((o) => o.slug));
previousSlugs
.filter((slug) => !currentSlugs.has(slug))
.forEach((slug) => {
fs.rmSync(path.resolve(clientDir, "assets", slug), {
recursive: true,
force: true,
});
fs.rmSync(path.resolve(serverDir, "assets", slug), {
recursive: true,
force: true,
});
});

if (fs.existsSync(clientConfigsDir))
fs.rmSync(clientConfigsDir, {recursive: true});
if (!fs.existsSync(clientConfigsDir))
Expand Down
85 changes: 85 additions & 0 deletions config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,92 @@ const CopyPlugin = require("copy-webpack-plugin");
const {CleanWebpackPlugin} = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const fs = require("fs");
const TerserPlugin = require("terser-webpack-plugin");
const setup = require("./setup");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const CURRENT_WORKING_DIR = process.cwd();
const DEFAULT_PORT = 8080;
const DEFAULT_SERVER_URL = "http://localhost:3030";

/**
* Recursively collect all file paths under a directory.
*/
const getAllFiles = (dirPath, results = []) => {
if (!fs.existsSync(dirPath)) return results;
fs.readdirSync(dirPath).forEach((entry) => {
const fullPath = path.join(dirPath, entry);
try {
if (fs.statSync(fullPath).isDirectory()) {
getAllFiles(fullPath, results);
} else {
results.push(fullPath);
}
} catch (err) {
if (err.code !== "ENOENT") throw err;
}
});
Comment thread
PRoIISHAAN marked this conversation as resolved.
return results;
};

/**
* Webpack plugin that watches every file inside the `organizations/` directory.
* When any of those files change, it re-runs setup (copying configs/assets)
* so the bundle always reflects the latest org configuration without a manual
* server restart.
*/
class OrganizationsWatchPlugin {
apply(compiler) {
const organizationsDir = path.resolve(CURRENT_WORKING_DIR, "organizations");

// After each compilation, register all org files as dependencies so webpack
// watches them even though they are outside the normal module graph.
compiler.hooks.afterCompile.tap(
"OrganizationsWatchPlugin",
(compilation) => {
// Watch the directory itself (catches new files / deleted files)
compilation.contextDependencies.add(organizationsDir);
// Watch every individual file (catches content changes)
getAllFiles(organizationsDir).forEach((filePath) => {
compilation.fileDependencies.add(filePath);
});
},
);

// Before each re-compilation triggered by a watch event, re-run setup so
// that the copied configs/assets are up-to-date before the bundle is built.
compiler.hooks.watchRun.tapAsync(
"OrganizationsWatchPlugin",
(comp, callback) => {
const changedFiles = comp.modifiedFiles || new Set();
const removedFiles = comp.removedFiles || new Set();
const anyOrgFileChanged = [...changedFiles, ...removedFiles].some(
(f) => {
const rel = path.relative(organizationsDir, f);
return rel && !rel.startsWith("..") && !path.isAbsolute(rel);
},
);
if (anyOrgFileChanged) {
Comment thread
PRoIISHAAN marked this conversation as resolved.
console.log(
"[OrganizationsWatchPlugin] Change detected in organizations/. Re-running setup…",
);
try {
setup.writeConfigurations();
console.log("[OrganizationsWatchPlugin] Setup completed.");
return callback();
} catch (err) {
console.error("[OrganizationsWatchPlugin] Setup error:", err);
return callback(err);
}
}
callback();
return callback();
Comment thread
PRoIISHAAN marked this conversation as resolved.
Outdated
},
);
}
}

let minimizers = [];

module.exports = (env, argv) => {
Expand Down Expand Up @@ -47,6 +126,12 @@ module.exports = (env, argv) => {
}),
];

// In development (watch) mode, automatically re-run setup when any file
// inside organizations/ changes so developers edit source files, not copies.
if (argv.mode === "development") {
plugins.push(new OrganizationsWatchPlugin());
}

let cssLoaders = ["style-loader", "css-loader"];

if (process.env.STATS)
Expand Down
Loading