diff --git a/README.md b/README.md index d272ded..60b5105 100644 --- a/README.md +++ b/README.md @@ -67,23 +67,23 @@ Stateless functional components where introduced in React v0.14. They have a muc ___Note___: You will still be able to set properties for stateless components! ## Adding PostCSS plugins -If you have enabled [PostCSS](https://github.com/postcss/postcss) at generation time, install your PostCSS plugins via npm and *require* it in **postcss** function in *cfg/base.js*. +If you have enabled [PostCSS](https://github.com/postcss/postcss) at generation time, install your PostCSS plugins via npm and *require* it in the **plugins** array in *postcss.config.js*. Example for autoprefixer: ```bash cd my-new-project npm install autoprefixer ``` -Require in *cfg/base.js* +Require in *postcss.config.js* ```JavaScript ... -postcss: function () { - return [ +module.exports = () => ({ + plugins: [ require('autoprefixer')({ browsers: ['last 2 versions', 'ie >= 8'] }) - ]; -} + ] +}); ... ``` diff --git a/generators/app/index.js b/generators/app/index.js index d45cb4d..d0b8532 100644 --- a/generators/app/index.js +++ b/generators/app/index.js @@ -150,11 +150,14 @@ class AppGenerator extends Generators.Base { } } }); + + if(this.postcss) { + this.copy('../../generators/app/templates/postcss.config.js', 'postcss.config.js'); + } } install() { - // Currently buggy! if(this.postcss) { const postcss = require('./postcss'); postcss.write(path.join(this.destinationRoot(), 'conf/webpack/Base.js')); diff --git a/generators/app/postcss.js b/generators/app/postcss.js index e1105da..b374c28 100644 --- a/generators/app/postcss.js +++ b/generators/app/postcss.js @@ -20,44 +20,37 @@ module.exports = { // of the chain. If we have a preprocessor, we will add // it before the initial loader const cssDialects = [ - '\\.cssmodule\\.css$', '^.((?!cssmodule).)*\\.css$' ]; + const cssModuleDialects = [ + '\\.cssmodule\\.css$' + ]; + const preprocessorDialects = [ - '\\.cssmodule\\.(sass|scss)$', '^.((?!cssmodule).)*\\.(sass|scss)$', - '\\.cssmodule\\.less$', '^.((?!cssmodule).)*\\.less$', - '\\.cssmodule\\.styl$', '^.((?!cssmodule).)*\\.styl$' ]; - // Prepare postCSS statement for inclusion - const postcssFunction = 'var postcss = { postcss: function() { return []; } }'; - const postcssAst = esprima.parse(postcssFunction); + const preprocessorModuleDialects = [ + '\\.cssmodule\\.(sass|scss)$', + '\\.cssmodule\\.less$', + '\\.cssmodule\\.styl$' + ]; + + const postcssConfig = 'const postcssQuery = { query: { importLoaders: 1 } };'; + const postcssAst = esprima.parse(postcssConfig); const postcss = postcssAst.body[0].declarations[0].init.properties[0]; // The postcss loader item to add - const postcssLoaderObject = 'var postcss = [{ loader: \'postcss-loader\'}]'; + const postcssLoaderObject = 'var postcss = [{ loader: \'postcss-loader\' }];'; const postcssLoaderAst = esprima.parse(postcssLoaderObject); const postcssLoader = postcssLoaderAst.body[0].declarations[0].init.elements[0]; - // Add postcss to the loaders array walk.walkAddParent(ast, (node) => { - - // Add the postcss key to the global configuration - - if( - node.type === 'MethodDefinition' && - node.key.name === 'defaultSettings' - ) { - const returnStatement = node.value.body.body[1]; - returnStatement.argument.properties.push(postcss); - } - // Parse all property nodes that use a regex. // This should only be available under module.(pre)loaders if( @@ -67,14 +60,28 @@ module.exports = { typeof node.value.regex !== 'undefined' ) { + // Enable importLoaders on non cssmodule dialacts + if( + cssDialects.indexOf(node.value.regex.pattern) !== -1 || + preprocessorDialects.indexOf(node.value.regex.pattern) !== -1 + ) { + node.parent.properties[1].value.elements[1].properties.push(postcss); + } + // Regular css usage - if(cssDialects.indexOf(node.value.regex.pattern) !== -1) { + if( + cssDialects.indexOf(node.value.regex.pattern) !== -1 || + cssModuleDialects.indexOf(node.value.regex.pattern) !== -1 + ) { const loaderData = node.parent.properties[1]; loaderData.value.elements.push(postcssLoader); } - - if(preprocessorDialects.indexOf(node.value.regex.pattern) !== -1) { + // CSS preprocessors + if( + preprocessorDialects.indexOf(node.value.regex.pattern) !== -1 || + preprocessorModuleDialects.indexOf(node.value.regex.pattern) !== -1 + ) { const loaderData = node.parent.properties[1]; const lastElm = loaderData.value.elements.pop(); loaderData.value.elements.push(postcssLoader); diff --git a/generators/app/templates/postcss.config.js b/generators/app/templates/postcss.config.js new file mode 100644 index 0000000..fe23259 --- /dev/null +++ b/generators/app/templates/postcss.config.js @@ -0,0 +1,3 @@ +module.exports = () => ({ + plugins: [] +}); diff --git a/test/generators/app/indexTest.js b/test/generators/app/indexTest.js index 599b150..e7b0ae4 100644 --- a/test/generators/app/indexTest.js +++ b/test/generators/app/indexTest.js @@ -225,46 +225,70 @@ describe('react-webpack:app with PostCSS support', () => { ]); }); - it('should insert the postcss loader into the style pipes', () => { + it('should insert the postcss loader into the cssmodule style pipes', () => { + assert.fileContent('conf/webpack/Base.js', `{ loader: 'css-loader', query: cssModulesQuery }, { loader: 'postcss-loader' }`); - assert.fileContent('conf/webpack/Base.js', `{ loader: 'css-loader' }, - { loader: 'postcss-loader' }`); + assert.fileContent('conf/webpack/Base.js', `{ loader: 'css-loader', query: cssModulesQuery }, { loader: 'postcss-loader' }, { loader: 'sass-loader' }`); - assert.fileContent('conf/webpack/Base.js', `{ loader: 'css-loader' }, - { loader: 'postcss-loader' }, - { loader: 'sass-loader' }`); + assert.fileContent('conf/webpack/Base.js', `{ loader: 'css-loader', query: cssModulesQuery }, { loader: 'postcss-loader' }, { loader: 'less-loader' }`); - assert.fileContent('conf/webpack/Base.js', `{ loader: 'css-loader' }, - { loader: 'postcss-loader' }, - { loader: 'less-loader' }`); + assert.fileContent('conf/webpack/Base.js', `{ loader: 'css-loader', query: cssModulesQuery }, { loader: 'postcss-loader' }, { loader: 'stylus-loader' }`); - assert.fileContent('conf/webpack/Base.js', `{ loader: 'css-loader' }, + }); + + it('should insert the postcss loader into the NON cssmodule style pipes', () => { + + assert.fileContent('conf/webpack/Base.js', `{ + loader: 'css-loader', + query: { importLoaders: 1 } + }, + { loader: 'postcss-loader' }`); + + assert.fileContent('conf/webpack/Base.js', `{ + loader: 'css-loader', + query: { importLoaders: 1 } + }, + { loader: 'postcss-loader' }, + { loader: 'sass-loader' }`); + + assert.fileContent('conf/webpack/Base.js', `{ + loader: 'css-loader', + query: { importLoaders: 1 } + }, + { loader: 'postcss-loader' }, + { loader: 'less-loader' }`); + + assert.fileContent('conf/webpack/Base.js', `{ + loader: 'css-loader', + query: { importLoaders: 1 } + }, { loader: 'postcss-loader' }, { loader: 'stylus-loader' }`); }); - it('should append the postcss function to the base config', () => { - - assert.fileContent('conf/webpack/Base.js', 'postcss: function () {'); + it('should generate the postCSS config', () => { + assert.file([ + 'postcss.config.js', + ]); }); it('should generate required source files', () => { diff --git a/utils/configopts.json b/utils/configopts.json index 0c7e26b..df1aa44 100644 --- a/utils/configopts.json +++ b/utils/configopts.json @@ -45,8 +45,8 @@ "name": "postcss", "value": "postcss", "packages": [ - { "name": "postcss", "version": "^5.0.21" }, - { "name": "postcss-loader", "version": "^0.9.1" } + { "name": "postcss", "version": "^5.2.6" }, + { "name": "postcss-loader", "version": "^1.1.1" } ] } ] @@ -57,7 +57,7 @@ "name": "cssmodules", "value": "cssmodules", "packages": [ - { "name": "react-css-modules", "version": "^3.7.10" } + { "name": "react-css-modules", "version": "^4.0.3" } ] } ] @@ -74,7 +74,7 @@ "value": "sass", "suffix": ".sass", "packages": [ - { "name": "sass-loader", "version": "^3.2.0" }, + { "name": "sass-loader", "version": "^4.0.2" }, { "name": "node-sass", "version": "^3.7.0" } ] }, @@ -83,7 +83,7 @@ "value": "scss", "suffix": ".scss", "packages": [ - { "name": "sass-loader", "version": "^3.2.0" }, + { "name": "sass-loader", "version": "^4.0.2" }, { "name": "node-sass", "version": "^3.7.0" } ] },