Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

stylis

Package Overview
Dependencies
Maintainers
1
Versions
174
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

stylis - npm Package Compare versions

Comparing version 3.5.4 to 4.0.0

dist/stylis.cjs

193

package.json
{
"name": "stylis",
"main": "stylis.js",
"unpkg": "stylis.min.js",
"jsdelivr": "stylis.min.js",
"types": "stylis.d.ts",
"description": "light - weight css preprocessor",
"version": "3.5.4",
"homepage": "https://github.com/thysultan/stylis.js",
"license": "MIT",
"author": {
"name": "Sultan Tarimo",
"email": "sultantarimo@me.com"
},
"keywords": [
"css",
"preprocessor"
],
"repository": {
"type": "git",
"url": "https://github.com/thysultan/stylis.js"
},
"bugs": {
"url": "https://github.com/thysultan/stylis.js/issues"
},
"scripts": {
"test": "node ./tests",
"minify": "uglifyjs stylis.js -o stylis.min.js --compress 'conditionals=false,if_return=false,booleans=false' --mangle --screw-ie8 --source-map url=stylis.min.js.map",
"prepublish": "npm run minify"
},
"files": [
"stylis.js",
"stylis.min.js",
"stylis.min.js.map",
"stylis.d.ts"
],
"devDependencies": {
"uglify-js": "^3.2.2"
}
"name": "stylis",
"version": "4.0.0",
"license": "MIT",
"description": "A Light–weight CSS Preprocessor",
"homepage": "https://github.com/thysultan/stylis.js",
"author": "Sultan Tarimo <sultantarimo@me.com>",
"repository": "https://github.com/thysultan/stylis.js",
"bugs": "https://github.com/thysultan/stylis.js/issues",
"type": "module",
"main": "dist/stylis.umd.js",
"module": "dist/stylis.esm.js",
"exports": {
"import": "./index.js",
"require": "./dist/stylis.cjs"
},
"files": [
"index.js",
"dist/",
"src/"
],
"scripts": {
"lint": "eslint ./",
"pretest": "npm run lint && npm run build",
"test": "nyc npm run spec",
"spec": "mocha --harmony --require esm script/setup.js --recursive test",
"build": "rollup --config script/build.js --configSrc ./",
"start": "rollup --config script/build.js --configSrc ./ --watch",
"prepare": "npm run build",
"postversion": "git push --follow-tags && npm publish",
"release-major": "npm version major -m '%s'",
"release-minor": "npm version minor -m '%s'",
"release-patch": "npm version patch -m '%s'"
},
"devDependencies": {
"stylis": "./",
"chai": "4.2.0",
"eslint": "6.8.0",
"esm": "3.2.25",
"mocha": "7.0.0",
"nyc": "15.0.0",
"rollup": "1.28.0",
"rollup-plugin-terser": "5.1.3",
"rollup-plugin-size": "0.2.1"
},
"nyc": {
"temp-dir": "./coverage/.nyc_output",
"exclude": [
"**/dist/",
"**/test/",
"**/script/"
],
"reporter": [
"lcov",
"text"
]
},
"esm": {
"cjs": true,
"cache": false
},
"eslintIgnore": [
"script/",
"test/",
"dist/",
"docs/"
],
"eslintConfig": {
"env": {
"commonjs": true,
"browser": true,
"node": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 7,
"sourceType": "module",
"ecmaFeatures": {
"impliedStrict": true
}
},
"rules": {
"indent": [
"error",
"tab",
{
"SwitchCase": 1
}
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"never"
],
"no-cond-assign": [
"off"
],
"no-redeclare": [
"off"
],
"no-fallthrough": [
"off"
],
"no-console": [
"off"
],
"no-unsafe-finally": [
"off"
],
"no-shadow-restricted-names": [
"error"
],
"no-whitespace-before-property": [
"error"
],
"eol-last": [
"error"
],
"func-call-spacing": [
"error",
"never"
],
"brace-style": [
"error",
"1tbs",
{
"allowSingleLine": true
}
],
"require-jsdoc": [
"error",
{
"require": {
"FunctionDeclaration": true
}
}
],
"no-trailing-spaces": [
"error",
{
"skipBlankLines": true
}
],
"no-constant-condition": [
"off"
]
}
}
}

382

README.md

@@ -5,369 +5,135 @@ # STYLIS

