Skip to content

Commit 859c576

Browse files
committed
switched everything to ESM, abandoning CommonJS
to do: * some tests are still red * `loadExtension` now returns a promise, but `plugins.js` has yet to be updated accordingly: much of it should disappear when we get rid of legacy plugins * documentation for end users * documentation for developers: some signatures have changed (due to avoidance of default exports and because dynamic `import` is async) in the process: * avoided default exports (note that this changes a few modules' signature) * replaced `promisify` with native alternatives * replaced pseudo-sets and -maps with actual `Set` and `Map` instances * introduce `async`/`await` where suitable - I did not, however, rewrite everything to use `async`/`await` * got rid of a few obsolete workarounds * tweaked stylistic details
1 parent e170f1d commit 859c576

File tree

29 files changed

+175
-245
lines changed

29 files changed

+175
-245
lines changed

bin/faucet

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
#!/usr/bin/env node
2-
"use strict";
2+
import { faucetDispatch } from "../lib/index.js";
3+
import { parseCLI } from "../lib/cli.js";
34

4-
let faucet = require("../lib");
5-
let parseCLI = require("../lib/cli");
6-
7-
let { referenceDir, config, options } = parseCLI();
8-
faucet(referenceDir, config, options);
5+
parseCLI.then(({ referenceDir, config, options }) => {
6+
faucetDispatch(referenceDir, config, options);
7+
});

lib/cli.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
"use strict";
2-
3-
let readConfig = require("./config");
4-
let { abort, repr } = require("./util");
5-
let parseArgs = require("minimist");
1+
import { readConfig } from "./config.js";
2+
import { abort, repr } from "./util/index.js";
3+
import parseArgs from "minimist";
64

75
let HELP = `
86
Usage:
@@ -27,7 +25,7 @@ Options:
2725
serve generated files via HTTP with live reloading
2826
`.trim();
2927

30-
module.exports = function parseCLI(argv = process.argv.slice(2), help = HELP) {
28+
export async function parseCLI(argv = process.argv.slice(2), help = HELP) {
3129
argv = parseArgs(argv, {
3230
boolean: ["watch", "fingerprint", "sourcemaps", "compact"],
3331
alias: {
@@ -56,6 +54,6 @@ module.exports = function parseCLI(argv = process.argv.slice(2), help = HELP) {
5654
}
5755

5856
let rootDir = process.cwd();
59-
let { referenceDir, config } = readConfig(rootDir, argv.config);
57+
let { referenceDir, config } = await readConfig(rootDir, argv.config);
6058
return { referenceDir, config, options };
61-
};
59+
}

lib/config.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
"use strict";
1+
import path from "path";
22

3-
let path = require("path");
4-
5-
module.exports = function readConfig(rootDir, filepath = "faucet.config.js") {
3+
export async function readConfig(rootDir, filepath = "faucet.config.js") {
64
let configPath = path.resolve(rootDir, filepath);
75
return {
86
referenceDir: path.dirname(configPath),
9-
config: require(configPath)
7+
config: await import(configPath)
108
};
11-
};
9+
}

lib/index.js

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
"use strict";
1+
import { liveServer, staticServer } from "./server.js";
2+
import { pluginsByBucket } from "./plugins.js";
3+
import { AssetManager } from "./manager.js";
4+
import { resolvePath } from "./util/resolve.js";
5+
import { abort, repr } from "./util/index.js";
6+
import { SerializedRunner } from "./util/runner.js";
7+
import browserslist from "browserslist";
28

3-
let server = require("./server");
4-
let { pluginsByBucket } = require("./plugins");
5-
let AssetManager = require("./manager");
6-
let resolvePath = require("./util/resolve");
7-
let { abort, repr } = require("./util");
8-
let SerializedRunner = require("./util/runner");
9-
let browserslist = require("browserslist");
10-
11-
module.exports = async function faucetDispatch(referenceDir, config,
9+
export async function faucetDispatch(referenceDir, config,
1210
{ watch, fingerprint, sourcemaps, compact, serve, liveserve }) {
1311
config = await config;
1412

@@ -39,7 +37,7 @@ module.exports = async function faucetDispatch(referenceDir, config,
3937
runner.run();
4038

4139
if(watch) {
42-
makeWatcher(config.watchDirs, referenceDir).
40+
await makeWatcher(config.watchDirs, referenceDir).
4341
on("edit", filepaths => {
4442
runner.rerun(filepaths);
4543
});
@@ -49,19 +47,19 @@ module.exports = async function faucetDispatch(referenceDir, config,
4947
abort("ERROR: serve and liveserve must not be used together");
5048
}
5149
if(serve) {
52-
server.static(serve, assetManager.manifest.webRoot);
50+
staticServer(serve, assetManager.manifest.webRoot);
5351
} else if(liveserve) {
54-
server.live(liveserve, assetManager.manifest.webRoot);
52+
liveServer(liveserve, assetManager.manifest.webRoot);
5553
}
56-
};
54+
}
5755

5856
function buildStep(plugins) {
5957
return files => Promise.all(plugins.map(plugin => plugin(files))).
6058
then(() => files);
6159
}
6260

63-
function makeWatcher(watchDirs, referenceDir) {
64-
let niteOwl = require("nite-owl");
61+
async function makeWatcher(watchDirs, referenceDir) {
62+
let niteOwl = await import("nite-owl");
6563

6664
if(watchDirs) {
6765
watchDirs = watchDirs.map(dir => resolvePath(dir, referenceDir,

lib/manager.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
"use strict";
1+
import { Manifest } from "./manifest.js";
2+
import { createFile } from "./util/files/index.js";
3+
import { resolvePath } from "./util/resolve.js";
4+
import { reportFileStatus, abort, generateFingerprint } from "./util/index.js";
5+
import path from "path";
26

3-
let Manifest = require("./manifest");
4-
let createFile = require("./util/files");
5-
let resolvePath = require("./util/resolve");
6-
let { reportFileStatus, abort, generateFingerprint } = require("./util");
7-
let path = require("path");
8-
9-
module.exports = class AssetManager {
7+
export class AssetManager {
108
constructor(referenceDir, { manifestConfig, fingerprint, exitOnError } = {}) {
119
this.referenceDir = referenceDir;
1210
this.fingerprint = fingerprint;
@@ -30,9 +28,9 @@ module.exports = class AssetManager {
3028
}
3129

3230
return createFile(filepath, data).
33-
then(_ => this.manifest &&
31+
then(() => this.manifest &&
3432
this._updateManifest(originalPath, filepath, targetDir)).
35-
then(_ => {
33+
then(() => {
3634
reportFileStatus(originalPath, this.referenceDir, error);
3735
if(error && this.exitOnError) {
3836
throw error;
@@ -57,4 +55,4 @@ module.exports = class AssetManager {
5755
actualPath = path.relative(referenceDir, actualPath);
5856
return this.manifest.set(originalPath, actualPath, targetDir);
5957
}
60-
};
58+
}

lib/manifest.js

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
"use strict";
1+
import { createFile } from "./util/files/index.js";
2+
import { resolvePath } from "./util/resolve.js";
3+
import { abort } from "./util/index.js";
4+
import path from "path";
25

3-
let createFile = require("./util/files");
4-
let resolvePath = require("./util/resolve");
5-
let { abort } = require("./util");
6-
let path = require("path");
7-
8-
module.exports = class Manifest {
6+
export class Manifest {
97
constructor(referenceDir, { target, key, value, baseURI, webRoot } = {}) {
108
if(value && (baseURI || webRoot)) {
119
abort("ERROR: `value` must not be used with `baseURI` and/or `webRoot`");
@@ -52,4 +50,4 @@ module.exports = class Manifest {
5250
return memo;
5351
}, {});
5452
}
55-
};
53+
}

lib/plugins.js

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
"use strict";
2-
3-
let { loadExtension, abort, repr } = require("./util");
1+
import { loadExtension, abort, repr } from "./util/index.js";
42

53
// common plugins included for convenience
64
let DEFAULTS = [{
@@ -22,15 +20,10 @@ let DEFAULT_KEYS = DEFAULTS.reduce((memo, plugin) => {
2220
}, new Set());
2321
let BUCKETS = new Set(["static", "scripts", "styles", "markup"]);
2422

25-
module.exports = {
26-
pluginsByBucket,
27-
_determinePlugins: determinePlugins
28-
};
29-
3023
// returns plugin functions grouped by bucket and filtered by relevance (based
3124
// on configuration)
32-
function pluginsByBucket(config, defaults) {
33-
let plugins = determinePlugins(config.plugins, defaults);
25+
export function pluginsByBucket(config, defaults) {
26+
let plugins = _determinePlugins(config.plugins, defaults);
3427
let buckets = [...BUCKETS].reduce((memo, bucket) => {
3528
memo[bucket] = [];
3629
return memo;
@@ -61,7 +54,7 @@ function pluginsByBucket(config, defaults) {
6154
// `plugins` is an array of plugins, each either a package identifier or a
6255
// `{ key, bucket, plugin }` object`, with `key` being the configuration key and
6356
// `plugin` being either a function or a package identifier
64-
function determinePlugins(plugins = [], defaults = DEFAULTS) {
57+
export function _determinePlugins(plugins = [], defaults = DEFAULTS) {
6558
if(!plugins.pop) { // for backwards compatibility
6659
plugins = modernize(plugins);
6760
}

lib/server.js

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
1-
let { loadExtension, abort, repr } = require("./util");
1+
import { loadExtension, abort, repr } from "./util/index.js";
22

33
let DEFAULTS = {
44
host: "localhost",
55
port: 3000
66
};
77

8-
exports.static = (config, webroot) => {
9-
let donny = loadExtension("donny", "failed to activate server");
10-
let [host, port] = parseHost(config);
8+
export async function liveServer(config, root) {
9+
let server = await loadExtension("live-server", "failed to activate live-server");
10+
let [host, port] = _parseHost(config);
11+
12+
server.start({ port, host, root, open: false });
13+
}
14+
15+
export async function staticServer(config, webroot) {
16+
let donny = await loadExtension("donny", "failed to activate server");
17+
let [host, port] = _parseHost(config);
1118

1219
donny({ port, bind: host, webroot }).
1320
then(() => {
1421
console.error(`serving ${repr(webroot)} at http://${host}:${port}`);
1522
});
16-
};
17-
18-
exports.live = (config, root) => {
19-
let liveServer = loadExtension("live-server", "failed to activate live-server");
20-
let [host, port] = parseHost(config);
21-
22-
liveServer.start({ port, host, root, open: false });
23-
};
24-
25-
exports._parseHost = parseHost;
23+
}
2624

27-
function parseHost(config) {
25+
export function _parseHost(config) {
2826
let { host, port } = DEFAULTS;
2927
if(config === true) {
3028
return [host, port];

lib/util/files/finder.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
1-
let fs = require("fs");
2-
let path = require("path");
3-
let { promisify } = require("util");
1+
import { readdir, stat } from "fs/promises";
2+
import path from "path";
43

5-
let stat = promisify(fs.stat);
6-
let readDir = promisify(fs.readdir);
7-
8-
module.exports = class FileFinder {
4+
export class FileFinder {
95
constructor(directory, { skipDotfiles, filter = () => true } = {}) {
106
this.directory = directory;
117
this.filter = filename => {
@@ -27,7 +23,7 @@ module.exports = class FileFinder {
2723
return filesWithinDirectory(this.directory, filepaths).
2824
then(filepaths => filepaths.filter(this.filter));
2925
}
30-
};
26+
}
3127

3228
function tree(filepath, referenceDir = filepath) {
3329
return stat(filepath).
@@ -36,7 +32,7 @@ function tree(filepath, referenceDir = filepath) {
3632
return [path.relative(referenceDir, filepath)];
3733
}
3834

39-
return readDir(filepath).
35+
return readdir(filepath).
4036
then(entries => {
4137
let res = Promise.all(entries.map(entry => {
4238
return tree(path.join(filepath, entry), referenceDir);

lib/util/files/index.js

Lines changed: 14 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,26 @@
1-
"use strict";
1+
import { writeFile } from "fs/promises";
2+
import { mkdirSync } from "fs";
3+
import path from "path";
24

3-
let { abort, repr } = require("../");
4-
let fs = require("fs");
5-
let path = require("path");
6-
let { promisify } = require("util");
7-
8-
let KNOWN = {}; // avoids redundant `mkdirp` invocations
9-
let LOCKS = {};
10-
11-
let writeFile = promisify(fs.writeFile);
5+
let KNOWN = new Set(); // avoids redundant `mkdir` invocations
6+
let LOCKS = new Map();
127

138
// avoids concurrent write operations and creates target directory if necessary
14-
module.exports = function createFile(filepath, contents) {
15-
let lock = LOCKS[filepath];
9+
export function createFile(filepath, contents) {
10+
let lock = LOCKS.get(filepath);
1611
if(lock) { // defer
17-
return lock.then(_ => createFile(filepath, contents));
12+
return lock.then(() => createFile(filepath, contents));
1813
}
1914

2015
// create directory if necessary
21-
if(!KNOWN[filepath]) {
22-
KNOWN[filepath] = true;
23-
// NB: `sync` avoids race condition for subsequent operations
24-
mkdirpSync(path.dirname(filepath));
16+
if(!KNOWN.has(filepath)) {
17+
KNOWN.add(filepath);
18+
mkdirSync(path.dirname(filepath), { recursive: true });
2519
}
2620

2721
let prom = writeFile(filepath, contents);
28-
LOCKS[filepath] = prom;
29-
return prom.then(_ => {
30-
delete LOCKS[filepath];
22+
LOCKS.set(filepath, prom);
23+
return prom.then(() => {
24+
LOCKS.delete(filepath);
3125
});
32-
};
33-
34-
function mkdirpSync(directory) {
35-
try {
36-
// NB: `recursive` option was introduced in Node v10.12.0
37-
fs.mkdirSync(directory, { recursive: true });
38-
} catch(err) {
39-
abort(`ERROR: auto-creating ${repr(directory)} requires ` +
40-
"Node v10.12.0 or above");
41-
}
4226
}

0 commit comments

Comments
 (0)