From 3fa2aebf4447c349e7a70eeed9736c2060236916 Mon Sep 17 00:00:00 2001 From: Marvin Hagemeister Date: Wed, 17 Mar 2021 23:35:04 +0100 Subject: [PATCH 1/3] Add colored namespaces to debug output --- .changeset/gorgeous-pants-brush.md | 5 ++ packages/wmr/package.json | 2 +- packages/wmr/src/lib/normalize-options.js | 3 + packages/wmr/src/lib/output-utils.js | 79 +++++++++++++++++++ .../wmr/src/lib/rollup-plugin-container.js | 15 +++- packages/wmr/src/plugins/aliases-plugin.js | 6 +- packages/wmr/src/plugins/bundle-plugin.js | 4 + yarn.lock | 8 +- 8 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 .changeset/gorgeous-pants-brush.md diff --git a/.changeset/gorgeous-pants-brush.md b/.changeset/gorgeous-pants-brush.md new file mode 100644 index 000000000..091a57ba8 --- /dev/null +++ b/.changeset/gorgeous-pants-brush.md @@ -0,0 +1,5 @@ +--- +'wmr': patch +--- + +Add colored namespaces to debug output when `DEBUG=true` is set. diff --git a/packages/wmr/package.json b/packages/wmr/package.json index 1512c9b74..b31bcf350 100644 --- a/packages/wmr/package.json +++ b/packages/wmr/package.json @@ -125,7 +125,7 @@ "husky": "^4.2.5", "jest": "^26.1.0", "jest-puppeteer": "^4.4.0", - "kolorist": "^1.2.7", + "kolorist": "^1.3.0", "lint-staged": "^10.2.11", "magic-string": "^0.25.7", "ncp": "^2.0.0", diff --git a/packages/wmr/src/lib/normalize-options.js b/packages/wmr/src/lib/normalize-options.js index 9e3b82b25..5a5c6b20c 100644 --- a/packages/wmr/src/lib/normalize-options.js +++ b/packages/wmr/src/lib/normalize-options.js @@ -3,6 +3,7 @@ import { promises as fs } from 'fs'; import url from 'url'; import { readEnvFiles } from './environment.js'; import { compileSingleModule } from './compile-single-module.js'; +import { debug } from './output-utils.js'; /** * @template {Options} T @@ -101,6 +102,8 @@ export async function normalizeOptions(options, mode) { if (custom[mode]) await custom[mode](options); } + debug('wmr:config')(options); + // @ts-ignore-next return options; } diff --git a/packages/wmr/src/lib/output-utils.js b/packages/wmr/src/lib/output-utils.js index 4e8c4a090..991f8b014 100644 --- a/packages/wmr/src/lib/output-utils.js +++ b/packages/wmr/src/lib/output-utils.js @@ -1,4 +1,6 @@ import * as kl from 'kolorist'; +import * as util from 'util'; +import { relative } from 'path'; /** @param {import('rollup').RollupOutput} bundle */ export function bundleStats(bundle) { @@ -85,3 +87,80 @@ export function codeFrame(code, loc) { } return frame; } + +// Taken from https://github.com/visionmedia/debug/blob/e47f96de3de5921584364b4ac91e2769d22a3b1f/src/node.js#L35 +// prettier-ignore +const colors = [ + 20, 21, 26, 27, 32, 33, 38, 39, 40, 41, 42, 43, 44, 45, 56, 57, 62, 63, 68, + 69, 74, 75, 76, 77, 78, 79, 80, 81, 92, 93, 98, 99, 112, 113, 128, 129, 134, + 135, 148, 149, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 178, 179, 184, 185, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 214, 215, 220, 221 +]; + +// Taken from: https://github.com/visionmedia/debug/blob/e47f96de3de5921584364b4ac91e2769d22a3b1f/src/common.js#L41-L50 +function selectColor(namespace) { + let hash = 0; + + for (let i = 0; i < namespace.length; i++) { + hash = (hash << 5) - hash + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return colors[Math.abs(hash) % colors.length]; +} + +/** + * Print namespaced log messages when the DEBUG environment + * variable is set. + * @param {string} namespace + * @param {number} [color] + * @returns {(...args: any[]) => void} + */ +export function debug(namespace, color = selectColor(namespace)) { + const ns = kl.ansi256(color)(` ${namespace} `); + return (...args) => { + if (process.env.DEBUG) { + const str = args.map(arg => { + const value = arg === null || typeof arg !== 'object' ? arg : util.inspect(arg, false, null, true); + + return value + .split('\n') + .map(line => ns + line) + .join('\n'); + }); + console.log.apply(console, str); + } + }; +} + +/** + * Serialize path to display special characters such as + * the null byte of necessary. + * @param {string} path + * @returns {string} + */ +export function formatPath(path) { + path = path || 'null'; + if (typeof path === 'object') { + path = path.id; + } + if (path.startsWith('\b') || path.startsWith('\0')) { + path = JSON.stringify(path); + } + if (path.startsWith(process.cwd())) { + path = relative(process.cwd(), path); + } + + return path; +} + +/** + * @param {string} from + * @param {import('rollup').ResolvedId | string | null} to + */ +export function formatResolved(from, to) { + from = formatPath(from); + to = formatPath(to); + return `${kl.cyan(from)} -> ${kl.dim(to)}`; +} diff --git a/packages/wmr/src/lib/rollup-plugin-container.js b/packages/wmr/src/lib/rollup-plugin-container.js index ad0d9856d..8aadcf874 100644 --- a/packages/wmr/src/lib/rollup-plugin-container.js +++ b/packages/wmr/src/lib/rollup-plugin-container.js @@ -2,8 +2,9 @@ import { resolve, relative, dirname, sep, posix } from 'path'; import { createHash } from 'crypto'; import { promises as fs } from 'fs'; import * as acorn from 'acorn'; -import acornClassFields from 'acorn-class-fields'; import * as kl from 'kolorist'; +import acornClassFields from 'acorn-class-fields'; +import { debug, formatResolved, formatPath } from './output-utils.js'; // Rollup respects "module", Node 14 doesn't. const cjsDefault = m => ('default' in m ? m.default : m); @@ -156,6 +157,10 @@ export function createPluginContainer(plugins, opts = {}) { } }; + const logResolve = debug('wmr:resolve'); + const logTransform = debug('wmr:transform'); + const logLoad = debug('wmr:load'); + const container = { ctx, @@ -221,6 +226,7 @@ export function createPluginContainer(plugins, opts = {}) { * @returns {Promise} */ async resolveId(id, importer, _skip) { + let originalId = id; const key = identifierPair(id, importer); const opts = {}; @@ -250,9 +256,7 @@ export function createPluginContainer(plugins, opts = {}) { Object.assign(opts, result); } - if (process.env.DEBUG) { - console.log(` ${kl.dim('plugin:') + kl.bold(kl.yellow(p.name))} ${JSON.stringify(id)}`); - } + logResolve(`${formatResolved(originalId, id)} [${p.name}]`); // resolveId() is hookFirst - first non-null result is returned. break; } @@ -270,6 +274,8 @@ export function createPluginContainer(plugins, opts = {}) { if (!plugin.transform) continue; const result = await plugin.transform.call(ctx, code, id); if (!result) continue; + + logTransform(`${kl.dim(formatPath(id))} [${plugin.name}]`); if (typeof result === 'object') { code = result.code; } else { @@ -288,6 +294,7 @@ export function createPluginContainer(plugins, opts = {}) { if (!plugin.load) continue; const result = await plugin.load.call(ctx, id); if (result) { + logLoad(`${formatPath(id)} [${plugin.name}]`); return result; } } diff --git a/packages/wmr/src/plugins/aliases-plugin.js b/packages/wmr/src/plugins/aliases-plugin.js index bd9b23258..1b9397a22 100644 --- a/packages/wmr/src/plugins/aliases-plugin.js +++ b/packages/wmr/src/plugins/aliases-plugin.js @@ -1,5 +1,6 @@ import { dirname, resolve } from 'path'; import { promises as fs } from 'fs'; +import { debug, formatResolved } from '../lib/output-utils.js'; /** * Package.json "aliases" field: {"a":"b"} @@ -9,6 +10,7 @@ import { promises as fs } from 'fs'; * @returns {import('rollup').Plugin} */ export default function aliasesPlugin({ aliases = {}, cwd } = {}) { + const log = debug('aliases'); let pkgFilename; let aliasesLoaded; async function fromPackageJson() { @@ -67,7 +69,9 @@ export default function aliasesPlugin({ aliases = {}, cwd } = {}) { if (aliased === id) return; // now allow other resolvers to handle the aliased version // (this is important since they may mark as external!) - return await this.resolve(aliased, importer, { skipSelf: true }); + const resolved = await this.resolve(aliased, importer, { skipSelf: true }); + log(formatResolved(id, resolved)); + return resolved; } }; } diff --git a/packages/wmr/src/plugins/bundle-plugin.js b/packages/wmr/src/plugins/bundle-plugin.js index 2a06e6cba..77d5762b9 100644 --- a/packages/wmr/src/plugins/bundle-plugin.js +++ b/packages/wmr/src/plugins/bundle-plugin.js @@ -1,4 +1,6 @@ import { relative } from 'path'; +import * as kl from 'kolorist'; +import { debug } from '../lib/output-utils.js'; /** * @param {object} [options] @@ -7,6 +9,7 @@ import { relative } from 'path'; * @returns {import('rollup').Plugin} */ export default function bundlePlugin({ cwd = '.', inline } = {}) { + const log = debug('bundle'); return { name: 'bundle-plugin', async resolveId(id, importer) { @@ -15,6 +18,7 @@ export default function bundlePlugin({ cwd = '.', inline } = {}) { if (resolved) { if (inline) { const url = '/' + relative(cwd, resolved.id).replace(/^\./, ''); + log(`[inline] ${kl.dim(url)}`); return { id: `data:text/javascript,export default${encodeURIComponent(JSON.stringify(url))}`, external: true diff --git a/yarn.lock b/yarn.lock index 79f28098a..5e85465d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5025,10 +5025,10 @@ kleur@^4.1.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== -kolorist@^1.2.7: - version "1.2.10" - resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.2.10.tgz#0f97a3f3a1dd75e980765c7cec8a1de258e580c6" - integrity sha512-S3QtGjCHyINclP4LSClgHw4gi/NxTFcSorqD9SWfrREHKtMyGfi6pyDCTbpQaqyZrMAjB4Exde8eco6kejkqQg== +kolorist@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.3.0.tgz#81345b3a15aaa5fa5f10159be72fd429dddd7321" + integrity sha512-8t4WbQ0FxMSJdWMDuvNhSRbxQiMAIN97CthZHtDpS9Zo8baG0nSvqTCCgcp4SKQdLD05LzWVYxWQyE2n820BfA== latest-version@^5.0.0: version "5.1.0" From 2024d8f858bde922f48c075753a5c4284678ee81 Mon Sep 17 00:00:00 2001 From: Marvin Hagemeister Date: Thu, 18 Mar 2021 15:10:26 +0100 Subject: [PATCH 2/3] Fix race condition in test assertions --- packages/wmr/test/fixtures.test.js | 19 ++++++++++++++----- packages/wmr/test/test-helpers.js | 19 ++++++++++++++++--- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/packages/wmr/test/fixtures.test.js b/packages/wmr/test/fixtures.test.js index c6d143c66..713b06249 100644 --- a/packages/wmr/test/fixtures.test.js +++ b/packages/wmr/test/fixtures.test.js @@ -1,6 +1,15 @@ import path from 'path'; import { promises as fs } from 'fs'; -import { setupTest, teardown, loadFixture, runWmrFast, getOutput, get } from './test-helpers.js'; +import { + setupTest, + teardown, + loadFixture, + runWmrFast, + getOutput, + get, + waitForMessage, + waitForNotMessage +} from './test-helpers.js'; import { rollup } from 'rollup'; import nodeBuiltinsPlugin from '../src/plugins/node-builtins-plugin.js'; @@ -64,28 +73,28 @@ describe('fixtures', () => { it('should print warning for missing index.html file in public dir', async () => { await loadFixture('empty', env); instance = await runWmrFast(env.tmp.path); - expect(instance.output.join('\n')).toMatch(`missing "index.html" file`); + await waitForMessage(instance.output, 'missing "index.html" file'); expect(await getOutput(env, instance)).toMatch(`Not Found`); }); it('should print warning for missing index.html file (no public dir)', async () => { await loadFixture('empty-nopublic', env); instance = await runWmrFast(env.tmp.path); - expect(instance.output.join('\n')).toMatch(`missing "index.html" file`); + await waitForMessage(instance.output, 'missing "index.html" file'); expect(await getOutput(env, instance)).toMatch(`Not Found`); }); it('should start successfully with only an HTML file in public dir', async () => { await loadFixture('htmlonly', env); instance = await runWmrFast(env.tmp.path); - expect(instance.output.join('\n')).not.toMatch(`missing an "index.html"`); + await waitForNotMessage(instance.output, `missing an "index.html"`); expect(await getOutput(env, instance)).toMatch(`

