Optimize initializer script#4233
Conversation
**Why**: It's expected to be a standalone script. Bundler adds overhead in compiled output.
mejiaj
left a comment
There was a problem hiding this comment.
Great work, thanks for this!
Added some comments and will let the team chime in with their thoughts.
| const source = require("vinyl-source-stream"); | ||
| const sourcemaps = require("gulp-sourcemaps"); | ||
| const uglify = require("gulp-uglify"); | ||
| const babel = require("gulp-babel"); |
There was a problem hiding this comment.
Some concerns about including gulp-babel since we're trying to get away from dependencies that don't update regularly.
Looking at their github, the last release was a year ago.
There was a problem hiding this comment.
Some concerns about including
gulp-babelsince we're trying to get away from dependencies that don't update regularly.Looking at their github, the last release was a year ago.
gulp-babel doesn't really do a whole lot, since it delegates most of the work to the underlying @babel/core peer dependency. The way I see it, a main risk for it becoming outdated would be if it keeps up with a future 8.0.0 release (since it's pinned to ^7.0.0).
Since gulp works with plain Node streams, it could be substituted with a stream. Babel doesn't come with a stream-based API, but we could emulate one with a little wrapper:
diff --git a/config/gulp/javascript.js b/config/gulp/javascript.js
index b549fc027..8edb6ce99 100644
--- a/config/gulp/javascript.js
+++ b/config/gulp/javascript.js
@@ -1,2 +1,3 @@
/* eslint-disable arrow-body-style */
+const { Transform } = require("stream");
const buffer = require("vinyl-buffer");
@@ -11,3 +12,3 @@ const sourcemaps = require("gulp-sourcemaps");
const uglify = require("gulp-uglify");
-const babel = require("gulp-babel");
+const babel = require("@babel/core");
const merge = require("merge-stream");
@@ -32,3 +33,17 @@ gulp.task(task, () => {
stream
- .pipe(babel({ presets: ["@babel/preset-env"] }))
+ .pipe(
+ new Transform({
+ objectMode: true,
+ async transform(file, _encoding, callback) {
+ const { code } = await babel.transformAsync(
+ file.contents.toString(),
+ { presets: ["@babel/preset-env"] }
+ );
+ // eslint-disable-next-line no-param-reassign
+ file.contents = Buffer.from(code);
+ this.push(file);
+ callback();
+ },
+ })
+ )
.pipe(rename({ basename }))This is basically a reimplementation of what gulp-babel does anyways.
Another option: We could write the uswds-init.js in ES5-safe JavaScript, then skip Babel for that file altogether, then revert back to babelify for the remaining entrypoint.
| revertClass(); | ||
| document.removeEventListener("load", verifyLoaded, true); | ||
| } | ||
| } |
Description
Optimizes initializer script load and runtime performance, reducing size by 55%, from 869 bytes (520 bytes gzipped) to 362 bytes (231 bytes gzipped), and avoiding delays in removing the document loading class.
Additional information
The intended optimizations here are to:
uswdsPresentwill be assigned as a result of loading the USWDS script, we can monitor forloadevents on page assets (images, scripts, styles, etc) to respond to this immediately. This avoids any delays that could happen if the script finishes loading between the 100ms polling that exists today, and may be less intensive overall especially for slow page loads, where the code only runs for each asset load and not every 100ms regardless.A few additional ideas were explored for more size savings, but not included here. Since
revertClassis safely idempotent, and since mostloadevents would happen only at the start of a page session, we could also consider to:revertClasswould be a noop after the fallback delay if the class had already been removed previouslyrevertClassto be called for everyloadevent afteruswdsPresentis assigned, but similar to the above note, each of these would be a noop anyways.document.addEventListener("load",function(){document.documentElement.classList.toggle("usa-js-loading",!window.uswdsPresent)},!0);Before you hit Submit, make sure you’ve done whichever of these applies to you:
npm testand make sure the tests for the files you have changed have passed.