-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cli: convert to ES modules #13045
cli: convert to ES modules #13045
Conversation
@@ -65,9 +68,18 @@ async function begin() { | |||
if (cliFlags.configPath) { | |||
// Resolve the config file path relative to where cli was called. | |||
cliFlags.configPath = path.resolve(process.cwd(), cliFlags.configPath); | |||
configJson = require(cliFlags.configPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of note.
if (rawTestDefns) { | ||
// Support commonjs. | ||
rawTestDefns = rawTestDefns.default || rawTestDefns; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
of note
wut. so... |
There's some pretty major stuff going on in here, can this be split up? Even if a lot of it is pretty straightforward, it would be nice to consider |
const getFlags = require('../../cli-flags.js').getFlags; | ||
|
||
import {strict as assert} from 'assert'; | ||
import fs from 'fs'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to be consistent with import fs from 'fs'
or import * as fs from 'fs
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fs
is commonjs and so has no default export, so the entire module (aka * as fs
) is treated as the default.
I have no idea which to go with, my first thought is leaning towards using the default import style.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import fs from 'fs'
is my preferred version by far
lighthouse-cli/test/smokehouse/test-definitions/issues/expectations.js
Outdated
Show resolved
Hide resolved
// Map plugin name to fixture since not actually installed in node_modules/. | ||
jest.mock('lighthouse-plugin-simple', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how does this work without this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
somehow require.resolve('lighthouse-plugin-simple')
resolves to /Users/cjamcl/src/lighthouse/lighthouse-core/test/fixtures/config-plugins/lighthouse-plugin-simple/plugin-simple.js
here. Not sure how the module is registered... the plugin-simple.js
bit at least is explained by that folder's package.json
main
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so weird, works here too. This completely goes against what I thought I knew about how resolve works :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just checked from master too, same there. this mock isn't needed for some reason unrelated to this PR. weeeeird
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't help but here:
{
moduleIdentifier: 'lighthouse-plugin-simple',
configDir: undefined,
category: 'plugin',
'require.resolve(moduleIdentifier)': '/Users/cjamcl/src/lighthouse/lighthouse-core/test/fixtures/config-plugins/lighthouse-plugin-simple/plugin-simple.js',
'require.resolve.paths(moduleIdentifier)': [
'/Users/cjamcl/src/lighthouse/lighthouse-core/config/node_modules',
'/Users/cjamcl/src/lighthouse/lighthouse-core/node_modules',
'/Users/cjamcl/src/lighthouse/node_modules',
'/Users/cjamcl/src/node_modules',
'/Users/cjamcl/node_modules',
'/Users/node_modules',
'/node_modules'
]
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK so it 100% fails when using the CLI directly (node lighthouse-cli https://www.example.com --plugins=lighthouse-plugin-simple
), so this must be a jest side effect. (--experimental-vm-modules
made no difference)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
didn't find much documentation on it, but looks like yeah, jest
walks through your project and automatically finds all the package.json
files. jest-resolve
has a ModuleMap, which internally had a _raw.map
, which looked like:
'gulp-lighthouse-recipe' => 'docs/recipes/gulp/package.json'
'custom-lighthouse-recipe' => 'docs/recipes/custom-audit/package.json'
'custom-lighthouse-pptr-recipe' => 'docs/recipes/custom-gatherer-puppeteer/package.json'
'lighthouse-plugin-example' => 'docs/recipes/lighthouse-plugin-example/package.json'
'lighthouse-logger' => 'lighthouse-logger/package.json'
'lighthouse' => 'package.json'
'lighthouse-plugin-config' => 'lighthouse-core/test/fixtures/config/lighthouse-plugin-config-helper/package.json'
'lighthouse-plugin-no-groups' => 'lighthouse-core/test/fixtures/config-plugins/lighthouse-plugin-no-groups/package.json'
'lighthouse-plugin-no-category' => 'lighthouse-core/test/fixtures/config-plugins/lighthouse-plugin-no-category/package.json'
'lighthouse-plugin-simple' => 'lighthouse-core/test/fixtures/config-plugins/lighthouse-plugin-simple/package.json'
'legacy-javascript' => 'lighthouse-core/scripts/legacy-javascript/package.json'
could be their haste modules, which apparently are "package.json
files outside of node_modules
folders anywhere in the file system". I didn't verify that's the path triggering this but close enough :)
Maybe worth leaving a comment that jest automatically resolves the '--plugins=lighthouse-plugin-simple'
flag to the correct location?
if (cliFlags.configPath.endsWith('.json')) { | ||
configJson = JSON.parse(fs.readFileSync(cliFlags.configPath, 'utf-8')); | ||
} else { | ||
const configModuleUrl = url.pathToFileURL(cliFlags.configPath).href; | ||
configJson = (await import(configModuleUrl)).default; | ||
} | ||
} else if (cliFlags.preset) { | ||
configJson = require(`../lighthouse-core/config/${cliFlags.preset}-config.js`); | ||
configJson = (await import(`../lighthouse-core/config/${cliFlags.preset}-config.js`)).default; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this seems like a place where a createRequire
would be justified. Pretty awkward without it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't that fail for es modules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh yeah, good point :(
lighthouse-cli/bin.js
Outdated
module.exports = { | ||
begin, | ||
export { | ||
begin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not an emergency, but it feels like we probably want
'comma-dangle': [2, {
imports: 'always-multiline',
exports: 'always-multiline',
}]
seems weird not to have one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agreed, will put up a separate PR
const y = manualArgv ? | ||
// @ts-expect-error - undocumented, but yargs() supports parsing a single `string`. | ||
yargs(manualArgv) : | ||
yargs(yargsHelpers.hideBin(process.argv)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the change? Seems way worse than having yargs
handle it :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh. at one point I may have tried updating yargs and found this to be necessary. I can probably revert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm... not sure what changed, as there is no yargs upgrade, but the old code results in this error:
TypeError: y.help is not a function
at getFlags (file:///Users/cjamcl/src/lighthouse/lighthouse-cli/cli-flags.js:28:18)
at begin (file:///Users/cjamcl/src/lighthouse/lighthouse-cli/bin.js:53:20)
at file:///Users/cjamcl/src/lighthouse/lighthouse-cli/index.js:11:1
at ModuleJob.run (internal/modules/esm/module_job.js:152:23)
at async Loader.import (internal/modules/esm/loader.js:177:24)
at async Object.loadESM (internal/process/esm_loader.js:68:5)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm... not sure what changed, as there is no yargs upgrade, but the old code results in this error:
must be some change to the esmodules export. Here's a similar case: yargs/yargs#1774
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shurg. this is exactly what their demo code does https://github.com/yargs/yargs#esm
tweaking the import to be *
creates type errors.
listAudits, | ||
listTraceCategories, | ||
}; | ||
export {listAudits} from './list-audits.js'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
complete nit, but not sure about this style. Maybe re-exporting is awkward no matter what, but I do like the explicitness of the other way
const y = manualArgv ? | ||
// @ts-expect-error - undocumented, but yargs() supports parsing a single `string`. | ||
yargs(manualArgv) : | ||
yargs(yargsHelpers.hideBin(process.argv)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm... not sure what changed, as there is no yargs upgrade, but the old code results in this error:
must be some change to the esmodules export. Here's a similar case: yargs/yargs#1774
lighthouse-cli/run.js
Outdated
@@ -7,22 +7,22 @@ | |||
|
|||
/* eslint-disable no-console */ | |||
|
|||
const path = require('path'); | |||
const psList = require('ps-list'); | |||
/** @typedef {Error & {code: string, friendlyMessage?: string}} ExitError */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what did you think about my typedef
after imports thing from #13046 (comment)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer local types at the top of the file, but not enough to discuss it much. I'm reverting the changes that were just moving things around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ha, damn, I thought I had convinced you, but oh well :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the short of it is that exactly what is being imported isn't too informing (and sometimes the import list is so long you glaze over all of it like it's a Java file); but the types are quite useful as to the data structures involved in the file. so for the same reason that fileoverview would be at top, I like local types to be too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For all the same reasons I think they should be closer to the code that uses them :) Definitions, just in the type domain instead of the value domain, so should be right next to the value definitions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just the last dangling comma and typedef style questions, but looks good! A very smooth transition
ref #12689
jest.unstable_mockModule
(only cli test that uses mocks isbin-test.js
).(split off into: #13046)