diff --git a/config/eslint.js b/config/eslint.js index 2a140b9e18a..6bc66282cea 100644 --- a/config/eslint.js +++ b/config/eslint.js @@ -69,6 +69,7 @@ module.exports = { 'no-cond-assign': [WARNING, 'always'], 'no-const-assign': WARNING, 'no-control-regex': WARNING, + 'no-css-modules': WARNING, 'no-delete-var': WARNING, 'no-dupe-args': WARNING, 'no-dupe-class-members': WARNING, diff --git a/config/rules/no-css-modules.js b/config/rules/no-css-modules.js new file mode 100644 index 00000000000..43ddc3027f6 --- /dev/null +++ b/config/rules/no-css-modules.js @@ -0,0 +1,32 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +module.exports = { + create: function (context) { + return { + ImportDeclaration: function(node) { + if (node) { + var specifiers = node.specifiers || []; + var value = node.source && node.source.value; + + if (value && value.indexOf('.css') !== -1 && specifiers.length) { + for (var i = 0; i < specifiers.length; i++) { + var specifier = specifiers[i]; + + context.report(specifier, 'CSS modules import is restricted. ' + + 'Please remove the \'{{importName}}\' portion of the import.', { + importName: specifier.imported ? specifier.imported.name : specifier.local.name + }); + } + } + } + } + }; + } +}; diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index 65b3936ccb8..65eca27cdf9 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -86,7 +86,8 @@ module.exports = { }, eslint: { configFile: path.join(__dirname, 'eslint.js'), - useEslintrc: false + useEslintrc: false, + rulesdir: 'config/rules' }, postcss: function() { return [autoprefixer]; diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index f372286a279..bb9fc1c8e0d 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -87,7 +87,8 @@ module.exports = { // TODO: consider separate config for production, // e.g. to enable no-console and no-debugger only in prod. configFile: path.join(__dirname, 'eslint.js'), - useEslintrc: false + useEslintrc: false, + rulesdir: 'config/rules' }, postcss: function() { return [autoprefixer]; diff --git a/scripts/eject.js b/scripts/eject.js index c8c32505406..856aa0c3954 100644 --- a/scripts/eject.js +++ b/scripts/eject.js @@ -104,6 +104,12 @@ prompt('Are you sure you want to eject? This action is permanent. [y/N]', functi }); delete hostPackage.scripts['eject']; + // explicitly specify ESLint config path for editor plugins + hostPackage.eslintConfig = { + extends: './config/eslint.js', + rulesdir: './config/rules', + }; + console.log('Writing package.json'); fs.writeFileSync( path.join(hostPath, 'package.json'), diff --git a/scripts/init.js b/scripts/init.js index be5d58b158f..1564e93b0c4 100644 --- a/scripts/init.js +++ b/scripts/init.js @@ -29,6 +29,12 @@ module.exports = function(hostPath, appName, verbose) { hostPackage.scripts[command] = 'react-scripts ' + command; }); + // explicitly specify ESLint config path for editor plugins + hostPackage.eslintConfig = { + extends: './node_modules/react-scripts/config/eslint.js', + rulesdir: './config/rules', + }; + fs.writeFileSync( path.join(hostPath, 'package.json'), JSON.stringify(hostPackage, null, 2) diff --git a/tasks/e2e.sh b/tasks/e2e.sh index 85edc4b08a4..e7a8247d14e 100755 --- a/tasks/e2e.sh +++ b/tasks/e2e.sh @@ -31,7 +31,7 @@ npm install scripts_path=$PWD/`npm pack` # lint -./node_modules/.bin/eslint --ignore-path .gitignore ./ +./node_modules/.bin/eslint --rulesdir ./config/rules --ignore-path .gitignore ./ # Test local start command npm start -- --smoke-test