light – weight css preprocessor
A Light–weight CSS Preprocessor.
- 3Kb
[![Coverage](https://coveralls.io/repos/github/thysultan/stylis.js/badge.svg?branch=master)](https://coveralls.io/github/thysultan/stylis.js)
[![Size](https://badgen.net/bundlephobia/minzip/stylis)](https://bundlephobia.com/result?p=stylis)
[![Licence](https://badgen.net/badge/license/MIT/blue)](https://github.com/dyo/dyo/blob/master/LICENSE.md)
[![NPM](https://badgen.net/npm/v/dyo)](https://www.npmjs.com/package/dyo)
[![npm](https://img.shields.io/npm/v/stylis.svg?style=flat)](https://www.npmjs.com/package/stylis) [![licence](https://img.shields.io/badge/licence-MIT-blue.svg?style=flat)](https://github.com/thysultan/stylis.js/blob/master/LICENSE.md) [![Build Status](https://semaphoreci.com/api/v1/thysultan/stylis-js/branches/master/shields_badge.svg)](https://semaphoreci.com/thysultan/stylis-js) ![dependencies](https://img.shields.io/badge/dependencies-none-green.svg?style=flat)
## Supports
* Edge
* IE 8+
* Chrome
* Firefox
* Safari
* Node
---
## Installation
#### direct download
* Use a Direct Download: `<script src=stylis.js></script>`
* Use a CDN: `<script src=unpkg.com/stylis></script>`
* Use NPM: `npm install stylis --save`
```html
<script src=stylis.min.js></script>
```
#### CDN
```html
<script src=https://unpkg.com/stylis@latest/stylis.min.js></script>
```
#### npm
```
npm install stylis --save
```
## Features
- selector namespacing/isolation
- inline global injection ex. `:global(selector)`
- nesting `a { &:hover {} }`
- selector namespacing
- vendor prefixing (flex-box, etc...)
- flat stylesheets `color: red; h1 { color: red; }`
- keyframe and animation namespacing
- plugins
- minification
- built to support [closure-compiler advanced mode](https://developers.google.com/closure/compiler)
- esm module compatible
- tree-shaking-able
---
## Abstract Syntax Structure
## Input
```javascript
stylis('#id', `
font-size: 2em;
// line comments
/* block comments */
:global(body) {background:red}
h1 {
h2 {
h3 {
content:'nesting'
}
}
```js
const declaration = {
value: 'color:red;',
type: 'decl',
props: 'color',
children: 'red',
line: 1, column: 1
}
@media (max-width: 600px) {
& {display:none}
const comment = {
value: '/*@noflip*/',
type: 'comm',
props: '/',
children: '@noflip',
line: 1, column: 1
}
&:before {
animation: slide 3s ease infinite
const ruleset = {
value: 'h1,h2',
type: 'rule',
props: ['h1', 'h2'],
children: [/* ... */],
line: 1, column: 1
}
@keyframes slide {
from { opacity: 0}
to { opacity: 1}
const atruleset = {
value: '@media (max-width:100), (min-width:100)',
type: '@media',
props: ['(max-width:100)', '(min-width:100)'],
children: [/* ... */],
line: 1, column: 1
}
& {
display: flex
}
&::placeholder {
color:red
}
`);
```
## Output
## Example:
```css
#id {font-size: 2em;}
body {background:red}
h1 h2 h3 {content: 'nesting'}
@media (max-width: 600px) {
#id {display:none}
}
#id:before {
-webkit-animation: slide-id 3s ease infinite;
animation: slide-id 3s ease infinite;
}
@-webkit-keyframes slide-id {
from { opacity: 0}
to { opacity: 1}
}
@keyframes slide-id {
from { opacity: 0}
to { opacity: 1}
}
#id {
display:-webkit-box;
display:-webkit-flex;
display:-ms-flexbox;
display:flex;
}
#id::-webkit-input-placeholder {color:red;}
#id::-moz-placeholder {color:red;}
#id:-ms-input-placeholder {color:red;}
#id::placeholder {color:red;}
```
## API
#### Stylis
```javascript
stylis(selector: {String}, css: {String})
```
#### Factory
```js
// factory pattern
var stylis = new stylis(options)
import {compile, serialize, stringify} from 'stylis'
// singleton pattern
var stylis = stylis
serialize(compile(`h1{all:unset}`), stringify)
```
When using the factory pattern the if an object is passed as optional `options` argument, this will be passed to `stylis.set(options)`
### Compile
#### Set
```javascript
// all options except compress and cascade are enabled by default
stylis.set({
// (dis/en)able :global selectors
global: {Boolean}
// (dis/en)able aggressive cascade isolation
// true for normal cascade(default) false for no cascading
cascade: {Boolean}
// (dis/en)able namespace keyframes + animations
keyframe: {Boolean}
// (dis/en)able vendor prefixing
prefix: {Boolean|Function(key: string, value: string, context: number)}
// (dis/en)able aggressive minification
compress: {Boolean}
// (dis/en)able (no)semicolon support
// false to enable no-semicolons (default)
semicolon: {Boolean},
// tell stylis to make an effort to preserve empty rules,
// i.e `.selector{ }`
preserve: {Boolean}
})
```
#### Vendor Prefixing
By default vendor is enabled, however there is an option to disable vendor prefixing, either completely or dynamically.
The following would disable prefixing.
```js
stylis.set({prefix: false})
compile('h1{all:unset}') === [{value: 'h1', type: 'rule', props: ['h1'], children: [/* ... */]}]
compile('--foo:unset;') === [{value: '--foo:unset;', type: 'decl', props: '--foo', children: 'unset'}]
```
Alternatively you can disable prefixing on a case by case basis by providing a function that returns a `boolean` indiciating whether to prefixing that particular rule.
### Tokenize
```js
stylis.set({
prefix: (key, value, context) => {
return false
}
})
tokenize('h1 h2 h3 [h4 h5] fn(args) "a b c"') === ['h1', 'h2', 'h3', '[h4 h5]', 'fn', '(args)', '"a b c"']
```
The arguments correspond to the rule that is about to be vendor prefixed. For example:
### Serialize
```js
// transform: none;
key = 'transform'
value = 'none'
context = 1
// :read-only {...}
key = ':read-only'
value = '...'
context = 2
// @keyframes {...}
key = '@keyframes'
value = '...'
context = 3
serialize(compile('h1{all:unset}'), stringify)
```
#### Use
## Middleware
```javascript
stylis.use(plugin: {Function|Array<Function>|null})
```
The middleware helper is a convinent helper utility, that for all intensive purposes you can do without if you intend to implement your own traversal logic. The `stringify` middleware is one such middleware that can be used in conjunction with it.
The use function is chainable ex. `stylis.use()()()`
Elements passed to middlewares have a `root` property that is the immediate root/parent of the current element **in the compiled output**, so it references the parent in the already expanded CSS-like structure. Elements have also `parent` property that is the immediate parent of the current element **from the input structure** (structure representing the input string).
## Plugins
### Traversal
The optional middleware function accepts four arguments with `this` pointing to a reference of the current stylis instance.
```js
(context, content, selectors, parent, line, column, length)
serialize(compile('h1{all:unset}'), middleware([(element, index, children) => {
assert(children === element.root.children && children[index] === element.children)
}, stringify])) === 'h1{all:unset;}'
```
Plugins are executed in stages identified by an `context` interger value.
The abstract syntax tree also includes an additional `return` property for more niche uses.
```
-2 /* post-process context */
-1 /* preparation context */
0 /* newline context */
### Prefixing
1 /* property context */
2 /* selector block context */
3 /* @at-rule block context */
```js
serialize(compile('h1{all:unset}'), middleware([(element, index, children, callback) => {
if (element.type === 'decl' && element.props === 'all' && element.children === 'unset')
element.return = 'color:red;' + element.value
}, stringify])) === 'h1{color:red;all:unset;}'
```
> Note: Since the newline context is intended for source-map plugins by default stylis will not execute plugins in this context unless enabled, this can be done through `stylis.use(true)` or disabled after that through `stylis.use(false)`.
- `-2` post processed context, before the compiled css output is returned
- `-1` preparation context, before the compiler starts
- `0` after every newline
- `1` on a property declaration ex. `color: red;`
- `2` after a selector block of css has been processed ex. `.foo {color:red;}`
- `3` after a `@at-rule` block of css has been processed ex. `@media {h1{color:red;}}`
If at any context(except 0) that the middleware returns a different string the content of css will be replaced with the return value.
To remove all plugins just call `.use` with null/no arguments.
```js
// removes all previously added plugins, then adds one
stylis.use(null)(ctx => {})
serialize(compile('h1{all:unset}'), middleware([(element, index, children, callback) => {
if (element.type === 'rule' && element.props.indexOf('h1') > -1)
return serialize([{...element, props: ['h2', 'h3']}], callback)
}, stringify])) === 'h2,h3{all:unset;}h1{all:unset;}'
```
For example we can add a feature `random()` to our css that when used prints a random number.
### Reading
```javascript
/**
* plugin
*
* @param {number} context
* @param {Array<string>} selector
* @param {Array<string>} parent
* @param {string} content
* @param {number} line
* @param {number} column
* @param {number} length
* @return {(string|void)?}
*/
const plugin = (context, content, selectors, parent, line, column, length) => {
switch (context) {
case 1: return content.replace(/random\(\)/g, Math.random())
}
}
/**
* use
*
* @param {(Array<function>|function|null|boolean)} plugin
* @return {Function} use
*/
stylis.use(plugin)
stylis(``, `h1 { width: calc(random()*10); }`)
```js
serialize(compile('h1{all:unset}'), middleware([stringify, (element, index, children) => {
assert(element.return === 'h1{all:unset;}')
}])) === 'h1{all:unset;color:red;}'
```
This will replace all instances of `random()` with a random number.
The middlewares in [src/Middleware.js](src/Middleware.js) dive into tangible examples of how you might implement a middleware, alternatively you could also create your own middleware system as `compile` returns all the nessessary structure to fork from.
Internally Before stylis processes `calc(random()*10);` it passes it to the plugin if a plugin exists; If in turn the plugin returns something different from what it received stylis will replace the content of the property with the return value and continue processing that.
The same can be said for a selector block, in both contexts an argument `selector` is passed that contains the current array of selectors that the block of css/property stylis is working on.
This array of selectors is mutable and will reflect the output of selectors if changed.
## Benchmark
Stylis is fast, and though it does not generate an AST you can with a plugin create an AST out of the resulting input, this and other aspects allow it to be very small(3KB).
Stylis is at-least 2X faster than its predecesor.
The benchmark results are using [https://github.com/postcss/benchmark](https://github.com/postcss/benchmark)
### License
> Note that the benchmark is not a one-2-one comparison because each library was developed for different goals and different set of features.
Stylis appears in all the benchmarks because by default stylis both parsers, processes and auto prefixes in one pass.
#### Parsers
```
Stylis x 54.28 ops/sec ±4.45% (58 runs sampled)
CSSTree x 39.73 ops/sec ±9.18% (56 runs sampled)
PostCSS x 21.11 ops/sec ±8.46% (57 runs sampled)
CSSOM x 19.20 ops/sec ±6.53% (36 runs sampled)
Mensch x 17.85 ops/sec ±13.39% (37 runs sampled)
Rework x 12.80 ops/sec ±4.42% (36 runs sampled)
PostCSS Full x 8.15 ops/sec ±7.79% (45 runs sampled)
Gonzales x 5.21 ops/sec ±7.75% (18 runs sampled)
Gonzales PE x 3.99 ops/sec ±10.37% (15 runs sampled)
Stylecow x 3.97 ops/sec ±9.48% (15 runs sampled)
ParserLib x 1.79 ops/sec ±8.58% (9 runs sampled)
Fastest test is Stylis at 1.37x faster than CSSTree
```
---
#### Preprocessors
```
Stylis x 26.26 ops/sec ±5.95% (49 runs sampled)
PostCSS x 16.23 ops/sec ±11.21% (47 runs sampled)
Rework x 10.65 ops/sec ±3.86% (55 runs sampled)
libsass x 6.83 ops/sec ±2.29% (22 runs sampled)
Less x 4.75 ops/sec ±9.14% (29 runs sampled)
Stylus x 3.67 ops/sec ±28.12% (25 runs sampled)
Stylecow x 2.15 ops/sec ±6.36% (15 runs sampled)
Ruby Sass x 0.31 ops/sec ±8.12% (6 runs sampled)
Fastest test is Stylis at 1.62x faster than PostCSS
```
---
#### Prefixers
```
Stylis x 45.52 ops/sec ±14.61% (77 runs sampled)
Autoprefixer x 13.32 ops/sec ±6.51% (67 runs sampled)
Stylecow x 2.28 ops/sec ±5.97% (16 runs sampled)
nib x 1.79 ops/sec ±25.32% (15 runs sampled)
Compass x 0.15 ops/sec ±9.34% (5 runs sampled)
Fastest test is Stylis at 3.4x faster than Autoprefixer
```
Stylis is [MIT licensed](./LICENSE).
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc