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

Improve performance by removing map/filter/join methods in hot path (failed) #20

Conversation

dcastil
Copy link
Owner

@dcastil dcastil commented Aug 24, 2021

Closes #17

I created a baseline benchmark which resulted in around 62k operations per second. The optimization of the hot path led to an increase to 63k operations per second. Because the improvements are negligible, I decided not to implement them as it reduces readability of the code.

I used following benchmark

import Benchmark from 'benchmark' // v2.1.4

import { createTailwindMerge } from '../dist/index.js'

const twMerge = createTailwindMerge((getDefaultConfig) => ({
    ...getDefaultConfig(),
    cacheSize: 0,
}))

twMerge('')

new Benchmark.Suite()
    .add('twMerge', () =>
        twMerge(
            'px-2 py-1 bg-red hover:bg-dark-red border text-white non-tailwind-class rounded-t-sm right-4',
            'p-3 bg-[#B91C1C] border-2 text-black other-non-tailwind-class',
            undefined,
            'rounded-lg inset-2',
            null
        )
    )
    .on('cycle', (e) => console.log('  ' + e.target))
    .run()

and following change to mergeClassList()

export function mergeClassList(classList: string, configUtils: ConfigUtils) {
    const { isPrefixValid, getClassGroupId, comparePrefixes, getConflictingClassGroupIds } =
        configUtils

    /**
     * Set of classGroupIds in following format:
     * `{importantModifier}{variantPrefixes}{classGroupId}`
     * @example ':standaloneClasses.1'
     * @example 'hover:focus:dynamicClasses.bg.2'
     * @example '!md:dynamicClasses.bg.0'
     */
    const classGroupsInConflict = new Set<string>()
    const classes = classList.trim().split(SPLIT_CLASSES_REGEX)

    let mergedClassList = ''

    for (let index = classes.length - 1; index >= 0; index -= 1) {
        const originalClassName = classes[index]!

        const hasImportantModifier = originalClassName.startsWith(IMPORTANT_MODIFIER)
        const classNameWithoutImportant = hasImportantModifier
            ? originalClassName.substring(1)
            : originalClassName

        const prefixes = classNameWithoutImportant.split(PREFIX_SEPARATOR_REGEX)
        const className = prefixes.pop()!

        const arePrefixesValid = prefixes.every(isPrefixValid)
        const classGroupId = arePrefixesValid ? getClassGroupId(className) : undefined

        // Not a Tailwind class
        if (!classGroupId) {
            mergedClassList = originalClassName + ' ' + mergedClassList
            continue
        }

        const variantPrefix =
            prefixes.length === 0
                ? ''
                : prefixes.sort(comparePrefixes).concat('').join(PREFIX_SEPARATOR)

        const fullPrefix = hasImportantModifier ? IMPORTANT_MODIFIER + variantPrefix : variantPrefix

        const classId = `${fullPrefix}:${classGroupId}`

        // Conflicting with succeeding class
        if (classGroupsInConflict.has(classId)) {
            continue
        }

        classGroupsInConflict.add(classId)

        getConflictingClassGroupIds(classGroupId).forEach((group) =>
            classGroupsInConflict.add(`${fullPrefix}:${group}`)
        )

        mergedClassList = originalClassName + ' ' + mergedClassList
    }

    return mergedClassList.trim()
}

@github-actions github-actions bot added the feature Is new feature label Aug 24, 2021
@dcastil dcastil changed the title Improve performance by removing map/filter/join methods in hot path Improve performance by removing map/filter/join methods in hot path (failed) Aug 24, 2021
@dcastil dcastil added the needs changelog edit Needs edit in changelog before release label Aug 24, 2021
@dcastil
Copy link
Owner Author

dcastil commented Aug 24, 2021

Changelog edit:

  • twMerge() allows passing null as argument

@dcastil dcastil marked this pull request as ready for review August 24, 2021 20:54
@dcastil dcastil merged commit 89ce322 into main Aug 24, 2021
@dcastil dcastil deleted the feature/17/improve-performance-by-removing-map-filter-join-in-hot-path branch August 24, 2021 20:55
@dcastil
Copy link
Owner Author

dcastil commented Aug 25, 2021

Also tested in Safari and Chrome. Unoptimized and optimized runs both have similar performance. → https://jsben.ch/EbZBz

Boilerplate block

const twMerge1 = () => {
  function e(){return(e=Object.assign||function(e){for(var r=1;r<arguments.length;r++){var t=arguments[r];for(var o in t)Object.prototype.hasOwnProperty.call(t,o)&&(e[o]=t[o])}return e}).apply(this,arguments)}function r(e){const r=function(e){const r={nextPart:{},validators:[]};return Object.entries(e.classGroups).forEach(([e,t])=>{o(t,r,e)}),r}(e);return{getClassGroupId:function(e){const o=e.split("-");return""===o[0]&&1!==o.length&&o.shift(),t(o,r)},getConflictingClassGroupIds:function(r){return e.conflictingClassGroups[r]||[]}}}function t(e,r){var o;if(0===e.length)return r.classGroupId;const n=r.nextPart[e[0]],i=n?t(e.slice(1),n):void 0;if(i)return i;if(0===r.validators.length)return;const a=e.join("-");return null==(o=r.validators.find(({validator:e})=>e(a)))?void 0:o.classGroupId}function o(e,r,t){e.forEach(e=>{"string"==typeof e?(""===e?r:n(r,e)).classGroupId=t:"function"==typeof e?r.validators.push({validator:e,classGroupId:t}):Object.entries(e).forEach(([e,i])=>{o(i,n(r,e),t)})})}function n(e,r){let t=e;return r.split("-").forEach(e=>{void 0===t.nextPart[e]&&(t.nextPart[e]={nextPart:{},validators:[]}),t=t.nextPart[e]}),t}function i(e){const r=Object.fromEntries(e.prefixes.flatMap(e=>a("",e)).map((e,r)=>[e,r]));return{isPrefixValid:function(e){return void 0!==r[e]},comparePrefixes:function(e,t){return r[e]-r[t]}}}function a(e,r){return"string"==typeof r?e.concat(r):Object.entries(r).flatMap(([r,t])=>t.flatMap(t=>a(`${e}${r}-`,t)))}const l=/^\[(.+)\]$/,s=/^\d+\/\d+$/,d=new Set(["px","full","screen"]),c=/\d+(%|px|em|rem|vh|vw|pt|pc|in|cm|mm|cap|ch|ex|lh|rlh|vi|vb|vmin|vmax)/;function u(e){return p(e)||!Number.isNaN(Number(e))||d.has(e)||s.test(e)}function p(e){var r;const t=null==(r=l.exec(e))?void 0:r[1];return!!t&&(t.startsWith("length:")||c.test(t))}function f(e){var r;const t=null==(r=l.exec(e))?void 0:r[1];return Number.isInteger(Number(t||e))}function b(e){return l.test(e)}const g=["sm","md","lg","xl","2xl"],m=["3xl","4xl","5xl","6xl","7xl"],v=["auto","contain","none"],x=["auto","hidden","visible","scroll"],h=[u],y=["auto",u],w=["",u],k=[f],j=["auto",f],z=[function(){return!0}],C=["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],G=["none","",...g,"3xl","full",p],O=["solid","dashed","dotted","double","none"],I=[{blend:["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"]}],P=["start","end","center","between","around","evenly"],N=["","0"],$=["first","last","only","odd","even","first-of-type","last-of-type","only-of-type","visited","target","default","checked","indeterminate","placeholder-shown","autofill","required","valid","invalid","in-range","out-of-range","read-only","empty","focus-within","hover","focus","focus-visible","active","disabled"];function E(){return{cacheSize:500,prefixes:[...g,"dark","motion-safe","motion-reduce","before","after","first-letter","first-line","selection","marker",...$,{group:$,peer:$}],classGroups:{container:["container"],decoration:[{decoration:["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none"]}],clear:[{clear:["left","right","both","none"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:C}],overflow:[{overflow:x}],"overflow-x":[{"overflow-x":x}],"overflow-y":[{"overflow-y":x}],overscroll:[{overscroll:v}],"overscroll-x":[{"overscroll-x":v}],"overscroll-y":[{"overscroll-y":v}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:y}],"inset-x":[{"inset-x":y}],"inset-y":[{"inset-y":y}],top:[{top:y}],right:[{right:y}],bottom:[{bottom:y}],left:[{left:y}],visibility:["visible","invisible"],z:[{z:h}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",b]}],"flex-grow":[{"flex-grow":["",f]}],"flex-shrink":[{"flex-shrink":["",f]}],order:[{order:["first","last","none",f]}],"grid-cols":[{"grid-cols":z}],"col-start-end":[{col:["auto",{span:k}]}],"col-start":[{"col-start":j}],"col-end":[{"col-end":j}],"grid-rows":[{"grid-rows":z}],"row-start-end":[{row:["auto",{span:k}]}],"row-start":[{"row-start":j}],"row-end":[{"row-end":j}],"grid-flow":[{"grid-flow":["row","col","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr"]}],"auto-rows":[{"auto-rows":["auto","min","max","fr"]}],gap:[{gap:h}],"gap-x":[{"gap-x":h}],"gap-y":[{"gap-y":h}],"justify-content":[{justify:P}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:P}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...P,"stretch"]}],"place-items":[{"place-items":["start","end","center","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:h}],px:[{px:h}],py:[{py:h}],pt:[{pt:h}],pr:[{pr:h}],pb:[{pb:h}],pl:[{pl:h}],m:[{m:y}],mx:[{mx:y}],my:[{my:y}],mt:[{mt:y}],mr:[{mr:y}],mb:[{mb:y}],ml:[{ml:y}],"space-x":[{"space-x":h}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":h}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max",u]}],"min-w":[{"min-w":["full","min","max",u]}],"max-w":[{"max-w":["0","none",...g,...m,"full","min","max","prose",{screen:g}]}],h:[{h:y}],"min-h":[{"min-h":["full","screen",u]}],"max-h":[{"max-h":h}],"font-family":[{font:z}],"font-size":[{text:["xs",...g,"base",...m,"8xl","9xl",p]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black"]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractons"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",p]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",u]}],"list-style-type":[{list:["none","disc","decimal"]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:z}],"placeholder-opacity":[{"placeholder-opacity":k}],"text-alignment":[{text:["left","center","right","justify"]}],"text-color":[{text:z}],"text-opacity":[{"text-opacity":k}],"text-decoration":["underline","line-through","no-underline"],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","overflow-ellipsis","overflow-clip"],"vertival-alignment":[{align:["baseline","top","middle","bottom","text-top","text-bottom"]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap"]}],break:[{break:["normal","words","all"]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":k}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:C}],"bg-repeeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain"]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]}]}],"bg-blend":[{bg:I}],"bg-color":[{bg:z}],"gradient-from":[{from:z}],"gradient-via":[{via:z}],"gradient-to":[{to:z}],rounded:[{rounded:G}],"rounded-t":[{"rounded-t":G}],"rounded-r":[{"rounded-r":G}],"rounded-b":[{"rounded-b":G}],"rounded-l":[{"rounded-l":G}],"rounded-tl":[{"rounded-tl":G}],"rounded-tr":[{"rounded-tr":G}],"rounded-br":[{"rounded-br":G}],"rounded-bl":[{"rounded-bl":G}],"border-w":[{border:w}],"border-w-t":[{"border-t":w}],"border-w-r":[{"border-r":w}],"border-w-b":[{"border-b":w}],"border-w-l":[{"border-l":w}],"border-opacity":[{"border-opacity":k}],"border-style":[{border:O}],"divide-x":[{"divide-x":w}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":w}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":k}],"divide-style":[{divide:O}],"border-color":[{border:z}],"border-color-t":[{"border-t":z}],"border-color-r":[{"border-r":z}],"border-color-b":[{"border-b":z}],"border-color-l":[{"border-l":z}],"divide-color":[{divide:z}],"ring-w":[{ring:w}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:z}],"ring-opacity":[{"ring-opacity":k}],"ring-offset-w":[{"ring-offset":h}],"ring-offset-color":[{"ring-offset":z}],shadow:[{shadow:["",...g,"inner","none"]}],opacity:[{opacity:k}],"mix-blend":[{"mix-blend":I}],filter:[{filter:["","none"]}],blur:[{blur:["none","",...g,"3xl",p]}],brightness:[{brightness:k}],contrast:[{contrast:k}],"drop-shadow":[{"drop-shadow":["",...g,"none"]}],grayscale:[{grayscale:N}],"hue-rotate":[{"hue-rotate":k}],invert:[{invert:N}],saturate:[{saturate:k}],sepia:[{sepia:N}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":["none","",...g,"3xl"]}],"backdrop-brightness":[{"backdrop-brightness":k}],"backdrop-contrast":[{"backdrop-contrast":k}],"backdrop-grayscale":[{"backdrop-grayscale":N}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":k}],"backdrop-invert":[{"backdrop-invert":N}],"backdrop-opacity":[{"backdrop-opacity":k}],"backdrop-saturate":[{"backdrop-saturate":k}],"backdrop-sepia":[{"backdrop-sepia":N}],"border-collapse":[{border:["collapse","separate"]}],"table-layout":[{table:["auto","fixed"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform"]}],duration:[{duration:k}],ease:[{ease:["linear","in","out","in-out"]}],delay:[{delay:k}],animate:[{animate:["none","spin","ping","pulse","bounce"]}],transform:[{transform:["","gpu","none"]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left"]}],scale:[{scale:k}],"scale-x":[{"scale-x":k}],"scale-y":[{"scale-y":k}],rotate:[{rotate:k}],"translate-x":[{"translate-x":h}],"translate-y":[{"translate-y":h}],"skew-x":[{"skew-x":k}],"skew-y":[{"skew-y":k}],appearance:["appearance-none"],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed",b]}],outline:[{outline:["none","white","black"]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],select:[{select:["none","text","all","auto"]}],fill:["fill-current"],stroke:[{stroke:["current"]}],"stroke-w":[{stroke:h}],sr:["sr-only","not-sr-only"],content:[{content:[b]}],"caret-color":[{caret:z}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["flex-grow","flex-shrink"],"col-start-end":["col-start","col-end"],"row-start-end":["row-start","row-end"],gap:["gap-x","gap-y"],p:["px","py","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],rounded:["rounded-t","rounded-r","rounded-b","rounded-l","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-w":["border-w-t","border-w-r","border-w-b","border-w-l"],"border-color":["border-color-t","border-color-r","border-color-b","border-color-l"]}}}const S=/\s+/,M=/:(?![^[]*\])/;function T(t){let o,n,a,l=function(d){return c=t(E),o=e({cache:(u=c.cacheSize,u>=1?function(e){if(!e)throw Error("hashlru must have a max value, of type number, greater than 0");var r=0,t=Object.create(null),o=Object.create(null);function n(n,i){t[n]=i,++r>=e&&(r=0,o=t,t=Object.create(null))}return{has:function(e){return void 0!==t[e]||void 0!==o[e]},remove:function(e){void 0!==t[e]&&(t[e]=void 0),void 0!==o[e]&&(o[e]=void 0)},get:function(e){var r=t[e];return void 0!==r?r:void 0!==(r=o[e])?(n(e,r),r):void 0},set:function(e,r){void 0!==t[e]?t[e]=r:n(e,r)},clear:function(){t=Object.create(null),o=Object.create(null)}}}(u):{get:()=>{},set:()=>{}})},i(c),r(c)),n=o.cache.get,a=o.cache.set,l=s,s(d);var c,u};function s(e){const r=n(e);if(r)return r;const t=function(e,r){const{isPrefixValid:t,getClassGroupId:o,comparePrefixes:n,getConflictingClassGroupIds:i}=r,a=new Set;return e.trim().split(S).map(e=>{const r=e.startsWith("!"),i=(r?e.substring(1):e).split(M),a=i.pop(),l=i.every(t)?o(a):void 0;if(!l)return{isTailwindClass:!1,originalClassName:e};const s=0===i.length?"":i.sort(n).concat("").join(":");return{isTailwindClass:!0,prefix:r?"!"+s:s,classGroupId:l,originalClassName:e}}).reverse().filter(e=>{if(!e.isTailwindClass)return!0;const{prefix:r,classGroupId:t}=e,o=`${r}:${t}`;return!a.has(o)&&(a.add(o),i(t).forEach(e=>a.add(`${r}:${e}`)),!0)}).reverse().map(e=>e.originalClassName).join(" ")}(e,o);return a(e,t),t}return function(...e){return l(e.join(" "))}}const V=T(e=>e());
  const createTailwindMerge = T;
	const twMerge = createTailwindMerge(c => {
		const config = c();
  	config.cacheSize = 0;
  	return config;
	});
	twMerge('');
  return twMerge;
};

const twMerge2 = () => {
  function e(){return(e=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(e[o]=r[o])}return e}).apply(this,arguments)}function t(e){const t=function(e){const t={nextPart:{},validators:[]};return Object.entries(e.classGroups).forEach(([e,r])=>{o(r,t,e)}),t}(e);return{getClassGroupId:function(e){const o=e.split("-");return""===o[0]&&1!==o.length&&o.shift(),r(o,t)},getConflictingClassGroupIds:function(t){return e.conflictingClassGroups[t]||[]}}}function r(e,t){var o;if(0===e.length)return t.classGroupId;const n=t.nextPart[e[0]],i=n?r(e.slice(1),n):void 0;if(i)return i;if(0===t.validators.length)return;const l=e.join("-");return null==(o=t.validators.find(({validator:e})=>e(l)))?void 0:o.classGroupId}function o(e,t,r){e.forEach(e=>{"string"==typeof e?(""===e?t:n(t,e)).classGroupId=r:"function"==typeof e?t.validators.push({validator:e,classGroupId:r}):Object.entries(e).forEach(([e,i])=>{o(i,n(t,e),r)})})}function n(e,t){let r=e;return t.split("-").forEach(e=>{void 0===r.nextPart[e]&&(r.nextPart[e]={nextPart:{},validators:[]}),r=r.nextPart[e]}),r}function i(e){const t=Object.fromEntries(e.prefixes.flatMap(e=>l("",e)).map((e,t)=>[e,t]));return{isPrefixValid:function(e){return void 0!==t[e]},comparePrefixes:function(e,r){return t[e]-t[r]}}}function l(e,t){return"string"==typeof t?e.concat(t):Object.entries(t).flatMap(([t,r])=>r.flatMap(r=>l(`${e}${t}-`,r)))}const a=/^\[(.+)\]$/,s=/^\d+\/\d+$/,d=new Set(["px","full","screen"]),c=/\d+(%|px|em|rem|vh|vw|pt|pc|in|cm|mm|cap|ch|ex|lh|rlh|vi|vb|vmin|vmax)/;function u(e){return f(e)||!Number.isNaN(Number(e))||d.has(e)||s.test(e)}function f(e){var t;const r=null==(t=a.exec(e))?void 0:t[1];return!!r&&(r.startsWith("length:")||c.test(r))}function p(e){var t;const r=null==(t=a.exec(e))?void 0:t[1];return Number.isInteger(Number(r||e))}function b(e){return a.test(e)}const g=["sm","md","lg","xl","2xl"],m=["3xl","4xl","5xl","6xl","7xl"],v=["auto","contain","none"],x=["auto","hidden","visible","scroll"],h=[u],y=["auto",u],w=["",u],k=[p],j=["auto",p],z=[function(){return!0}],G=["bottom","center","left","left-bottom","left-top","right","right-bottom","right-top","top"],O=["none","",...g,"3xl","full",f],P=["solid","dashed","dotted","double","none"],I=[{blend:["normal","multiply","screen","overlay","darken","lighten","color-dodge","color-burn","hard-light","soft-light","difference","exclusion","hue","saturation","color","luminosity"]}],C=["start","end","center","between","around","evenly"],$=["","0"],E=["first","last","only","odd","even","first-of-type","last-of-type","only-of-type","visited","target","default","checked","indeterminate","placeholder-shown","autofill","required","valid","invalid","in-range","out-of-range","read-only","empty","focus-within","hover","focus","focus-visible","active","disabled"];function N(){return{cacheSize:500,prefixes:[...g,"dark","motion-safe","motion-reduce","before","after","first-letter","first-line","selection","marker",...E,{group:E,peer:E}],classGroups:{container:["container"],decoration:[{decoration:["slice","clone"]}],box:[{box:["border","content"]}],display:["block","inline-block","inline","flex","inline-flex","table","inline-table","table-caption","table-cell","table-column","table-column-group","table-footer-group","table-header-group","table-row-group","table-row","flow-root","grid","inline-grid","contents","list-item","hidden"],float:[{float:["right","left","none"]}],clear:[{clear:["left","right","both","none"]}],isolation:["isolate","isolation-auto"],"object-fit":[{object:["contain","cover","fill","none","scale-down"]}],"object-position":[{object:G}],overflow:[{overflow:x}],"overflow-x":[{"overflow-x":x}],"overflow-y":[{"overflow-y":x}],overscroll:[{overscroll:v}],"overscroll-x":[{"overscroll-x":v}],"overscroll-y":[{"overscroll-y":v}],position:["static","fixed","absolute","relative","sticky"],inset:[{inset:y}],"inset-x":[{"inset-x":y}],"inset-y":[{"inset-y":y}],top:[{top:y}],right:[{right:y}],bottom:[{bottom:y}],left:[{left:y}],visibility:["visible","invisible"],z:[{z:h}],"flex-direction":[{flex:["row","row-reverse","col","col-reverse"]}],"flex-wrap":[{flex:["wrap","wrap-reverse","nowrap"]}],flex:[{flex:["1","auto","initial","none",b]}],"flex-grow":[{"flex-grow":["",p]}],"flex-shrink":[{"flex-shrink":["",p]}],order:[{order:["first","last","none",p]}],"grid-cols":[{"grid-cols":z}],"col-start-end":[{col:["auto",{span:k}]}],"col-start":[{"col-start":j}],"col-end":[{"col-end":j}],"grid-rows":[{"grid-rows":z}],"row-start-end":[{row:["auto",{span:k}]}],"row-start":[{"row-start":j}],"row-end":[{"row-end":j}],"grid-flow":[{"grid-flow":["row","col","row-dense","col-dense"]}],"auto-cols":[{"auto-cols":["auto","min","max","fr"]}],"auto-rows":[{"auto-rows":["auto","min","max","fr"]}],gap:[{gap:h}],"gap-x":[{"gap-x":h}],"gap-y":[{"gap-y":h}],"justify-content":[{justify:C}],"justify-items":[{"justify-items":["start","end","center","stretch"]}],"justify-self":[{"justify-self":["auto","start","end","center","stretch"]}],"align-content":[{content:C}],"align-items":[{items:["start","end","center","baseline","stretch"]}],"align-self":[{self:["auto","start","end","center","stretch","baseline"]}],"place-content":[{"place-content":[...C,"stretch"]}],"place-items":[{"place-items":["start","end","center","stretch"]}],"place-self":[{"place-self":["auto","start","end","center","stretch"]}],p:[{p:h}],px:[{px:h}],py:[{py:h}],pt:[{pt:h}],pr:[{pr:h}],pb:[{pb:h}],pl:[{pl:h}],m:[{m:y}],mx:[{mx:y}],my:[{my:y}],mt:[{mt:y}],mr:[{mr:y}],mb:[{mb:y}],ml:[{ml:y}],"space-x":[{"space-x":h}],"space-x-reverse":["space-x-reverse"],"space-y":[{"space-y":h}],"space-y-reverse":["space-y-reverse"],w:[{w:["auto","min","max",u]}],"min-w":[{"min-w":["full","min","max",u]}],"max-w":[{"max-w":["0","none",...g,...m,"full","min","max","prose",{screen:g}]}],h:[{h:y}],"min-h":[{"min-h":["full","screen",u]}],"max-h":[{"max-h":h}],"font-family":[{font:z}],"font-size":[{text:["xs",...g,"base",...m,"8xl","9xl",f]}],"font-smoothing":["antialiased","subpixel-antialiased"],"font-style":["italic","not-italic"],"font-weight":[{font:["thin","extralight","light","normal","medium","semibold","bold","extrabold","black"]}],"fvn-normal":["normal-nums"],"fvn-ordinal":["ordinal"],"fvn-slashed-zero":["slashed-zero"],"fvn-figure":["lining-nums","oldstyle-nums"],"fvn-spacing":["proportional-nums","tabular-nums"],"fvn-fraction":["diagonal-fractions","stacked-fractons"],tracking:[{tracking:["tighter","tight","normal","wide","wider","widest",f]}],leading:[{leading:["none","tight","snug","normal","relaxed","loose",u]}],"list-style-type":[{list:["none","disc","decimal"]}],"list-style-position":[{list:["inside","outside"]}],"placeholder-color":[{placeholder:z}],"placeholder-opacity":[{"placeholder-opacity":k}],"text-alignment":[{text:["left","center","right","justify"]}],"text-color":[{text:z}],"text-opacity":[{"text-opacity":k}],"text-decoration":["underline","line-through","no-underline"],"text-transform":["uppercase","lowercase","capitalize","normal-case"],"text-overflow":["truncate","overflow-ellipsis","overflow-clip"],"vertival-alignment":[{align:["baseline","top","middle","bottom","text-top","text-bottom"]}],whitespace:[{whitespace:["normal","nowrap","pre","pre-line","pre-wrap"]}],break:[{break:["normal","words","all"]}],"bg-attachment":[{bg:["fixed","local","scroll"]}],"bg-clip":[{"bg-clip":["border","padding","content","text"]}],"bg-opacity":[{"bg-opacity":k}],"bg-origin":[{"bg-origin":["border","padding","content"]}],"bg-position":[{bg:G}],"bg-repeeat":[{bg:["no-repeat",{repeat:["","x","y","round","space"]}]}],"bg-size":[{bg:["auto","cover","contain"]}],"bg-image":[{bg:["none",{"gradient-to":["t","tr","r","br","b","bl","l","tl"]}]}],"bg-blend":[{bg:I}],"bg-color":[{bg:z}],"gradient-from":[{from:z}],"gradient-via":[{via:z}],"gradient-to":[{to:z}],rounded:[{rounded:O}],"rounded-t":[{"rounded-t":O}],"rounded-r":[{"rounded-r":O}],"rounded-b":[{"rounded-b":O}],"rounded-l":[{"rounded-l":O}],"rounded-tl":[{"rounded-tl":O}],"rounded-tr":[{"rounded-tr":O}],"rounded-br":[{"rounded-br":O}],"rounded-bl":[{"rounded-bl":O}],"border-w":[{border:w}],"border-w-t":[{"border-t":w}],"border-w-r":[{"border-r":w}],"border-w-b":[{"border-b":w}],"border-w-l":[{"border-l":w}],"border-opacity":[{"border-opacity":k}],"border-style":[{border:P}],"divide-x":[{"divide-x":w}],"divide-x-reverse":["divide-x-reverse"],"divide-y":[{"divide-y":w}],"divide-y-reverse":["divide-y-reverse"],"divide-opacity":[{"divide-opacity":k}],"divide-style":[{divide:P}],"border-color":[{border:z}],"border-color-t":[{"border-t":z}],"border-color-r":[{"border-r":z}],"border-color-b":[{"border-b":z}],"border-color-l":[{"border-l":z}],"divide-color":[{divide:z}],"ring-w":[{ring:w}],"ring-w-inset":["ring-inset"],"ring-color":[{ring:z}],"ring-opacity":[{"ring-opacity":k}],"ring-offset-w":[{"ring-offset":h}],"ring-offset-color":[{"ring-offset":z}],shadow:[{shadow:["",...g,"inner","none"]}],opacity:[{opacity:k}],"mix-blend":[{"mix-blend":I}],filter:[{filter:["","none"]}],blur:[{blur:["none","",...g,"3xl",f]}],brightness:[{brightness:k}],contrast:[{contrast:k}],"drop-shadow":[{"drop-shadow":["",...g,"none"]}],grayscale:[{grayscale:$}],"hue-rotate":[{"hue-rotate":k}],invert:[{invert:$}],saturate:[{saturate:k}],sepia:[{sepia:$}],"backdrop-filter":[{"backdrop-filter":["","none"]}],"backdrop-blur":[{"backdrop-blur":["none","",...g,"3xl"]}],"backdrop-brightness":[{"backdrop-brightness":k}],"backdrop-contrast":[{"backdrop-contrast":k}],"backdrop-grayscale":[{"backdrop-grayscale":$}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":k}],"backdrop-invert":[{"backdrop-invert":$}],"backdrop-opacity":[{"backdrop-opacity":k}],"backdrop-saturate":[{"backdrop-saturate":k}],"backdrop-sepia":[{"backdrop-sepia":$}],"border-collapse":[{border:["collapse","separate"]}],"table-layout":[{table:["auto","fixed"]}],transition:[{transition:["none","all","","colors","opacity","shadow","transform"]}],duration:[{duration:k}],ease:[{ease:["linear","in","out","in-out"]}],delay:[{delay:k}],animate:[{animate:["none","spin","ping","pulse","bounce"]}],transform:[{transform:["","gpu","none"]}],"transform-origin":[{origin:["center","top","top-right","right","bottom-right","bottom","bottom-left","left","top-left"]}],scale:[{scale:k}],"scale-x":[{"scale-x":k}],"scale-y":[{"scale-y":k}],rotate:[{rotate:k}],"translate-x":[{"translate-x":h}],"translate-y":[{"translate-y":h}],"skew-x":[{"skew-x":k}],"skew-y":[{"skew-y":k}],appearance:["appearance-none"],cursor:[{cursor:["auto","default","pointer","wait","text","move","help","not-allowed",b]}],outline:[{outline:["none","white","black"]}],"pointer-events":[{"pointer-events":["none","auto"]}],resize:[{resize:["none","y","x",""]}],select:[{select:["none","text","all","auto"]}],fill:["fill-current"],stroke:[{stroke:["current"]}],"stroke-w":[{stroke:h}],sr:["sr-only","not-sr-only"],content:[{content:[b]}],"caret-color":[{caret:z}]},conflictingClassGroups:{overflow:["overflow-x","overflow-y"],overscroll:["overscroll-x","overscroll-y"],inset:["inset-x","inset-y","top","right","bottom","left"],"inset-x":["right","left"],"inset-y":["top","bottom"],flex:["flex-grow","flex-shrink"],"col-start-end":["col-start","col-end"],"row-start-end":["row-start","row-end"],gap:["gap-x","gap-y"],p:["px","py","pt","pr","pb","pl"],px:["pr","pl"],py:["pt","pb"],m:["mx","my","mt","mr","mb","ml"],mx:["mr","ml"],my:["mt","mb"],"font-size":["leading"],"fvn-normal":["fvn-ordinal","fvn-slashed-zero","fvn-figure","fvn-spacing","fvn-fraction"],"fvn-ordinal":["fvn-normal"],"fvn-slashed-zero":["fvn-normal"],"fvn-figure":["fvn-normal"],"fvn-spacing":["fvn-normal"],"fvn-fraction":["fvn-normal"],rounded:["rounded-t","rounded-r","rounded-b","rounded-l","rounded-tl","rounded-tr","rounded-br","rounded-bl"],"rounded-t":["rounded-tl","rounded-tr"],"rounded-r":["rounded-tr","rounded-br"],"rounded-b":["rounded-br","rounded-bl"],"rounded-l":["rounded-tl","rounded-bl"],"border-w":["border-w-t","border-w-r","border-w-b","border-w-l"],"border-color":["border-color-t","border-color-r","border-color-b","border-color-l"]}}}const S=/\s+/,M=/:(?![^[]*\])/;function V(r){let o,n,l,a=function(d){return c=r(N),o=e({cache:(u=c.cacheSize,u>=1?function(e){if(!e)throw Error("hashlru must have a max value, of type number, greater than 0");var t=0,r=Object.create(null),o=Object.create(null);function n(n,i){r[n]=i,++t>=e&&(t=0,o=r,r=Object.create(null))}return{has:function(e){return void 0!==r[e]||void 0!==o[e]},remove:function(e){void 0!==r[e]&&(r[e]=void 0),void 0!==o[e]&&(o[e]=void 0)},get:function(e){var t=r[e];return void 0!==t?t:void 0!==(t=o[e])?(n(e,t),t):void 0},set:function(e,t){void 0!==r[e]?r[e]=t:n(e,t)},clear:function(){r=Object.create(null),o=Object.create(null)}}}(u):{get:()=>{},set:()=>{}})},i(c),t(c)),n=o.cache.get,l=o.cache.set,a=s,s(d);var c,u};function s(e){const t=n(e);if(t)return t;const r=function(e,t){const{isPrefixValid:r,getClassGroupId:o,comparePrefixes:n,getConflictingClassGroupIds:i}=t,l=new Set,a=e.trim().split(S);let s="";for(let e=a.length-1;e>=0;e-=1){const t=a[e],d=t.startsWith("!"),c=(d?t.substring(1):t).split(M),u=c.pop(),f=c.every(r)?o(u):void 0;if(!f){s=t+" "+s;continue}const p=0===c.length?"":c.sort(n).concat("").join(":"),b=d?"!"+p:p,g=`${b}:${f}`;l.has(g)||(l.add(g),i(f).forEach(e=>l.add(`${b}:${e}`)),s=t+" "+s)}return s.trim()}(e,o);return l(e,r),r}return function(...e){return a(e.join(" "))}}const W=V(e=>e());
  const createTailwindMerge = V;
	const twMerge = createTailwindMerge(c => {
		const config = c();
  	config.cacheSize = 0;
  	return config;
	});
	twMerge('');
  return twMerge;
};

Unptimized

twMerge1(
	'px-2 py-1 bg-red hover:bg-dark-red border text-white non-tailwind-class rounded-t-sm right-4',
	'p-3 bg-[#B91C1C] border-2 text-black other-non-tailwind-class',
	undefined,
	'rounded-lg inset-2',
	null
);

Optimized

twMerge2(
	'px-2 py-1 bg-red hover:bg-dark-red border text-white non-tailwind-class rounded-t-sm right-4',
	'p-3 bg-[#B91C1C] border-2 text-black other-non-tailwind-class',
	undefined,
	'rounded-lg inset-2',
	null
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
context-v0 Related to tailwind-merge v0 feature Is new feature needs changelog edit Needs edit in changelog before release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Move from array map/filter/join to for loops and string concatenation in hot path to increase performance
1 participant