html-bundler-webpack-plugin
Version:
Generates complete single-page or multi-page website from source assets. Build-in support for Markdown, Eta, EJS, Handlebars, Nunjucks, Pug. Alternative to html-webpack-plugin.
157 lines (130 loc) • 4.28 kB
JavaScript
const { readDirRecursiveSync } = require('../Common/FileUtils');
/**
* Snapshot of files.
*
* This module supports the detection of file name changes: add/delete/rename files in the directory.
* File content change detection is not supported.
*
* Used in watch mode to compare the file's list before and after changes in a directory.
*/
// TODO: refactor to non static class
class Snapshot {
static fs = null;
static dirs = [];
static includes = [];
static excludes = [];
static prevFiles = [];
static currFiles = [];
static missingFiles = new Map();
/**
* @param {FileSystem} fs
* @param {string|Array<string>} dir The directory for snapshot.
* @param {Array<RegExp>} includes The filter to read only matched files.
* @param {Array<RegExp>} excludes The filter to ignore matched files.
*/
static init({ fs, dir, includes = [], excludes = [/[\\/]node_modules[\\/]/] }) {
this.fs = fs;
this.dirs = Array.isArray(dir) ? dir : [dir];
this.includes = includes;
this.excludes = excludes;
}
/**
* Create snapshot of files in the directory.
*/
static create() {
const { fs, dirs, includes, excludes } = this;
const hasPrevFiles = this.prevFiles.length > 0;
if (hasPrevFiles) {
this.prevFiles = [...this.currFiles];
}
this.currFiles = [];
for (const dir of dirs) {
const files = readDirRecursiveSync(dir, { fs, includes, excludes });
this.currFiles.push(...files);
}
if (!hasPrevFiles) {
this.prevFiles = [...this.currFiles];
}
}
/**
* Get the list of old file names which are changed.
*
* @return {Array}
*/
static getOldFiles() {
return this.getDiff(this.prevFiles, this.currFiles);
}
/**
* Get the list of new file names which are changed.
*
* @return {Array}
*/
static getNewFiles() {
return this.getDiff(this.currFiles, this.prevFiles);
}
/**
* Detect the action type by file manipulation.
*
* Limitation: currently supports for change only a single file.
*
* TODO: fix when added/removed many files, then Webpack calls many times the `invalid` hook for each file,
* in this case only for first calling of `invalid` hook the action type is correct - add/remove,
* for next calls is detected no changes, because the snapshot take current state of dir
*
* @return {{oldFileName: string, newFileName: string, actionType: string}}
*/
static detectFileChange() {
const oldFiles = this.getOldFiles();
const newFiles = this.getNewFiles();
const hasOldFiles = oldFiles.length > 0;
const hasNewFiles = newFiles.length > 0;
let actionType = '';
let oldFileName = '';
let newFileName = '';
if (!hasOldFiles && hasNewFiles) {
// a file is created in the directory or coped/removed into the directory
actionType = 'add';
newFileName = newFiles[0];
} else if (hasOldFiles && !hasNewFiles) {
// a file is deleted or removed outer the directory
actionType = 'remove';
oldFileName = oldFiles[0];
} else if (hasOldFiles && hasNewFiles) {
// a file is renamed in the directory
actionType = 'rename';
oldFileName = oldFiles[0];
newFileName = newFiles[0];
} else if (!hasOldFiles && !hasNewFiles) {
// a file content is modified
actionType = 'modify';
}
return { actionType, oldFileName, newFileName };
}
static getMissingFiles() {
return this.missingFiles;
}
static addMissingFile(issuer, file) {
let files = this.missingFiles.get(issuer);
if (!files) this.missingFiles.set(issuer, new Set([file]));
else files.add(file);
}
static deleteMissingFile(issuer, file) {
let files = this.missingFiles.get(issuer);
if (files) files.delete(file);
if (files.size === 0) this.missingFiles.delete(issuer);
}
static hasMissingFile(issuer, file) {
let files = this.missingFiles.get(issuer);
if (!files) return false;
return !!Array.from(files).find((missingFile) => file.endsWith(missingFile));
}
static getDiff(a, b) {
return a.filter((x) => !b.includes(x));
}
static reset() {}
static clear() {
this.prevFiles = [];
this.currFiles = [];
}
}
module.exports = Snapshot;