Skip to content

Commit

Permalink
feat(react): add support for react (#11)
Browse files Browse the repository at this point in the history
* feat(react): add support for react - initial dev

Still need some adjustments, but the basic dev workflow is working

* feat(react): check required files before building and start of prod mode

* Now it is checked if the following files are present: `public/index.html` or one of the following`src/index.tsx` or `src/index.js`. If one of them is missing, it should throw and stop the build
* Start of the prod build (added just the stubs, but the config is still the same as the dev one)

* feat(react): added webpack config for production and ts config for web

* feat(react): better report on the prod build

* feat(react): added option to generate webpack's bundle stats

* feat(react): make scripts throw on unhandled rejections

* feat(react): add a better error overlay to the dev server

Use the same overlay that create-react-app uses 😁

* feat(react): add WatchMissingNodeModulesPlugin and ModuleScopePlugin

* feat(react): better reporting for the dev builds

* feat(react): added required files to the npm final build

* feat(react): moved deps that were wrongly put on devDeps

* feat(react): added some missing config on eslint.web

* feat(react): removed WatchMissingNodeModulesPlugin

It was being problematic on the published package (was fine on local dev though 🤷‍♂️)

* feat(react): fixed coverage collection on ts files

* feat(react): removed the babel-core bridge requirement

Apparently, it no longer errors when not installed.

* feat(react): added some missing eslint settings

* feat(react): allow custom babel config for the webpack builds

User-suplied babel config must be a `.babel.js` file.

* style(lint): change double quotes to single quotes

* chore: change the default output dir to 'dist'

* feat(react): "fix" eslint errors when using React.Fragment
  • Loading branch information
GabeDuarteM authored Sep 18, 2018
1 parent 911ed90 commit 5976488
Show file tree
Hide file tree
Showing 29 changed files with 5,910 additions and 604 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require("./src/config/eslintrc")
module.exports = require("./src/config/eslintrc.base")
2 changes: 1 addition & 1 deletion eslint.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require('./dist/config/eslintrc')
module.exports = require('./dist/config/eslintrc.base')
1 change: 1 addition & 0 deletions eslint.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/config/eslintrc.web')
4,961 changes: 4,482 additions & 479 deletions package-lock.json

Large diffs are not rendered by default.

29 changes: 28 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@
"dist",
"babel.js",
"eslint.js",
"eslint.web.js",
"prettier.js",
"semver.js",
"typescript.json"
"typescript.json",
"typescript.web.json"
],
"repository": {
"type": "git",
Expand All @@ -53,42 +55,67 @@
"@babel/preset-typescript": "^7.0.0",
"arrify": "^1.0.1",
"babel-core": "^7.0.0-bridge.0",
"babel-loader": "^8.0.2",
"babel-plugin-macros": "^2.4.0",
"babel-plugin-minify-dead-code-elimination": "^0.4.3",
"browserslist": "^4.1.1",
"case-sensitive-paths-webpack-plugin": "^2.1.2",
"chalk": "^2.4.1",
"cross-spawn": "^6.0.5",
"eslint": "^5.6.0",
"eslint-config-prettier": "^3.0.1",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-prettier": "^2.6.2",
"eslint-plugin-typescript": "^0.12.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.1.1",
"eslint-plugin-react": "^7.11.1",
"file-loader": "^2.0.0",
"glob": "^7.1.2",
"html-webpack-plugin": "^3.2.0",
"is-ci": "^1.2.1",
"jest": "^23.6.0",
"lodash.get": "^4.4.2",
"lodash.has": "^4.5.2",
"mkdirp": "^0.5.1",
"prettier": "^1.14.0",
"react-dev-utils": "^6.0.0-next.a671462c",
"read-pkg-up": "^4.0.0",
"rimraf": "^2.6.2",
"semver": "^5.5.1",
"simple-git": "^1.96.0",
"sw-precache-webpack-plugin": "^0.11.5",
"thread-loader": "^1.2.0",
"typescript": "^3.0.1",
"typescript-eslint-parser": "^18.0.0",
"uglifyjs-webpack-plugin": "^1.2.5",
"url-loader": "^1.1.1",
"webpack": "^4.19.0",
"webpack-dev-server": "^3.1.8",
"webpack-manifest-plugin": "^2.0.4",
"which": "^1.3.1",
"yargs-parser": "^10.1.0"
},
"devDependencies": {
"@types/arrify": "^1.0.4",
"@types/case-sensitive-paths-webpack-plugin": "^2.1.2",
"@types/chalk": "^2.2.0",
"@types/cross-spawn": "^6.0.0",
"@types/fs-extra": "^5.0.4",
"@types/glob": "^5.0.35",
"@types/html-webpack-plugin": "^3.2.0",
"@types/is-ci": "^1.1.0",
"@types/lodash.get": "^4.4.4",
"@types/lodash.has": "^4.5.4",
"@types/mkdirp": "^0.5.2",
"@types/node": "^10.7.1",
"@types/read-pkg-up": "^3.0.1",
"@types/rimraf": "^2.0.2",
"@types/sw-precache-webpack-plugin": "^0.11.0",
"@types/uglifyjs-webpack-plugin": "^1.1.0",
"@types/webpack": "^4.4.11",
"@types/webpack-dev-server": "^3.1.0",
"@types/webpack-manifest-plugin": "^1.3.2",
"@types/which": "^1.3.1",
"fs-extra": "^7.0.0",
"semantic-release": "^15.9.15",
Expand Down
1 change: 1 addition & 0 deletions src/@types/react-dev-utils/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'react-dev-utils/*'
3 changes: 3 additions & 0 deletions src/config/babelrc.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
declare const createBabelConfig: () => any

export default createBabelConfig
29 changes: 27 additions & 2 deletions src/config/babelrc.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,41 @@
// @ts-check
const semver = require('semver')

const { ifAnyDep, pkg } = require('../utils')

const getNodeVersion = ({ engines: { node: nodeVersion = '8' } = {} }) => {
const oldestVersion = semver
.validRange(nodeVersion)
.replace(/[>=<|]/g, ' ')
.split(' ')
.filter(Boolean)
.sort(semver.compare)[0]
if (!oldestVersion) {
throw new Error(
`Unable to determine the oldest version in the range in your package.json at engines.node: "${nodeVersion}". Please attempt to make it less ambiguous.`,
)
}
return oldestVersion
}

const isTest = (process.env.BABEL_ENV || process.env.NODE_ENV) === 'test'
const isReact = ifAnyDep('react', true, false)

const envTargets = isTest ? { node: 'current' } : { node: '8' }
const envTargets = isTest
? { node: 'current' }
: !isReact
? { node: getNodeVersion(pkg) }
: undefined
const envOptions = { modules: false, loose: true, targets: envTargets }

module.exports = () => ({
presets: [
require.resolve('@babel/preset-typescript'),
isReact && require.resolve('@babel/preset-react'),
[require.resolve('@babel/preset-env'), envOptions],
],
].filter(Boolean),
plugins: [
require.resolve('babel-plugin-macros'),
[
require.resolve('@babel/plugin-proposal-class-properties'),
{ loose: true },
Expand Down
2 changes: 1 addition & 1 deletion src/config/eslintrc.js → src/config/eslintrc.base.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = {
settings: {
'import/resolver': {
node: {
extensions: ['.mjs', '.js', '.json', 'ts'],
extensions: ['.mjs', '.js', '.json', '.ts'],
},
},
'import/extensions': ['.js', '.mjs', '.ts'],
Expand Down
221 changes: 221 additions & 0 deletions src/config/eslintrc.web.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
// @ts-check
const baseConfig = require('./eslintrc.base')

const config = {
...baseConfig,
plugins: [...baseConfig.plugins, 'react', 'jsx-a11y'],
parserOptions: {
...baseConfig.parserOptions,
ecmaFeatures: {
...baseConfig.parserOptions.ecmaFeatures,
jsx: true,
},
},
settings: {
...baseConfig.settings,
'import/resolver': {
...baseConfig.settings['import/resolver'],
node: {
extensions: [
...baseConfig.settings['import/resolver'].node.extensions,
'.tsx',
],
},
},
'import/extensions': [...baseConfig.settings['import/extensions'], '.tsx'],
react: {
pragma: 'React',
version: '16.0',
},
},
rules: {
...baseConfig.rules,
'react/button-has-type': [
'error',
{
button: true,
submit: true,
reset: false,
},
],
'react/default-props-match-prop-types': [
'error',
{ allowRequiredDefaults: false },
],
'react/destructuring-assignment': ['error', 'always'],
'react/forbid-prop-types': [
'error',
{
forbid: ['any', 'array', 'object'],
checkContextTypes: true,
checkChildContextTypes: true,
},
],
'react/no-access-state-in-setstate': 'error',
'react/no-array-index-key': 'error',
'react/no-children-prop': 'error',
'react/no-danger': 'error',
'react/no-danger-with-children': 'error',
'react/no-deprecated': 'error',
'react/no-did-update-set-state': 'error',
'react/no-direct-mutation-state': 'error',
'react/no-find-dom-node': 'error',
'react/no-is-mounted': 'error',
'react/no-multi-comp': ['error', { ignoreStateless: true }],
'react/no-redundant-should-component-update': 'error',
'react/no-render-return-value': 'error',
'react/no-typos': 'error',
'react/no-string-refs': 'error',
'react/no-this-in-sfc': 'error',
'react/no-unescaped-entities': 'error',
'react/no-unknown-property': 'error',
'react/no-unsafe': 'error',
'react/no-unused-prop-types': [
'error',
{
skipShapeProps: true,
},
],
'react/no-unused-state': 'error',
'react/no-will-update-set-state': 'error',
'react/prefer-es6-class': 'error',
'react/prefer-stateless-function': [
'error',
{ ignorePureComponents: true },
],
'react/react-in-jsx-scope': 'error',
'react/require-render-return': 'error',
'react/style-prop-object': 'error',
'react/void-dom-elements-no-children': 'error',
'react/jsx-boolean-value': 'error',
'react/jsx-filename-extension': ['error', { extensions: ['.js', '.tsx'] }],
'react/jsx-handler-names': 'error',
'react/jsx-key': 'error',
'react/jsx-no-bind': [
'error',
{
ignoreRefs: true,
allowFunctions: false,
allowBind: false,
ignoreDOMComponents: true,
},
],
'react/jsx-no-comment-textnodes': 'error',
'react/jsx-no-duplicate-props': ['error', { ignoreCase: true }],
'react/jsx-no-target-blank': 'error',
'react/jsx-no-undef': 'error',
'react/jsx-curly-brace-presence': [
'error',
{ props: 'never', children: 'never' },
],
'react/jsx-pascal-case': [
'error',
{
allowAllCaps: true,
},
],
'react/jsx-uses-react': 'error',
'react/jsx-uses-vars': 'error',

'jsx-a11y/accessible-emoji': 'error',
'jsx-a11y/alt-text': 'error',
'jsx-a11y/anchor-has-content': 'error',
'jsx-a11y/anchor-is-valid': [
'error',
{
components: ['Link'],
specialLink: ['to'],
},
],
'jsx-a11y/aria-activedescendant-has-tabindex': 'error',
'jsx-a11y/aria-props': 'error',
'jsx-a11y/aria-proptypes': 'error',
'jsx-a11y/aria-role': ['error', { ignoreNonDom: false }],
'jsx-a11y/aria-unsupported-elements': 'error',
'jsx-a11y/click-events-have-key-events': 'error',
'jsx-a11y/heading-has-content': 'error',
'jsx-a11y/html-has-lang': 'error',
'jsx-a11y/iframe-has-title': 'error',
'jsx-a11y/img-redundant-alt': 'error',
'jsx-a11y/interactive-supports-focus': 'error',
'jsx-a11y/lang': 'error',
'jsx-a11y/media-has-caption': 'error',
'jsx-a11y/mouse-events-have-key-events': 'error',
'jsx-a11y/no-access-key': 'error',
'jsx-a11y/no-autofocus': ['error', { ignoreNonDOM: true }],
'jsx-a11y/no-distracting-elements': 'error',
'jsx-a11y/no-interactive-element-to-noninteractive-role': [
'error',
{
tr: ['none', 'presentation'],
},
],
'jsx-a11y/no-noninteractive-element-interactions': [
'error',
{
handlers: [
'onClick',
'onMouseDown',
'onMouseUp',
'onKeyPress',
'onKeyDown',
'onKeyUp',
],
},
],
'jsx-a11y/no-noninteractive-element-to-interactive-role': [
'error',
{
ul: [
'listbox',
'menu',
'menubar',
'radiogroup',
'tablist',
'tree',
'treegrid',
],
ol: [
'listbox',
'menu',
'menubar',
'radiogroup',
'tablist',
'tree',
'treegrid',
],
li: ['menuitem', 'option', 'row', 'tab', 'treeitem'],
table: ['grid'],
td: ['gridcell'],
},
],
'jsx-a11y/no-noninteractive-tabindex': [
'error',
{
tags: [],
roles: ['tabpanel'],
},
],
'jsx-a11y/no-redundant-roles': 'error',
'jsx-a11y/no-static-element-interactions': [
'error',
{
handlers: [
'onClick',
'onMouseDown',
'onMouseUp',
'onKeyPress',
'onKeyDown',
'onKeyUp',
],
},
],
'jsx-a11y/role-has-required-aria-props': 'error',
'jsx-a11y/role-supports-aria-props': 'error',
'jsx-a11y/scope': 'error',
'jsx-a11y/tabindex-no-positive': 'error',
'no-multi-str': 'off', // keep this until https://github.com/eslint/typescript-eslint-parser/issues/503 is closed
},
}

module.exports = config
3 changes: 2 additions & 1 deletion src/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

module.exports = {
babel: require('./babelrc'),
eslint: require('./eslintrc'),
eslint: require('./eslintrc.base'),
eslintWeb: require('./eslintrc.web'),
prettier: require('./prettierrc'),
release: require('./releaserc'),
}
6 changes: 3 additions & 3 deletions src/config/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ const useBuiltInBabelConfig = !hasFile('.babelrc') && !hasPkgProp('babel')

const jestConfig = {
testEnvironment: 'node',
moduleFileExtensions: ['js', 'json', 'ts'],
collectCoverageFrom: ['src/**/*.+(js|ts)'],
moduleFileExtensions: ['js', 'json', 'ts', 'tsx'],
collectCoverageFrom: ['src/**/*.(js|ts|tsx)'],
testMatch,
testPathIgnorePatterns: [...testIgnores],
coveragePathIgnorePatterns: [...testIgnores, 'src/(umd|cjs|esm)-entry.js$'],
transformIgnorePatterns: ['[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$'],
}

if (useBuiltInBabelConfig) {
jestConfig.transform = { '^.+\\.(j|t)s$': here('./babel-transform') }
jestConfig.transform = { '^.+\\.(j|t)sx?$': here('./babel-transform') }
}

module.exports = jestConfig
Loading

0 comments on commit 5976488

Please sign in to comment.