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

Added minify option to createGenerateId #1075

Merged
merged 13 commits into from
May 21, 2019
Merged
4 changes: 4 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Next

### Breaking Changes

- [jss] Add option for opt-in minification of class names. ([#1075](https://github.com/cssinjs/jss/pull/1075))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a feature and a breaking change


### Bug fixes

- [jss-plugin-expand] Fix attributes spread for `border-bottom`, `border-top`, `border-left` and `border-right` ([#1083](https://github.com/cssinjs/jss/pull/1083))
Expand Down
13 changes: 13 additions & 0 deletions docs/jss-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Options:
- `plugins` - an array of functions, will be passed to `jss.use`.
- `Renderer` - if null, JSS will not render to DOM, or pass a custom Renderer.
- `insertionPoint` - string value of a DOM comment node which marks the start of sheets or a rendered DOM node. Sheets rendered by this Jss instance are inserted after this point sequentially.
- `id` - The options for the `createGenerateId`. This is an object which contains a single attribute called `minify` which should be a `boolean`.

**Note**: Each `jss.setup()` call will perform a shallow merge with the old options except for `plugins`. Passed `plugins` will get added to the existing plugins.

Expand Down Expand Up @@ -420,6 +421,18 @@ console.log(sheet.toString())
}
```

## Minify selectors

When you want to minify your selectors in production for example, you can configure this in your `jss.setup` call.

> Note: This is disabled by default.

```js
import jss from 'jss'
// Pass the id option to jss.setup and set minify to true.
jss.setup({id: {minify: true}})
```

## Extract dynamic styles

`getDynamicStyles(styles)`
Expand Down
28 changes: 14 additions & 14 deletions packages/jss/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
{
"dist/jss.js": {
"bundled": 58914,
"minified": 21845,
"gzipped": 6575
"bundled": 59273,
"minified": 22057,
"gzipped": 6633
},
"dist/jss.min.js": {
"bundled": 57748,
"minified": 20928,
"gzipped": 6133
"bundled": 57866,
"minified": 21259,
"gzipped": 6269
},
"dist/jss.cjs.js": {
"bundled": 54372,
"minified": 23761,
"gzipped": 6624
"bundled": 54344,
"minified": 23853,
"gzipped": 6655
},
"dist/jss.esm.js": {
"bundled": 53876,
"minified": 23357,
"gzipped": 6541,
"bundled": 53828,
"minified": 23429,
"gzipped": 6566,
"treeshaked": {
"rollup": {
"code": 18988,
"code": 19318,
"import_statements": 281
},
"webpack": {
"code": 20403
"code": 20740
}
}
}
Expand Down
24 changes: 17 additions & 7 deletions packages/jss/src/Jss.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import type {
Plugin,
JssOptions,
InternalJssOptions,
JssStyle,
GenerateId
JssStyle
} from './types'
import type {GenerateId} from './utils/createGenerateId'

let instanceCounter = 0

Expand All @@ -29,12 +29,13 @@ export default class Jss {
plugins = new PluginsRegistry()

options: InternalJssOptions = {
id: {minify: false},
createGenerateId: createGenerateIdDefault,
Renderer: isInBrowser ? DomRenderer : null,
plugins: []
}

generateId: GenerateId = createGenerateIdDefault()
generateId: GenerateId = createGenerateIdDefault({minify: false})

constructor(options?: JssOptions) {
for (let i = 0; i < internalPlugins.length; i++) {
Expand All @@ -49,10 +50,19 @@ export default class Jss {
* deduplication logic.
*/
setup(options?: JssOptions = {}): this {
const {createGenerateId} = options
if (createGenerateId) {
this.options.createGenerateId = createGenerateId
this.generateId = createGenerateId()
if (options.createGenerateId) {
this.options.createGenerateId = options.createGenerateId
}

if (options.id) {
this.options.id = {
...this.options.id,
...options.id
}
}

if (options.createGenerateId || options.id) {
this.generateId = this.options.createGenerateId(this.options.id)
}

if (options.insertionPoint != null) this.options.insertionPoint = options.insertionPoint
Expand Down
11 changes: 8 additions & 3 deletions packages/jss/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ export type Styles<Name extends string = string> = Record<Name, Style>
export type Classes<Name extends string = string> = Record<Name, string>
export type Keyframes<Name extends string = string> = Record<Name, string>

export interface CreateGenerateIdOptions {
minify?: boolean
}

export type CreateGenerateId = (options?: CreateGenerateIdOptions) => GenerateId

export type GenerateId = (rule: Rule, sheet?: StyleSheet<string>) => string

export type JssValue =
Expand All @@ -12,8 +18,6 @@ export type JssValue =
| null
| false

export type CreateGenerateId = () => GenerateId

export type InsertionPoint = string | HTMLElement

export interface UpdateOptions {
Expand Down Expand Up @@ -215,13 +219,14 @@ export interface Jss {
createRule(style: Style, options?: RuleFactoryOptions): Rule
createRule<Name extends string>(name: Name, style: Style, options?: RuleFactoryOptions): Rule
}

/**
* Creates a new instance of JSS.
*/
declare const sheets: SheetsRegistry
export {sheets, SheetsManager, SheetsRegistry, RuleList}
export function create(options?: Partial<JssOptions>): Jss
export function createGenerateId(): GenerateId
export const createGenerateId: CreateGenerateId
export function createRule(name: string, decl: Style, options: RuleOptions): Rule
export function toCssValue(value: JssValue, ignoreImportant: boolean): string
export function getDynamicStyles(styles: Styles): Styles | null
Expand Down
2 changes: 1 addition & 1 deletion packages/jss/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export type {
JssOptions,
JssStyle,
Plugin,
GenerateId,
RuleListOptions,
Rule,
Renderer,
Expand All @@ -37,6 +36,7 @@ export type {
BaseRule,
ContainerRule
} from './types'
export type {GenerateId, CreateGenerateId, CreateGenerateIdOptions} from './utils/createGenerateId'

export type {
Jss,
Expand Down
7 changes: 3 additions & 4 deletions packages/jss/src/types/jss.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {FontFaceRule} from '../plugins/fontFaceRule'
import type {CSSStyleRule, AnyCSSRule} from './cssom'
import type {HTMLElementWithStyleMap} from './dom'
import type RuleList from '../RuleList'
import type {CreateGenerateId, CreateGenerateIdOptions, GenerateId} from '../utils/createGenerateId'

export type {RuleList, StyleSheet}

Expand Down Expand Up @@ -55,8 +56,6 @@ export type Rule =
| ViewportRule
| BaseRule

export type GenerateId = (rule: Rule, sheet?: StyleSheet) => string

// TODO
// Find a way to declare all types: Object|string|Array<Object>
export type JssStyle = Object
Expand Down Expand Up @@ -151,10 +150,9 @@ export type Plugin = {|

export type InsertionPoint = string | HTMLElementWithStyleMap

type CreateGenerateId = () => GenerateId

export type JssOptions = {
createGenerateId?: CreateGenerateId,
id?: CreateGenerateIdOptions,
plugins?: Array<Plugin>,
insertionPoint?: InsertionPoint,
Renderer?: Class<Renderer> | null
Expand All @@ -163,6 +161,7 @@ export type JssOptions = {
export type InternalJssOptions = {|
createGenerateId: CreateGenerateId,
plugins: Array<Plugin>,
id: CreateGenerateIdOptions,
insertionPoint?: InsertionPoint,
Renderer?: Class<Renderer> | null
|}
Expand Down
18 changes: 13 additions & 5 deletions packages/jss/src/utils/createGenerateId.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
/* @flow */
import warning from 'tiny-warning'
import type {Rule, GenerateId} from '../types'
import type {Rule} from '../types'
import StyleSheet from '../StyleSheet'
import moduleId from './moduleId'

const maxRules = 1e10

export type CreateGenerateIdOptions = {|
minify: boolean
|}
export type GenerateId = (rule: Rule, sheet?: StyleSheet) => string

export type CreateGenerateId = (options: CreateGenerateIdOptions) => GenerateId

/**
* Returns a function which generates unique class names based on counters.
* When new generator function is created, rule counter is reseted.
* We need to reset the rule counter for SSR for each request.
*/
export default (): GenerateId => {
const createGenerateId: CreateGenerateId = (options = {}) => {
let ruleCounter = 0
const env = process.env.NODE_ENV
const defaultPrefix = env === 'production' ? 'c' : ''
const defaultPrefix = options.minify ? 'c' : ''

return (rule: Rule, sheet?: StyleSheet): string => {
ruleCounter += 1
Expand All @@ -31,10 +37,12 @@ export default (): GenerateId => {
if (sheet.options.jss.id != null) jssId += sheet.options.jss.id
}

if (env === 'production') {
if (options.minify) {
return `${prefix}${moduleId}${jssId}${ruleCounter}`
}

return `${prefix + rule.key}-${moduleId}${jssId && `-${jssId}`}-${ruleCounter}`
}
}

export default createGenerateId
11 changes: 2 additions & 9 deletions packages/jss/src/utils/escape.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
const escapeRegex = /([[\].#*$><+~=|^:(),"'`\s])/g
const nativeEscape = typeof CSS !== 'undefined' && CSS.escape

export default str => {
// We don't need to escape it in production, because we are not using user's
// input for selectors, we are generating a valid selector.
if (process.env.NODE_ENV === 'production') return str

const nativeEscape = typeof CSS !== 'undefined' && CSS.escape

return nativeEscape ? nativeEscape(str) : str.replace(escapeRegex, '\\$1')
}
export default str => (nativeEscape ? nativeEscape(str) : str.replace(escapeRegex, '\\$1'))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will always need to escape the string now because the user might not minify the string

We could also pass here the sheet options and check if the user wants to minify the selector

22 changes: 0 additions & 22 deletions packages/jss/tests/functional/sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,28 +346,6 @@ describe('Functional: sheet', () => {
})
})