Hello wmr

`); }); it('should start successfully with only an HTML file (no public dir)', async () => { await loadFixture('htmlonly-nopublic', env); instance = await runWmrFast(env.tmp.path); - expect(instance.output.join('\n')).not.toMatch(`missing an "index.html"`); + await waitForNotMessage(instance.output, `missing an "index.html"`); expect(await getOutput(env, instance)).toMatch(`

Hello wmr

`); }); }); diff --git a/packages/wmr/test/test-helpers.js b/packages/wmr/test/test-helpers.js index 75f059df6..9ccd191fb 100644 --- a/packages/wmr/test/test-helpers.js +++ b/packages/wmr/test/test-helpers.js @@ -154,13 +154,13 @@ export async function waitFor(fn, timeout = 2000) { /** * @param {string[]} haystack * @param {string | RegExp} message - * @param {number} timeout + * @param {number} [timeout] * @returns {Promise} */ export async function waitForMessage(haystack, message, timeout = 5000) { const found = await waitFor(() => { if (typeof message === 'string') { - if (haystack.includes(message)) { + if (haystack.some(line => line.includes(message))) { return true; } } else { @@ -175,10 +175,23 @@ export async function waitForMessage(haystack, message, timeout = 5000) { }); if (!found) { - throw new Error(`Message ${message} didn't appear in ${timeout}ms`); + throw new Error(`Message ${message} didn't appear in ${timeout}ms\n\nActual output:\n\n${haystack.join('\n')}`); } } +/** + * @param {string[]} haystack + * @param {string | RegExp} message + * @param {number} [timeout] + * @returns {Promise} + */ +export async function waitForNotMessage(haystack, message, timeout = 1000) { + try { + await waitForMessage(haystack, message, timeout); + throw new Error(`Expected message to not be present: ${message}`); + } catch (err) {} +} + /** * @param {WmrInstance} instance * @param {string} urlPath From 1e8b01b5f3fbfa562186b2dda7386926ff18019d Mon Sep 17 00:00:00 2001 From: Marvin Hagemeister Date: Thu, 18 Mar 2021 15:21:59 +0100 Subject: [PATCH 3/3] Update kolorist to 1.3.2 (fixes windows issue) --- packages/wmr/package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/wmr/package.json b/packages/wmr/package.json index b31bcf350..c26bf2759 100644 --- a/packages/wmr/package.json +++ b/packages/wmr/package.json @@ -125,7 +125,7 @@ "husky": "^4.2.5", "jest": "^26.1.0", "jest-puppeteer": "^4.4.0", - "kolorist": "^1.3.0", + "kolorist": "^1.3.2", "lint-staged": "^10.2.11", "magic-string": "^0.25.7", "ncp": "^2.0.0", diff --git a/yarn.lock b/yarn.lock index 5e85465d4..173fb2afb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5025,10 +5025,10 @@ kleur@^4.1.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== -kolorist@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.3.0.tgz#81345b3a15aaa5fa5f10159be72fd429dddd7321" - integrity sha512-8t4WbQ0FxMSJdWMDuvNhSRbxQiMAIN97CthZHtDpS9Zo8baG0nSvqTCCgcp4SKQdLD05LzWVYxWQyE2n820BfA== +kolorist@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.3.2.tgz#3d939b3b2e42e7cf9b2ac1f385c33041cfe42207" + integrity sha512-0AABCl2usZg6CptLfHW4N3ZhGUT6vgHO6CtBOsRJKQGgvhKRWryUtXGfADLpK2XxbLh/VOXFX7EluitkSgP/eA== latest-version@^5.0.0: version "5.1.0"