-
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): use rollup to build lighthouse-core bundles #12771
Conversation
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.
My initial impression is that there appear to be several more gotchas and issues with global scope than with our browserify system today.
I'm definitely a bit nervous since we typically don't discover bundled specific bugs until after LH makes its way to DevTools + PSI. The importance of our bundled smokes will be much greater after this :)
build/build-bundle.js
Outdated
const nodePolyfills = rollupPluginTypeCoerce(require('rollup-plugin-node-polyfills')); | ||
const nodeResolve = rollupPluginTypeCoerce(require('rollup-plugin-node-resolve')); | ||
const replace = rollupPluginTypeCoerce(require('rollup-plugin-replace')); | ||
// @ts-expect-error: no types |
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.
psh, what a loser maintainer 😄
json(), | ||
nodeResolve({preferBuiltins: true}), | ||
nodePolyfills(), | ||
// Rollup sees the usages of these functions in page functions (ex: see AnchorElements) |
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.
yikes, this is going to be really annoying to remember. maybe we should tweak our evaluate
API to support a keyed-object so we don't have to think about it?
or better yet always force deps to be function parameters? there are just too many gotchas these days with the .toString
name reliance
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'm for it. link should do the trick.
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.
IMO if we're going to keep the magically-interspersed Node and evaluate()
browser code (which #10816 was a culmination of us deciding it was a lot nicer to go that way) we should embrace explicit import of functions and not require everything to live in page-functions
(a lot of times it's a lot nicer just to have support functions defined locally).
This would allow type checking of functions we currently @ts-expect-error
and make evaluated code more robust all without added ceremony. The downside is minifiers are still kind of dumb about keeping consistent minified functions names across modules even after bundling, but there are ways around that or we could just live with somewhat worse minification.
I have an old branch for this I can put up for discussion since I know there's a variety of opinions on each of these points :)
edit: up at #12795
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.
(...expanding on the fact that custom page functions outside page-functions.js exists ...)
My linked idea (having a pageFunctions
namespace) can support custom functions like this:
const pageFunctions = {
...require('../../lib/page-functions.js'),
myFnDeclaredHere,
};
function myFnDeclaredHere() { }
// ...
function getMetaElements() {
return pageFunctions.getElementsInDocument('head meta').map(el => {
const meta = /** @type {HTMLMetaElement} */ (el);
pageFunctions.myFnDeclaredHere(); // also i exist.
return {
name: meta.name.toLowerCase(),
content: meta.content,
property: meta.attributes.property ? meta.attributes.property.value : undefined,
httpEquiv: meta.httpEquiv ? meta.httpEquiv.toLowerCase() : undefined,
charset: meta.attributes.charset ? meta.attributes.charset.value : undefined,
};
});
}
const code = pageFunctions.createEvalCode(getMetaElements, {
deps: [
pageFunctions.getElementsInDocument,
pageFunctions.myFnDeclaredHere,
],
});
// `pageFunctions.createEvalCode` would inject a var `pageFunctions` with all values passed to deps, using the `.name` as keys
in theory (plus removing the *String
usages), that should keep the mangled names the same
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.
#12795 has not been resolved–is this blocking for this PR?
build/rollup-brfs.js
Outdated
const src = new Readable(); | ||
src.push(code); | ||
src.push(null); | ||
const stream = src.pipe(brfs(id, options)); |
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.
aw, look who's pipe
ing now :)
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.
don't be fooled, i copy/pasted this.
build/rollup-postprocess.js
Outdated
let token; | ||
while (token = find.exec(code)) { | ||
let value; | ||
if (typeof replace === 'function') { |
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.
seems like we're not using all of these features? was this copied from somewhere or did you need them in a previous version?
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 copy/pasted it. I'll add a link to the original source.
Computing artifact: LanternMaxPotentialFID | ||
Auditing: Cumulative Layout Shift | ||
Computing artifact: CumulativeLayoutShift | ||
Computing artifact: CumulativeLayoutShift$1 |
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.
was this fixed already?
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 computed artifacts the exact name doesn't matter, so I didn't bother. only impacts the log message https://github.com/GoogleChrome/lighthouse/blob/f90efbf/lighthouse-core/computed/computed-artifact.js#L30 . Could do the same name trimming here if you like.
|
build/build-bundle.js
Outdated
if (isDevtools(entryPath)) { | ||
const localeKeys = Object.keys(require('../shared/localization/locales.js')); | ||
/** @type {Record<string, {}>} */ | ||
const localesShim = {}; | ||
for (const key of localeKeys) localesShim[key] = {}; | ||
shimsObj['./locales.js'] = `export default ${JSON.stringify(localesShim)}`; | ||
} |
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 looks like there's some stuff that might need another pass to make sure it'll work ok. We don't want to include the locales in the dt bundle like this, for instance
Tried it out in LR, oddly I get |
Computing artifact: PageDependencyGraph | ||
Computing artifact: LoadSimulator | ||
Computing artifact: NetworkAnalysis | ||
Computing artifact: FirstContentfulPaint$3 |
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.
whats up with these dolla bills?
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.
ref #12689
Motivation: we need a build system that supports ES modules
Upfront: an alternative to this is to introduce Babel to our Browserify pipeline. However, not only would we then have babel, we'd also still have Browserify.
build-bundle.js
Dynamic modules
This is probably the most complex bit
Since Rollup's whole concept doesn't support dynamic modules (it does not create a module system like Browserify bundling commonjs does; instead everything goes into one scope and module exports/imports are transformed into local scope references), we need a workaround for our config/audit/gatherer loading (
config-helpers.js
).The solution is to replace dynamic
require
calls withrequireWrapper
, which will first look in a map ofstring -> module
for a match before falling back to the realrequire
.When not bundled, the map is empty, and this just defers to
require
.In the Rollup config,
rollup-plugin-replace
is used to replace* BUILD_REPLACE_BUNDLED_MODULES */
with some programmatically code. Rollup treats this the same as if we wrote it in the original source file. The result is that bundled code will load dynamic modules from this map. It will still fallback torequire
if not found, which will throw an Error (no change in behavior there).Resultant code:
Aliases
A couple of modules don't play nice with
rollup-plugin-commonjs
:debug
andurl
.For
debug
, I suspect the issue is the very complex entry module that jumps through a dozen hoops to setmodule.exports
.For
url
, IIRC the issue was something like Rollup was creatingURL
when we neededUrl
(or maybe vice verse). I sidestepped the issue by just directly aliasingurl
tolighthouse-core/lib/url-shim.js
. I don't quite recall whyurl
is being included in the bundle...Shims
To ignore a module,
rollup-plugin-shim
(made w/ <3 by an amazing developer) can be used to replace the text of the module withexport default {};
There was an issue with how Rollup resolved
lighthouse
within the pubads code–it was usingAudit
(to extend from) way before being defined. My hunch is that Rollup treatedlighthouse-core/index.js
as different fromlighthouse
in pubads (akanode_modules/lighthouse-plugin-publisher-ads/node_modules/lighthouse/...
), even though it is yarn linked. It was resolved by shimminglighthouse
with code that just re-exportsAudit
.brfs
there is a rollup plugin for
brfs
but it is used a deprecated rollup api. I had to copy the code, un-TS it, and update the api hook it used.brfs uses an old acorn that doesn't know esmodules, which means it must run before the commonjs plugin turns modules to esm. so ... even with all this work we are still blocked from using esmodules in our source code, although a single plugin is a much smaller roadblock. I didn't put any effort into figuring our workarounds for this (replacing brfs / updating brfs's parser).
EDIT: #13231 has fixed this part