describe('.addRule() with invalid decl to attached sheet', () => {
before(() => {
process.env.NODE_ENV = 'production'
})

after(() => {
process.env.NODE_ENV = 'development'
})

it('should warn', () => {
const sheet = jss.createStyleSheet().attach()
sheet.addRule('%%%%', {color: 'red'})
expect(spy.callCount).to.be(1)
expect(
spy.calledWithExactly(
'Warning: [JSS] Can not insert an unsupported rule \n.%%%%-id {\n color: red;\n}'
)
).to.be(true)
sheet.detach()
})
})

describe('.addRules() with an attached sheet', () => {
let sheet
beforeEach(() => {
Expand Down
12 changes: 4 additions & 8 deletions packages/jss/tests/unit/createGenerateId.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,13 @@ describe('Unit: jss - createGenerateId', () => {
expect(generate({key: 'a'})).to.be('a-6-1')
})

it('should generate a production class name', () => {
process.env.NODE_ENV = 'production'
const generate = createGenerateId()
it('should generate a minified class name', () => {
const generate = createGenerateId({minify: true})
expect(generate()).to.be('c141')
process.env.NODE_ENV = 'development'
})

it('should add prefix a production class name', () => {
process.env.NODE_ENV = 'production'
const generate = createGenerateId()
it('should add prefix a minified class name', () => {
const generate = createGenerateId({minify: true})
expect(generate({key: 'a'}, sheetMock)).to.be('p1401')
process.env.NODE_ENV = 'development'
})
})
6 changes: 0 additions & 6 deletions packages/jss/tests/unit/escape.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,5 @@ describe('Unit: jss - escape', () => {
it('should escape in development', () => {
expect(escape('test()')).to.be('test\\(\\)')
})

it('should not escape in production', () => {
process.env.NODE_ENV = 'production'
expect(escape('test()')).to.be('test()')
process.env.NODE_ENV = 'development'
})
})
})
28 changes: 14 additions & 14 deletions packages/react-jss/.size-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
{
"dist/react-jss.js": {
"bundled": 109904,
"minified": 37407,
"gzipped": 12068
"bundled": 110053,
"minified": 37477,
"gzipped": 12101
},
"dist/react-jss.min.js": {
"bundled": 85345,
"minified": 30142,
"gzipped": 9883
"bundled": 85529,
"minified": 30234,
"gzipped": 9928
},
"dist/react-jss.cjs.js": {
"bundled": 15499,
"minified": 7158,
"gzipped": 2476
"bundled": 15587,
"minified": 7215,
"gzipped": 2499
},
"dist/react-jss.esm.js": {
"bundled": 14818,
"minified": 6578,
"gzipped": 2359,
"bundled": 14906,
"minified": 6635,
"gzipped": 2384,
"treeshaked": {
"rollup": {
"code": 1946,
"code": 2018,
"import_statements": 457
},
"webpack": {
"code": 3346
"code": 3422
}
}
}
Expand Down
Loading