Skip to content

Commit

Permalink
Reduce bundle size (#363)
Browse files Browse the repository at this point in the history
## TL;DR;

- 1.8kB raw filesize reduction with some not-too-extreme code golfing

## Before

String/identifier analysis: `Total size: 18.0 kB, string size: 2.9 kB
(15.9%)`

## After

String/identifier analysis: `Total size: 16.2 kB, string size: 2.8 kB
(17.4%)`
  • Loading branch information
bartveneman authored Nov 21, 2023
1 parent 1cf7361 commit 37070ca
Show file tree
Hide file tree
Showing 16 changed files with 454 additions and 307 deletions.
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@
"analytics",
"performance",
"styleguide",
"metrics"
"metrics",
"designsystem",
"fonts",
"colors",
"quality",
"code"
],
"dependencies": {
"@bramus/specificity": "^2.3.0",
Expand Down
14 changes: 9 additions & 5 deletions src/aggregate-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ function Mode(arr) {
let maxOccurrences = -1
let maxOccurenceCount = 0
let sum = 0
let len = arr.length

for (let i = 0; i < arr.length; i++) {
for (let i = 0; i < len; i++) {
let element = arr[i]
let updatedCount = (frequencies.get(element) || 0) + 1
frequencies.set(element, updatedCount)
Expand Down Expand Up @@ -70,7 +71,9 @@ class AggregateCollection {
}

aggregate() {
if (this._items.length === 0) {
let len = this._items.length

if (len === 0) {
return {
min: 0,
max: 0,
Expand All @@ -86,19 +89,20 @@ class AggregateCollection {
/** @type Number[] */
let sorted = this._items.slice().sort((a, b) => a - b)
let min = sorted[0]
let max = sorted[sorted.length - 1]
let max = sorted[len - 1]

let mode = Mode(sorted)
let median = Median(sorted)
let sum = this._sum

return {
min,
max,
mean: this._sum / sorted.length,
mean: sum / len,
mode,
median,
range: max - min,
sum: this._sum,
sum: sum,
}
}

Expand Down
48 changes: 30 additions & 18 deletions src/atrules/atrules.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { strEquals, startsWith, endsWith } from '../string-utils.js'
import walk from 'css-tree/walker'
import {
Identifier,
MediaQuery,
MediaFeature,
Declaration,
} from '../css-tree-node-types.js'

/**
* Check whether node.property === property and node.value === value,
Expand All @@ -10,9 +16,10 @@ import walk from 'css-tree/walker'
* @returns true if declaratioNode is the given property: value, false otherwise
*/
function isPropertyValue(node, property, value) {
let firstChild = node.value.children.first
return strEquals(property, node.property)
&& node.value.children.first.type === 'Identifier'
&& strEquals(value, node.value.children.first.name)
&& firstChild.type === Identifier
&& strEquals(value, firstChild.name)
}

/**
Expand All @@ -24,7 +31,7 @@ export function isSupportsBrowserhack(prelude) {
let returnValue = false

walk(prelude, function (node) {
if (node.type === 'Declaration') {
if (node.type === Declaration) {
if (
isPropertyValue(node, '-webkit-appearance', 'none')
|| isPropertyValue(node, '-moz-appearance', 'meterbar')
Expand All @@ -47,38 +54,43 @@ export function isMediaBrowserhack(prelude) {
let returnValue = false

walk(prelude, function (node) {
if (node.type === 'MediaQuery'
&& node.children.size === 1
&& node.children.first.type === 'Identifier'
let children = node.children
let name = node.name
let value = node.value

if (node.type === MediaQuery
&& children.size === 1
&& children.first.type === Identifier
) {
node = node.children.first
let n = children.first.name
// Note: CSSTree adds a trailing space to \\9
if (startsWith('\\0', node.name) || endsWith('\\9 ', node.name)) {
if (startsWith('\\0', n) || endsWith('\\9 ', n)) {
returnValue = true
return this.break
}
}
if (node.type === 'MediaFeature') {
if (node.value !== null && node.value.unit === '\\0') {
if (node.type === MediaFeature) {
if (value !== null && value.unit === '\\0') {
returnValue = true
return this.break
}
if (strEquals('-moz-images-in-menus', node.name)
|| strEquals('min--moz-device-pixel-ratio', node.name)
|| strEquals('-ms-high-contrast', node.name)
if (strEquals('-moz-images-in-menus', name)
|| strEquals('min--moz-device-pixel-ratio', name)
|| strEquals('-ms-high-contrast', name)
) {
returnValue = true
return this.break
}
if (strEquals('min-resolution', node.name)
&& strEquals('.001', node.value.value)
&& strEquals('dpcm', node.value.unit)
if (strEquals('min-resolution', name)
&& strEquals('.001', value.value)
&& strEquals('dpcm', value.unit)
) {
returnValue = true
return this.break
}
if (strEquals('-webkit-min-device-pixel-ratio', node.name)) {
if ((strEquals('0', node.value.value) || strEquals('10000', node.value.value))) {
if (strEquals('-webkit-min-device-pixel-ratio', name)) {
let val = value.value
if ((strEquals('0', val) || strEquals('10000', val))) {
returnValue = true
return this.break
}
Expand Down
69 changes: 42 additions & 27 deletions src/collection.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
export class Collection {
constructor({ useLocations = false }) {
/** @param {boolean} useLocations */
constructor(useLocations = false) {
/** @type {Map<string, number[]>} */
this._items = new Map()
this._total = 0
/** @type {number[]} */
this.node_lines = []
/** @type {number[]} */
this.node_columns = []
/** @type {number[]} */
this.node_lengths = []
/** @type {number[]} */
this.node_offsets = []

if (useLocations) {
/** @type {number[]} */
this._node_lines = []
/** @type {number[]} */
this._node_columns = []
/** @type {number[]} */
this._node_lengths = []
/** @type {number[]} */
this._node_offsets = []
}

/** @type {boolean} */
this._useLocations = useLocations
Expand All @@ -20,13 +24,18 @@ export class Collection {
* @param {string} item
* @param {import('css-tree').CssLocation} node_location
*/
push(item, node_location) {
p(item, node_location) {
let index = this._total

this.node_lines[index] = node_location.start.line
this.node_columns[index] = node_location.start.column
this.node_offsets[index] = node_location.start.offset
this.node_lengths[index] = node_location.end.offset - node_location.start.offset
if (this._useLocations) {
let start = node_location.start
let start_offset = start.offset

this._node_lines[index] = start.line
this._node_columns[index] = start.column
this._node_offsets[index] = start_offset
this._node_lengths[index] = node_location.end.offset - start_offset
}

if (this._items.has(item)) {
/** @type number[] */
Expand All @@ -53,35 +62,41 @@ export class Collection {
*
* @returns {{ total: number; totalUnique: number; uniquenessRatio: number; unique: Record<string, number>; __unstable__uniqueWithLocations: Record<string, CssLocation[]>}}
*/
count() {
c() {
let useLocations = this._useLocations
let uniqueWithLocations = new Map()
let unique = {}
this._items.forEach((list, key) => {
let nodes = list.map(index => ({
line: this.node_lines[index],
column: this.node_columns[index],
offset: this.node_offsets[index],
length: this.node_lengths[index],
}))
uniqueWithLocations.set(key, nodes)
let items = this._items
let size = items.size

items.forEach((list, key) => {
if (useLocations) {
let nodes = list.map(index => ({
line: this._node_lines[index],
column: this._node_columns[index],
offset: this._node_offsets[index],
length: this._node_lengths[index],
}))
uniqueWithLocations.set(key, nodes)
}
unique[key] = list.length
})

if (this._useLocations) {
return {
total: this._total,
totalUnique: this._items.size,
totalUnique: size,
unique,
uniquenessRatio: this._total === 0 ? 0 : this._items.size / this._total,
uniquenessRatio: this._total === 0 ? 0 : size / this._total,
__unstable__uniqueWithLocations: Object.fromEntries(uniqueWithLocations),
}
}

return {
total: this._total,
totalUnique: this._items.size,
totalUnique: size,
unique,
uniquenessRatio: this._total === 0 ? 0 : this._items.size / this._total,
uniquenessRatio: this._total === 0 ? 0 : size / this._total,
}
}
}
17 changes: 9 additions & 8 deletions src/context-collection.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { Collection } from './collection.js'

class ContextCollection {
constructor({ useLocations = false }) {
this._list = new Collection({ useLocations })
/** @param {boolean} useLocations */
constructor(useLocations) {
this._list = new Collection(useLocations)
/** @type {Map<string, Collection>} */
this._contexts = new Map()
/** @type {boolean} */
this.useLocations = useLocations
this._useLocations = useLocations
}

/**
Expand All @@ -16,13 +17,13 @@ class ContextCollection {
* @param {import('css-tree').CssLocation} node_location
*/
push(item, context, node_location) {
this._list.push(item, node_location)
this._list.p(item, node_location)

if (!this._contexts.has(context)) {
this._contexts.set(context, new Collection({ useLocations: this.useLocations }))
this._contexts.set(context, new Collection(this._useLocations))
}

this._contexts.get(context).push(item, node_location)
this._contexts.get(context).p(item, node_location)
}

count() {
Expand All @@ -37,10 +38,10 @@ class ContextCollection {
let itemsPerContext = new Map()

for (let [context, value] of this._contexts.entries()) {
itemsPerContext.set(context, value.count())
itemsPerContext.set(context, value.c())
}

return Object.assign(this._list.count(), {
return Object.assign(this._list.c(), {
itemsPerContext: Object.fromEntries(itemsPerContext)
})
}
Expand Down
12 changes: 8 additions & 4 deletions src/countable-collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@ class CountableCollection {
}

count() {
let items = this._items
let size = items.size
let total = this._total

return {
total: this._total,
totalUnique: this._items.size,
unique: Object.fromEntries(this._items),
uniquenessRatio: this._total === 0 ? 0 : this._items.size / this._total,
total: total,
totalUnique: size,
unique: Object.fromEntries(items),
uniquenessRatio: total === 0 ? 0 : size / total,
}
}
}
Expand Down
30 changes: 30 additions & 0 deletions src/css-tree-node-types.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Atrule
export const Atrule = 'Atrule'
export const MediaQuery = 'MediaQuery'
export const MediaFeature = 'MediaFeature'
// Rule
export const Rule = 'Rule'

// Selector
export const Selector = 'Selector'
export const TypeSelector = 'TypeSelector'
export const PseudoClassSelector = 'PseudoClassSelector'
export const AttributeSelector = 'AttributeSelector'
export const IdSelector = 'IdSelector'
export const ClassSelector = 'ClassSelector'
export const PseudoElementSelector = 'PseudoElementSelector'

// Declaration
export const Declaration = 'Declaration'

// Values
export const Value = 'Value'
export const Identifier = 'Identifier'
export const Nth = 'Nth'
export const Combinator = 'Combinator'
export const Nr = 'Number'
export const Dimension = 'Dimension'
export const Operator = 'Operator'
export const Hash = 'Hash'
export const Url = 'Url'
export const Func = 'Function'
Loading

0 comments on commit 37070ca

Please sign in to comment.