-
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
misc(build): bundle pub ads plugin for devtools #9924
Conversation
// HACK: manually include the lighthouse-plugin-publisher-ads audits. | ||
/** @type {Array<string>} */ | ||
// @ts-ignore | ||
const pubAdsAudits = require('lighthouse-plugin-publisher-ads/plugin.js').audits.map(a => a.path); |
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.
or whatever is a good way to get this list...readdir doesn't work cause there's more than just the audits in that directory
build/build-bundle.js
Outdated
@@ -83,6 +88,7 @@ async function browserifyFile(entryPath, distPath) { | |||
} | |||
|
|||
// Expose the audits, gatherers, and computed artifacts so they can be dynamically loaded. | |||
// Exposed path relative to lighthouse-core/config/config-helpers.js (where loading occurs). |
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.
important information, passed down over generations of build revisions, but only implicitly specified :)
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.
// Exposed path relative to lighthouse-core/config/config-helpers.js (where loading occurs). | |
// Exposed path MUST be a relative path from lighthouse-core/config/config-helpers.js (where loading occurs). |
doesn't have to be spec style like this but I didn't totally understand this until rereading all the code to see what it did, any complete sentence might've helped :)
requirePath = resolveModule(audit.path, configDir, 'audit'); | ||
const absolutePath = resolveModule(audit.path, configDir, 'audit'); | ||
// Use a relative path so bundler can easily expose it. | ||
requirePath = path.relative(__dirname, absolutePath); |
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.
needs to be relative, otherwise we'd need to be browserify exposing an absolute path
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 don't totally understand the comment and this line. Isn't the bundler exposing the pub audits by manually requiring in its config file?
It seems like this path of requireAudits is only hit when we're requiring in the audits as we execute the bundle where we're in brfs land and don't have real dirnames anymore. Is that right?
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.
It seems like this path of requireAudits is only hit when we're requiring in the audits as we execute the bundle where we're in brfs land and don't have real dirnames anymore. Is that right?
right. Internal to the bundle they have some module name that can be required. Since they're required dynamically, the name they're exposed as has to be figured out at runtime, and the easiest way to do that is to use the same name that is passed to require()
in non-browserified execution. The existing code was doing that with an absolute path here, and even though we could expose the modules with the same absolute path in build-bundle
, those are going to be different based on what machine it's run on, etc. Hence using a relative path here, which also works non-browserified.
It's basically the dynamic require.resolve()
equivalent of the ../audits/${audit.path}
for the core audits a few lines above this.
package.json
Outdated
@@ -119,6 +119,8 @@ | |||
"isomorphic-fetch": "^2.2.1", | |||
"jest": "^24.3.0", | |||
"jsdom": "^12.2.0", | |||
"lighthouse-plugin-publisher-ads": "./node_modules/lighthouse-plugin-publisher-ads-wrapper/lighthouse-plugin-publisher-ads/", | |||
"lighthouse-plugin-publisher-ads-wrapper": "https://github.com/googleads/publisher-ads-lighthouse-plugin", |
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.
it would be really helpful if lighthouse-plugin-publisher-ads
was published on npm so we didn't have to add the wrapper from github and then add the plugin with a relative path into the wrapper module :)
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.
yarn
errors for me:
error Package "lighthouse-plugin-publisher-ads" refers to a non-existing file '"/usr/local/google/home/cjamcl/code/lighthouse/node_modules/lighthouse-plugin-publisher-ads-wrapper/lighthouse-plugin-publisher-ads"'.
I assume this only worked for you because you initially had lighthouse-plugin-publisher-ads-wrapper
installed before adding the other 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.
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.
yarn errors for me
Yeah, we'll get it published before landing. Too bad the hack isn't reproducible from package.json though.
clients/devtools-entry.js
Outdated
@@ -14,13 +14,15 @@ const {registerLocaleData, lookupLocale} = require('../lighthouse-core/lib/i18n/ | |||
|
|||
/** | |||
* Return a version of the default config, filtered to only run the specified | |||
* categories. | |||
* categories. Exclude `lighthouse-plugin-publisher-ads` to not include the |
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 pub ads runs even if categoryIDs
doesn't include the plugin category?
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'll reword that to be less confusing :) it's trying to say it's the same as the others... It'll run if it's in categoryIDs, otherwise no
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.
+1 to a reword :)
we should also add a test for the onlyCategories
/plugins
interaction, it seems non-obvious to me what the behavior should be I never really thought about it.
Let me know when this is quite working and I can verify it works from the Audits panel (assuming you're not setup to verify that?) |
SG. Feel free to poke at the browserify error, otherwise I probably won't be getting to this until tomorrow. |
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.
Error: unsupported type for static module: LogicalExpression
at expression:
opts.fs || fs
while parsing file: /usr/local/google/home/cjamcl/code/lighthouse/node_modules/mkdirp/index.js while parsing file: /usr/local/google/home/cjamcl/code/lighthouse/node_modules/mkdirp/index.js
This means that there is some code that defines a module using a logical expression. (not determinable until runtime). See mkdirp.
A dirty workaround is to ignore this module.
.ignore('mkdirp')
Doing so reveals a couple transitive modules that are pulled in by ws
. Obviously, that shouldn't be browserified so let's ignore that too.
.ignore('ws')
Rather than ignore these modules explicitly, we should understand why they get used now. It's clearly due to one of the pub ad audit modules. I narrowed it down to:
const {Audit} = require('lighthouse');
This breaks everything.
const Audit = require('lighthouse/lighthouse-core/audits/audit.js');
That seems to work.
why: The wrapper
module has lighthouse
as a direct dependency. our bundle script ignore the cri.js
but via a very specific path that only matches our actual (non node_modules) cri.js
. The fix above works because lighthouse/lighthouse-core/audits/audit.js
doesn't include cri.js
, but lighthouse
does.
@paulirish link
works because it allows our cri.js ignoring to work (doesn't use vendored lighthouse).
package.json
Outdated
@@ -119,6 +119,8 @@ | |||
"isomorphic-fetch": "^2.2.1", | |||
"jest": "^24.3.0", | |||
"jsdom": "^12.2.0", | |||
"lighthouse-plugin-publisher-ads": "./node_modules/lighthouse-plugin-publisher-ads-wrapper/lighthouse-plugin-publisher-ads/", | |||
"lighthouse-plugin-publisher-ads-wrapper": "https://github.com/googleads/publisher-ads-lighthouse-plugin", |
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.
yarn
errors for me:
error Package "lighthouse-plugin-publisher-ads" refers to a non-existing file '"/usr/local/google/home/cjamcl/code/lighthouse/node_modules/lighthouse-plugin-publisher-ads-wrapper/lighthouse-plugin-publisher-ads"'.
I assume this only worked for you because you initially had lighthouse-plugin-publisher-ads-wrapper
installed before adding the other one.
Yes, that was the implicit request :P
Ah, nice find! Yeah, that would do it. I guess we'll need the plugin to reach in more directly. |
build/build-bundle.js
Outdated
@@ -83,6 +88,7 @@ async function browserifyFile(entryPath, distPath) { | |||
} | |||
|
|||
// Expose the audits, gatherers, and computed artifacts so they can be dynamically loaded. | |||
// Exposed path relative to lighthouse-core/config/config-helpers.js (where loading occurs). |
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.
// Exposed path relative to lighthouse-core/config/config-helpers.js (where loading occurs). | |
// Exposed path MUST be a relative path from lighthouse-core/config/config-helpers.js (where loading occurs). |
doesn't have to be spec style like this but I didn't totally understand this until rereading all the code to see what it did, any complete sentence might've helped :)
@@ -92,6 +98,13 @@ async function browserifyFile(entryPath, distPath) { | |||
bundle = bundle.require(gatherer, {expose: gatherer.replace(driverPath, '../gather/')}); | |||
}); | |||
|
|||
// HACK: manually include the lighthouse-plugin-publisher-ads audits. | |||
if (isDevtools(entryPath)) { |
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.
kinda feels like we should resolve those functions to booleans called isDevtools
and call the functions isDevtoolsEntry
or something
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.
kinda feels like we should resolve those functions to booleans called
isDevtools
and call the functionsisDevtoolsEntry
or something
yeah, I had a similar thought. Not sure why they're like that...I assume it made sense as a one-off and we've just c/p it multiple times now
build/build-bundle.js
Outdated
// HACK: manually include the lighthouse-plugin-publisher-ads audits. | ||
if (isDevtools(entryPath)) { | ||
pubAdsAudits.forEach(pubAdAudit => { | ||
bundle = bundle.require(pubAdAudit, {expose: '../../node_modules/' + pubAdAudit}); |
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.
add a note that all the audits are already prefixed with the module/plugin name?
requirePath = resolveModule(audit.path, configDir, 'audit'); | ||
const absolutePath = resolveModule(audit.path, configDir, 'audit'); | ||
// Use a relative path so bundler can easily expose it. | ||
requirePath = path.relative(__dirname, absolutePath); |
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 don't totally understand the comment and this line. Isn't the bundler exposing the pub audits by manually requiring in its config file?
It seems like this path of requireAudits is only hit when we're requiring in the audits as we execute the bundle where we're in brfs land and don't have real dirnames anymore. Is that right?
# i tried this in the repo root
yarn link
yarn link lighthouse after that |
My review was edited with the root cause of the bundling issue and a workaround. |
I haven't done the bundle analysis yet, but that sounds like what we might want then (we don't want duplicate lighthouse files in our bundle). But there's a way more evil way of doing this :)
🔥 😈 😈 😈 🔥 |
seems good. |
b7fee07
to
082715b
Compare
This appears to be working and the bundle looks good. It does currently require a
in the base directory to get a symlink ( @connorjclark should be good to try out and we can work on build ergonomics. |
It might actually need a few more dynamically included files... Maybe plugin.js for the plugin config? I can add that |
This is basically all that's required to get a hard-coded plugin into one of our bundles. Not quite working yet...browserify is having an issue with walking and parsing transitive dependencies that I haven't resolved yet.
(+ #9936 )