Skip to content

Commit

Permalink
core(minification-estimator): minify nested template literals in Java…
Browse files Browse the repository at this point in the history
…Script (#11395)
  • Loading branch information
adamraine committed Sep 9, 2020
1 parent 3d828a3 commit 9c64af7
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 1 deletion.
26 changes: 25 additions & 1 deletion lighthouse-core/lib/minification-estimator.js
Expand Up @@ -50,6 +50,12 @@ function computeTokenLength(content, features) {
let isInRegexCharacterClass = false;
let stringOpenChar = null;

/**
* Acts as stack for brace tracking.
* @type {('templateBrace'|'normalBrace')[]}
*/
const templateLiteralDepth = [];

for (let i = 0; i < content.length; i++) {
const twoChars = content.substr(i, 2);
const char = twoChars.charAt(0);
Expand Down Expand Up @@ -78,7 +84,13 @@ function computeTokenLength(content, features) {
// String characters count
totalTokenLength++;

if (char === '\\') {
if (stringOpenChar === '`' && twoChars === '${') {
// Start new template literal
templateLiteralDepth.push('templateBrace');
isInString = false;
totalTokenLength++;
i++;
} else if (char === '\\') {
// Skip over any escaped characters
totalTokenLength++;
i++;
Expand Down Expand Up @@ -129,6 +141,18 @@ function computeTokenLength(content, features) {
isInRegex = true;
// Regex characters count
totalTokenLength++;
} else if (char === '{' && templateLiteralDepth.length) {
// Start normal code brace if inside a template literal
templateLiteralDepth.push('normalBrace');
totalTokenLength++;
} else if (char === '}' && templateLiteralDepth.length) {
// End one template literal if closing brace is for a template literal
if (templateLiteralDepth[templateLiteralDepth.length - 1] === 'templateBrace') {
isInString = true;
stringOpenChar = '`';
}
templateLiteralDepth.pop();
totalTokenLength++;
} else if (isAStringOpenChar) {
// Start the string
isInString = true;
Expand Down
22 changes: 22 additions & 0 deletions lighthouse-core/test/lib/minification-estimator-test.js
Expand Up @@ -227,5 +227,27 @@ describe('minification estimator', () => {
// Already-minified source script. estimated 1% smaller minified
expect(minificationPct).toBeCloseTo(0.01);
});

it('should handle nested template literals', () => {
// Basic nested literals
const nestedTemplates = 'window.myString=`foo${` bar ${` baz ${` bam `} `} `} `';
expect(computeJSTokenLength(nestedTemplates)).toEqual(nestedTemplates.length);

// Can get rid of 5 spaces after inner code braces
const nestedWithCode = 'window.myString=`foo${` bar ${{} }`}`';
expect(computeJSTokenLength(nestedWithCode)).toEqual(nestedWithCode.length - 5);

// Ignore braces in string
const nestedTemplatesBrace = 'window.myString=`{foo${` }bar ${` baz ${` bam `} `} `} `';
expect(computeJSTokenLength(nestedTemplatesBrace)).toEqual(nestedTemplatesBrace.length);

// Handles multiple string braces (Has 4 spaces)
const nestedStrings = 'window.myString=`${({foo: bar.map(() => ({baz: `${\'}\'}`}))})}`';
expect(computeJSTokenLength(nestedStrings)).toEqual(nestedStrings.length - 4);

// Handles braces outside template literal (2 spaces + 4 spaces)
const outerBraces = '{ foo:{bar:`baz ${bam.get({} )}`}}';
expect(computeJSTokenLength(outerBraces)).toEqual(outerBraces.length - 6);
});
});
});

0 comments on commit 9c64af7

Please sign in to comment.