Skip to content
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

perf: build browser bundles at build-time #922

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

KuznetsovRoman
Copy link
Member

@KuznetsovRoman KuznetsovRoman commented May 8, 2024

What is done

  • Build 2 browser bundles at build-time, instead of building them in runtime.
  • Moved 3 dependencies to devDeps, as they are not used anywhere else.
  • clientBridge.build now only reads one of these two bundles, without obligation to bundle them.

Benchmark

Setup

  • browser: local chrome
  • protocol: devtools
  • plugins: html-reporter, test-repeater (60 retries, when turned on)
  • isolation: disabled
  • test: empty

Before

First test

2500ms per test body on average

Screenshot

Other tests

200ms per test body on average

Screenshot

After

First test

1900ms per test body on average

Screenshot

Other tests

40ms per test body on average

Screenshot

"build": "tsc --build && npm run copy-static && npm run build-bundle -- --minify",
"build-bundle": "esbuild ./src/bundle/index.ts --outdir=./build/src/bundle --bundle --format=cjs --platform=node --target=ES2021",
"copy-static": "copyfiles 'src/browser/client-scripts/*' build",
"build": "tsc --build && npm run build-bundles",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed "copy-static" build, replaced "npm run build-bundle" with "npm run build-bundles".
"npm run build-bundles" also builds browser bundle

"copy-static": "copyfiles 'src/browser/client-scripts/*' build",
"build": "tsc --build && npm run build-bundles",
"build-node-bundle": "esbuild ./src/bundle/index.ts --outdir=./build/src/bundle --bundle --format=cjs --platform=node --target=ES2021",
"build-browser-bundle": "node ./src/browser/client-scripts/build.js",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also tried to use browserify CLI, but it does not seem to support nested objects as transform params


const lib = opts.calibration && opts.calibration.needsCompatLib ? "./lib.compat.js" : "./lib.native.js";
const ignoreAreas = opts.supportDeprecated ? "./ignore-areas.deprecated.js" : "./ignore-areas.js";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

opts.supportDeprecated seems like a dead code. Haven't found any mentions about "supportDeprecated" anywhere else

"uglifyify",
);
const scriptFileName = needsCompatLib ? "bundle.compat.js" : "bundle.js";
const scriptFilePath = path.join(__dirname, "..", "client-scripts", scriptFileName);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read already-bundled code instead of bundling it here

assert.calledWith(writeFileStub, path.join(targetDir, "bundle.compat.js"), sinon.match(Buffer));
};

it("should build bundles for compat and native library", async function () {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use one test for two cases because "browserify" is slow, and i dont want to stub it.

@KuznetsovRoman KuznetsovRoman force-pushed the TESTPLANE-16.browserify branch 4 times, most recently from 815fc7e to 4adf8a3 Compare May 8, 2024 14:47
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff consists of marking nested deps as "dev only" and some @types packages

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved this one out of "client-scripts" folder, as now "client-scripts" don't exist in "build" ("build" directory would only have "bundle.js" and "bundle.compat.js" files)

But this one is needed for "calibrator", and it is not a part of client-scripts bundle


return ClientBridge.create(browser, scripts);
});
exports.build = async (browser, opts = {}) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to rewrite this file to typescript, but a lot of testing files depend on ability to mock this "build" method and we won't be able to do that with esm exports

Comment on lines +7 to +12
/**
* @param {object} opts
* @param {boolean} opts.needsCompatLib
* @returns {Promise<Buffer>}
*/
const bundleScript = async opts => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am using plain JS with JSDoc instead of ts-node because ts-node is very slow, and it takes twice as more time to launch than running this script itself:

time ./node_modules/.bin/ts-node -e ""
./node_modules/.bin/ts-node -e ""  3.76s user 0.26s system 143% cpu 2.803 total
time node src/browser/client-scripts/build.js      
node src/browser/client-scripts/build.js  1.51s user 0.12s system 128% cpu 1.271 total

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As i haven't found any chances we could get "opts.supportDeprecated" truthy value inside of clientBridge.build calls, it seems to be the dead code

const DIRECTION = { FORWARD: "forward", REVERSE: "reverse" };

module.exports = class Calibrator {
constructor() {
this._cache = {};
this._script = fs.readFileSync(path.join(__dirname, "calibrate-client-script.js"), "utf8");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you change the path to the calibrate script? it would be better to keep all client scripts in the client-scripts directory

const bundleScript = async opts => {
const lib = opts.needsCompatLib ? "./lib.compat.js" : "./lib.native.js";
const script = browserify({
entries: "./scripts/index.js",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

client-scripts/scripts/ doesn't look very nice (scripts/scripts). Maybe it would be better to rename with build or bundle

await Promise.all(
[
{ needsCompatLib: true, fileName: "bundle.compat.js" },
{ needsCompatLib: false, fileName: "bundle.js" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be more clearer to save compat/native naming

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants