Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: lukeed/clsx
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 6232a9e5649143a28419a04f786a15f63a0b7edd
Choose a base ref
...
head repository: lukeed/clsx
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: a60db12a53aee6a14218a62d8a0624f556b87032
Choose a head ref
  • 12 commits
  • 9 files changed
  • 5 contributors

Commits on Jul 16, 2023

  1. Copy the full SHA
    4c9a55d View commit details

Commits on Oct 20, 2023

  1. Copy the full SHA
    42354d3 View commit details

Commits on Dec 29, 2023

  1. chore(ci): update node matrix

    lukeed committed Dec 29, 2023
    Copy the full SHA
    308a238 View commit details
  2. fix(ci): replace nyc -> c8

    lukeed committed Dec 29, 2023
    Copy the full SHA
    6e2468e View commit details
  3. chore: cache arguments/array lengths (#26)

    * feat: enhance performance
    
    * chore: undo Extracting k to the outer level
    
    Co-authored-by: Sukka <isukkaw@gmail.com>
    
    * Apply suggestions from code review
    
    ---------
    
    Co-authored-by: Sukka <isukkaw@gmail.com>
    Co-authored-by: Luke Edwards <luke.edwards05@gmail.com>
    3 people authored Dec 29, 2023
    Copy the full SHA
    deff09b View commit details
  4. chore: dedicated string vs number var usage;

    - related: #23
    lukeed committed Dec 29, 2023
    Copy the full SHA
    554ad31 View commit details
  5. chore: update benchmarks;

    - Closes #88
    lukeed committed Dec 29, 2023
    Copy the full SHA
    6e3b2b9 View commit details
  6. chore: update module size

    lukeed committed Dec 29, 2023
    Copy the full SHA
    bf64e71 View commit details
  7. Copy the full SHA
    855eec2 View commit details
  8. 2.0.1

    lukeed committed Dec 29, 2023
    Copy the full SHA
    5cac14c View commit details
  9. feat: add clsx/lite module

    lukeed committed Dec 29, 2023
    Copy the full SHA
    1a49142 View commit details
  10. 2.1.0

    lukeed committed Dec 29, 2023
    Copy the full SHA
    a60db12 View commit details
Showing with 240 additions and 70 deletions.
  1. +10 −10 .github/workflows/ci.yml
  2. +3 −1 bench/index.js
  3. +23 −22 bench/readme.md
  4. +49 −16 bin/index.js
  5. +22 −10 package.json
  6. +49 −4 readme.md
  7. +8 −7 src/index.js
  8. +13 −0 src/lite.js
  9. +63 −0 test/lite.js
20 changes: 10 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -8,10 +8,10 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
nodejs: [8, 10, 12, 14, 16]
nodejs: [8, 10, 12, 14, 16, 18]
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ matrix.nodejs }}

@@ -25,24 +25,24 @@ jobs:
run: npm install

- name: (coverage) Install
if: matrix.nodejs >= 16
run: npm install -g nyc
if: matrix.nodejs >= 18
run: npm install -g c8

- name: Build
run: npm run build

- name: Test
run: npm test
if: matrix.nodejs < 16
if: matrix.nodejs < 18

- name: (coverage) Test
run: nyc --include=src npm test
if: matrix.nodejs >= 16
run: c8 --include=src npm test
if: matrix.nodejs >= 18

- name: (coverage) Report
if: matrix.nodejs >= 16
if: matrix.nodejs >= 18
run: |
nyc report --reporter=text-lcov > coverage.lcov
c8 report --reporter=text-lcov > coverage.lcov
bash <(curl -s https://codecov.io/bash)
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
4 changes: 3 additions & 1 deletion bench/index.js
Original file line number Diff line number Diff line change
@@ -3,14 +3,16 @@ const classnames = require('classnames');
const classcat = require('classcat');
const clsx = require('../dist/clsx');
const old = require('clsx');
const lite = require('../dist/lite');

function bench(name, ...args) {
console.log(`\n# ${name}`);
new Suite()
.add('classcat* ', () => classcat.apply(classcat, [args]))
.add('classcat ', () => classcat.apply(classcat, [args]))
.add('classnames ', () => classnames.apply(classnames, args))
.add('clsx (prev) ', () => old.apply(old, args))
.add('clsx ', () => clsx.apply(clsx, args))
.add('clsx (lite) ', () => lite.apply(lite, args))
.on('cycle', e => console.log(' ' + e.target))
.run();
}
45 changes: 23 additions & 22 deletions bench/readme.md
Original file line number Diff line number Diff line change
@@ -4,45 +4,46 @@
## Node

These are the results while running this directory's benchmark suite in Node v10.13.0.
These are the results while running this directory's benchmark suite in Node v20.10.0.

> **Note:** The `` denotes that the candidate has a different API and is not compatible with `classnames` usage.
```
# Strings
classcat ≠ x 8,719,816 ops/sec ±0.69% (91 runs sampled)
classnames x 3,992,284 ops/sec ±1.64% (94 runs sampled)
clsx x 12,784,134 ops/sec ±0.42% (97 runs sampled)
classcat ≠ x 9,613,381 ops/sec ±0.16% (94 runs sampled)
classnames x 6,540,072 ops/sec ±0.11% (101 runs sampled)
clsx x 12,924,662 ops/sec ±0.15% (102 runs sampled)
clsx/lite x 13,122,004 ops/sec ±0.40% (99 runs sampled)
# Objects
classcat ≠ x 8,680,509 ops/sec ±0.36% (97 runs sampled)
classnames x 3,772,978 ops/sec ±0.46% (96 runs sampled)
clsx x 9,412,010 ops/sec ±0.42% (95 runs sampled)
classcat ≠ x 8,936,903 ops/sec ±0.12% (100 runs sampled)
classnames x 6,143,319 ops/sec ±0.14% (100 runs sampled)
clsx x 9,444,110 ops/sec ±0.11% (102 runs sampled)
# Arrays
classcat ≠ x 7,589,602 ops/sec ±0.62% (95 runs sampled)
classnames x 1,665,275 ops/sec ±1.83% (93 runs sampled)
clsx x 9,141,916 ops/sec ±0.42% (95 runs sampled)
classcat ≠ x 8,247,121 ops/sec ±0.12% (98 runs sampled)
classnames x 3,451,489 ops/sec ±0.18% (99 runs sampled)
clsx x 9,401,030 ops/sec ±0.18% (101 runs sampled)
# Nested Arrays
classcat ≠ x 6,411,409 ops/sec ±0.84% (93 runs sampled)
classnames x 1,164,706 ops/sec ±1.60% (95 runs sampled)
clsx x 7,165,151 ops/sec ±0.47% (91 runs sampled)
classcat ≠ x 6,759,204 ops/sec ±0.31% (97 runs sampled)
classnames x 2,015,566 ops/sec ±0.18% (100 runs sampled)
clsx x 7,315,032 ops/sec ±0.43% (99 runs sampled)
# Nested Arrays w/ Objects
classcat ≠ x 6,447,346 ops/sec ±0.68% (92 runs sampled)
classnames x 1,597,180 ops/sec ±1.49% (93 runs sampled)
clsx x 7,651,411 ops/sec ±0.56% (95 runs sampled)
classcat ≠ x 6,726,315 ops/sec ±0.16% (98 runs sampled)
classnames x 3,059,235 ops/sec ±0.45% (99 runs sampled)
clsx x 7,352,761 ops/sec ±0.44% (98 runs sampled)
# Mixed
classcat ≠ x 6,595,879 ops/sec ±0.42% (96 runs sampled)
classnames x 2,129,199 ops/sec ±1.46% (94 runs sampled)
clsx x 8,119,210 ops/sec ±0.42% (93 runs sampled)
classcat ≠ x 6,956,920 ops/sec ±0.21% (97 runs sampled)
classnames x 4,171,381 ops/sec ±0.15% (98 runs sampled)
clsx x 8,468,116 ops/sec ±0.11% (96 runs sampled)
# Mixed (Bad Data)
classcat ≠ x 1,771,920 ops/sec ±0.41% (96 runs sampled)
classnames x 1,166,577 ops/sec ±0.84% (94 runs sampled)
clsx x 2,238,939 ops/sec ±0.34% (95 runs sampled)
classcat ≠ x 2,128,702 ops/sec ±0.13% (101 runs sampled)
classnames x 1,925,670 ops/sec ±0.19% (100 runs sampled)
clsx x 2,996,516 ops/sec ±0.07% (100 runs sampled)
```

## Browsers
65 changes: 49 additions & 16 deletions bin/index.js
Original file line number Diff line number Diff line change
@@ -4,8 +4,6 @@ const zlib = require('zlib');
const { minify } = require('terser');
const pkg = require('../package.json');

if (!fs.existsSync('dist')) fs.mkdirSync('dist');

/**
* @param {string} file
* @param {string} source
@@ -17,22 +15,57 @@ function write(file, source) {
compress: true,
});

fs.writeFileSync(file, result.code);
console.log('~> "%s" (%d b)', file, zlib.gzipSync(result.code).byteLength);
if (result.code) {
fs.writeFileSync(file, result.code);
let size = zlib.gzipSync(result.code).byteLength;
console.log('~> "%s" (%d b)', file, size);
} else {
console.error('!! "%s" ::', file, result.error);
}
}

let input = fs.readFileSync('src/index.js', 'utf8');
/**
* @typedef Export
* @property {Condition} import
* @property {Condition} default
*/

// copy for ESM
write(pkg.module, input);
/**
* @typedef Condition
* @property {string} types
* @property {string} default
*/

// transform ESM -> CJS exports
write(pkg.main, input.replace('export function', 'function').replace(
'export default clsx;',
'module.exports = clsx;\n'
+ 'module.exports.clsx = clsx;'
));
/**
* @param {string} file
* @param {"." | "./lite"} entry
*/
function bundle(file, entry) {
fs.existsSync('dist') || fs.mkdirSync('dist');

/**
* @type {Export}
*/
let output = pkg.exports[entry];
let input = fs.readFileSync(file, 'utf8');

// copy for ESM file
write(output.import.default, input);

// transform ESM -> CJS exports
write(output.default.default, input.replace('export function', 'function').replace(
'export default clsx;',
'module.exports = clsx;\n'
+ 'module.exports.clsx = clsx;'
));

if (entry === '.') {
// transform ESM -> UMD exports
input = input.replace('export function', 'function').replace('export default clsx;', 'return clsx.clsx=clsx, clsx;');
write(pkg.unpkg, '!function(global,factory){"object"==typeof exports&&"undefined"!=typeof module?module.exports=factory():"function"==typeof define&&define.amd?define(factory):global.clsx=factory()}(this,function(){' + input + '});');
}
}

// transform ESM -> UMD exports
input = input.replace('export function', 'function').replace('export default clsx;', 'return clsx.clsx=clsx, clsx;');
write(pkg.unpkg, '!function(global,factory){"object"==typeof exports&&"undefined"!=typeof module?module.exports=factory():"function"==typeof define&&define.amd?define(factory):global.clsx=factory()}(this,function(){' + input + '});');
bundle('src/index.js', '.');
console.log('---');
bundle('src/lite.js', './lite');
32 changes: 22 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,35 @@
{
"name": "clsx",
"version": "2.0.0",
"version": "2.1.0",
"repository": "lukeed/clsx",
"description": "A tiny (234B) utility for constructing className strings conditionally.",
"description": "A tiny (239B) utility for constructing className strings conditionally.",
"module": "dist/clsx.mjs",
"unpkg": "dist/clsx.min.js",
"main": "dist/clsx.js",
"types": "clsx.d.ts",
"license": "MIT",
"exports": {
"import": {
"types": "./clsx.d.mts",
"default": "./dist/clsx.mjs"
".": {
"import": {
"types": "./clsx.d.mts",
"default": "./dist/clsx.mjs"
},
"default": {
"types": "./clsx.d.ts",
"default": "./dist/clsx.js"
}
},
"default": {
"types": "./clsx.d.ts",
"default": "./dist/clsx.js"
"./lite": {
"import": {
"types": "./clsx.d.mts",
"default": "./dist/lite.mjs"
},
"default": {
"types": "./clsx.d.ts",
"default": "./dist/lite.js"
}
}
},
"types": "clsx.d.ts",
"license": "MIT",
"author": {
"name": "Luke Edwards",
"email": "luke.edwards05@gmail.com",
53 changes: 49 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# clsx [![CI](https://github.com/lukeed/clsx/workflows/CI/badge.svg)](https://github.com/lukeed/clsx/actions?query=workflow%3ACI) [![codecov](https://badgen.net/codecov/c/github/lukeed/clsx)](https://codecov.io/gh/lukeed/clsx)

> A tiny (234B) utility for constructing `className` strings conditionally.<Br>Also serves as a [faster](/bench) & smaller drop-in replacement for the `classnames` module.
> A tiny (239B) utility for constructing `className` strings conditionally.<Br>Also serves as a [faster](bench) & smaller drop-in replacement for the `classnames` module.
This module is available in three formats:

* **ES Module**: `dist/clsx.m.js`
* **ES Module**: `dist/clsx.mjs`
* **CommonJS**: `dist/clsx.js`
* **UMD**: `dist/clsx.min.js`

@@ -66,9 +66,48 @@ clsx(true, false, '', null, undefined, 0, NaN);
//=> ''
```

## Modes

There are multiple "versions" of `clsx` available, which allows you to bring only the functionality you need!

#### `clsx`
> **Size (gzip):** 239 bytes<br>
> **Availability:** CommonJS, ES Module, UMD
The default `clsx` module; see [API](#API) for info.

```js
import { clsx } from 'clsx';
// or
import clsx from 'clsx';
```

#### `clsx/lite`
> **Size (gzip):** 140 bytes<br>
> **Availability:** CommonJS, ES Module<br>
> **CAUTION:** Accepts **ONLY** string arguments!
Ideal for applications that ***only*** use the string-builder pattern.

Any non-string arguments are ignored!

```js
import { clsx } from 'clsx/lite';
// or
import clsx from 'clsx/lite';

// string
clsx('hello', true && 'foo', false && 'bar');
// => "hello foo"

// NOTE: Any non-string input(s) ignored
clsx({ foo: true });
//=> ""
```

## Benchmarks

For snapshots of cross-browser results, check out the [`bench`](/bench) directory~!
For snapshots of cross-browser results, check out the [`bench`](bench) directory~!

## Support

@@ -81,8 +120,8 @@ All browsers that support [`Array.isArray`](https://developer.mozilla.org/en-US/
## Tailwind Support

Here some additional (optional) steps to enable classes autocompletion using `clsx` with Tailwind CSS.
<details>

<details>
<summary>
Visual Studio Code
</summary>
@@ -100,6 +139,12 @@ Here some additional (optional) steps to enable classes autocompletion using `cl
```
</details>

You may find the [`clsx/lite`](#clsxlite) module useful within Tailwind contexts. This is especially true if/when your application **only** composes classes in this pattern:

```js
clsx('text-base', props.active && 'text-primary', props.className);
```

## Related

- [obj-str](https://github.com/lukeed/obj-str) - A smaller (96B) and similiar utility that only works with Objects.
15 changes: 8 additions & 7 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,8 @@ function toVal(mix) {
str += mix;
} else if (typeof mix === 'object') {
if (Array.isArray(mix)) {
for (k=0; k < mix.length; k++) {
var len=mix.length;
for (k=0; k < len; k++) {
if (mix[k]) {
if (y = toVal(mix[k])) {
str && (str += ' ');
@@ -14,10 +15,10 @@ function toVal(mix) {
}
}
} else {
for (k in mix) {
if (mix[k]) {
for (y in mix) {
if (mix[y]) {
str && (str += ' ');
str += k;
str += y;
}
}
}
@@ -27,9 +28,9 @@ function toVal(mix) {
}

export function clsx() {
var i=0, tmp, x, str='';
while (i < arguments.length) {
if (tmp = arguments[i++]) {
var i=0, tmp, x, str='', len=arguments.length;
for (; i < len; i++) {
if (tmp = arguments[i]) {
if (x = toVal(tmp)) {
str && (str += ' ');
str += x
13 changes: 13 additions & 0 deletions src/lite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export function clsx() {
var i=0, tmp, str='', len=arguments.length;
for (; i < len; i++) {
if (tmp = arguments[i]) {
if (typeof tmp === 'string') {
str += (str && ' ') + tmp;
}
}
}
return str;
}

export default clsx;
Loading