From 170a78380ec8cefb2a3c1e527df00f56463a931d Mon Sep 17 00:00:00 2001 From: Tieme van Veen Date: Tue, 29 Dec 2015 18:01:19 +0100 Subject: [PATCH 01/97] Sourcemaps documentation --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 60da45f..59e2104 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,8 @@ React CSS Modules implement automatic mapping of CSS modules. Every CSS class is - [Options](#options) - [`allowMultiple`](#allowmultiple) - [`errorWhenNotFound`](#errorwhennotfound) +- [SASS, SCSS, LESS and other CSS Preprocessors](#sass-scss-less-and-other-css-preprocessors) + - [Enable Sourcemaps](#enable-sourcemaps) - [React Hot Module Replacement](#react-hot-module-replacement) - [Class Composition](#class-composition) - [What Problems does Class Composition Solve?](#what-problems-does-class-composition-solve) @@ -367,6 +369,17 @@ Throws an error when `styleName` cannot be mapped to an existing CSS Module. } ``` +### Enable Sourcemaps + +To enable CSS Source maps, you'll need to pass the sourceMap-option to the css-loader: + +```js +{ + test: /\.scss$/, + loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass') +} +``` + ## React Hot Module Replacement [Hot module reloading](https://github.com/gaearon/react-transform-hmr) (HMR) does not reload the CSS document (see https://github.com/gajus/react-css-modules/issues/51). It only reloads the `class` HTML attribute value. From e6e7b82b3203cb7ba7eef7cf91807436ea3ce3bb Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Tue, 9 Feb 2016 01:29:23 +0000 Subject: [PATCH 02/97] Remove BrowserSync recomendation in favour of style-laader (HMR). --- README.md | 80 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index af36917..c3a94e9 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ React CSS Modules implement automatic mapping of CSS modules. Every CSS class is - [Usage](#usage) - [Module Bundler](#module-bundler) - [webpack](#webpack) + - [Development](#development) + - [Production](#production) - [Browserify](#browserify) - [Extending Component Styles](#extending-component-styles) - [`styles` Property](#styles-property) @@ -25,7 +27,6 @@ React CSS Modules implement automatic mapping of CSS modules. Every CSS class is - [`errorWhenNotFound`](#errorwhennotfound) - [SASS, SCSS, LESS and other CSS Preprocessors](#sass-scss-less-and-other-css-preprocessors) - [Enable Sourcemaps](#enable-sourcemaps) -- [React Hot Module Replacement](#react-hot-module-replacement) - [Class Composition](#class-composition) - [What Problems does Class Composition Solve?](#what-problems-does-class-composition-solve) - [Class Composition Using CSS Preprocessors](#class-composition-using-css-preprocessors) @@ -134,8 +135,49 @@ Setup consists of: #### webpack -* Install [`style-loader`](https://www.npmjs.com/package/style-loader) and [`css-loader`](https://www.npmjs.com/package/css-loader). -* You need to use [`extract-text-webpack-plugin`](https://www.npmjs.com/package/extract-text-webpack-plugin) to aggregate the CSS into a single file. +##### Development + +In development environment, you want to [Enable Sourcemaps](#enable-sourcemaps) and webpack [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement.html) (HMR). [`style-loader`](https://github.com/webpack/style-loader) already supports HMR. Therefore, Hot Module Replacement will work out of the box. + +* Install [`style-loader`](https://www.npmjs.com/package/style-loader). +* Install [`css-loader`](https://www.npmjs.com/package/css-loader). +* Setup `/\.css$/` loader: + +```js +{ + test: /\.css$/, + loaders: [ + 'style?sourceMap', + 'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]' + ] +} +``` + +##### Production + +In production environment, you want to extract chunks of CSS into a single stylesheet file. + +> Advantages: +> +> * Fewer style tags (older IE has a limit) +> * CSS SourceMap (with `devtool: "source-map"` and `css-loader?sourceMap`) +> * CSS requested in parallel +> * CSS cached separate +> * Faster runtime (less code and DOM operations) +> +> Caveats: +> +> * Additional HTTP request +> * Longer compilation time +> * More complex configuration +> * No runtime public path modification +> * No Hot Module Replacement + +– [extract-text-webpack-plugin](https://github.com/webpack/extract-text-webpack-plugin) + +* Install [`style-loader`](https://www.npmjs.com/package/style-loader). +* Install [`css-loader`](https://www.npmjs.com/package/css-loader). +* Use [`extract-text-webpack-plugin`](https://www.npmjs.com/package/extract-text-webpack-plugin) to extract chunks of CSS into a single stylesheet. * Setup `/\.css$/` loader: ```js @@ -155,7 +197,7 @@ new ExtractTextPlugin('app.css', { Refer to [webpack-demo](https://github.com/css-modules/webpack-demo) or [react-css-modules-examples](https://github.com/gajus/react-css-modules-examples) for an example of a complete setup. -#### Browserify +##### Browserify Refer to [`css-modulesify`](https://github.com/css-modules/css-modulesify). @@ -421,31 +463,31 @@ Throws an error when `styleName` cannot be mapped to an existing CSS Module. ```js { test: /\.scss$/, - loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass') + loaders: [ + 'style', + 'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]', + 'resolve-url', + 'sass' + ] } ``` -### Enable Sourcemaps +### Enable Sourcemaps + +To enable CSS Source maps, add `sourceMap` parameter to the css-loader and to the `sass-loader`: -To enable CSS Source maps, you'll need to pass the sourceMap-option to the css-loader: - ```js { test: /\.scss$/, - loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!sass') + loaders: [ + 'style?sourceMap', + 'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]', + 'resolve-url', + 'sass?sourceMap' + ] } ``` -## React Hot Module Replacement - -[Hot module reloading](https://github.com/gaearon/react-transform-hmr) (HMR) does not reload the CSS document (see https://github.com/gajus/react-css-modules/issues/51). It only reloads the `class` HTML attribute value. - -To enable CSS reloading, wrap [`webpack-dev-server`](https://webpack.github.io/docs/webpack-dev-server.html) configuration using [BrowserSync](https://www.browsersync.io/). BrowserSync enables CSS reloading when it detects a file change. - -[React CSS Modules examples](https://github.com/gajus/react-css-modules-examples) repository includes a configuration example using [BrowserSync configuration using webpack-dev-server](https://github.com/gajus/react-css-modules-examples/blob/master/webpack.config.browsersync.js). - -Note that `webpack-dev-server` program [does not write bundle files to the disk](https://github.com/webpack/webpack-dev-server/issues/62). Use [write-file-webpack-plugin](https://github.com/gajus/write-file-webpack-plugin) plugin to force writing to the disk. This will enable BrowserSync to detect changes. - ## Class Composition CSS Modules promote composition pattern, i.e. every CSS Module that is used in a component should define all properties required to describe an element, e.g. From 99f8972339fdbf64d292d191f0fd31f5fdc1af71 Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Tue, 9 Feb 2016 01:40:26 +0000 Subject: [PATCH 03/97] Text separation. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index c3a94e9..5c8c0ef 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,8 @@ Setup consists of: In development environment, you want to [Enable Sourcemaps](#enable-sourcemaps) and webpack [Hot Module Replacement](https://webpack.github.io/docs/hot-module-replacement.html) (HMR). [`style-loader`](https://github.com/webpack/style-loader) already supports HMR. Therefore, Hot Module Replacement will work out of the box. +Setup: + * Install [`style-loader`](https://www.npmjs.com/package/style-loader). * Install [`css-loader`](https://www.npmjs.com/package/css-loader). * Setup `/\.css$/` loader: @@ -175,6 +177,8 @@ In production environment, you want to extract chunks of CSS into a single style – [extract-text-webpack-plugin](https://github.com/webpack/extract-text-webpack-plugin) +Setup: + * Install [`style-loader`](https://www.npmjs.com/package/style-loader). * Install [`css-loader`](https://www.npmjs.com/package/css-loader). * Use [`extract-text-webpack-plugin`](https://www.npmjs.com/package/extract-text-webpack-plugin) to extract chunks of CSS into a single stylesheet. From 9114949a14aeaa77540bff26bdb77cf6c446f995 Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Wed, 24 Feb 2016 10:53:43 +0000 Subject: [PATCH 04/97] Test node 4 and 5. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e0fced4..e07d95b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: node_js node_js: - - '4.1' - - '4.0' + - 5 + - 4 notifications: email: false sudo: false From 8ae87c66ad24fab5c6e67d6fe100ebaf59c275ba Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Wed, 24 Feb 2016 14:40:02 +0000 Subject: [PATCH 05/97] Bumped dependencies. New pragmatist build is meant to fix #84. --- package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index abe4a58..c5163fc 100644 --- a/package.json +++ b/package.json @@ -21,14 +21,14 @@ "license": "BSD-3-Clause", "dependencies": { "es6-map": "^0.1.3", - "hoist-non-react-statics": "^1.0.4", - "lodash": "^4.2.0", - "object-unfreeze": "^1.0.0" + "hoist-non-react-statics": "^1.0.5", + "lodash": "^4.5.1", + "object-unfreeze": "^1.0.2" }, "devDependencies": { "chai": "^3.5.0", - "jsdom": "^8.0.2", - "pragmatist": "^3.0.3", + "jsdom": "^8.0.4", + "pragmatist": "^3.0.16", "react": "^0.15.0-alpha.1", "react-addons-test-utils": "^0.15.0-alpha.1", "react-dom": "^0.15.0-alpha.1" From 733d9fa5352a76c4a1a79246d9f9e3996bae5cf8 Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Wed, 24 Feb 2016 14:40:07 +0000 Subject: [PATCH 06/97] 3.7.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c5163fc..a831ae4 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "css", "modules" ], - "version": "3.7.4", + "version": "3.7.5", "author": { "name": "Gajus Kuizinas", "email": "gajus@gajus.com", From 324f950f25eebbd042abd1b76576c693da159e6b Mon Sep 17 00:00:00 2001 From: Gajus Kuizinas Date: Wed, 24 Feb 2016 15:17:35 +0000 Subject: [PATCH 07/97] Code style. --- package.json | 4 ++-- src/extendReactClass.js | 11 ++++----- src/generateAppendClassName.js | 25 ++++++++------------ src/index.js | 27 +++++++--------------- src/isIterable.js | 17 +++++--------- src/linkClass.js | 13 ++++++----- src/makeConfiguration.js | 4 +--- src/parseStyleName.js | 4 +--- src/wrapStatelessFunction.js | 17 ++++---------- tests/extendReactClass.js | 42 ++++++++++++++-------------------- tests/linkClass.js | 25 ++++++++------------ tests/makeConfiguration.js | 4 +--- tests/reactCssModules.js | 33 +++++++++++--------------- tests/wrapStatelessFunction.js | 32 ++++++++------------------ 14 files changed, 92 insertions(+), 166 deletions(-) diff --git a/package.json b/package.json index a831ae4..c8e6a8e 100644 --- a/package.json +++ b/package.json @@ -36,11 +36,11 @@ "scripts": { "pragmatist": "node ./node_modules/.bin/pragmatist --es5", "lint": "npm run pragmatist lint", - "test": "npm run pragmatist test", + "test": "npm run pragmatist test --type-annotations", "build": "npm run pragmatist build", "watch": "npm run pragmatist watch", "watch-lint": "npm run pragmatist watch-lint", - "watch-test": "npm run pragmatist watch-test", + "watch-test": "npm run pragmatist watch-test --type-annotations", "watch-build": "npm run pragmatist watch-build" } } diff --git a/src/extendReactClass.js b/src/extendReactClass.js index 0f8f22f..45b36a7 100644 --- a/src/extendReactClass.js +++ b/src/extendReactClass.js @@ -11,13 +11,10 @@ import hoistNonReactStatics from 'hoist-non-react-statics'; * @param {Object} options * @returns {ReactClass} */ -export default (Component, defaultStyles, options) => { - let WrappedComponent; - - WrappedComponent = class extends Component { +export default (Component: Object, defaultStyles: Object, options: Object) => { + const WrappedComponent = class extends Component { render () { - let renderResult, - styles; + let styles; if (this.props.styles) { styles = this.props.styles; @@ -31,7 +28,7 @@ export default (Component, defaultStyles, options) => { styles = {}; } - renderResult = super.render(); + const renderResult = super.render(); if (renderResult) { return linkClass(renderResult, styles, options); diff --git a/src/generateAppendClassName.js b/src/generateAppendClassName.js index d9ea204..b4e6bd8 100644 --- a/src/generateAppendClassName.js +++ b/src/generateAppendClassName.js @@ -1,20 +1,15 @@ import Map from 'es6-map'; -let stylesIndex; - -stylesIndex = new Map(); +const stylesIndex = new Map(); export default (styles, styleNames: Array, errorWhenNotFound: boolean): string => { let appendClassName, - styleName, stylesIndexMap; stylesIndexMap = stylesIndex.get(styles); if (stylesIndexMap) { - let styleNameIndex; - - styleNameIndex = stylesIndexMap.get(styleNames); + const styleNameIndex = stylesIndexMap.get(styleNames); if (styleNameIndex) { return styleNameIndex; @@ -25,15 +20,15 @@ export default (styles, styleNames: Array, errorWhenNotFound: boolean): appendClassName = ''; - for (styleName in styleNames) { - let className; - - className = styles[styleNames[styleName]]; + for (const styleName in styleNames) { + if (styleNames.hasOwnProperty(styleName)) { + const className = styles[styleNames[styleName]]; - if (className) { - appendClassName += ' ' + className; - } else if (errorWhenNotFound === true) { - throw new Error('"' + styleNames[styleName] + '" CSS module is undefined.'); + if (className) { + appendClassName += ' ' + className; + } else if (errorWhenNotFound === true) { + throw new Error('"' + styleNames[styleName] + '" CSS module is undefined.'); + } } } diff --git a/src/index.js b/src/index.js index ffc2a67..6c1a78c 100644 --- a/src/index.js +++ b/src/index.js @@ -2,29 +2,22 @@ import _ from 'lodash'; import extendReactClass from './extendReactClass'; import wrapStatelessFunction from './wrapStatelessFunction'; -let decoratorConstructor, - functionConstructor, - isReactComponent; +/** + * @see https://github.com/gajus/react-css-modules#options + */ +type OptionsType = {}; /** * Determines if the given object has the signature of a class that inherits React.Component. - * - * @param {*} maybeReactComponent - * @returns {boolean} */ -isReactComponent = (maybeReactComponent) => { +const isReactComponent = (maybeReactComponent: any): boolean => { return 'prototype' in maybeReactComponent && _.isFunction(maybeReactComponent.prototype.render); }; /** * When used as a function. - * - * @param {Function} Component - * @param {Object} defaultStyles CSS Modules class map. - * @param {Object} options {@link https://github.com/gajus/react-css-modules#options} - * @returns {Function} */ -functionConstructor = (Component, defaultStyles, options) => { +const functionConstructor = (Component: Function, defaultStyles: Object, options: OptionsType): Function => { let decoratedClass; if (isReactComponent(Component)) { @@ -44,13 +37,9 @@ functionConstructor = (Component, defaultStyles, options) => { /** * When used as a ES7 decorator. - * - * @param {Object} defaultStyles CSS Modules class map. - * @param {Object} options {@link https://github.com/gajus/react-css-modules#options} - * @returns {Function} */ -decoratorConstructor = (defaultStyles, options) => { - return (Component) => { +const decoratorConstructor = (defaultStyles: Object, options: OptionsType): Function => { + return (Component: Function) => { return functionConstructor(Component, defaultStyles, options); }; }; diff --git a/src/isIterable.js b/src/isIterable.js index 9e4c449..ac6dc72 100644 --- a/src/isIterable.js +++ b/src/isIterable.js @@ -1,28 +1,23 @@ import _ from 'lodash'; -let ITERATOR_SYMBOL, - OLD_ITERATOR_SYMBOL; - -ITERATOR_SYMBOL = _.isFunction(Symbol) && Symbol.iterator; -OLD_ITERATOR_SYMBOL = '@@iterator'; +const ITERATOR_SYMBOL = _.isFunction(Symbol) && Symbol.iterator; +const OLD_ITERATOR_SYMBOL = '@@iterator'; /** * @see https://github.com/lodash/lodash/issues/1668 * @see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Iteration_protocols - * @param {Object} target - * @returns {boolean} */ -export default (target) => { +export default (maybeIterable: any): boolean => { let iterator; - if (!_.isObject(target)) { + if (!_.isObject(maybeIterable)) { return false; } if (ITERATOR_SYMBOL) { - iterator = target[ITERATOR_SYMBOL]; + iterator = maybeIterable[ITERATOR_SYMBOL]; } else { - iterator = target[OLD_ITERATOR_SYMBOL]; + iterator = maybeIterable[OLD_ITERATOR_SYMBOL]; } return _.isFunction(iterator); diff --git a/src/linkClass.js b/src/linkClass.js index 42982e4..618561b 100644 --- a/src/linkClass.js +++ b/src/linkClass.js @@ -6,13 +6,16 @@ import parseStyleName from './parseStyleName'; import generateAppendClassName from './generateAppendClassName'; import objectUnfreeze from 'object-unfreeze'; +import { + ReactElement +} from 'react'; + let linkElement; linkElement = (element, styles, configuration) => { let appendClassName, elementIsFrozen, - elementShallowCopy, - styleNames; + elementShallowCopy; elementShallowCopy = element; @@ -24,7 +27,7 @@ linkElement = (element, styles, configuration) => { elementShallowCopy.props = objectUnfreeze(elementShallowCopy.props); } - styleNames = parseStyleName(elementShallowCopy.props.styleName || '', configuration.allowMultiple); + const styleNames = parseStyleName(elementShallowCopy.props.styleName || '', configuration.allowMultiple); if (React.isValidElement(elementShallowCopy.props.children)) { elementShallowCopy.props.children = linkElement(React.Children.only(elementShallowCopy.props.children), styles, configuration); @@ -66,14 +69,12 @@ linkElement = (element, styles, configuration) => { * @returns {ReactElement} */ export default (element, styles = {}, userConfiguration) => { - let configuration; - // @see https://github.com/gajus/react-css-modules/pull/30 if (!_.isObject(element)) { return element; } - configuration = makeConfiguration(userConfiguration); + const configuration = makeConfiguration(userConfiguration); return linkElement(element, styles, configuration); }; diff --git a/src/makeConfiguration.js b/src/makeConfiguration.js index 6a93c40..22d0298 100644 --- a/src/makeConfiguration.js +++ b/src/makeConfiguration.js @@ -1,9 +1,7 @@ import _ from 'lodash'; import Map from 'es6-map'; -let userConfigurationIndex; - -userConfigurationIndex = new Map(); +const userConfigurationIndex = new Map(); /** * @typedef CSSModules~Options diff --git a/src/parseStyleName.js b/src/parseStyleName.js index 67354f2..39c328a 100644 --- a/src/parseStyleName.js +++ b/src/parseStyleName.js @@ -1,8 +1,6 @@ import _ from 'lodash'; -let styleNameIndex; - -styleNameIndex = {}; +const styleNameIndex = {}; export default (styleNamePropertyValue: string, allowMultiple: boolean): Array => { let styleNames; diff --git a/src/wrapStatelessFunction.js b/src/wrapStatelessFunction.js index 829694e..6ac5cea 100644 --- a/src/wrapStatelessFunction.js +++ b/src/wrapStatelessFunction.js @@ -1,22 +1,13 @@ -/* eslint-disable react/prop-types */ - import _ from 'lodash'; import React from 'react'; import linkClass from './linkClass'; /** * @see https://facebook.github.io/react/blog/2015/09/10/react-v0.14-rc1.html#stateless-function-components - * @param {Function} Component - * @param {Object} defaultStyles - * @param {Object} options - * @returns {Function} */ -export default (Component, defaultStyles, options) => { - let WrappedComponent; - - WrappedComponent = (props = {}, ...args) => { - let renderResult, - styles, +export default (Component: Function, defaultStyles: Object, options: Object): Function => { + const WrappedComponent = (props = {}, ...args) => { + let styles, useProps; if (props.styles) { @@ -33,7 +24,7 @@ export default (Component, defaultStyles, options) => { styles = {}; } - renderResult = Component(useProps, ...args); + const renderResult = Component(useProps, ...args); if (renderResult) { return linkClass(renderResult, styles, options); diff --git a/tests/extendReactClass.js b/tests/extendReactClass.js index 5cf56ef..2348bd5 100644 --- a/tests/extendReactClass.js +++ b/tests/extendReactClass.js @@ -17,8 +17,11 @@ describe('extendReactClass', () => { }); context('using default styles', () => { it('exposes styles through this.props.styles property', (done) => { - let Component, - styles; + let Component; + + const styles = { + foo: 'foo-1' + }; Component = class extends React.Component { render () { @@ -27,17 +30,12 @@ describe('extendReactClass', () => { } }; - styles = { - foo: 'foo-1' - }; - Component = extendReactClass(Component, styles); TestUtils.renderIntoDocument(); }); it('does not affect the other instance properties', (done) => { - let Component, - styles; + let Component; Component = class extends React.Component { render () { @@ -46,7 +44,7 @@ describe('extendReactClass', () => { } }; - styles = { + const styles = { foo: 'foo-1' }; @@ -57,8 +55,11 @@ describe('extendReactClass', () => { }); context('overwriting default styles using "styles" property of the extended component', () => { it('overwrites default styles', (done) => { - let Component, - styles; + let Component; + + const styles = { + foo: 'foo-1' + }; Component = class extends React.Component { render () { @@ -67,10 +68,6 @@ describe('extendReactClass', () => { } }; - styles = { - foo: 'foo-1' - }; - Component = extendReactClass(Component, { bar: 'bar-0', foo: 'foo-0' @@ -81,11 +78,9 @@ describe('extendReactClass', () => { }); context('rendering Component that returns null', () => { it('generates