From 17dfc2f3011b4243a2ca86c19af50394492115e0 Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Sun, 9 Mar 2025 13:06:17 +0100 Subject: [PATCH 01/10] Clean up utils --- lib/index.js | 5 +- lib/manager.js | 21 +++- lib/manifest.js | 3 +- lib/{util => }/runner.js | 0 lib/util/{files/index.js => files.js} | 0 lib/util/files/finder.js | 59 ----------- lib/util/index.js | 42 ++++---- lib/util/resolve.js | 29 ------ test/test_manager.js | 17 +++- test/test_runner.js | 2 +- test/test_util.js | 137 -------------------------- 11 files changed, 64 insertions(+), 251 deletions(-) rename lib/{util => }/runner.js (100%) rename lib/util/{files/index.js => files.js} (100%) delete mode 100644 lib/util/files/finder.js delete mode 100644 lib/util/resolve.js delete mode 100644 test/test_util.js diff --git a/lib/index.js b/lib/index.js index 6606d1f..5726f35 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,9 +3,8 @@ let server = require("./server"); let { pluginsByBucket } = require("./plugins"); let { AssetManager } = require("./manager"); -let { resolvePath } = require("./util/resolve"); -let { abort, repr } = require("./util"); -let { SerializedRunner } = require("./util/runner"); +let { abort, repr, resolvePath } = require("./util"); +let { SerializedRunner } = require("./runner"); let browserslist = require("browserslist"); exports.faucetDispatch = async function faucetDispatch(referenceDir, config, diff --git a/lib/manager.js b/lib/manager.js index c75f97a..313b640 100644 --- a/lib/manager.js +++ b/lib/manager.js @@ -2,9 +2,9 @@ let { Manifest } = require("./manifest"); let { createFile } = require("./util/files"); -let { resolvePath } = require("./util/resolve"); -let { reportFileStatus, abort, generateFingerprint } = require("./util"); +let { reportFileStatus, abort, resolvePath } = require("./util"); let path = require("path"); +let crypto = require("crypto"); exports.AssetManager = class AssetManager { constructor(referenceDir, { manifestConfig, fingerprint, exitOnError } = {}) { @@ -58,3 +58,20 @@ exports.AssetManager = class AssetManager { return this.manifest.set(originalPath, actualPath, targetDir); } }; + +function generateFingerprint(filepath, data) { + let filename = path.basename(filepath); + let ext = filename.indexOf(".") === -1 ? "" : "." + filename.split(".").pop(); + let name = ext.length === 0 ? filename : path.basename(filepath, ext); + let hash = generateHash(data); + return path.join(path.dirname(filepath), `${name}-${hash}${ext}`); +} + +// exported for testing +exports.generateFingerprint = generateFingerprint; + +function generateHash(str) { + let hash = crypto.createHash("md5"); + hash.update(str); + return hash.digest("hex"); +} diff --git a/lib/manifest.js b/lib/manifest.js index 51db3ff..6e74f2a 100644 --- a/lib/manifest.js +++ b/lib/manifest.js @@ -1,8 +1,7 @@ "use strict"; let { createFile } = require("./util/files"); -let { resolvePath } = require("./util/resolve"); -let { abort } = require("./util"); +let { abort, resolvePath } = require("./util"); let path = require("path"); exports.Manifest = class Manifest { diff --git a/lib/util/runner.js b/lib/runner.js similarity index 100% rename from lib/util/runner.js rename to lib/runner.js diff --git a/lib/util/files/index.js b/lib/util/files.js similarity index 100% rename from lib/util/files/index.js rename to lib/util/files.js diff --git a/lib/util/files/finder.js b/lib/util/files/finder.js deleted file mode 100644 index 2cf86d9..0000000 --- a/lib/util/files/finder.js +++ /dev/null @@ -1,59 +0,0 @@ -let { readdir, stat } = require("fs/promises"); -let path = require("path"); - -exports.FileFinder = class FileFinder { - constructor(directory, { skipDotfiles, filter = () => true } = {}) { - this.directory = directory; - this.filter = filename => { - if(skipDotfiles && isDotfile(filename)) { - return false; - } - return filter(filename); - }; - } - - // returns a list of relative file paths within the respective directory - all() { - return tree(this.directory). - then(filenames => filenames.filter(this.filter)); - } - - // returns all file paths that match the filter function - match(filepaths) { - return filesWithinDirectory(this.directory, filepaths). - then(filepaths => filepaths.filter(this.filter)); - } -}; - -function tree(filepath, referenceDir = filepath) { - return stat(filepath). - then(res => { - if(!res.isDirectory()) { - return [path.relative(referenceDir, filepath)]; - } - - return readdir(filepath). - then(entries => { - let res = Promise.all(entries.map(entry => { - return tree(path.join(filepath, entry), referenceDir); - })); - return res.then(flatten); - }); - }); -} - -function filesWithinDirectory(directory, files) { - return new Promise(resolve => { - resolve(files. - map(filepath => path.relative(directory, filepath)). - filter(filename => !filename.startsWith(".."))); - }); -} - -function isDotfile(filename) { - return path.basename(filename).startsWith("."); -} - -function flatten(arr) { - return [].concat.apply([], arr); -} diff --git a/lib/util/index.js b/lib/util/index.js index 0698bc2..0b2a104 100644 --- a/lib/util/index.js +++ b/lib/util/index.js @@ -1,10 +1,7 @@ "use strict"; +let fs = require("fs"); let path = require("path"); -let crypto = require("crypto"); - -exports.abort = abort; -exports.repr = repr; // reports success or failure for a given file path (typically regarding // compilation or write operations) @@ -26,18 +23,11 @@ exports.loadExtension = async (pkg, errorMessage, supplier = pkg) => { } }; -exports.generateFingerprint = (filepath, data) => { - let filename = path.basename(filepath); - let ext = filename.indexOf(".") === -1 ? "" : "." + filename.split(".").pop(); - let name = ext.length === 0 ? filename : path.basename(filepath, ext); - let hash = generateHash(data); - return path.join(path.dirname(filepath), `${name}-${hash}${ext}`); -}; - function abort(msg, code = 1) { console.error(msg); process.exit(code); } +exports.abort = abort; function repr(value, jsonify = true) { if(jsonify) { @@ -45,9 +35,27 @@ function repr(value, jsonify = true) { } return `\`${value}\``; } +exports.repr = repr; -function generateHash(str) { - let hash = crypto.createHash("md5"); - hash.update(str); - return hash.digest("hex"); -} +exports.resolvePath = (filepath, referenceDir, { enforceRelative } = {}) => { + if(/^\.?\.\//.test(filepath)) { // starts with `./` or `../` + return path.resolve(referenceDir, filepath); + } else if(enforceRelative) { + abort(`ERROR: path must be relative: ${repr(filepath)}`); + } else { // attempt via Node resolution algorithm + try { + return require.resolve(filepath, { paths: [referenceDir] }); + } catch(err) { + // attempt to resolve non-JavaScript package references by relying + // on typical package paths (simplistic approximation of Node's + // resolution algorithm) + let resolved = path.resolve(referenceDir, "node_modules", filepath); + try { + fs.statSync(resolved); // ensures file/directory exists + } catch(_err) { + abort(`ERROR: could not resolve ${repr(filepath)}`); + } + return resolved; + } + } +}; diff --git a/lib/util/resolve.js b/lib/util/resolve.js deleted file mode 100644 index afb8124..0000000 --- a/lib/util/resolve.js +++ /dev/null @@ -1,29 +0,0 @@ -"use strict"; - -let { abort, repr } = require("./"); -let fs = require("fs"); -let path = require("path"); - -exports.resolvePath = function resolvePath(filepath, referenceDir, - { enforceRelative } = {}) { - if(/^\.?\.\//.test(filepath)) { // starts with `./` or `../` - return path.resolve(referenceDir, filepath); - } else if(enforceRelative) { - abort(`ERROR: path must be relative: ${repr(filepath)}`); - } else { // attempt via Node resolution algorithm - try { - return require.resolve(filepath, { paths: [referenceDir] }); - } catch(err) { - // attempt to resolve non-JavaScript package references by relying - // on typical package paths (simplistic approximation of Node's - // resolution algorithm) - let resolved = path.resolve(referenceDir, "node_modules", filepath); - try { - fs.statSync(resolved); // ensures file/directory exists - } catch(_err) { - abort(`ERROR: could not resolve ${repr(filepath)}`); - } - return resolved; - } - } -}; diff --git a/test/test_manager.js b/test/test_manager.js index 9ae62c2..9a8c667 100644 --- a/test/test_manager.js +++ b/test/test_manager.js @@ -1,6 +1,6 @@ "use strict"; -let { AssetManager } = require("../lib/manager"); +let { AssetManager, generateFingerprint } = require("../lib/manager"); let { describe, it, before, after } = require("node:test"); let path = require("path"); let assert = require("assert"); @@ -51,3 +51,18 @@ describe("asset manager", () => { }, /exit 1/); }); }); + +describe("fingerprinting", () => { + it("generates a content-dependent hash", () => { + let fingerprint = generateFingerprint("/path/to/foo.js", "lorem ipsum"); + assertSame(fingerprint, "/path/to/foo-80a751fde577028640c419000e33eba6.js"); + + fingerprint = generateFingerprint("/path/to/bar.js", "dolor sit amet"); + assertSame(fingerprint, "/path/to/bar-7afed6210e0b8fce023f06abd4490fa0.js"); + }); + + it("supports files without extension", () => { + let fingerprint = generateFingerprint("/path/to/baz", "lipsum"); + assertSame(fingerprint, "/path/to/baz-8047cfaac755e5c7f77af066123980a5"); + }); +}); diff --git a/test/test_runner.js b/test/test_runner.js index 8a20d0f..2da2bf6 100644 --- a/test/test_runner.js +++ b/test/test_runner.js @@ -1,6 +1,6 @@ "use strict"; -let { SerializedRunner } = require("../lib/util/runner"); +let { SerializedRunner } = require("../lib/runner"); let { describe, it } = require("node:test"); let { strictEqual: assertSame, deepStrictEqual: assertDeep } = require("assert"); diff --git a/test/test_util.js b/test/test_util.js deleted file mode 100644 index cad64c9..0000000 --- a/test/test_util.js +++ /dev/null @@ -1,137 +0,0 @@ -"use strict"; - -let { generateFingerprint } = require("../lib/util"); -let { FileFinder } = require("../lib/util/files/finder"); -let { describe, it } = require("node:test"); -let path = require("path"); -let assert = require("assert"); - -let assertSame = assert.strictEqual; -let assertDeep = assert.deepStrictEqual; - -let FIXTURES_PATH = path.resolve(__dirname, "fixtures"); - -describe("fingerprinting", () => { - it("generates a content-dependent hash", () => { - let fingerprint = generateFingerprint("/path/to/foo.js", "lorem ipsum"); - assertSame(fingerprint, "/path/to/foo-80a751fde577028640c419000e33eba6.js"); - - fingerprint = generateFingerprint("/path/to/bar.js", "dolor sit amet"); - assertSame(fingerprint, "/path/to/bar-7afed6210e0b8fce023f06abd4490fa0.js"); - }); - - it("supports files without extension", () => { - let fingerprint = generateFingerprint("/path/to/baz", "lipsum"); - assertSame(fingerprint, "/path/to/baz-8047cfaac755e5c7f77af066123980a5"); - }); -}); - -describe("FileFinder", () => { - it("finds all files within a folder", () => { - let fileFinder = new FileFinder(FIXTURES_PATH); - - return fileFinder.all(). - then(allFiles => { - assertDeep(allFiles, [ - "dud.js", - "dummy/.keep", - "dummy/index.js", - "dummy/src.js", - "node_modules/dummy/images/.keep", - "node_modules/dummy/index.js", - "node_modules/dummy/pkg.js", - "node_modules/faucet-pipeline-dummy/index.js", - "node_modules/faucet-pipeline-invalid-a/index.js", - "node_modules/faucet-pipeline-invalid-b/index.js", - "node_modules/faucet-pipeline-invalid-c/index.js", - "node_modules/faucet-pipeline-js/index.js", - "node_modules/faucet-pipeline-sass/index.js", - "node_modules/faucet-pipeline-static/index.js" - ]); - }); - }); - - it("finds all files within a folder without dotfiles", () => { - let fileFinder = new FileFinder(FIXTURES_PATH, { skipDotfiles: true }); - - return fileFinder.all(). - then(allFiles => { - assertDeep(allFiles, [ - "dud.js", - "dummy/index.js", - "dummy/src.js", - "node_modules/dummy/index.js", - "node_modules/dummy/pkg.js", - "node_modules/faucet-pipeline-dummy/index.js", - "node_modules/faucet-pipeline-invalid-a/index.js", - "node_modules/faucet-pipeline-invalid-b/index.js", - "node_modules/faucet-pipeline-invalid-c/index.js", - "node_modules/faucet-pipeline-js/index.js", - "node_modules/faucet-pipeline-sass/index.js", - "node_modules/faucet-pipeline-static/index.js" - ]); - }); - }); - - it("finds all files within a folder with a filter", () => { - let fileFinder = new FileFinder(FIXTURES_PATH, { - filter: filename => path.basename(filename) === "index.js" - }); - - return fileFinder.all(). - then(allFiles => { - assertDeep(allFiles, [ - "dummy/index.js", - "node_modules/dummy/index.js", - "node_modules/faucet-pipeline-dummy/index.js", - "node_modules/faucet-pipeline-invalid-a/index.js", - "node_modules/faucet-pipeline-invalid-b/index.js", - "node_modules/faucet-pipeline-invalid-c/index.js", - "node_modules/faucet-pipeline-js/index.js", - "node_modules/faucet-pipeline-sass/index.js", - "node_modules/faucet-pipeline-static/index.js" - ]); - }); - }); - - it("matches given files", () => { - let fileFinder = new FileFinder(FIXTURES_PATH); - let foo = [ - path.resolve(FIXTURES_PATH, "dummy/index.js"), - path.resolve(FIXTURES_PATH, "something.js"), - path.resolve(FIXTURES_PATH, "../other/something.js") - ]; - - fileFinder.match(foo). - then(allFiles => { - assertDeep(allFiles, ["dummy/index.js", "something.js"]); - }); - }); - - it("matches given files without dotfiles", () => { - let fileFinder = new FileFinder(FIXTURES_PATH, { skipDotfiles: true }); - let foo = [ - path.resolve(FIXTURES_PATH, ".secret") - ]; - - return fileFinder.match(foo). - then(allFiles => { - assertDeep(allFiles, []); - }); - }); - - it("matches given files with custom finder", () => { - let fileFinder = new FileFinder(FIXTURES_PATH, { - filter: filename => path.basename(filename) === "index.js" - }); - let foo = [ - path.resolve(FIXTURES_PATH, "index.js"), - path.resolve(FIXTURES_PATH, "something.js") - ]; - - fileFinder.match(foo). - then(allFiles => { - assertDeep(allFiles, ["index.js"]); - }); - }); -}); From 93d35ecaabb5d39d111f6c2a4d1ccba18f6555d1 Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Sat, 15 Mar 2025 18:33:52 +0100 Subject: [PATCH 02/10] Allow to use static as `assets` --- lib/plugins.js | 4 ++++ test/test_plugins.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/lib/plugins.js b/lib/plugins.js index b940706..a0115f9 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -15,6 +15,10 @@ let DEFAULTS = [{ key: "static", bucket: "static", plugin: "faucet-pipeline-static" +}, { + key: "assets", + bucket: "static", + plugin: "faucet-pipeline-static" }, { key: "images", bucket: "static", diff --git a/test/test_plugins.js b/test/test_plugins.js index 637b3ab..f33a892 100644 --- a/test/test_plugins.js +++ b/test/test_plugins.js @@ -21,6 +21,10 @@ let DEFAULTS = { bucket: "static", plugin: "faucet-pipeline-static" }, + assets: { + bucket: "static", + plugin: "faucet-pipeline-static" + }, images: { bucket: "static", plugin: "faucet-pipeline-images" From 82a763554a9897939afc56e3a1b2673fe93e68b8 Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Tue, 22 Apr 2025 12:45:27 +0200 Subject: [PATCH 03/10] Remove `browsers` as a param to plugins This moves the responsibility to the plugin, where it makes more sense. This also removes the need for browserslist as a dependency in core. --- lib/index.js | 7 +------ package.json | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/index.js b/lib/index.js index 5726f35..2f0dd97 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,7 +5,6 @@ let { pluginsByBucket } = require("./plugins"); let { AssetManager } = require("./manager"); let { abort, repr, resolvePath } = require("./util"); let { SerializedRunner } = require("./runner"); -let browserslist = require("browserslist"); exports.faucetDispatch = async function faucetDispatch(referenceDir, config, { watch, fingerprint, sourcemaps, compact, serve, liveserve }) { @@ -16,16 +15,12 @@ exports.faucetDispatch = async function faucetDispatch(referenceDir, config, fingerprint, exitOnError: !watch }); - let browsers = browserslist.findConfig(referenceDir) || {}; - if(browsers.substr) { - browsers = [browsers]; - } let plugins = await pluginsByBucket(config); // initialize plugins with corresponding configuration let buckets = Object.keys(plugins).reduce((memo, bucket) => { memo[bucket] = plugins[bucket].map(({ plugin, config }) => { - return plugin(config, assetManager, { browsers, sourcemaps, compact }); + return plugin(config, assetManager, { sourcemaps, compact }); }); return memo; }, {}); diff --git a/package.json b/package.json index 48bd905..f5786a5 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "node": ">= 18" }, "dependencies": { - "browserslist": "~4.24.4", "nite-owl": "~5.0.5" }, "devDependencies": { From 1a40eb532bb8754db4d2ab62bf5c980fc511162d Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Tue, 22 Apr 2025 12:46:29 +0200 Subject: [PATCH 04/10] Make nite-owl an optional dependency --- lib/index.js | 5 +++-- package.json | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/index.js b/lib/index.js index 2f0dd97..fb15b08 100644 --- a/lib/index.js +++ b/lib/index.js @@ -3,7 +3,7 @@ let server = require("./server"); let { pluginsByBucket } = require("./plugins"); let { AssetManager } = require("./manager"); -let { abort, repr, resolvePath } = require("./util"); +let { abort, repr, resolvePath, loadExtension } = require("./util"); let { SerializedRunner } = require("./runner"); exports.faucetDispatch = async function faucetDispatch(referenceDir, config, @@ -57,7 +57,8 @@ function buildStep(plugins) { } async function makeWatcher(watchDirs, referenceDir) { - let niteOwl = await require("nite-owl"); + // XXX: Rename to faucet-pipeline-watch? + let niteOwl = await loadExtension("nite-owl", "failed to activate watching"); if(watchDirs) { watchDirs = watchDirs.map(dir => resolvePath(dir, referenceDir, diff --git a/package.json b/package.json index f5786a5..ef13474 100644 --- a/package.json +++ b/package.json @@ -27,9 +27,6 @@ "engines": { "node": ">= 18" }, - "dependencies": { - "nite-owl": "~5.0.5" - }, "devDependencies": { "eslint-config-fnd": "^1.13.0", "release-util-fnd": "^3.0.0" From b8ad2958470a0852b1b2b231ff210a6ff9e7df1b Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Sat, 26 Apr 2025 17:52:19 +0200 Subject: [PATCH 05/10] Make the baseURI available on the manifest --- lib/manifest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/manifest.js b/lib/manifest.js index 6e74f2a..7bf9bb1 100644 --- a/lib/manifest.js +++ b/lib/manifest.js @@ -11,6 +11,7 @@ exports.Manifest = class Manifest { } this.webRoot = webRoot = resolvePath(webRoot || "./", referenceDir, { enforceRelative: true }); + this.baseURI = baseURI || "/"; if(target) { this.filepath = resolvePath(target, referenceDir, { enforceRelative: true }); @@ -26,8 +27,7 @@ exports.Manifest = class Manifest { if(value) { this.valueTransform = value; } else { - baseURI = baseURI || "/"; - this.valueTransform = filepath => baseURI + path.relative(webRoot, filepath); + this.valueTransform = filepath => this.baseURI + path.relative(webRoot, filepath); } } From c9c4c9f6e61349b52df9536fe7c206135b2e9058 Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Mon, 19 May 2025 09:29:58 +0200 Subject: [PATCH 06/10] Add types for plugins --- lib/types.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 lib/types.ts diff --git a/lib/types.ts b/lib/types.ts new file mode 100644 index 0000000..4a982ea --- /dev/null +++ b/lib/types.ts @@ -0,0 +1,26 @@ +export interface FaucetPlugin { + (config: T[], assetManager: AssetManager, options: FaucetPluginOptions): FaucetPluginFunc +} + +export interface FaucetPluginFunc { + (filepaths: string[]): Promise +} + +export interface FaucetPluginOptions { + sourcemaps: boolean, + compact: boolean +} + +export interface AssetManager { + resolvePath: (path: string, opts?: ResolvePathOpts) => string + writeFile: (targetPath: string, content: Buffer, options: WriteFileOpts) => Promise +} + +export interface ResolvePathOpts { + enforceRelative?: boolean +} + +export interface WriteFileOpts { + targetDir: string, + fingerprint?: boolean +} From 85af0177303e5847c43385a2e1193fc3e37b2db8 Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Tue, 20 May 2025 12:03:14 +0200 Subject: [PATCH 07/10] Clean up --- lib/cli.js | 26 ++++++++------------------ lib/config.js | 11 ----------- lib/index.js | 16 ++++++++-------- 3 files changed, 16 insertions(+), 37 deletions(-) delete mode 100644 lib/config.js diff --git a/lib/cli.js b/lib/cli.js index ae8713b..550e27c 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -1,8 +1,8 @@ "use strict"; -let { readConfig } = require("./config"); let { abort, repr } = require("./util"); let { parseArgs } = require("node:util"); +let path = require("node:path"); let HELP = ` Usage: @@ -37,7 +37,8 @@ exports.parseCLI = async function parseCLI() { }, config: { type: "string", - short: "c" + short: "c", + default: "faucet.config.js" }, watch: { type: "boolean", @@ -69,21 +70,10 @@ exports.parseCLI = async function parseCLI() { abort(HELP, 0); } - let options = { - watch: values.watch, - fingerprint: values.fingerprint, - sourcemaps: values.sourcemaps, - compact: values.compact, - serve: values.serve, - liveserve: values.liveserve + let configPath = path.resolve(process.cwd(), values.config); + return { + referenceDir: path.dirname(configPath), + config: await require(configPath), + options: values }; - - if(options.watch && options.fingerprint) { // for convenience - console.error("you might consider disabling fingerprinting in watch " + - "mode to avoid littering your file system with obsolete bundles"); - } - - let rootDir = process.cwd(); - let { referenceDir, config } = await readConfig(rootDir, values.config); - return { referenceDir, config, options }; }; diff --git a/lib/config.js b/lib/config.js deleted file mode 100644 index b87fa5c..0000000 --- a/lib/config.js +++ /dev/null @@ -1,11 +0,0 @@ -"use strict"; - -let path = require("path"); - -exports.readConfig = async function readConfig(rootDir, filepath = "faucet.config.js") { - let configPath = path.resolve(rootDir, filepath); - return { - referenceDir: path.dirname(configPath), - config: await require(configPath) - }; -}; diff --git a/lib/index.js b/lib/index.js index fb15b08..38760a8 100644 --- a/lib/index.js +++ b/lib/index.js @@ -8,8 +8,6 @@ let { SerializedRunner } = require("./runner"); exports.faucetDispatch = async function faucetDispatch(referenceDir, config, { watch, fingerprint, sourcemaps, compact, serve, liveserve }) { - config = await config; - let assetManager = new AssetManager(referenceDir, { manifestConfig: config.manifest, fingerprint, @@ -33,12 +31,14 @@ exports.faucetDispatch = async function faucetDispatch(referenceDir, config, runner.run(); if(watch) { - makeWatcher(config.watchDirs, referenceDir). - then(watcher => { - watcher.on("edit", filepaths => { - runner.rerun(filepaths); - }); - }); + if(fingerprint) { + console.error("you might consider disabling fingerprinting in watch " + + "mode to avoid littering your file system with obsolete bundles"); + } + let watcher = await makeWatcher(config.watchDirs, referenceDir); + watcher.on("edit", filepaths => { + runner.rerun(filepaths); + }); } if(serve && liveserve) { From 73777b8cb60e321050ddeac68b6cdc17b40e323e Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Tue, 20 May 2025 13:45:48 +0200 Subject: [PATCH 08/10] Remove liveserver option --- lib/cli.js | 6 ++++-- lib/index.js | 7 +------ lib/server.js | 7 ------- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/cli.js b/lib/cli.js index 550e27c..1ee5762 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -23,8 +23,6 @@ Options: reduce output size (where supported) --serve [HOST:]PORT serve generated files via HTTP - --liveserve [HOST:]PORT - serve generated files via HTTP with live reloading `.trim(); exports.parseCLI = async function parseCLI() { @@ -70,6 +68,10 @@ exports.parseCLI = async function parseCLI() { abort(HELP, 0); } + if(values.liveserve) { + abort("The --liveserve option was removed. Please use --serve instead", 0); + } + let configPath = path.resolve(process.cwd(), values.config); return { referenceDir: path.dirname(configPath), diff --git a/lib/index.js b/lib/index.js index 38760a8..d3518c0 100644 --- a/lib/index.js +++ b/lib/index.js @@ -7,7 +7,7 @@ let { abort, repr, resolvePath, loadExtension } = require("./util"); let { SerializedRunner } = require("./runner"); exports.faucetDispatch = async function faucetDispatch(referenceDir, config, - { watch, fingerprint, sourcemaps, compact, serve, liveserve }) { + { watch, fingerprint, sourcemaps, compact, serve }) { let assetManager = new AssetManager(referenceDir, { manifestConfig: config.manifest, fingerprint, @@ -41,13 +41,8 @@ exports.faucetDispatch = async function faucetDispatch(referenceDir, config, }); } - if(serve && liveserve) { - abort("ERROR: serve and liveserve must not be used together"); - } if(serve) { server.static(serve, assetManager.manifest.webRoot); - } else if(liveserve) { - server.live(liveserve, assetManager.manifest.webRoot); } }; diff --git a/lib/server.js b/lib/server.js index 9ecb696..0d8bf25 100644 --- a/lib/server.js +++ b/lib/server.js @@ -13,13 +13,6 @@ exports.static = async (config, webroot) => { console.error(`serving ${repr(webroot)} at http://${host}:${port}`); }; -exports.live = async (config, root) => { - let liveServer = await loadExtension("live-server", "failed to activate live-server"); - let [host, port] = parseHost(config); - - liveServer.start({ port, host, root, open: false }); -}; - exports._parseHost = parseHost; function parseHost(config) { From 7bf71e24cdda979daaf7283c2154a6712ac99f97 Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Tue, 20 May 2025 15:11:47 +0200 Subject: [PATCH 09/10] Remove finally polyfill --- lib/runner.js | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/lib/runner.js b/lib/runner.js index 90ec0af..9207d1d 100644 --- a/lib/runner.js +++ b/lib/runner.js @@ -7,7 +7,7 @@ exports.SerializedRunner = class SerializedRunner { run(...args) { if(!this._pending) { // prevent concurrent execution - this._pending = augment(this.asyncOp(...args)). + this._pending = this.asyncOp(...args). finally(() => { this._pending = null; }); @@ -24,7 +24,7 @@ exports.SerializedRunner = class SerializedRunner { let enqueue = this._pending; let res = this.run(...args); if(enqueue) { - this._queued = res = augment(res). + this._queued = res = res. finally(() => { this._queued = null; }). @@ -33,20 +33,3 @@ exports.SerializedRunner = class SerializedRunner { return res; } }; - -function augment(promise) { - promise.finally = always; - return promise; -} - -// poor man's `Promise#finally` polyfill -function always(fn) { - return this. - then(res => { - fn(); - return res; - }, err => { - fn(); - throw err; - }); -} From 3bf9b980f4fe42c075c56e8e2cfefa92b8b83de1 Mon Sep 17 00:00:00 2001 From: Lucas Dohmen Date: Tue, 20 May 2025 16:11:01 +0200 Subject: [PATCH 10/10] Remove AssetManager#packagesDir --- lib/manager.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/manager.js b/lib/manager.js index 313b640..3593ae8 100644 --- a/lib/manager.js +++ b/lib/manager.js @@ -43,14 +43,6 @@ exports.AssetManager = class AssetManager { }); } - get packagesDir() { - let memo = this._packagesDir; - if(!memo) { - memo = this._packagesDir = this.resolvePath("./node_modules"); - } - return memo; - } - _updateManifest(originalPath, actualPath, targetDir) { let { referenceDir } = this; originalPath = path.relative(referenceDir, originalPath);