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

Version of axe-core without polyfills #1935

Closed
straker opened this issue Dec 10, 2019 · 8 comments
Closed

Version of axe-core without polyfills #1935

straker opened this issue Dec 10, 2019 · 8 comments
Assignees
Labels
feat New feature or enhancement performance Performance related issues

Comments

@straker
Copy link
Contributor

straker commented Dec 10, 2019

To help reduce our bundled size, we should release a version of axe-core without our polyfills. With 3.4.0, we added 60KB minified to our codebase, mostly from the addition of core-js Unit32Array polyfills needed for the ligature icon detection. This can get us under size more quickly while we determine a better long term solution.

@straker straker added feat New feature or enhancement performance Performance related issues labels Dec 10, 2019
@connorjclark
Copy link
Contributor

I confirmed that a minified webpack bundled w/ just these polyfills is ~32 KB.

@straker
Copy link
Contributor Author

straker commented Mar 4, 2020

We decided that we will make axe.js in 4.0.0 be polyfill free instead of introducing a new file. For older browsers that require a polyfill, we will document how to bring in the necessary polyfill.

@connorjclark
Copy link
Contributor

@paulirish and I are interested in this feature so that we can reduce Lighthouse's bundle size. Is there anything we could do to help?

@straker
Copy link
Contributor Author

straker commented Sep 16, 2020

Glad you asked. We tried to get ahold of Paul awhile ago in regards to #2357, specifically trying to figure out how large axe-core's gizzped size should be, especially when bundled into Lighthouse. If you could help us figure that out that'd be most helpful.

Once we have a target we can figure out the best approach from there.

@connorjclark
Copy link
Contributor

connorjclark commented Sep 17, 2020

We're attempting to bring Lighthouse's bundle for DevTools down to 1MB unzipped. We have a document tracking this: https://docs.google.com/document/d/15DyId8C9bGnk1ZpgaIekYG_RDEC_KYNQW3Tsp6vs11Q/edit#

1 MB is a long shot for us, but the number isn't particular important, it just serves as a guide. In the same mindset, we can't provide a "real" target number for aXe, because dropping axe from Lighthouse just isn't an option, and at the end of the day we'd accept whatever size as the cost of integration.

What's most important to us is not bundling anything extraneous, like polyfills, as those are usually low-pickings for improvements.

You mentioned 100KB gzipped–that sounds like a great goal to me. If after removing polyfills aXe is still above that number, I'd love to help with some of the tougher ideas you might have.

Is there anything we can do to assist in the polyfill effort? And does that also include axios?


Here's some ideas:

  • I noticed valid-langs.js is quite big for being a list of strings. 55KB. I don't know what it gzips down too, but maybe there's a more compact way to encode this data (trie? would require changing the interface of this function to "isValidLang" instead of returning a list).
  • We saw a ~23% decrease by switching from uglify to terser. How does aXe create axe.min.js ?

Do you have a list of opportunities for bundle size reduction?

@straker
Copy link
Contributor Author

straker commented Sep 17, 2020

Thanks for all the great information. I did a bit of an assessment a bit ago and here is what I found (direct copy and paste):

One of the large contributors to our increase in file size from v3.5 to v4.0 is our conversion to ES Modules, more specifically our use of Webpack. Wepbacks output structure is not very concise and adds a lot of boilerplate to function resolutions.

For example, instead of using a function directly Webpack does this:

// aria-hidden-body-evaluate.js
function ariaHiddenBodyEvaluate(node) {
    return node.getAttribute('aria-hidden') !== 'true';
}
export default ariaHiddenBodyEvaluate;
// webpack
'./lib/checks/aria/aria-hidden-body-evaluate.js': function libChecksAriaAriaHiddenBodyEvaluateJs(module, __webpack_exports__, __webpack_require__) {
  'use strict';
  __webpack_require__.r(__webpack_exports__);
  function ariaHiddenBodyEvaluate(node) {
    return node.getAttribute('aria-hidden') !== 'true';
  }
  __webpack_exports__['default'] = ariaHiddenBodyEvaluate;
}

One way to reduce our file size would be to convert to something that provides a better output, such as Rollup. Rollup just combines the files in an order that would allow dependency resolution without imports.

Converting to Rollup from Webpack isn't a straight forward task though as Webpack handles some things for us such as npm path resolution, circular dependencies, and JSON parsing. There are plugins to handle those in Rollup (minus circular dependencies which we would need to manually resolve), but it would take a bit of work to make sure it all works. However, the benefit would be significant for our end file size.

Besides our Webpack size, I initially thought that most of our file size would come from our polyfills and 3rd party imports (such as bundling Axios into our project). However, removing those from our code only reduced the file size by 10 kB (minified + gzipped)

Run Minified Gzipped
current 553 kB 138 kB
no imports / polyfills 481 kB 123 kB

I know we've also duplicating our standards table and the aria.lookupTable (something we cannot remove until v5.0), but that only removes a few bytes.

Run Minified Gzipped
current 553 kB 138 kB
no imports / polyfills 481 kB 123 kB
above + no lookupTable 446 kB 117 kB

Therefore, the majority of our file size comes from internal code. Looking at the different directories we can see where it comes from (Note: files are not minified, and the aria.lookupTable is not included).

Dir Unminified Gzipped
lib/checks 120 kB 59.4 kB
lib/commons 249 kB 87.6 kB
lib/core 305 kB 107 kB
lib/rules 52.5 kB 30.7 kB
lib/standards 20.6 kB 3.73 kB

We can see that the two largest areas of our codebase are lib/core and lib/commons. Diving deeper we can see which areas are taking up the most room.

Dir Unminified Gzipped
lib/core/base 74 kB 21 kB
lib/core/public 16.5 kB 6.87 kB
lib/core/reporters 9.42 kB 4.38 kB
lib/core/utils 198 kB 72.3 kB
--------------- -- --
lib/commons/aria 85.6.6 kB 20.8 kB
lib/commons/color 22.1 kB 9.36 kB
lib/commons/dom 64.3 kB 26.6 kB
lib/commons/forms 2.98 kB 1.78 kB
lib/commons/matches 11.3 kB 5.29 kB
lib/commons/table 16.3 kB 6.88 kB
lib/commons/text 45.6 kB 16.6 kB

As you can see, the largest areas of our code base are the utility functions, base code, and commons aria, dom, and text functions.

This means that the only way to significantly reduce our file size is to remove a good portion of our primary code base. We will have to audit what each function is doing and even if we still need to do it. Removing code is a better way to reduce file size than trying to rewrite it to be smaller.

In terms of things like Axios, I want to do a deeper audit of how we use our bundled dependencies. I know that Axios is only used in one place and should be able to be replaced by an HTTP call. Switch to terser is a good idea, we do create a min file.

@straker
Copy link
Contributor Author

straker commented Sep 25, 2020

@connorjclark thanks for the suggestion about the trie, was able to reduce that file to 2 kB gzipped #2527.

@WilcoFiers WilcoFiers modified the milestones: axe-core 4.1, axe-core 4.2 Oct 19, 2020
@straker
Copy link
Contributor Author

straker commented Nov 12, 2020

We've been making great strides in our file size for our 4.1 release, having reduced the total size down to 108 kB minified and gzipped (down from 140 kB). As such we don't feel like we need a version without polyfills for now, so I'm going to close this issue. We will reconsider this in the future if we cannot gain other file size wins in other parts of the code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat New feature or enhancement performance Performance related issues
Projects
None yet
Development

No branches or pull requests

4 participants