diff --git a/config/paths.js b/config/paths.js index cc6891d6a..186eab7a7 100644 --- a/config/paths.js +++ b/config/paths.js @@ -41,8 +41,8 @@ const getPublicUrl = appPackageJson => // like /todos/42/static/js/bundle.7289d.js. We have to know the root. function getServedPath(appPackageJson) { const publicUrl = getPublicUrl(appPackageJson); - const servedUrl = envPublicUrl || - (publicUrl ? url.parse(publicUrl).pathname : '/'); + const servedUrl = + envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/'); return ensureSlash(servedUrl, true); } @@ -60,7 +60,6 @@ module.exports = { appNodeModules: resolveApp('node_modules'), appTsConfig: resolveApp('tsconfig.json'), appTsProdConfig: resolveApp('tsconfig.prod.json'), - appTsLint: resolveApp('tslint.json'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), }; @@ -84,7 +83,6 @@ module.exports = { appTsConfig: resolveApp('tsconfig.json'), appTsProdConfig: resolveApp('tsconfig.prod.json'), appTsTestConfig: resolveApp('tsconfig.test.json'), - appTsLint: resolveApp('tslint.json'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), // These properties only exist before ejecting: @@ -94,7 +92,8 @@ module.exports = { const ownPackageJson = require('../package.json'); const reactScriptsPath = resolveApp(`node_modules/${ownPackageJson.name}`); -const reactScriptsLinked = fs.existsSync(reactScriptsPath) && +const reactScriptsLinked = + fs.existsSync(reactScriptsPath) && fs.lstatSync(reactScriptsPath).isSymbolicLink(); // config before publish: we're in ./packages/react-scripts/config/ @@ -116,7 +115,6 @@ if ( appNodeModules: resolveOwn('node_modules'), appTsConfig: resolveOwn('template/tsconfig.json'), appTsProdConfig: resolveOwn('template/tsconfig.prod.json'), - appTsLint: resolveOwn('template/tslint.json'), appTsTestConfig: resolveOwn('template/tsconfig.test.json'), publicUrl: getPublicUrl(resolveOwn('package.json')), servedPath: getServedPath(resolveOwn('package.json')), diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index 924e3e4f0..8608febce 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -15,6 +15,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin'); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin'); +const eslintFormatter = require('react-dev-utils/eslintFormatter'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const getClientEnvironment = require('./env'); @@ -134,10 +135,28 @@ module.exports = { // We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176. // { parser: { requireEnsure: false } }, + // First, run the linter. + // It's important to do this before Babel processes the JS. { - test: /\.(js|jsx|mjs)$/, - loader: require.resolve('source-map-loader'), + test: /\.(js|jsx|mjs|ts|tsx)$/, enforce: 'pre', + use: [ + require.resolve('source-map-loader'), + { + options: { + formatter: eslintFormatter, + eslintPath: require.resolve('eslint'), + baseConfig: { + extends: [require.resolve('eslint-config-react-app-ts')], + }, + // @remove-on-eject-begin + ignore: false, + useEslintrc: false, + // @remove-on-eject-end + }, + loader: require.resolve('eslint-loader'), + }, + ], include: paths.appSrc, }, { @@ -275,12 +294,11 @@ module.exports = { // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack // You can remove this if you don't use Moment.js: new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), - // Perform type checking and linting in a separate process to speed up compilation + // Perform type checking in a separate process to speed up compilation new ForkTsCheckerWebpackPlugin({ async: false, watch: paths.appSrc, tsconfig: paths.appTsConfig, - tslint: paths.appTsLint, }), ], // Some libraries import Node modules but don't use them in the browser. diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index 0d6dd8e38..e9ccef4ce 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -16,6 +16,7 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin'); +const eslintFormatter = require('react-dev-utils/eslintFormatter'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const paths = require('./paths'); @@ -140,10 +141,31 @@ module.exports = { // TODO: Disable require.ensure as it's not a standard language feature. // We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176. // { parser: { requireEnsure: false } }, + + // First, run the linter. + // It's important to do this before Babel processes the JS. { - test: /\.(js|jsx|mjs)$/, - loader: require.resolve('source-map-loader'), + test: /\.(js|jsx|mjs|ts|tsx)$/, enforce: 'pre', + use: [ + require.resolve('source-map-loader'), + { + options: { + formatter: eslintFormatter, + eslintPath: require.resolve('eslint'), + // TODO: consider separate config for production, + // e.g. to enable no-console and no-debugger only in production. + baseConfig: { + extends: [require.resolve('eslint-config-react-app-ts')], + }, + // @remove-on-eject-begin + ignore: false, + useEslintrc: false, + // @remove-on-eject-end + }, + loader: require.resolve('eslint-loader'), + }, + ], include: paths.appSrc, }, { @@ -382,11 +404,10 @@ module.exports = { // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack // You can remove this if you don't use Moment.js: new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), - // Perform type checking and linting in a separate process to speed up compilation + // Perform type checking in a separate process to speed up compilation new ForkTsCheckerWebpackPlugin({ async: false, tsconfig: paths.appTsProdConfig, - tslint: paths.appTsLint, }), ], // Some libraries import Node modules but don't use them in the browser. diff --git a/eslintrc b/eslintrc index 5e603ecd1..263586734 100644 --- a/eslintrc +++ b/eslintrc @@ -1,3 +1,3 @@ { - "extends": "react-app" + "extends": "react-app-ts" } diff --git a/package.json b/package.json index 048896ac3..5b38ddc43 100644 --- a/package.json +++ b/package.json @@ -10,12 +10,19 @@ "bugs": { "url": "https://github.com/wmonk/create-react-app/issues" }, - "files": ["bin", "config", "scripts", "template", "utils"], + "files": [ + "bin", + "config", + "scripts", + "template", + "utils" + ], "bin": { "react-scripts-ts": "./bin/react-scripts-ts.js" }, "dependencies": { "autoprefixer": "7.1.6", + "babel-eslint": "7.2.3", "babel-jest": "20.0.3", "babel-loader": "7.1.2", "babel-preset-react-app": "^3.1.2", @@ -24,6 +31,14 @@ "css-loader": "0.28.7", "dotenv": "4.0.0", "dotenv-expand": "4.2.0", + "eslint": "4.10.0", + "eslint-config-react-app": "^2.1.0", + "eslint-config-react-app-ts": "^1.0.1", + "eslint-loader": "1.9.0", + "eslint-plugin-flowtype": "2.39.1", + "eslint-plugin-import": "2.8.0", + "eslint-plugin-jsx-a11y": "5.1.1", + "eslint-plugin-react": "7.4.0", "extract-text-webpack-plugin": "3.0.2", "file-loader": "1.1.5", "fork-ts-checker-webpack-plugin": "^0.2.8", @@ -35,17 +50,16 @@ "postcss-loader": "2.0.8", "promise": "8.0.1", "raf": "3.4.0", - "source-map-loader": "^0.2.1", "react-dev-utils": "^5.0.2", "resolve": "1.6.0", + "source-map-loader": "^0.2.1", "style-loader": "0.19.0", "sw-precache-webpack-plugin": "0.11.4", "ts-jest": "22.0.1", "ts-loader": "^2.3.7", "tsconfig-paths-webpack-plugin": "^2.0.0", - "tslint": "^5.7.0", - "tslint-config-prettier": "^1.10.0", - "tslint-react": "^3.2.0", + "tslib": "^1.9.3", + "typescript-eslint-parser": "^18.0.0", "uglifyjs-webpack-plugin": "1.2.5", "url-loader": "0.6.2", "webpack": "3.8.1", diff --git a/template/src/registerServiceWorker.ts b/template/src/registerServiceWorker.ts index 28c89f7b6..5d7b98109 100644 --- a/template/src/registerServiceWorker.ts +++ b/template/src/registerServiceWorker.ts @@ -1,4 +1,3 @@ -// tslint:disable:no-console // In production, we register a service worker to serve assets from local cache. // This lets the app load faster on subsequent visits in production, and gives diff --git a/template/tslint.json b/template/tslint.json deleted file mode 100644 index bfdc862cf..000000000 --- a/template/tslint.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], - "linterOptions": { - "exclude": [ - "config/**/*.js", - "node_modules/**/*.ts", - "coverage/lcov-report/*.js" - ] - } -}