-
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
report: gzip treemap data #12519
report: gzip treemap data #12519
Changes from 31 commits
d5123ca
267d578
d7281c0
ff0bfd1
c417fcb
8ac3a39
720c427
f0e8949
6d6e453
ef3e69e
c9c60df
585bfa0
a638270
9eb78f6
d985f61
13a4671
07e3c8d
ea226a6
5365e53
a6ff9bb
b473636
50ff2f1
ca16fff
5b2f7d3
b8e6b84
c6dafbd
56a55e0
363022e
e33568a
941cadb
d55f819
b8d8aff
f757094
f0a38c0
d45dc4b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/** | ||
* @license Copyright 2021 The Lighthouse Authors. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
'use strict'; | ||
|
||
/* global self btoa atob window CompressionStream Response */ | ||
|
||
const btoaIso = typeof btoa !== 'undefined' ? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Iso? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. isomorphic There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. prefer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ah gotcha, yeah There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think there's fair consensus that 'atob' is one of the worst named APIs of the web… so i don't love calling our stuff that. should either go full out There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I totally agree, and I fully support never naming our APIs However, internal to this I think there's value in reflecting what underlying methods are being used to perform this so I'd strongly prefer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sg |
||
btoa : | ||
/** @param {string} str */ | ||
(str) => Buffer.from(str).toString('base64'); | ||
const atobIso = typeof atob !== 'undefined' ? | ||
atob : | ||
/** @param {string} str */ | ||
(str) => Buffer.from(str, 'base64').toString(); | ||
|
||
/** | ||
* Takes an UTF-8 string and returns a base64 encoded string. | ||
* If gzip is true, the UTF-8 bytes are gzipped before base64'd, using | ||
* CompressionStream (currently only in Chrome), falling back to pako | ||
* (which is only used to encode in our Node tests). | ||
* @param {string} string | ||
* @param {{gzip: boolean}} options | ||
* @return {Promise<string>} | ||
*/ | ||
async function toBase64(string, options) { | ||
let bytes = new TextEncoder().encode(string); | ||
|
||
if (options.gzip) { | ||
if (typeof CompressionStream !== 'undefined') { | ||
const cs = new CompressionStream('gzip'); | ||
const writer = cs.writable.getWriter(); | ||
writer.write(bytes); | ||
writer.close(); | ||
const compAb = await new Response(cs.readable).arrayBuffer(); | ||
bytes = new Uint8Array(compAb); | ||
} else { | ||
/** @type {import('pako')=} */ | ||
const pako = window.pako; | ||
bytes = pako.gzip(string); | ||
} | ||
} | ||
|
||
let binaryString = ''; | ||
// This is ~25% faster than building the string one character at a time. | ||
// https://jsbench.me/2gkoxazvjl | ||
const chunkSize = 5000; | ||
for (let i = 0; i < bytes.length; i += chunkSize) { | ||
binaryString += String.fromCharCode(...bytes.subarray(i, i + chunkSize)); | ||
} | ||
return btoaIso(binaryString); | ||
} | ||
|
||
/** | ||
* @param {string} encoded | ||
* @param {{gzip: boolean}} options | ||
* @return {string} | ||
*/ | ||
function fromBase64(encoded, options) { | ||
const binaryString = atobIso(encoded); | ||
const bytes = Uint8Array.from(binaryString, c => c.charCodeAt(0)); | ||
|
||
if (options.gzip) { | ||
/** @type {import('pako')=} */ | ||
const pako = window.pako; | ||
return pako.ungzip(bytes, {to: 'string'}); | ||
} else { | ||
return new TextDecoder().decode(bytes); | ||
} | ||
} | ||
|
||
if (typeof module !== 'undefined' && module.exports) { | ||
module.exports = {toBase64, fromBase64}; | ||
} else { | ||
self.TextEncoding = {toBase64, fromBase64}; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/** | ||
* @license Copyright 2021 The Lighthouse Authors. All Rights Reserved. | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
'use strict'; | ||
|
||
const TextEncoding = require('../../../../report/html/renderer/text-encoding.js'); | ||
|
||
/* eslint-env jest */ | ||
|
||
describe('TextEncoding', () => { | ||
beforeAll(() => { | ||
global.window = {pako: require('pako')}; | ||
}); | ||
|
||
afterAll(() => { | ||
global.window = undefined; | ||
}); | ||
|
||
/** @type {string} */ | ||
async function test(str) { | ||
for (const gzip of [false, true]) { | ||
const binary = await TextEncoding.toBase64(str, {gzip}); | ||
const roundtrip = TextEncoding.fromBase64(binary, {gzip}); | ||
expect(roundtrip.length).toEqual(str.length); | ||
expect(roundtrip).toEqual(str); | ||
} | ||
} | ||
|
||
it('works', async () => { | ||
await test(''); | ||
await test('hello'); | ||
await test('😃'); | ||
await test('{åß∂œ∑´}'); | ||
await test('Some examples of emoji are 😃, 🧘🏻♂️, 🌍, 🍞, 🚗, 📞, 🎉, ♥️, 🍆, and 🏁.'); | ||
await test('.'.repeat(125183)); | ||
await test('😃'.repeat(125183)); | ||
await test(JSON.stringify(require('../../../../../lighthouse-treemap/app/debug.json'))); | ||
}); | ||
}); |
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.
speaking of #12570 (comment), there used to be a thing with the closure license checker and the files in
renderer/
, which is why they all have the usual long(er) form of the Apache 2 header. Have you tried importing this yet? Or is that no longer flaggededit: or I guess it was license-header line length? Weird. But still, same question :)
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 something that would only show up in the CL check, which I never did (just built and manually tested). If that's the case, I'll edit in the import and just make a new PR here that can land whenever.
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.
Is there any downside to changing it 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.
snippet renderer has the same comment and is in BUILD, so it should be fine