From 28f4bb0e555ec4e955d659eb0917f715b37e4094 Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Mon, 22 Apr 2019 20:57:49 +0200 Subject: [PATCH 01/70] initial commit Signed-off-by: Tobias Winkler --- .all-contributorsrc | 174 + .editorconfig | 14 + .eslintrc.js | 89 + .gitattributes | 107 + .github/ISSUE_TEMPLATE/bug_report.md | 27 + .github/ISSUE_TEMPLATE/feature_request.md | 17 + .github/PULL_REQUEST_TEMPLATE.md | 23 + .github/issue-close-app.yml | 14 + .github/lock.yml | 29 + .gitignore | 10 + .nvmrc | 1 + .prettierignore | 7 + .prettierrc | 8 + .stylelintrc | 7 + .travis.yml | 25 + CODE_OF_CONDUCT.md | 76 + CONTRIBUTING.md | 157 + Changelog.md | 347 + LICENSE.md | 21 + README.md | 169 + app/.htaccess | 52 + app/.nginx.conf | 112 + app/app.js | 96 + app/components/A/index.js | 15 + app/components/A/tests/index.test.js | 52 + app/components/Button/A.js | 9 + app/components/Button/StyledButton.js | 9 + app/components/Button/Wrapper.js | 9 + app/components/Button/buttonStyles.js | 26 + app/components/Button/index.js | 43 + app/components/Button/tests/A.test.js | 27 + .../Button/tests/StyledButton.test.js | 27 + app/components/Button/tests/Wrapper.test.js | 27 + app/components/Button/tests/index.test.js | 59 + app/components/Footer/Wrapper.js | 10 + app/components/Footer/index.js | 30 + app/components/Footer/messages.js | 21 + app/components/Footer/tests/Wrapper.test.js | 29 + .../tests/__snapshots__/index.test.js.snap | 49 + app/components/Footer/tests/index.test.js | 30 + app/components/H1/index.js | 8 + app/components/H1/tests/index.test.js | 20 + app/components/H2/index.js | 7 + app/components/H2/tests/index.test.js | 20 + app/components/H3/index.js | 7 + app/components/H3/tests/index.test.js | 20 + app/components/Header/A.js | 8 + app/components/Header/HeaderLink.js | 25 + app/components/Header/Img.js | 11 + app/components/Header/NavBar.js | 5 + app/components/Header/banner.jpg | Bin 0 -> 205990 bytes app/components/Header/index.js | 29 + app/components/Header/messages.js | 19 + app/components/Header/tests/A.test.js | 29 + app/components/Header/tests/Img.test.js | 36 + .../Header/tests/__snapshots__/A.test.js.snap | 16 + .../tests/__snapshots__/Img.test.js.snap | 15 + .../tests/__snapshots__/index.test.js.snap | 36 + app/components/Header/tests/index.test.js | 27 + app/components/Img/index.js | 22 + app/components/Img/tests/index.test.js | 49 + app/components/IssueIcon/index.js | 16 + app/components/IssueIcon/tests/index.test.js | 11 + app/components/List/Ul.js | 12 + app/components/List/Wrapper.js | 13 + app/components/List/index.js | 33 + app/components/List/tests/Ul.test.js | 31 + app/components/List/tests/Wrapper.test.js | 30 + app/components/List/tests/index.test.js | 26 + app/components/ListItem/Item.js | 11 + app/components/ListItem/Wrapper.js | 16 + app/components/ListItem/index.js | 19 + app/components/ListItem/tests/Item.test.js | 28 + app/components/ListItem/tests/Wrapper.test.js | 32 + app/components/ListItem/tests/index.test.js | 19 + app/components/LoadingIndicator/Circle.js | 53 + app/components/LoadingIndicator/Wrapper.js | 10 + app/components/LoadingIndicator/index.js | 23 + .../LoadingIndicator/tests/Circle.test.js | 22 + .../LoadingIndicator/tests/Wrapper.test.js | 30 + .../tests/__snapshots__/index.test.js.snap | 379 + .../LoadingIndicator/tests/index.test.js | 12 + app/components/ReposList/index.js | 34 + .../tests/__snapshots__/index.test.js.snap | 100 + app/components/ReposList/tests/index.test.js | 59 + app/components/Toggle/Select.js | 9 + app/components/Toggle/index.js | 37 + app/components/Toggle/tests/Select.test.js | 27 + .../tests/__snapshots__/index.test.js.snap | 18 + app/components/Toggle/tests/index.test.js | 35 + app/components/ToggleOption/index.js | 21 + .../tests/__snapshots__/index.test.js.snap | 9 + .../ToggleOption/tests/index.test.js | 32 + app/configureStore.js | 59 + app/containers/App/actions.js | 59 + app/containers/App/constants.js | 14 + app/containers/App/index.js | 50 + app/containers/App/reducer.js | 46 + app/containers/App/selectors.js | 49 + .../tests/__snapshots__/index.test.js.snap | 35 + app/containers/App/tests/actions.test.js | 43 + app/containers/App/tests/index.test.js | 14 + app/containers/App/tests/reducer.test.js | 66 + app/containers/App/tests/selectors.test.js | 85 + app/containers/FeaturePage/List.js | 8 + app/containers/FeaturePage/ListItem.js | 7 + app/containers/FeaturePage/ListItemTitle.js | 7 + app/containers/FeaturePage/Loadable.js | 11 + app/containers/FeaturePage/index.js | 77 + app/containers/FeaturePage/messages.js | 99 + app/containers/FeaturePage/tests/List.test.js | 35 + .../FeaturePage/tests/ListItem.test.js | 35 + .../FeaturePage/tests/ListItemTitle.test.js | 35 + .../tests/__snapshots__/index.test.js.snap | 111 + .../FeaturePage/tests/index.test.js | 19 + app/containers/HomePage/AtPrefix.js | 8 + app/containers/HomePage/CenteredSection.js | 8 + app/containers/HomePage/Form.js | 7 + app/containers/HomePage/Input.js | 10 + app/containers/HomePage/Loadable.js | 11 + app/containers/HomePage/Section.js | 11 + app/containers/HomePage/actions.js | 32 + app/containers/HomePage/constants.js | 12 + app/containers/HomePage/index.js | 138 + app/containers/HomePage/messages.js | 32 + app/containers/HomePage/reducer.js | 29 + app/containers/HomePage/saga.js | 38 + app/containers/HomePage/selectors.js | 16 + .../HomePage/tests/AtPrefix.test.js | 35 + .../HomePage/tests/CenteredSection.test.js | 35 + app/containers/HomePage/tests/Form.test.js | 35 + app/containers/HomePage/tests/Input.test.js | 27 + app/containers/HomePage/tests/Section.test.js | 27 + .../tests/__snapshots__/index.test.js.snap | 67 + .../tests/__snapshots__/saga.test.js.snap | 55 + app/containers/HomePage/tests/actions.test.js | 17 + app/containers/HomePage/tests/index.test.js | 120 + app/containers/HomePage/tests/reducer.test.js | 28 + app/containers/HomePage/tests/saga.test.js | 57 + .../HomePage/tests/selectors.test.js | 26 + app/containers/LanguageProvider/actions.js | 14 + app/containers/LanguageProvider/constants.js | 7 + app/containers/LanguageProvider/index.js | 42 + app/containers/LanguageProvider/reducer.js | 26 + app/containers/LanguageProvider/selectors.js | 20 + .../LanguageProvider/tests/actions.test.js | 15 + .../LanguageProvider/tests/index.test.js | 49 + .../LanguageProvider/tests/reducer.test.js | 22 + .../LanguageProvider/tests/selectors.test.js | 11 + app/containers/LocaleToggle/Wrapper.js | 7 + app/containers/LocaleToggle/index.js | 54 + app/containers/LocaleToggle/messages.js | 19 + .../LocaleToggle/tests/Wrapper.test.js | 28 + .../tests/__snapshots__/index.test.js.snap | 22 + .../LocaleToggle/tests/index.test.js | 60 + app/containers/NotFoundPage/Loadable.js | 11 + app/containers/NotFoundPage/index.js | 21 + app/containers/NotFoundPage/messages.js | 15 + .../NotFoundPage/tests/index.test.js | 21 + app/containers/RepoListItem/IssueIcon.js | 10 + app/containers/RepoListItem/IssueLink.js | 13 + app/containers/RepoListItem/RepoLink.js | 12 + app/containers/RepoListItem/Wrapper.js | 10 + app/containers/RepoListItem/index.js | 56 + .../RepoListItem/tests/IssueIcon.test.js | 30 + .../RepoListItem/tests/IssueLink.test.js | 30 + .../RepoListItem/tests/RepoLink.test.js | 30 + .../RepoListItem/tests/Wrapper.test.js | 28 + .../__snapshots__/IssueIcon.test.js.snap | 18 + .../__snapshots__/IssueLink.test.js.snap | 30 + .../tests/__snapshots__/RepoLink.test.js.snap | 26 + .../tests/__snapshots__/index.test.js.snap | 41 + .../RepoListItem/tests/index.test.js | 75 + app/global-styles.js | 32 + app/i18n.js | 51 + app/images/favicon.ico | Bin 0 -> 370070 bytes app/images/icon-512x512.png | Bin 0 -> 16733 bytes app/index.html | 33 + app/reducers.js | 24 + app/tests/i18n.test.js | 28 + app/tests/store.test.js | 43 + app/translations/de.json | 31 + app/translations/en.json | 31 + app/utils/checkStore.js | 21 + app/utils/constants.js | 3 + app/utils/history.js | 3 + app/utils/injectReducer.js | 45 + app/utils/injectSaga.js | 61 + app/utils/loadable.js | 13 + app/utils/reducerInjectors.js | 34 + app/utils/request.js | 44 + app/utils/sagaInjectors.js | 91 + app/utils/tests/checkStore.test.js | 33 + app/utils/tests/injectReducer.test.js | 98 + app/utils/tests/injectSaga.test.js | 149 + app/utils/tests/reducerInjectors.test.js | 100 + app/utils/tests/request.test.js | 80 + app/utils/tests/sagaInjectors.test.js | 231 + appveyor.yml | 45 + babel.config.js | 33 + docs/README.md | 128 + docs/css/README.md | 283 + docs/css/linting.md | 11 + docs/css/remove.md | 27 + docs/css/sanitize.md | 17 + docs/forks/README.md | 25 + docs/general/README.md | 133 + docs/general/commands.md | 149 + docs/general/components.md | 84 + docs/general/debugging.md | 77 + docs/general/deployment.md | 121 + docs/general/editor.md | 40 + docs/general/faq.md | 260 + docs/general/files.md | 34 + docs/general/gotchas.md | 114 + docs/general/introduction.md | 219 + docs/general/remove.md | 49 + docs/general/server-configs.md | 36 + docs/general/webstorm-debug.png | Bin 0 -> 453421 bytes docs/general/webstorm-eslint.png | Bin 0 -> 114499 bytes docs/general/workflow.png | Bin 0 -> 72522 bytes docs/js/README.md | 38 + docs/js/async-components.md | 28 + docs/js/i18n.md | 108 + docs/js/immer.md | 50 + docs/js/redux-saga.md | 77 + docs/js/redux.md | 79 + docs/js/remove.md | 83 + docs/js/reselect.md | 72 + docs/js/routing.md | 60 + docs/maintenance/dependency.md | 269 + docs/testing/README.md | 28 + docs/testing/component-testing.md | 193 + docs/testing/remote-testing.md | 12 + docs/testing/unit-testing.md | 356 + internals/generators/component/index.js | 92 + internals/generators/component/index.js.hbs | 36 + .../generators/component/loadable.js.hbs | 9 + .../generators/component/messages.js.hbs | 16 + internals/generators/component/test.js.hbs | 61 + internals/generators/container/actions.js.hbs | 13 + .../generators/container/actions.test.js.hbs | 13 + .../generators/container/constants.js.hbs | 7 + internals/generators/container/index.js | 177 + internals/generators/container/index.js.hbs | 90 + .../generators/container/messages.js.hbs | 16 + internals/generators/container/reducer.js.hbs | 20 + .../generators/container/reducer.test.js.hbs | 32 + internals/generators/container/saga.js.hbs | 6 + .../generators/container/saga.test.js.hbs | 15 + .../generators/container/selectors.js.hbs | 22 + .../container/selectors.test.js.hbs | 7 + internals/generators/container/test.js.hbs | 62 + internals/generators/index.js | 75 + .../generators/language/add-locale-data.hbs | 1 + internals/generators/language/app-locale.hbs | 1 + .../language/format-translation-messages.hbs | 1 + internals/generators/language/index.js | 111 + .../generators/language/intl-locale-data.hbs | 1 + .../language/polyfill-intl-locale.hbs | 1 + .../language/translation-messages.hbs | 1 + .../generators/language/translations-json.hbs | 1 + internals/generators/utils/componentExists.js | 21 + internals/mocks/cssModule.js | 1 + internals/mocks/image.js | 1 + internals/scripts/analyze.js | 27 + internals/scripts/clean.js | 63 + internals/scripts/extract-intl.js | 164 + .../scripts/generate-templates-for-linting.js | 385 + internals/scripts/helpers/checkmark.js | 11 + internals/scripts/helpers/get-npm-config.js | 3 + internals/scripts/helpers/progress.js | 19 + internals/scripts/helpers/xmark.js | 11 + internals/scripts/npmcheckversion.js | 8 + internals/templates/app.js | 83 + internals/templates/configureStore.js | 59 + .../templates/containers/App/constants.js | 10 + internals/templates/containers/App/index.js | 28 + .../templates/containers/App/selectors.js | 11 + .../tests/__snapshots__/index.test.js.snap | 17 + .../containers/App/tests/index.test.js | 14 + .../containers/App/tests/selectors.test.js | 13 + .../templates/containers/HomePage/Loadable.js | 7 + .../templates/containers/HomePage/index.js | 18 + .../templates/containers/HomePage/messages.js | 15 + .../tests/__snapshots__/index.test.js.snap | 9 + .../containers/HomePage/tests/index.test.js | 18 + .../containers/LanguageProvider/actions.js | 14 + .../containers/LanguageProvider/constants.js | 7 + .../containers/LanguageProvider/index.js | 51 + .../containers/LanguageProvider/reducer.js | 25 + .../containers/LanguageProvider/selectors.js | 19 + .../containers/NotFoundPage/Loadable.js | 7 + .../containers/NotFoundPage/index.js | 19 + .../containers/NotFoundPage/messages.js | 15 + .../tests/__snapshots__/index.test.js.snap | 9 + .../NotFoundPage/tests/index.test.js | 18 + internals/templates/global-styles.js | 31 + internals/templates/i18n.js | 46 + internals/templates/index.html | 29 + internals/templates/reducers.js | 22 + internals/templates/tests/i18n.test.js | 28 + internals/templates/tests/store.test.js | 32 + internals/templates/translations/en.json | 1 + internals/templates/utils/checkStore.js | 21 + internals/templates/utils/constants.js | 3 + internals/templates/utils/history.js | 3 + internals/templates/utils/injectReducer.js | 45 + internals/templates/utils/injectSaga.js | 61 + internals/templates/utils/loadable.js | 13 + internals/templates/utils/reducerInjectors.js | 34 + internals/templates/utils/sagaInjectors.js | 91 + .../templates/utils/tests/checkStore.test.js | 33 + .../utils/tests/injectReducer.test.js | 98 + .../templates/utils/tests/injectSaga.test.js | 149 + .../utils/tests/reducerInjectors.test.js | 100 + .../utils/tests/sagaInjectors.test.js | 231 + internals/testing/test-bundler.js | 3 + internals/webpack/webpack.base.babel.js | 126 + internals/webpack/webpack.dev.babel.js | 52 + internals/webpack/webpack.prod.babel.js | 150 + jest.config.js | 31 + package-lock.json | 17162 ++++++++++++++++ package.json | 167 + server/argv.js | 1 + server/index.js | 56 + server/logger.js | 38 + server/middlewares/addDevMiddlewares.js | 38 + server/middlewares/addProdMiddlewares.js | 18 + server/middlewares/frontendMiddleware.js | 19 + server/port.js | 3 + 331 files changed, 32027 insertions(+) create mode 100644 .all-contributorsrc create mode 100644 .editorconfig create mode 100644 .eslintrc.js create mode 100644 .gitattributes create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/issue-close-app.yml create mode 100644 .github/lock.yml create mode 100644 .gitignore create mode 100644 .nvmrc create mode 100644 .prettierignore create mode 100644 .prettierrc create mode 100644 .stylelintrc create mode 100644 .travis.yml create mode 100644 CODE_OF_CONDUCT.md create mode 100644 CONTRIBUTING.md create mode 100644 Changelog.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100644 app/.htaccess create mode 100644 app/.nginx.conf create mode 100644 app/app.js create mode 100644 app/components/A/index.js create mode 100644 app/components/A/tests/index.test.js create mode 100644 app/components/Button/A.js create mode 100644 app/components/Button/StyledButton.js create mode 100644 app/components/Button/Wrapper.js create mode 100644 app/components/Button/buttonStyles.js create mode 100644 app/components/Button/index.js create mode 100644 app/components/Button/tests/A.test.js create mode 100644 app/components/Button/tests/StyledButton.test.js create mode 100644 app/components/Button/tests/Wrapper.test.js create mode 100644 app/components/Button/tests/index.test.js create mode 100644 app/components/Footer/Wrapper.js create mode 100644 app/components/Footer/index.js create mode 100644 app/components/Footer/messages.js create mode 100644 app/components/Footer/tests/Wrapper.test.js create mode 100644 app/components/Footer/tests/__snapshots__/index.test.js.snap create mode 100644 app/components/Footer/tests/index.test.js create mode 100644 app/components/H1/index.js create mode 100644 app/components/H1/tests/index.test.js create mode 100644 app/components/H2/index.js create mode 100644 app/components/H2/tests/index.test.js create mode 100644 app/components/H3/index.js create mode 100644 app/components/H3/tests/index.test.js create mode 100644 app/components/Header/A.js create mode 100644 app/components/Header/HeaderLink.js create mode 100644 app/components/Header/Img.js create mode 100644 app/components/Header/NavBar.js create mode 100644 app/components/Header/banner.jpg create mode 100644 app/components/Header/index.js create mode 100644 app/components/Header/messages.js create mode 100644 app/components/Header/tests/A.test.js create mode 100644 app/components/Header/tests/Img.test.js create mode 100644 app/components/Header/tests/__snapshots__/A.test.js.snap create mode 100644 app/components/Header/tests/__snapshots__/Img.test.js.snap create mode 100644 app/components/Header/tests/__snapshots__/index.test.js.snap create mode 100644 app/components/Header/tests/index.test.js create mode 100644 app/components/Img/index.js create mode 100644 app/components/Img/tests/index.test.js create mode 100644 app/components/IssueIcon/index.js create mode 100644 app/components/IssueIcon/tests/index.test.js create mode 100644 app/components/List/Ul.js create mode 100644 app/components/List/Wrapper.js create mode 100644 app/components/List/index.js create mode 100644 app/components/List/tests/Ul.test.js create mode 100644 app/components/List/tests/Wrapper.test.js create mode 100644 app/components/List/tests/index.test.js create mode 100644 app/components/ListItem/Item.js create mode 100644 app/components/ListItem/Wrapper.js create mode 100644 app/components/ListItem/index.js create mode 100644 app/components/ListItem/tests/Item.test.js create mode 100644 app/components/ListItem/tests/Wrapper.test.js create mode 100644 app/components/ListItem/tests/index.test.js create mode 100644 app/components/LoadingIndicator/Circle.js create mode 100644 app/components/LoadingIndicator/Wrapper.js create mode 100644 app/components/LoadingIndicator/index.js create mode 100644 app/components/LoadingIndicator/tests/Circle.test.js create mode 100644 app/components/LoadingIndicator/tests/Wrapper.test.js create mode 100644 app/components/LoadingIndicator/tests/__snapshots__/index.test.js.snap create mode 100644 app/components/LoadingIndicator/tests/index.test.js create mode 100644 app/components/ReposList/index.js create mode 100644 app/components/ReposList/tests/__snapshots__/index.test.js.snap create mode 100644 app/components/ReposList/tests/index.test.js create mode 100644 app/components/Toggle/Select.js create mode 100644 app/components/Toggle/index.js create mode 100644 app/components/Toggle/tests/Select.test.js create mode 100644 app/components/Toggle/tests/__snapshots__/index.test.js.snap create mode 100644 app/components/Toggle/tests/index.test.js create mode 100644 app/components/ToggleOption/index.js create mode 100644 app/components/ToggleOption/tests/__snapshots__/index.test.js.snap create mode 100644 app/components/ToggleOption/tests/index.test.js create mode 100644 app/configureStore.js create mode 100644 app/containers/App/actions.js create mode 100644 app/containers/App/constants.js create mode 100644 app/containers/App/index.js create mode 100644 app/containers/App/reducer.js create mode 100644 app/containers/App/selectors.js create mode 100644 app/containers/App/tests/__snapshots__/index.test.js.snap create mode 100644 app/containers/App/tests/actions.test.js create mode 100644 app/containers/App/tests/index.test.js create mode 100644 app/containers/App/tests/reducer.test.js create mode 100644 app/containers/App/tests/selectors.test.js create mode 100644 app/containers/FeaturePage/List.js create mode 100644 app/containers/FeaturePage/ListItem.js create mode 100644 app/containers/FeaturePage/ListItemTitle.js create mode 100644 app/containers/FeaturePage/Loadable.js create mode 100644 app/containers/FeaturePage/index.js create mode 100644 app/containers/FeaturePage/messages.js create mode 100644 app/containers/FeaturePage/tests/List.test.js create mode 100644 app/containers/FeaturePage/tests/ListItem.test.js create mode 100644 app/containers/FeaturePage/tests/ListItemTitle.test.js create mode 100644 app/containers/FeaturePage/tests/__snapshots__/index.test.js.snap create mode 100644 app/containers/FeaturePage/tests/index.test.js create mode 100644 app/containers/HomePage/AtPrefix.js create mode 100644 app/containers/HomePage/CenteredSection.js create mode 100644 app/containers/HomePage/Form.js create mode 100644 app/containers/HomePage/Input.js create mode 100644 app/containers/HomePage/Loadable.js create mode 100644 app/containers/HomePage/Section.js create mode 100644 app/containers/HomePage/actions.js create mode 100644 app/containers/HomePage/constants.js create mode 100644 app/containers/HomePage/index.js create mode 100644 app/containers/HomePage/messages.js create mode 100644 app/containers/HomePage/reducer.js create mode 100644 app/containers/HomePage/saga.js create mode 100644 app/containers/HomePage/selectors.js create mode 100644 app/containers/HomePage/tests/AtPrefix.test.js create mode 100644 app/containers/HomePage/tests/CenteredSection.test.js create mode 100644 app/containers/HomePage/tests/Form.test.js create mode 100644 app/containers/HomePage/tests/Input.test.js create mode 100644 app/containers/HomePage/tests/Section.test.js create mode 100644 app/containers/HomePage/tests/__snapshots__/index.test.js.snap create mode 100644 app/containers/HomePage/tests/__snapshots__/saga.test.js.snap create mode 100644 app/containers/HomePage/tests/actions.test.js create mode 100644 app/containers/HomePage/tests/index.test.js create mode 100644 app/containers/HomePage/tests/reducer.test.js create mode 100644 app/containers/HomePage/tests/saga.test.js create mode 100644 app/containers/HomePage/tests/selectors.test.js create mode 100644 app/containers/LanguageProvider/actions.js create mode 100644 app/containers/LanguageProvider/constants.js create mode 100644 app/containers/LanguageProvider/index.js create mode 100644 app/containers/LanguageProvider/reducer.js create mode 100644 app/containers/LanguageProvider/selectors.js create mode 100644 app/containers/LanguageProvider/tests/actions.test.js create mode 100644 app/containers/LanguageProvider/tests/index.test.js create mode 100644 app/containers/LanguageProvider/tests/reducer.test.js create mode 100644 app/containers/LanguageProvider/tests/selectors.test.js create mode 100644 app/containers/LocaleToggle/Wrapper.js create mode 100644 app/containers/LocaleToggle/index.js create mode 100644 app/containers/LocaleToggle/messages.js create mode 100644 app/containers/LocaleToggle/tests/Wrapper.test.js create mode 100644 app/containers/LocaleToggle/tests/__snapshots__/index.test.js.snap create mode 100644 app/containers/LocaleToggle/tests/index.test.js create mode 100644 app/containers/NotFoundPage/Loadable.js create mode 100644 app/containers/NotFoundPage/index.js create mode 100644 app/containers/NotFoundPage/messages.js create mode 100644 app/containers/NotFoundPage/tests/index.test.js create mode 100644 app/containers/RepoListItem/IssueIcon.js create mode 100644 app/containers/RepoListItem/IssueLink.js create mode 100644 app/containers/RepoListItem/RepoLink.js create mode 100644 app/containers/RepoListItem/Wrapper.js create mode 100644 app/containers/RepoListItem/index.js create mode 100644 app/containers/RepoListItem/tests/IssueIcon.test.js create mode 100644 app/containers/RepoListItem/tests/IssueLink.test.js create mode 100644 app/containers/RepoListItem/tests/RepoLink.test.js create mode 100644 app/containers/RepoListItem/tests/Wrapper.test.js create mode 100644 app/containers/RepoListItem/tests/__snapshots__/IssueIcon.test.js.snap create mode 100644 app/containers/RepoListItem/tests/__snapshots__/IssueLink.test.js.snap create mode 100644 app/containers/RepoListItem/tests/__snapshots__/RepoLink.test.js.snap create mode 100644 app/containers/RepoListItem/tests/__snapshots__/index.test.js.snap create mode 100644 app/containers/RepoListItem/tests/index.test.js create mode 100644 app/global-styles.js create mode 100644 app/i18n.js create mode 100644 app/images/favicon.ico create mode 100755 app/images/icon-512x512.png create mode 100644 app/index.html create mode 100644 app/reducers.js create mode 100644 app/tests/i18n.test.js create mode 100644 app/tests/store.test.js create mode 100644 app/translations/de.json create mode 100644 app/translations/en.json create mode 100644 app/utils/checkStore.js create mode 100644 app/utils/constants.js create mode 100644 app/utils/history.js create mode 100644 app/utils/injectReducer.js create mode 100644 app/utils/injectSaga.js create mode 100644 app/utils/loadable.js create mode 100644 app/utils/reducerInjectors.js create mode 100644 app/utils/request.js create mode 100644 app/utils/sagaInjectors.js create mode 100644 app/utils/tests/checkStore.test.js create mode 100644 app/utils/tests/injectReducer.test.js create mode 100644 app/utils/tests/injectSaga.test.js create mode 100644 app/utils/tests/reducerInjectors.test.js create mode 100644 app/utils/tests/request.test.js create mode 100644 app/utils/tests/sagaInjectors.test.js create mode 100644 appveyor.yml create mode 100644 babel.config.js create mode 100644 docs/README.md create mode 100644 docs/css/README.md create mode 100644 docs/css/linting.md create mode 100644 docs/css/remove.md create mode 100644 docs/css/sanitize.md create mode 100644 docs/forks/README.md create mode 100644 docs/general/README.md create mode 100644 docs/general/commands.md create mode 100644 docs/general/components.md create mode 100644 docs/general/debugging.md create mode 100644 docs/general/deployment.md create mode 100644 docs/general/editor.md create mode 100644 docs/general/faq.md create mode 100644 docs/general/files.md create mode 100644 docs/general/gotchas.md create mode 100644 docs/general/introduction.md create mode 100644 docs/general/remove.md create mode 100644 docs/general/server-configs.md create mode 100644 docs/general/webstorm-debug.png create mode 100644 docs/general/webstorm-eslint.png create mode 100644 docs/general/workflow.png create mode 100644 docs/js/README.md create mode 100644 docs/js/async-components.md create mode 100644 docs/js/i18n.md create mode 100644 docs/js/immer.md create mode 100644 docs/js/redux-saga.md create mode 100644 docs/js/redux.md create mode 100644 docs/js/remove.md create mode 100644 docs/js/reselect.md create mode 100644 docs/js/routing.md create mode 100644 docs/maintenance/dependency.md create mode 100644 docs/testing/README.md create mode 100644 docs/testing/component-testing.md create mode 100644 docs/testing/remote-testing.md create mode 100644 docs/testing/unit-testing.md create mode 100644 internals/generators/component/index.js create mode 100644 internals/generators/component/index.js.hbs create mode 100644 internals/generators/component/loadable.js.hbs create mode 100644 internals/generators/component/messages.js.hbs create mode 100644 internals/generators/component/test.js.hbs create mode 100644 internals/generators/container/actions.js.hbs create mode 100644 internals/generators/container/actions.test.js.hbs create mode 100644 internals/generators/container/constants.js.hbs create mode 100644 internals/generators/container/index.js create mode 100644 internals/generators/container/index.js.hbs create mode 100644 internals/generators/container/messages.js.hbs create mode 100644 internals/generators/container/reducer.js.hbs create mode 100644 internals/generators/container/reducer.test.js.hbs create mode 100644 internals/generators/container/saga.js.hbs create mode 100644 internals/generators/container/saga.test.js.hbs create mode 100644 internals/generators/container/selectors.js.hbs create mode 100644 internals/generators/container/selectors.test.js.hbs create mode 100644 internals/generators/container/test.js.hbs create mode 100644 internals/generators/index.js create mode 100644 internals/generators/language/add-locale-data.hbs create mode 100644 internals/generators/language/app-locale.hbs create mode 100644 internals/generators/language/format-translation-messages.hbs create mode 100644 internals/generators/language/index.js create mode 100644 internals/generators/language/intl-locale-data.hbs create mode 100644 internals/generators/language/polyfill-intl-locale.hbs create mode 100644 internals/generators/language/translation-messages.hbs create mode 100644 internals/generators/language/translations-json.hbs create mode 100644 internals/generators/utils/componentExists.js create mode 100644 internals/mocks/cssModule.js create mode 100644 internals/mocks/image.js create mode 100644 internals/scripts/analyze.js create mode 100644 internals/scripts/clean.js create mode 100644 internals/scripts/extract-intl.js create mode 100644 internals/scripts/generate-templates-for-linting.js create mode 100644 internals/scripts/helpers/checkmark.js create mode 100644 internals/scripts/helpers/get-npm-config.js create mode 100644 internals/scripts/helpers/progress.js create mode 100644 internals/scripts/helpers/xmark.js create mode 100644 internals/scripts/npmcheckversion.js create mode 100644 internals/templates/app.js create mode 100644 internals/templates/configureStore.js create mode 100644 internals/templates/containers/App/constants.js create mode 100644 internals/templates/containers/App/index.js create mode 100644 internals/templates/containers/App/selectors.js create mode 100644 internals/templates/containers/App/tests/__snapshots__/index.test.js.snap create mode 100644 internals/templates/containers/App/tests/index.test.js create mode 100644 internals/templates/containers/App/tests/selectors.test.js create mode 100644 internals/templates/containers/HomePage/Loadable.js create mode 100644 internals/templates/containers/HomePage/index.js create mode 100644 internals/templates/containers/HomePage/messages.js create mode 100644 internals/templates/containers/HomePage/tests/__snapshots__/index.test.js.snap create mode 100644 internals/templates/containers/HomePage/tests/index.test.js create mode 100644 internals/templates/containers/LanguageProvider/actions.js create mode 100644 internals/templates/containers/LanguageProvider/constants.js create mode 100644 internals/templates/containers/LanguageProvider/index.js create mode 100644 internals/templates/containers/LanguageProvider/reducer.js create mode 100644 internals/templates/containers/LanguageProvider/selectors.js create mode 100644 internals/templates/containers/NotFoundPage/Loadable.js create mode 100644 internals/templates/containers/NotFoundPage/index.js create mode 100644 internals/templates/containers/NotFoundPage/messages.js create mode 100644 internals/templates/containers/NotFoundPage/tests/__snapshots__/index.test.js.snap create mode 100644 internals/templates/containers/NotFoundPage/tests/index.test.js create mode 100644 internals/templates/global-styles.js create mode 100644 internals/templates/i18n.js create mode 100644 internals/templates/index.html create mode 100644 internals/templates/reducers.js create mode 100644 internals/templates/tests/i18n.test.js create mode 100644 internals/templates/tests/store.test.js create mode 100644 internals/templates/translations/en.json create mode 100644 internals/templates/utils/checkStore.js create mode 100644 internals/templates/utils/constants.js create mode 100644 internals/templates/utils/history.js create mode 100644 internals/templates/utils/injectReducer.js create mode 100644 internals/templates/utils/injectSaga.js create mode 100644 internals/templates/utils/loadable.js create mode 100644 internals/templates/utils/reducerInjectors.js create mode 100644 internals/templates/utils/sagaInjectors.js create mode 100644 internals/templates/utils/tests/checkStore.test.js create mode 100644 internals/templates/utils/tests/injectReducer.test.js create mode 100644 internals/templates/utils/tests/injectSaga.test.js create mode 100644 internals/templates/utils/tests/reducerInjectors.test.js create mode 100644 internals/templates/utils/tests/sagaInjectors.test.js create mode 100644 internals/testing/test-bundler.js create mode 100644 internals/webpack/webpack.base.babel.js create mode 100644 internals/webpack/webpack.dev.babel.js create mode 100644 internals/webpack/webpack.prod.babel.js create mode 100644 jest.config.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 server/argv.js create mode 100644 server/index.js create mode 100644 server/logger.js create mode 100644 server/middlewares/addDevMiddlewares.js create mode 100644 server/middlewares/addProdMiddlewares.js create mode 100644 server/middlewares/frontendMiddleware.js create mode 100644 server/port.js diff --git a/.all-contributorsrc b/.all-contributorsrc new file mode 100644 index 0000000..f48f6d7 --- /dev/null +++ b/.all-contributorsrc @@ -0,0 +1,174 @@ +{ + "projectName": "react-boilerplate", + "projectOwner": "react-boilerplate", + "repoType": "github", + "repoHost": "https://github.com", + "files": [ + "README.md" + ], + "imageSize": 80, + "commit": true, + "contributors": [ + { + "login": "mxstbr", + "name": "Max Stoiber", + "avatar_url": "https://avatars0.githubusercontent.com/u/7525670?v=4", + "profile": "https://mxstbr.com", + "contributions": [ + "code", + "doc", + "ideas", + "review", + "test" + ] + }, + { + "login": "julienben", + "name": "Julien Benchetrit", + "avatar_url": "https://avatars2.githubusercontent.com/u/8948127?v=4", + "profile": "https://julien.engineering/", + "contributions": [ + "code", + "question", + "doc", + "review", + "maintenance" + ] + }, + { + "login": "gretzky", + "name": "Sara Federico", + "avatar_url": "https://avatars1.githubusercontent.com/u/15176096?v=4", + "profile": "http://sarafederi.co", + "contributions": [ + "code", + "review", + "question", + "doc", + "maintenance" + ] + }, + { + "login": "justingreenberg", + "name": "Justin Greenberg", + "avatar_url": "https://avatars1.githubusercontent.com/u/1539088?v=4", + "profile": "https://justingreenberg.com", + "contributions": [ + "code", + "review" + ] + }, + { + "login": "jwinn", + "name": "Jon Winn", + "avatar_url": "https://avatars3.githubusercontent.com/u/891726?v=4", + "profile": "https://github.com/jwinn", + "contributions": [ + "code", + "review" + ] + }, + { + "login": "Mensae", + "name": "Johan Meester", + "avatar_url": "https://avatars2.githubusercontent.com/u/474743?v=4", + "profile": "https://meester-johan.info/", + "contributions": [ + "code", + "test", + "doc" + ] + }, + { + "login": "Dattaya", + "name": "Yaroslav Kiliba", + "avatar_url": "https://avatars3.githubusercontent.com/u/387256?v=4", + "profile": "https://github.com/Dattaya", + "contributions": [ + "code" + ] + }, + { + "login": "gihrig", + "name": "Glen Ihrig", + "avatar_url": "https://avatars2.githubusercontent.com/u/1481063?v=4", + "profile": "https://github.com/gihrig", + "contributions": [ + "code" + ] + }, + { + "login": "somus", + "name": "Somasundaram Ayyappan", + "avatar_url": "https://avatars3.githubusercontent.com/u/1802828?v=4", + "profile": "https://github.com/somus", + "contributions": [ + "code" + ] + }, + { + "login": "oliverturner", + "name": "Oliver Turner", + "avatar_url": "https://avatars0.githubusercontent.com/u/21795?v=4", + "profile": "https://www.codedsignal.co.uk/", + "contributions": [ + "code" + ] + }, + { + "login": "samit4me", + "name": "Samuel Sharpe", + "avatar_url": "https://avatars3.githubusercontent.com/u/3248531?v=4", + "profile": "https://github.com/samit4me", + "contributions": [ + "code" + ] + }, + { + "login": "KarandikarMihir", + "name": "Mihir Karandikar", + "avatar_url": "https://avatars3.githubusercontent.com/u/17466938?v=4", + "profile": "https://karandikarmihir.github.io/", + "contributions": [ + "code" + ] + }, + { + "login": "v", + "name": "Vaibhav Verma", + "avatar_url": "https://avatars2.githubusercontent.com/u/627846?v=4", + "profile": "http://www.vverma.net", + "contributions": [ + "code" + ] + }, + { + "login": "sedubois", + "name": "Sébastien Dubois", + "avatar_url": "https://avatars1.githubusercontent.com/u/4217871?v=4", + "profile": "https://imagineclarity.com", + "contributions": [ + "code" + ] + }, + { + "login": "chaintng", + "name": "Chainarong Tangsurakit", + "avatar_url": "https://avatars2.githubusercontent.com/u/2979072?v=4", + "profile": "https://www.chaintng.com", + "contributions": [ + "code" + ] + }, + { + "login": "amilajack", + "name": "Amila Welihinda", + "avatar_url": "https://avatars1.githubusercontent.com/u/6374832?v=4", + "profile": "https://amilajack.com", + "contributions": [ + "code" + ] + } + ], + "contributorsPerLine": 8 +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5370727 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..0ee1945 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,89 @@ +const fs = require('fs'); +const path = require('path'); + +const prettierOptions = JSON.parse( + fs.readFileSync(path.resolve(__dirname, '.prettierrc'), 'utf8'), +); + +module.exports = { + parser: 'babel-eslint', + extends: ['airbnb', 'prettier', 'prettier/react'], + plugins: ['prettier', 'redux-saga', 'react', 'react-hooks', 'jsx-a11y'], + env: { + jest: true, + browser: true, + node: true, + es6: true, + }, + parserOptions: { + ecmaVersion: 6, + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + }, + rules: { + 'prettier/prettier': ['error', prettierOptions], + 'arrow-body-style': [2, 'as-needed'], + 'class-methods-use-this': 0, + 'import/imports-first': 0, + 'import/newline-after-import': 0, + 'import/no-dynamic-require': 0, + 'import/no-extraneous-dependencies': 0, + 'import/no-named-as-default': 0, + 'import/no-unresolved': 2, + 'import/no-webpack-loader-syntax': 0, + 'import/prefer-default-export': 0, + indent: [ + 2, + 2, + { + SwitchCase: 1, + }, + ], + 'jsx-a11y/aria-props': 2, + 'jsx-a11y/heading-has-content': 0, + 'jsx-a11y/label-has-associated-control': [ + 2, + { + // NOTE: If this error triggers, either disable it or add + // your custom components, labels and attributes via these options + // See https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/label-has-associated-control.md + controlComponents: ['Input'], + }, + ], + 'jsx-a11y/label-has-for': 0, + 'jsx-a11y/mouse-events-have-key-events': 2, + 'jsx-a11y/role-has-required-aria-props': 2, + 'jsx-a11y/role-supports-aria-props': 2, + 'max-len': 0, + 'newline-per-chained-call': 0, + 'no-confusing-arrow': 0, + 'no-console': 1, + 'no-unused-vars': 2, + 'no-use-before-define': 0, + 'prefer-template': 2, + 'react/destructuring-assignment': 0, + 'react-hooks/rules-of-hooks': 'error', + 'react/jsx-closing-tag-location': 0, + 'react/forbid-prop-types': 0, + 'react/jsx-first-prop-new-line': [2, 'multiline'], + 'react/jsx-filename-extension': 0, + 'react/jsx-no-target-blank': 0, + 'react/jsx-uses-vars': 2, + 'react/require-default-props': 0, + 'react/require-extension': 0, + 'react/self-closing-comp': 0, + 'react/sort-comp': 0, + 'redux-saga/no-yield-in-race': 2, + 'redux-saga/yield-effects': 2, + 'require-yield': 0, + }, + settings: { + 'import/resolver': { + webpack: { + config: './internals/webpack/webpack.prod.babel.js', + }, + }, + }, +}; diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c917234 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,107 @@ +# From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes + +# Handle line endings automatically for files detected as text +# and leave all files detected as binary untouched. +* text=auto + +# +# The above will handle all files NOT found below +# + +# +## These files are text and should be normalized (Convert crlf => lf) +# + +# source code +*.php text +*.css text +*.sass text +*.scss text +*.less text +*.styl text +*.js text eol=lf +*.coffee text +*.json text +*.htm text +*.html text +*.xml text +*.svg text +*.txt text +*.ini text +*.inc text +*.pl text +*.rb text +*.py text +*.scm text +*.sql text +*.sh text +*.bat text + +# templates +*.ejs text +*.hbt text +*.jade text +*.haml text +*.hbs text +*.dot text +*.tmpl text +*.phtml text + +# server config +.htaccess text +.nginx.conf text + +# git config +.gitattributes text +.gitignore text +.gitconfig text + +# code analysis config +.jshintrc text +.jscsrc text +.jshintignore text +.csslintrc text + +# misc config +*.yaml text +*.yml text +.editorconfig text + +# build config +*.npmignore text +*.bowerrc text + +# Heroku +Procfile text +.slugignore text + +# Documentation +*.md text +LICENSE text +AUTHORS text + + +# +## These files are binary and should be left untouched +# + +# (binary is a macro for -text -diff) +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.mov binary +*.mp4 binary +*.mp3 binary +*.flv binary +*.fla binary +*.swf binary +*.gz binary +*.zip binary +*.7z binary +*.ttf binary +*.eot binary +*.woff binary +*.pyc binary +*.pdf binary diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..c2f460b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,27 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +Before opening a new issue, please take a moment to review our [**community guidelines**](https://github.com/react-boilerplate/react-boilerplate/blob/master/CONTRIBUTING.md) to make the contribution process easy and effective for everyone involved. + +## Description +A clear and concise description of what the bug is. + +## Steps to reproduce +Steps to reproduce the behavior: + +(Add link to a demo on https://jsfiddle.net or similar if possible) + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +## Versions + +- React-Boilerplate: +- Node/NPM: +- Browser: diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..066b2d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..1ddadf9 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,23 @@ +## React Boilerplate + +Thank you for contributing! Please take a moment to review our [**contributing guidelines**](https://github.com/react-boilerplate/react-boilerplate/blob/master/CONTRIBUTING.md) +to make the process easy and effective for everyone involved. + +**Please open an issue** before embarking on any significant pull request, especially those that +add a new library or change existing tests, otherwise you risk spending a lot of time working +on something that might not end up being merged into the project. + +Before opening a pull request, please ensure: + +- [ ] You have followed our [**contributing guidelines**](https://github.com/react-boilerplate/react-boilerplate/blob/master/CONTRIBUTING.md) +- [ ] Double-check your branch is based on `dev` and targets `dev` +- [ ] Pull request has tests (we are going for 100% coverage!) +- [ ] Code is well-commented, linted and follows project conventions +- [ ] Documentation is updated (if necessary) +- [ ] Internal code generators and templates are updated (if necessary) +- [ ] Description explains the issue/use-case resolved and auto-closes related issues + +Be kind to code reviewers, please try to keep pull requests as small and focused as possible :) + +**IMPORTANT**: By submitting a patch, you agree to allow the project +owners to license your work under the terms of the [MIT License](https://github.com/react-boilerplate/react-boilerplate/blob/master/LICENSE.md). diff --git a/.github/issue-close-app.yml b/.github/issue-close-app.yml new file mode 100644 index 0000000..18794e3 --- /dev/null +++ b/.github/issue-close-app.yml @@ -0,0 +1,14 @@ +comment: This issue was automatically closed because it does not follow either one of our templates. Please open a new issue and fill out the template that appears instead of deleting it. If you're reporting an issue, it's especially important that you provide detailed steps for how to reproduce it. + +issueConfigs: + + - content: + - Description + - Steps to reproduce + - Versions + + - content: + - Is your feature request related to a problem + - Describe the solution you'd like + - Describe alternatives you've considered + - Additional context diff --git a/.github/lock.yml b/.github/lock.yml new file mode 100644 index 0000000..21e1541 --- /dev/null +++ b/.github/lock.yml @@ -0,0 +1,29 @@ +# Configuration for lock-threads - https://github.com/dessant/lock-threads + +# Number of days of inactivity before a closed issue or pull request is locked +daysUntilLock: 30 + +# Issues and pull requests with these labels will not be locked. Set to `[]` to disable +exemptLabels: [] + +# Label to add before locking, such as `outdated`. Set to `false` to disable +lockLabel: false + +# Comment to post before locking. Set to `false` to disable +lockComment: > + This thread has been automatically locked since there has not been + any recent activity after it was closed. Please open a new issue for + related bugs. + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings just for `issues` or `pulls` +# issues: +# exemptLabels: +# - help-wanted +# lockLabel: outdated + +# pulls: +# daysUntilLock: 30 + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5d06c05 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Don't check auto-generated stuff into git +coverage +build +node_modules +stats.json + +# Cruft +.DS_Store +npm-debug.log +.idea diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..0312896 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +lts/dubnium diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..d71a79b --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +build/ +node_modules/ +internals/generators/ +internals/scripts/ +package-lock.json +yarn.lock +package.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..0b0eae1 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/.stylelintrc b/.stylelintrc new file mode 100644 index 0000000..9e72e47 --- /dev/null +++ b/.stylelintrc @@ -0,0 +1,7 @@ +{ + "processors": ["stylelint-processor-styled-components"], + "extends": [ + "stylelint-config-recommended", + "stylelint-config-styled-components" + ] +} diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..44220cd --- /dev/null +++ b/.travis.yml @@ -0,0 +1,25 @@ +language: node_js + +node_js: + - 'node' + - 'lts/*' + +script: + - node ./internals/scripts/generate-templates-for-linting + - npm test -- --maxWorkers=4 + - npm run build + +before_install: + - export CHROME_BIN=chromium-browser + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + +notifications: + email: + on_failure: change + +after_success: 'npm run coveralls' + +cache: + directories: + - node_modules diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..2ba83bd --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [INSERT EMAIL ADDRESS]. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..f9d89b3 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,157 @@ +# Contributing to react-boilerplate + +Love react-boilerplate and want to help? Thanks so much, there's something to do for everybody! + +Please take a moment to review this document in order to make the contribution process easy and effective for everyone involved. + +Following these guidelines helps to communicate that you respect the time of the developers managing and developing this open source project. In return, they should reciprocate that respect in addressing your issue or assessing patches and features. + +## Using the issue tracker + +The [issue tracker](https://github.com/react-boilerplate/react-boilerplate/issues) is +the preferred channel for [bug reports](#bugs), [features requests](#features) +and [submitting pull requests](#pull-requests). + + + +## Bug reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. +Good bug reports are extremely helpful - thank you! + +Guidelines for bug reports: + +1. **Use the GitHub issue search** — check if the issue has already been reported. + +2. **Check if the issue has been fixed** — try to reproduce it using the latest `master` or development branch in the repository. + +3. **Isolate the problem** — ideally create a [reduced test case](https://css-tricks.com/reduced-test-cases/) and a live example. + +4. **Use the bug report template** — please fill in the template which appears when you open a new issue. + +A good bug report shouldn't leave others needing to chase you up for more information. Please try to be as detailed as possible in your report. What is your environment? What steps will reproduce the issue? What browser(s) and OS +experience the problem? What would you expect to be the outcome? All these details will help people to fix any potential bugs. + +Example: + +> ## Description +> A clear and concise description of what the bug is. +> +> Any other information you want to share that is relevant to the issue being +> reported. This might include the lines of code that you have identified as +> causing the bug, and potential solutions (and your opinions on their +> merits). +> +> ## Steps to reproduce +> Steps to reproduce the behavior: +> +> 1. This is the first step +> 2. This is the second step +> 3. Further steps, etc. +> +> (Add link to a demo on https://jsfiddle.net or similar if possible) +> +> **Expected behavior** +> A clear and concise description of what you expected to happen. +> +> **Screenshots** +> If applicable, add screenshots to help explain your problem. +> +> ## Versions +> +> - React-Boilerplate: +> - Node/NPM: +> - Browser: + + + +## Feature requests + +Feature requests are welcome. But take a moment to find out whether your idea fits with the scope and aims of the project. It's up to _you_ to make a strong case to convince the project's developers of the merits of this feature. Please provide as many details and as much context as possible. + +There is also a template for feature requests. Please make sure to use it. + + + +## Pull requests + +Good pull requests - patches, improvements, new features - are a fantastic +help. They should remain focused in scope and avoid containing unrelated +commits. + +**Please ask first** before embarking on any significant pull request (e.g. +implementing features, refactoring code, porting to a different language), +otherwise you risk spending a lot of time working on something that the +project's developers might not want to merge into the project. + +Please adhere to the coding conventions used throughout a project (indentation, +accurate comments, etc.) and any other requirements (such as test coverage). + +Since the `master` branch is what people actually use in production, we have a +`dev` branch that unstable changes get merged into first. Only when we +consider that stable we merge it into the `master` branch and release the +changes for real. + +Adhering to the following process is the best way to get your work +included in the project: + +1. [Fork](https://help.github.com/articles/fork-a-repo/) the project, clone your fork, and configure the remotes: + + ```bash + # Clone your fork of the repo into the current directory + git clone https://github.com//react-boilerplate.git + # Navigate to the newly cloned directory + cd react-boilerplate + # Assign the original repo to a remote called "upstream" + git remote add upstream https://github.com/react-boilerplate/react-boilerplate.git + ``` + +2. If you cloned a while ago, get the latest changes from upstream: + + ```bash + git checkout dev + git pull upstream dev + ``` + +3. Create a new topic branch (off the `dev` branch) to contain your feature, change, or fix: + + ```bash + git checkout -b + ``` + +4. Commit your changes in logical chunks. Please adhere to these [git commit message guidelines](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) or your code is unlikely be merged into the main project. Use Git's [interactive rebase](https://help.github.com/articles/about-git-rebase/) feature to tidy up your commits before making them public. + +5. Locally merge (or rebase) the upstream dev branch into your topic branch: + + ```bash + git pull [--rebase] upstream dev + ``` + +6. Push your topic branch up to your fork: + + ```bash + git push origin + ``` + +7. [Open a Pull Request](https://help.github.com/articles/using-pull-requests/) + with a clear title and description. + +**IMPORTANT**: By submitting a patch, you agree to allow the project +owners to license your work under the terms of the [MIT License](https://github.com/react-boilerplate/react-boilerplate/blob/master/LICENSE.md). + +# Collaborating guidelines + +You can find the list of all contributors in [README.md](./README.md). + +There are few basic rules to ensure high quality of the boilerplate: + +- Before merging, a PR requires at least two approvals from the collaborators unless it's an architectural change, a large feature, etc. If it is, then at least 50% of the core team have to agree to merge it, with every team member having a full veto right. (i.e. every single one can block any PR) +- A PR should remain open for at least two days before merging (does not apply for trivial contributions like fixing a typo). This way everyone has enough time to look into it. + +You are always welcome to discuss and propose improvements to this guideline. + +# Add yourself as a contributor + +This project follows the [All Contributors specification](https://allcontributors.org/). To add yourself to the table of contributors in the README file, please use the [bot](https://allcontributors.org/docs/en/bot/overview) or the [CLI](https://allcontributors.org/docs/en/cli/overview) as part of your PR. + +If you've already added yourself to the list and are making a new type of contribution, you can run it again and select the new contribution type. diff --git a/Changelog.md b/Changelog.md new file mode 100644 index 0000000..8f342b8 --- /dev/null +++ b/Changelog.md @@ -0,0 +1,347 @@ +# Changelog + +## RBP v4: "The One With Hooks (And Much More)" Edition (April 2019) + +### News + +React Boilerplate v4.0.0 is out and it's a doozy! Here are the highlights: + +- React has added many new features and it's time for React Boilerplate to embrace them. + - We now use `React.lazy` and `Suspense` for component lazy-loading instead of an external library. + - We've added `useInjectSaga` and `useInjectReducer` hooks to manage saga and reducer injection. They're integrated into the generators and thus become the new defaults. (Should you need them, the HOCs are still there.) + - The generators don't support classes anymore. The `PureComponent` vs `Component` choice was replaced with an option to wrap your component inside `React.memo`. +- After much deliberation, `Immutable.js` is finally gone. We've added `Immer` instead. With it, we can write very concise and readable reducers while sticking to native JavaScript data structures. +- Following the release of React Hooks, it's become even clearer that `react-testing-library` is now the industry-standard for React DOM testing. Workarounds for the incompatibilities between `enzyme` and `styled-components` are gone and we can now write leaner and more meaningful tests. + +There are many more changes to our documentation, internals and general project setup. You can find a full changelog below. + +Huge thanks to @Mensae, @gretzky, @jwinn and everyone who helped review or submit PRs! If I've forgotten your contribution in the credits below, please let me know. + +We hope you enjoy this release and welcome any feedback, bug reports or feature suggestions you can send our way! + +### Main + +- **Remove `Immutable.js` in favor of `Immer`** (**@julienben**, **@robertaird**) +- **Migrate from `enzyme` to `react-testing-library`** (**@mensae**) + - New instructions for snapshot and behavior testing +- **Embracing Hooks** (**@julienben**) + - Add `eslint-plugin-react-hooks` + - Migrate all class components to functions + - Add `useInjectSaga` and `useInjectReducer` hooks + - Remove generator options to extend `Component` or `PureComponent`. Replace with a `React.memo` option. +- **Use `React.lazy` and `Suspense` instead of `loadable-components` to code-split and asynchronously load components** (**@julienben**) + +### Documentation updates + +- Update Heroku deployment instructions (**@TheAncientGoat**) +- Add subfolder deployment instructions (**@nshimiye**) +- Add AWS EB deployment instructions (**@Al-un**) +- Spelling and grammar fixes (**@khayyamsaleem**, **@ngtan**) + +### Internals updates + +- Many dependency updates including: (**@julienben**) + - react and react-dom (`16.6` to `16.8.6`) + - react-redux (`5` to `7`) (**@bumi001**, **@jwinn**) + - connected-react-router (`4` to `6`) + - react-router-dom (`4` to `5`) + - redux-saga (`0.16` to `1`) + - sanitize.css (`4` to `8`) +- Update default saga injection mode to DAEMON (**@howardya**) +- Update generators to reflect all the stack changes +- Migrate default Node version to `lts/dubnium` (**@julienben**) +- Fix support for `stylelint` (**@jwinn**) +- Fix setup script for Windows environments (**@mensae**) +- Generate passing tests for components/containers (**@mjhost**) +- Rewrite generators code (**@mensae**) +- Complete rewrite or `generate-templates-for-linting.js` (**@mensae**) +- `webpack.DefinePlugin` => `webpack.EnvironmentPlugin` (**@nshimiye**) +- New Webpack code splitting config (**@julienben**) +- Remove `process.noDeprecation = true` (**@spawnia**) +- Miscellaneous fixes (**@ngtan**) + +### Project maintenance + +- Switch from Gitter to Spectrum (**@gretzky**) +- Update Code of Conduct and Contribution Guidelines (**@julienben**) +- New Issue Templates (**@gretzky**) +- New bots to help with issue management (**@gretzky**) +- Better recognition of contributors via adherence to [All Contributors](https://allcontributors.org/) specification (**@julienben**) + +## 3.7 October 2018 + +### News + +Welcome to a new React Boilerplate release with improvements aplenty, bug fixes and major dependency upgrades! Big thanks to @gretzky, @justingreenberg, @jwinn and everyone who helped review and submit PRs for this release! + +For existing projects, the only way to upgrade from `3.6.0` is to manually apply the changes from #2403 to your project. Please be careful when doing so as it isn't officially supported and could break things on your end. + +Next steps will include re-thinking immutability in the store (RFC @ #2092), re-organizing docs, saga improvements, smart bundling and plenty more. Please keep the PRs coming. And if you're up for it, remember that you can use the dev branch to test all the latest updates and report bugs! + +### Main + +- **Upgrades to Babel 7, React 16.6, ESLint 5, styled-components 4** (@julienben) + - Config file and Babel plugin cleanup (@gretzky) + - Fix extract-intl script for Babel 7 (@fanixk) +- **Webpack improvements** + - Removal of dll plugin (@gretzky) + - Gzipping and better optimization config in prod (@gretzky) + - react-app-polyfill for targeted IE support (@gretzky) + - Switch from UglifyJS to Terser plugin (@robertaird) + - Icons generated by webpack-pwa-manifest plugin (@Mensae) +- **Switch from Yarn back to npm** (@julienben) + - CI improvements (@jwinn) +- **New documentation section for forks** + - SSR (@gretzky) + - Electron (@mjangir) + - TypeScript (@Can-Sahin) + +### Other Updates + +- Migration from deprecated react-router-redux to connected-react-router (@julienben) +- Migration from react-loadable to loadable-components (@julienben) +- Quick start - Clone to a named directory (@spawnia) +- Scoped variables in i18n messages (@hatsuo) +- Use .prettierrc path relative to .eslintrc.js (@abeMedia) +- Fixes to generators (@julienben, @hatsuo, @ngtan) +- babel-plugin-lodash for easier import syntax (@julienben) +- Bug fix in setup script (@autechr3) + +Lots of additional documentation updates thanks to @doaboa, @cheickmec, @nicogreenarry, @sduquej, @diwakar-s-maurya. + +## 3.6 June 2018 + +### News + +Major version updates are finally here! It's been awhile, but we're a small team that's been pushing this for awhile. Thanks to several users' PRs, we were able to cherry-pick a lot from the dev branch to push this release out. We decided because of the amount of dependencies that needed to be updated- we would overshoot some of the changes made on the dev branch and just grab the most pressing ones. + +Next steps for us will be revisiting the dev branch, revisiting outstanding PRs and RFCs (like Immutable), and also plugging away at a create-react-app spinoff for react-boilerplate. + +### Main + +- **Upgrade Webpack to v4** (@julienben @stern-shawn) + - Syntax / function changes (mode, optimization, etc.) + - Remove webpack loader syntax from main app + - Better SVG handling +- **Upgrade Redux to v4** (@gretzky) +- **Upgrade React to v16** (@blling @gretzky) +- **Upgrade Enzyme to v3** (@blling @gretzky) + - Add in new Adapter, as required + - Minor Jest config tweaks to include new Enzyme setup config +- **Upgrade styled-components to v3** (@julienben) + - Reconfigure Jest snapshot testing for styled-components (@gretzky) +- **Added support for node v9, v8** (@julienben) + - Removed support for node v6 +- **Add Prettier** (@julienben) +- **Upgrade ESLint to v4** (@julienben) +- **Add stylelint and stylelint config** (@julienben) + +### Other Updates + +- Add `--fix` flag to eslint command (@shobhitchittora) +- Correct babel plugin order (@petrhanak) +- Add missing `import PropTypes` to component generators (@GoldAnna) +- Remove unnecessary `onRejected()` from FontFaceObserver (@akarve) +- Include "Setting Up Your Editor" in documentation (@mjbvz) +- Add login / authentication flow example into documentation (@tinavanschelt) +- More detailed redux-saga usage documentation (@acharlop) +- Fix ejection error of done sagas (@outdooricon) + +## 3.5 September 2017 + +### News + +So, a few things have changed in the JS ecosystem since the original release of React Boilerplate, and there was a discussion in #1776 around the it's future. TLDR; we had two incompatible PRs — one for server-side rendering, and another for react-router v4. The community decided that we would keep our dependencies up to date (upgrade react-router) and establish a clear mission for React Boilerplate: + +**React Boilerplate is a rock-solid foundation for crafting large, high-performance enterprise-grade frontend web applications that have advanced/custom requirements.** + +- Static output designed for CDN and edge caches +- Extreme Developer Ergonomics + - Parallelized Tests + - DLL manifest in development for blazing rebuilds + - Scaffolding tools +- Pre-baked i18n support +- Low level tooling that gives developer complete control + +We may include SSR in a future version, but for now this is our focus... create-react-app and next.js are doing an awesome job and strongly recommend these projects for most use cases. + +### Breaking + +- **Upgrade React Router to v4.x.x** (@anuraaga, @Dattaya, et al) + - Use React-Loadable for data lifecycle management + - Refactor `asyncInjectors`: improve code splitting/saga management + - For a complete overview of changes, please see #1746 + +### Main + +- **Upgrade React to v15.6** (@g0ddish) +- **Upgrade Webpack and related dependencies to v3.x.x** (@KarandikarMihir) +- **Upgrade `styled-components` to v2.x.x** (@justingreenberg) +- Replace `babel-preset-hmre` with vanilla Webpack HMR (@Dattaya) +- Serve Dlls via `add-asset-html-webpack-plugin` (@skidding) +- Migrate from `React.PropTypes` to `prop-types` (@dennybiasioll + +### Other Updates + +- Add Stateless Functions to Container generator (@outdooricon) +- Change development sourcemap style (@samit4me) +- Create new documentation for dependency updates (@gihrig) +- Downgrade `sanitize.css` (@Dattaya) +- Enable rule `react/no-array-index-key` (@carloscuatin) +- Fix `Intl` polyfill in language generator (@tmf) +- Handle 204 and 205 HTTP response (@williamdclt) +- Icon updates and improvements (@samit4me) +- Import only necessary components for RRv4 (@sorin-davidoi) +- Improve `` component tests (@chaintng) +- Improve component tests in demo (@dennybiasiolli) +- Improve setup to recognize repo before clearing git (@Aftabnack) +- Make build output less verbose (@KarandikarMihir) +- Move `onSubmitForm` test into `mapDispatchToProps` test (@tomasfrancisco) +- NPM script and dependency updates, many fixes (@gihrig) +- Remove state update in componentWillUpdate (@mawi12345) +- Remove unused Sinon dependency (@avdeev) +- Remove route names from `app/routes` (@beardedtim) +- Rename `store.js` to `configureStore.js` to prevent conflict (@howardya) +- Separate `dev` and `prod` middleware (@tomazy) +- Sort ESLint config in `package.json` (@bt) +- Support OpenType fonts with `.otf` file extension (@kachkaev) +- Turn `App` into a functional component (@Dattaya) +- Update FAQ for styles getting overridden (@samit4me) +- Update the 'tagged template literals' link (@joncass) +- Use camelcase for reducer and saga key to match selector (@anuraaga) +- Use correct selector names in tests (@Dattaya) +- Use local instance of `shelljs` (@KarandikarMihir) +- Use optimized version of the RBP banner (@tomazy) +- Use relative path for `manifest.json` (@mrharel) + +Many fixes to documentation thanks to @Aftabnack, @auchenberg, @danielrob, @gregoralbrecht, @JonathanMerklin, @marciopuga, @NicholasAnthony, @Skaronator, and @vedatmahir + +## 3.4 January 2017 + +### Main + +- **Switch to Jest for testing**, massive thanks to @dmitriiabramov +- **Update to webpack 2 RC** (includes switching from `System.import` to `import()`), thanks to @Dattaya +- **Add progress bar while loading code splitted routes**, thanks to @KarandikarMihir +- **Add the "Hitchhikers Guide to `react-boilerplate` to the docs**, massive thanks to @KarandikarMihir +- Update all dependencies, as always huge thanks to @gihrig, our master of dependencies +- Enable `import/first` eslint rule and rewrite all imports, huge thanks to @KarandikarMihir +- Add Node v7 support and deprecate v4 support, thanks to @samit4me @MariusRumpf +- Prevent i18n language duplication, thanks to @harijoe +- Add the webpack circular dependency plugin to avoid hard to debug errors, thanks to @haikyuu +- Refactor all selectors and generators with new naming convention, thanks to @Dattaya +- Update generator templates, thanks to @Virsaviya @jeremyadavis +- Add support for the `--host` parameter when running `npm start`, thanks to @ifedotov +- Showcase reselects `createStructuredSelector` in the example, thanks to @Dattaya +- Exclude test files from coverage report, thanks to @samit4me +- Lint the templates for the generators, thanks to @Dattaya +- Huge improvement to DX testing a freshly cleaned project, thanks to @outdooricon + +### Other Updates + +- **Remove the webpack DedupePlugin** as it leads to errors in production and is now included by default, thanks to @samit4me +- Remove the `npm run pagespeed` command and all related dependencies and files, thanks to @mkhazov +- Trigger a full page reload when HMR fails, thanks @kachkaev +- Don't import all of lodash, thanks to @jwinn +- Improve `.editconfig`, thanks to @avdeev +- Improve the example components, thanks to @tomazy +- Fix `npm run clean` not working as expected, thanks to @adjnor +- Fix the i18n button not updating with new state, thanks to @adjnor +- Fix console error when changing language, thanks to @samit4me +- Fix default polyfill language, thanks to @web2style +- Fix language generation, thanks to @chaintng +- Switch to new webpack query syntax, thanks to @shrynx +- Add an Introductory document to help people get started, thanks to @KarandikarMihir +- Add security configuration recommendations for Nginx (`.nginx.conf`), thanks to @supergicko +- Add and fix lots to stuff in the documentation, thanks to @pavlin-policar, @samit4me @outdooricon @PierrickGT @nndung179 @outdooricon @kelsonic @jimmyheaddon +- A wide variety of small fixes, thanks to @Dattaya @gihrig @outdooricon + +### News + +Welcome @KarandikarMihir to the team! Karandikar has been all over the repo, providing fixes and features. Happy to have him on board to make `react-boilerplate` even better! + +Special thanks as always to @gihrig for diligently testing everything and keeping our dependencies up to date! + +Also, huge props to @samit4me and @Dattaya for being everywhere and fixing so many issues and of course to @KarandikarMihir for all his hard work. + +If you want to help us make react-boilerplate great, please use the `dev` branch, test all the things and report all the bugs! + +### Supporters + +This release was made possible by [Fullstack React](https://www.fullstackreact.com/) and [Serverless](http://serverless.com)! _Want to support us too? [Click here!](http://opencollective.com/react-boilerplate)_ + +## RBP v3.0: The "JS Fatigue Antivenin" Edition + +React Boilerplate (RBP) v3.0.0 is out, and it's a _complete_ rewrite! :tada: + +We've focused on becoming a rock-solid foundation to start your next project +with, no matter what its scale. You get to focus on writing your app because we +focus on making that as easy as pie. + +website! + +## Highlights + +- **Scaffolding**: Thanks to @somus, you can now run `npm run generate` in your + terminal and immediately create new components, containers, sagas, routes and + selectors! No more context switching, no more "Create new file, copy and paste + that boilerplate structure, bla bla": just `npm run generate ` and go. + + Oh... and starting a project got a whole lot easier too: `npm run setup`. Done. + +- **Revamped architecture**: Following the incredible discussion in #27 (thanks + everybody for sharing your thoughts), we now have a weapons-grade, domain-driven + application architecture. + + "Smart" containers are now isolated from stateless and/or generic components, + tests are now co-located with the code that they validate. + +- **New industry-standard JS utilities** We're now making the most of... + + - ImmutableJS + - reselect + - react-router-redux + - redux-saga + +- **Huge CSS Improvements** + + - _[CSS Modules](docs/css/css-modules.md)_: Finally, truly modular, reusable + styles! + - _Page-specific CSS_: smart Webpack configuration means that only the CSS + your components need is served + - _Standards rock:_ Nothing beats consistent styling so we beefed up the + quality checks with **[stylelint](docs/css/stylelint.md)** to help ensure + that you and your team stay on point. + +- **Performance** + + - _Code splitting_: splitting/chunking by route means the leanest, meanest + payload (because the fastest code is the code you don't load!) + +- **Testing setup**: Thanks to @jbinto's herculean efforts, testing is now a + first-class citizen of this boilerplate. (the example app has _99% test coverage!_) + Karma and enzyme take care of unit testing, while ngrok tunnels your local + server for access from anywhere in the world – perfect for testing on different + devices in different locations. + +- **New server setup**: Thanks to the mighty @grabbou, we now use express.js to + give users a production-ready server right out of the box. Hot reloading is + still as available as always, but adding a custom API or a non-React page to + your application is now easier than ever :smile: + +- **Cleaner layout:** We've taken no prisoners with our approach to keeping your + code the star of the show: wherever possible, the new file layout keeps the + config in the background so that you can keep your focus where it needs to be. + +- **Documentation**: Thanks to @oliverturner, this boilerplate has some of the best + documentation going. Not just clearly explained usage guides, but easy-to-follow + _removal_ guides for most features too. RBP is just a launchpad: don't want to + use a bundled feature? Get rid of it quickly and easily without having to dig + through the code. + +- **Countless small improvements**: Everything, from linting pre-commit (thanks + @okonet!) to code splitting to cross-OS compatibility is now tested and ready + to go: + + - We finally added a **[CoC](CODE_OF_CONDUCT.md)** + - Windows compatibility has improved massively diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..5057791 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Maximilian Stoiber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..0907904 --- /dev/null +++ b/README.md @@ -0,0 +1,169 @@ +react boilerplate banner + +
+ +
Start your next react project in seconds
+
A highly scalable, offline-first foundation with the best DX and a focus on performance and best practices
+ +
+ +
+ + + Dependency Status + + + + devDependency Status + + + + Build Status + + + + Test Coverage + + + Chat with us on Spectrum + + +
+ + +
+ +
+ Created by Max Stoiber and maintained with ❤️ by an amazing team of developers. +
+ +## Features + +
+
Quick scaffolding
+
Create components, containers, routes, selectors and sagas - and their tests - right from the CLI!
+ +
Instant feedback
+
Enjoy the best DX (Developer eXperience) and code your app at the speed of thought! Your saved changes to the CSS and JS are reflected instantaneously without refreshing the page. Preserve application state even when you update something in the underlying code!
+ +
Predictable state management
+
Unidirectional data flow allows for change logging and time travel debugging.
+ +
Next generation JavaScript
+
Use template strings, object destructuring, arrow functions, JSX syntax and more.
+ +
Next generation CSS
+
Write composable CSS that's co-located with your components for complete modularity. Unique generated class names keep the specificity low while eliminating style clashes. Ship only the styles that are on the page for the best performance.
+ +
Industry-standard routing
+
It's natural to want to add pages (e.g. `/about`) to your application, and routing makes this possible.
+ +
Industry-standard i18n internationalization support
+
Scalable apps need to support multiple languages, easily add and support multiple languages with `react-intl`.
+ +
Offline-first
+
The next frontier in performant web apps: availability without a network connection from the instant your users load the app.
+ +
Static code analysis
+
Focus on writing new features without worrying about formatting or code quality. With the right editor setup, your code will automatically be formatted and linted as you work.
+ +
SEO
+
We support SEO (document head tags management) for search engines that support indexing of JavaScript content. (eg. Google)
+
+ +But wait... there's more! + +- _The best test setup:_ Automatically guarantee code quality and non-breaking + changes. (Seen a react app with 100% test coverage before?) +- _Native web app:_ Your app's new home? The home screen of your users' phones. +- _The fastest fonts:_ Say goodbye to vacant text. +- _Stay fast_: Profile your app's performance from the comfort of your command + line! +- _Catch problems:_ AppVeyor and TravisCI setups included by default, so your + tests get run automatically on Windows and Unix. + +There’s also a fantastic video on how to structure your React.js apps with scalability in mind. It provides rationale for the majority of boilerplate's design decisions. + +Keywords: React.js, Redux, Hot Reloading, ESNext, Babel, react-router, Offline First, ServiceWorker, `styled-components`, redux-saga, FontFaceObserver + +## Quick start + +1. Make sure that you have Node.js v8.15.1 and npm v5 or above installed. +2. Clone this repo using `git clone --depth=1 https://github.com/react-boilerplate/react-boilerplate.git ` +3. Move to the appropriate directory: `cd `.
+4. Run `npm run setup` in order to install dependencies and clean the git repo.
+ _At this point you can run `npm start` to see the example app at `http://localhost:3000`._ +5. Run `npm run clean` to delete the example app. + +Now you're ready to rumble! + +> Please note that this boilerplate is **production-ready and not meant for beginners**! If you're just starting out with react or redux, please refer to https://github.com/petehunt/react-howto instead. If you want a solid, battle-tested base to build your next product upon and have some experience with react, this is the perfect start for you. + +## Documentation + +- [**The Hitchhiker's Guide to `react-boilerplate`**](docs/general/introduction.md): An introduction for newcomers to this boilerplate. +- [Overview](docs/general): A short overview of the included tools +- [**Commands**](docs/general/commands.md): Getting the most out of this boilerplate +- [Testing](docs/testing): How to work with the built-in test harness +- [Styling](docs/css): How to work with the CSS tooling +- [Your app](docs/js): Supercharging your app with Routing, Redux, simple + asynchronicity helpers, etc. +- [**Troubleshooting**](docs/general/gotchas.md): Solutions to common problems faced by developers. + +## Contributors + +Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): + + + +
Max Stoiber
Max Stoiber

💻 📖 🤔 👀 ⚠️
Julien Benchetrit
Julien Benchetrit

💻 💬 📖 👀 🚧
Sara Federico
Sara Federico

💻 👀 💬 📖 🚧
Justin Greenberg
Justin Greenberg

💻 👀
Jon Winn
Jon Winn

💻 👀
Johan Meester
Johan Meester

💻 ⚠️ 📖
Yaroslav Kiliba
Yaroslav Kiliba

💻
Glen Ihrig
Glen Ihrig

💻
Somasundaram Ayyappan
Somasundaram Ayyappan

💻
Oliver Turner
Oliver Turner

💻
Samuel Sharpe
Samuel Sharpe

💻
Mihir Karandikar
Mihir Karandikar

💻
Vaibhav Verma
Vaibhav Verma

💻
Sébastien Dubois
Sébastien Dubois

💻
Chainarong Tangsurakit
Chainarong Tangsurakit

💻
Amila Welihinda
Amila Welihinda

💻
+ + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! + + +## Supporters + +This project would not be possible without the support of these amazing folks. [**Become a sponsor**](https://opencollective.com/react-boilerplate) to get your company in front of thousands of engaged react developers and help us out! + + + + + + + + + + + + +--- + + + + + + + + + + + + +## License + +This project is licensed under the MIT license, Copyright (c) 2019 Maximilian +Stoiber. For more information see `LICENSE.md`. diff --git a/app/.htaccess b/app/.htaccess new file mode 100644 index 0000000..40252ae --- /dev/null +++ b/app/.htaccess @@ -0,0 +1,52 @@ + + + + ####################################################################### + # GENERAL # + ####################################################################### + + # Make apache follow sym links to files + Options +FollowSymLinks + # If somebody opens a folder, hide all files from the resulting folder list + IndexIgnore */* + + + ####################################################################### + # REWRITING # + ####################################################################### + + # Enable rewriting + RewriteEngine On + + # If its not HTTPS + RewriteCond %{HTTPS} off + + # Comment out the RewriteCond above, and uncomment the RewriteCond below if you're using a load balancer (e.g. CloudFlare) for SSL + # RewriteCond %{HTTP:X-Forwarded-Proto} !https + + # Redirect to the same URL with https://, ignoring all further rules if this one is in effect + RewriteRule ^(.*) https://%{HTTP_HOST}/$1 [R,L] + + # If we get to here, it means we are on https:// + + # If the file with the specified name in the browser doesn't exist + RewriteCond %{REQUEST_FILENAME} !-f + + # and the directory with the specified name in the browser doesn't exist + RewriteCond %{REQUEST_FILENAME} !-d + + # and we are not opening the root already (otherwise we get a redirect loop) + RewriteCond %{REQUEST_FILENAME} !\/$ + + # Rewrite all requests to the root + RewriteRule ^(.*) / + + + + + # Do not cache sw.js, required for offline-first updates. + + Header set Cache-Control "private, no-cache, no-store, proxy-revalidate, no-transform" + Header set Pragma "no-cache" + + diff --git a/app/.nginx.conf b/app/.nginx.conf new file mode 100644 index 0000000..6a71831 --- /dev/null +++ b/app/.nginx.conf @@ -0,0 +1,112 @@ +## +# Put this file in /etc/nginx/conf.d folder and make sure +# you have a line 'include /etc/nginx/conf.d/*.conf;' +# in your main nginx configuration file +## + +## +# Redirect to the same URL with https:// +## + +server { + + listen 80; + +# Type your domain name below + server_name example.com; + + return 301 https://$server_name$request_uri; + +} + +## +# HTTPS configurations +## + +server { + + listen 443 ssl; + +# Type your domain name below + server_name example.com; + +# Configure the Certificate and Key you got from your CA (e.g. Lets Encrypt) + ssl_certificate /path/to/certificate.crt; + ssl_certificate_key /path/to/server.key; + + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + +# Only use TLS v1.2 as Transport Security Protocol + ssl_protocols TLSv1.2; + +# Only use ciphersuites that are considered modern and secure by Mozilla + ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; + +# Do not let attackers downgrade the ciphersuites in Client Hello +# Always use server-side offered ciphersuites + ssl_prefer_server_ciphers on; + +# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months) + add_header Strict-Transport-Security max-age=15768000; + +# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits +# Uncomment if you want to use your own Diffie-Hellman parameter, which can be generated with: openssl ecparam -genkey -out dhparam.pem -name prime256v1 +# See https://wiki.mozilla.org/Security/Server_Side_TLS#DHE_handshake_and_dhparam +# ssl_dhparam /path/to/dhparam.pem; + + +## OCSP Configuration START +# If you want to provide OCSP Stapling, you can uncomment the following lines +# See https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx for more infos about OCSP and its use case +# fetch OCSP records from URL in ssl_certificate and cache them + +#ssl_stapling on; +#ssl_stapling_verify on; + +# verify chain of trust of OCSP response using Root CA and Intermediate certs (you will get this file from your CA) +#ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; + +## OCSP Configuration END + +# To let nginx use its own DNS Resolver +# resolver ; + + +# Always serve index.html for any request + location / { + # Set path + root /var/www/; + try_files $uri /index.html; + } + +# Do not cache sw.js, required for offline-first updates. + location /sw.js { + add_header Cache-Control "no-cache"; + proxy_cache_bypass $http_pragma; + proxy_cache_revalidate on; + expires off; + access_log off; + } + +## +# If you want to use Node/Rails/etc. API server +# on the same port (443) config Nginx as a reverse proxy. +# For security reasons use a firewall like ufw in Ubuntu +# and deny port 3000/tcp. +## + +# location /api/ { +# +# proxy_pass http://localhost:3000; +# proxy_http_version 1.1; +# proxy_set_header X-Forwarded-Proto https; +# proxy_set_header Upgrade $http_upgrade; +# proxy_set_header Connection 'upgrade'; +# proxy_set_header Host $host; +# proxy_cache_bypass $http_upgrade; +# +# } + +} diff --git a/app/app.js b/app/app.js new file mode 100644 index 0000000..4c96195 --- /dev/null +++ b/app/app.js @@ -0,0 +1,96 @@ +/** + * app.js + * + * This is the entry file for the application, only setup and boilerplate + * code. + */ + +// Needed for redux-saga es6 generator support +import '@babel/polyfill'; + +// Import all the third party stuff +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Provider } from 'react-redux'; +import { ConnectedRouter } from 'connected-react-router'; +import FontFaceObserver from 'fontfaceobserver'; +import history from 'utils/history'; +import 'sanitize.css/sanitize.css'; + +// Import root app +import App from 'containers/App'; + +// Import Language Provider +import LanguageProvider from 'containers/LanguageProvider'; + +// Load the favicon and the .htaccess file +import '!file-loader?name=[name].[ext]!./images/favicon.ico'; +import 'file-loader?name=.htaccess!./.htaccess'; // eslint-disable-line import/extensions + +import configureStore from './configureStore'; + +// Import i18n messages +import { translationMessages } from './i18n'; + +// Observe loading of Open Sans (to remove open sans, remove the tag in +// the index.html file and this observer) +const openSansObserver = new FontFaceObserver('Open Sans', {}); + +// When Open Sans is loaded, add a font-family using Open Sans to the body +openSansObserver.load().then(() => { + document.body.classList.add('fontLoaded'); +}); + +// Create redux store with history +const initialState = {}; +const store = configureStore(initialState, history); +const MOUNT_NODE = document.getElementById('app'); + +const render = messages => { + ReactDOM.render( + + + + + + + , + MOUNT_NODE, + ); +}; + +if (module.hot) { + // Hot reloadable React components and translation json files + // modules.hot.accept does not accept dynamic dependencies, + // have to be constants at compile-time + module.hot.accept(['./i18n', 'containers/App'], () => { + ReactDOM.unmountComponentAtNode(MOUNT_NODE); + render(translationMessages); + }); +} + +// Chunked polyfill for browsers without Intl support +if (!window.Intl) { + new Promise(resolve => { + resolve(import('intl')); + }) + .then(() => + Promise.all([ + import('intl/locale-data/jsonp/en.js'), + import('intl/locale-data/jsonp/de.js'), + ]), + ) // eslint-disable-line prettier/prettier + .then(() => render(translationMessages)) + .catch(err => { + throw err; + }); +} else { + render(translationMessages); +} + +// Install ServiceWorker and AppCache in the end since +// it's not most important operation and if main code fails, +// we do not want it installed +if (process.env.NODE_ENV === 'production') { + require('offline-plugin/runtime').install(); // eslint-disable-line global-require +} diff --git a/app/components/A/index.js b/app/components/A/index.js new file mode 100644 index 0000000..0ff7d0e --- /dev/null +++ b/app/components/A/index.js @@ -0,0 +1,15 @@ +/** + * A link to a certain page, an anchor tag + */ + +import styled from 'styled-components'; + +const A = styled.a` + color: #41addd; + + &:hover { + color: #6cc0e5; + } +`; + +export default A; diff --git a/app/components/A/tests/index.test.js b/app/components/A/tests/index.test.js new file mode 100644 index 0000000..cb4c7be --- /dev/null +++ b/app/components/A/tests/index.test.js @@ -0,0 +1,52 @@ +/** + * Testing our link component + */ + +import React from 'react'; +import { render } from 'react-testing-library'; + +import A from '../index'; + +const href = 'http://mxstbr.com/'; +const children =

Test

; +const renderComponent = (props = {}) => + render( + + {children} + , + ); + +describe('', () => { + it('should render an tag', () => { + const { container } = renderComponent(); + expect(container.querySelector('a')).not.toBeNull(); + }); + + it('should have an href attribute', () => { + const { container } = renderComponent(); + expect(container.querySelector('a').href).toEqual(href); + }); + + it('should have children', () => { + const { container } = renderComponent(); + expect(container.querySelector('a').children).toHaveLength(1); + }); + + it('should have a class attribute', () => { + const className = 'test'; + const { container } = renderComponent({ className }); + expect(container.querySelector('a').classList).toContain(className); + }); + + it('should adopt a target attribute', () => { + const target = '_blank'; + const { container } = renderComponent({ target }); + expect(container.querySelector('a').target).toEqual(target); + }); + + it('should adopt a type attribute', () => { + const type = 'text/html'; + const { container } = renderComponent({ type }); + expect(container.querySelector('a').type).toEqual(type); + }); +}); diff --git a/app/components/Button/A.js b/app/components/Button/A.js new file mode 100644 index 0000000..0f9b0cf --- /dev/null +++ b/app/components/Button/A.js @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +import buttonStyles from './buttonStyles'; + +const A = styled.a` + ${buttonStyles}; +`; + +export default A; diff --git a/app/components/Button/StyledButton.js b/app/components/Button/StyledButton.js new file mode 100644 index 0000000..ceb46ea --- /dev/null +++ b/app/components/Button/StyledButton.js @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +import buttonStyles from './buttonStyles'; + +const StyledButton = styled.button` + ${buttonStyles}; +`; + +export default StyledButton; diff --git a/app/components/Button/Wrapper.js b/app/components/Button/Wrapper.js new file mode 100644 index 0000000..e69d209 --- /dev/null +++ b/app/components/Button/Wrapper.js @@ -0,0 +1,9 @@ +import styled from 'styled-components'; + +const Wrapper = styled.div` + width: 100%; + text-align: center; + margin: 4em 0; +`; + +export default Wrapper; diff --git a/app/components/Button/buttonStyles.js b/app/components/Button/buttonStyles.js new file mode 100644 index 0000000..3276bf1 --- /dev/null +++ b/app/components/Button/buttonStyles.js @@ -0,0 +1,26 @@ +import { css } from 'styled-components'; + +const buttonStyles = css` + display: inline-block; + box-sizing: border-box; + padding: 0.25em 2em; + text-decoration: none; + border-radius: 4px; + -webkit-font-smoothing: antialiased; + -webkit-touch-callout: none; + user-select: none; + cursor: pointer; + outline: 0; + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; + font-weight: bold; + font-size: 16px; + border: 2px solid #41addd; + color: #41addd; + + &:active { + background: #41addd; + color: #fff; + } +`; + +export default buttonStyles; diff --git a/app/components/Button/index.js b/app/components/Button/index.js new file mode 100644 index 0000000..4bbe435 --- /dev/null +++ b/app/components/Button/index.js @@ -0,0 +1,43 @@ +/** + * + * Button.js + * + * A common button, if you pass it a prop "route" it'll render a link to a react-router route + * otherwise it'll render a link with an onclick + */ + +import React, { Children } from 'react'; +import PropTypes from 'prop-types'; + +import A from './A'; +import StyledButton from './StyledButton'; +import Wrapper from './Wrapper'; + +function Button(props) { + // Render an anchor tag + let button = ( + + {Children.toArray(props.children)} + + ); + + // If the Button has a handleRoute prop, we want to render a button + if (props.handleRoute) { + button = ( + + {Children.toArray(props.children)} + + ); + } + + return {button}; +} + +Button.propTypes = { + handleRoute: PropTypes.func, + href: PropTypes.string, + onClick: PropTypes.func, + children: PropTypes.node.isRequired, +}; + +export default Button; diff --git a/app/components/Button/tests/A.test.js b/app/components/Button/tests/A.test.js new file mode 100644 index 0000000..ca7e831 --- /dev/null +++ b/app/components/Button/tests/A.test.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { render } from 'react-testing-library'; + +import A from '../A'; + +describe('', () => { + it('should render an tag', () => { + const { container } = render(); + expect(container.querySelector('a')).not.toBeNull(); + }); + + it('should have a class attribute', () => { + const { container } = render(); + expect(container.querySelector('a').hasAttribute('class')).toBe(true); + }); + + it('should adopt a valid attribute', () => { + const id = 'test'; + const { container } = render(); + expect(container.querySelector('a').id).toEqual(id); + }); + + it('should not adopt an invalid attribute', () => { + const { container } = render(); + expect(container.querySelector('a[attribute="test"]')).toBeNull(); + }); +}); diff --git a/app/components/Button/tests/StyledButton.test.js b/app/components/Button/tests/StyledButton.test.js new file mode 100644 index 0000000..d4b29a1 --- /dev/null +++ b/app/components/Button/tests/StyledButton.test.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { render } from 'react-testing-library'; + +import StyledButton from '../StyledButton'; + +describe('', () => { + it('should render an , + ); + +describe('; +} +``` + +> For more information about Stylesheets and the `css-loader` see https://github.com/webpack-contrib/css-loader + +## CSS Modules + +### Setup + +Modify [`webpack.base.babel.js`][webpackconfig] +to look like: + +```diff +{ + test: /\.css$/, + exclude: /node_modules/, +- use: ['style-loader', 'css-loader'], ++ use: [ ++ 'style-loader', ++ { ++ loader: 'css-loader', ++ options: { ++ modules: true, ++ }, ++ }, ++ ], +} +``` + +### Usage + +The syntax is very similar to using a [Stylesheet](#stylesheet) +and this often catches people out. +The key difference in CSS Modules is that you import styles to a variable. + +**`Button.css`** + +```css +.danger { + background-color: red; +} +``` + +**`Button.js`** + +```js +import React from 'react'; +import styles from './Button.css'; // different import compared to stylesheets + +function Button() { + // different usage to stylesheets + return ; +} +``` + +**IMPORTANT: if you enable this rule, [stylesheets](#stylesheet) will no longer work, +it's one or the other unless you include or exclude specific directories.** + +> For more information about CSS Modules see https://github.com/css-modules/css-modules + +## Sass + +### Setup + +Install `sass-loader` and the `node-sass` dependancy. + +``` +npm i -D sass-loader node-sass +``` + +Modify [`webpack.base.babel.js`][webpackconfig] +to look like: + +```diff +{ +- test: /\.css$/, ++ test: /\.scss$/, + exclude: /node_modules/, +- use: ['style-loader', 'css-loader'], ++ use: ['style-loader', 'css-loader', 'sass-loader'], +} +``` + +### Usage + +**`Button.scss`** + +```scss +$error-color: red; + +.danger { + background-color: $error-color; +} +``` + +**`Button.js`** + +```js +import React from 'react'; +import './Button.scss'; + +function Button() { + return ; +} +``` + +> For more information about Sass and the `sass-loader` see https://github.com/webpack-contrib/sass-loader + +## LESS + +### Setup + +Install `less-loader` and the `less` dependancy. + +``` +npm i -D less-loader less +``` + +Modify [`webpack.base.babel.js`][webpackconfig] +to look like: + +```diff +{ +- test: /\.css$/, ++ test: /\.less$/, + exclude: /node_modules/, +- use: ['style-loader', 'css-loader'], ++ use: [ ++ 'style-loader', ++ { ++ loader: 'css-loader', ++ options: { ++ importLoaders: 1, ++ }, ++ }, ++ 'less-loader', ++], +} +``` + +### Usage + +**`Button.less`** + +```less +@error-color: red; + +.danger { + background-color: @error-color; +} +``` + +**`Button.js`** + +```js +import React from 'react'; +import './Button.less'; + +function Button() { + return ; +} +``` + +> For more information about LESS and the `less-loader` see https://github.com/webpack-contrib/less-loader. + +[webpackconfig]: ../../internals/webpack/webpack.base.babel.js 'Webpack config' diff --git a/docs/css/linting.md b/docs/css/linting.md new file mode 100644 index 0000000..d703c19 --- /dev/null +++ b/docs/css/linting.md @@ -0,0 +1,11 @@ +# Linting + +We use `stylelint` for CSS linting. `stylelint` catches syntax errors and helps you and your team stay consistent with modern CSS standards and conventions. + +We've pre-configured it specifically for the boilerplate's `styled-components` setup (and following that package's [recommendations](https://www.styled-components.com/docs/tooling#stylelint)). + +However, you can (and should!) adapt it to your own style setup if you decide to modify it. + +You can trigger `stylelint` using the `npm run lint:css` command or you can integrate with your IDE by downloading the relevant plugin. We recommend the latter. + +See the [official documentation](https://stylelint.io/) for more information! diff --git a/docs/css/remove.md b/docs/css/remove.md new file mode 100644 index 0000000..d45eac7 --- /dev/null +++ b/docs/css/remove.md @@ -0,0 +1,27 @@ +## Removing `sanitize.css` + +To remove `sanitize.css` you will need to remove it from both: + +- [`app.js`](../../app/app.js) + +```diff +import FontFaceObserver from 'fontfaceobserver'; +import history from 'utils/history'; +-import 'sanitize.css/sanitize.css'; + +// Import root app +import App from 'containers/App'; +``` + +- [`package.json`](../../package.json)! + +```diff +"dependencies": { + ... + "redux-saga": "0.14.3", + "reselect": "2.5.4", +- "sanitize.css": "4.1.0", + "styled-components": "1.4.3", + ... +}, +``` diff --git a/docs/css/sanitize.md b/docs/css/sanitize.md new file mode 100644 index 0000000..747ba2c --- /dev/null +++ b/docs/css/sanitize.md @@ -0,0 +1,17 @@ +# `sanitize.css` + +Sanitize.css makes browsers render elements more in +line with developer expectations (e.g. having the box model set to a cascading +`box-sizing: border-box`) and preferences (its defaults can be individually +overridden). + +It was selected over older projects like `normalize.css` and `reset.css` due +to its greater flexibility and better alignment with CSSNext features like CSS +variables. + +See the [official documentation](https://github.com/10up/sanitize.css) for more +information. + +--- + +_Don't like this feature? [Click here](remove.md)_ diff --git a/docs/forks/README.md b/docs/forks/README.md new file mode 100644 index 0000000..24f7477 --- /dev/null +++ b/docs/forks/README.md @@ -0,0 +1,25 @@ +# Forks + +## Electron + +Electron is a very popular open source library developed by GitHub. It enables the creation of cross-platform desktop applications using HTML, CSS and Javascript. This fork provide steps through which you can kickstart an Electron application using `react-boilerplate`. + +Electron provides a combined single runtime of Chromium and Node.js. No server is needed to host your React application. You can simply package the entire source code in a `.exe`, `.dmg` or `.deb` file. + +This fork gives you two options: + +1. Clone the repository for a fresh start: [reactron](https://github.com/mjangir/reactron) + +2. Read the steps to [convert an existing RBP-based project to an Electron application](https://github.com/mjangir/reactron/wiki/Convert-Existing-To-Electron) + +## Server-side rendering + +This repo receives many requests for server-side rendering and there have been plenty of long discussions on the topic. None have led to an implementation that we're happy to merge into the main repo. That being said, @gretzky has a fork which you can use as a solid starting point for your SSR needs: [react-boilerplate-ssr](https://github.com/gretzky/react-boilerplate-ssr) + +## TypeScript + +Since we don't support TypeScript out of the box, for those in need, we can direct you to a TypeScript implementation of this repo. + +TS Fork: [react-boilerplate-typescript](https://github.com/Can-Sahin/react-boilerplate-typescript) + +Details: [Docs](https://github.com/Can-Sahin/react-boilerplate-typescript/blob/master/docs/general/typescript.md) diff --git a/docs/general/README.md b/docs/general/README.md new file mode 100644 index 0000000..090caa4 --- /dev/null +++ b/docs/general/README.md @@ -0,0 +1,133 @@ +# Introduction + +The JavaScript ecosystem evolves at incredible speed: staying current can feel +overwhelming. So, instead of you having to stay on top of every new tool, +feature and technique to hit the headlines, this project aims to lighten the +load by providing a curated baseline of the most valuable ones. + +Using React Boilerplate, you get to start your app with our community's current +ideas on what represents optimal developer experience, best practice, most +efficient tooling and cleanest project structure. + +- [**CLI Commands**](commands.md) +- [Setting up your editor](editor.md) +- [Tool Configuration](files.md) +- [Server Configurations](server-configs.md) +- [Deployment](deployment.md) _(currently Heroku & AWS specific)_ +- [FAQ](faq.md) +- [Gotchas](gotchas.md) + +# Feature overview + +## Quick scaffolding + +Automate the creation of components, containers, routes, selectors and sagas - +and their tests - right from the CLI! + +Run `npm run generate` in your terminal and choose one of the parts you want +to generate. They'll automatically be imported in the correct places and have +everything set up correctly. + +> We use [plop] to generate new components, you can find all the logic and +> templates for the generation in `internals/generators`. + +[plop]: https://github.com/amwmedia/plop + +## Instant feedback + +Enjoy the best DX and code your app at the speed of thought! Your saved changes +to the CSS and JS are reflected instantaneously without refreshing the page. +Preserve application state even when you update something in the underlying code! + +## Predictable state management + +We use Redux to manage our applications state. We have also added optional +support for the [Chrome Redux DevTools Extension] – if you have it installed, +you can see, play back and change your action history! + +[chrome redux devtools extension]: https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd + +## Next generation JavaScript + +Use ESNext template strings, object destructuring, arrow functions, JSX syntax +and more, today. This is possible thanks to Babel with the `env`, `stage-0` +and `react` presets! + +## Next generation CSS + +Write composable CSS that's co-located with your components using [`styled-components`] +for complete modularity. Unique generated class names keep the specificity low +while eliminating style clashes. Ship only the styles that are used on the +visible page for the best performance. + +[`styled-components`]: ../css/README.md#styled-components + +## Industry-standard routing + +It's natural to want to add pages (e.g. `/about`) to your application, and +routing makes this possible. Thanks to [react-router] with [connected-react-router], +that's as easy as pie and the url is auto-synced to your application state! + +[react-router]: https://github.com/ReactTraining/react-router +[connected-react-router]: https://github.com/supasate/connected-react-router + +## Static code analysis + +Focus on writing new features without worrying about formatting or code quality. With the right editor setup, your code will automatically be formatted and linted as you work. + +Read more about linting in our [introduction](./introduction.md) and don't forget to setup your by following [our instructions](./editor.md). + +# Optional extras + +_Don't like any of these features? [Click here](remove.md)_ + +## Offline-first + +The next frontier in performant web apps: availability without a network +connection from the instant your users load the app. This is done with a +ServiceWorker and a fallback to AppCache, so this feature even works on older +browsers! + +> All your files are included automatically. No manual intervention needed +> thanks to Webpack's [`offline-plugin`](https://github.com/NekR/offline-plugin) + +### Add To Homescreen + +After repeat visits to your site, users will get a prompt to add your application +to their homescreen. Combined with offline caching, this means your web app can +be used exactly like a native application (without the limitations of an app store). + +The name and icon to be displayed are set in the `manifest.json` generated by +Webpack's `webpack-pwa-manifest` plugin. Configure the name, colors, and icons +in `webpack.prod.babel.js` and try it! + +## Performant Web Font Loading + +If you simply use web fonts in your project, the page will stay blank until +these fonts are downloaded. That means a lot of waiting time in which users +could already read the content. + +[FontFaceObserver](https://github.com/bramstein/fontfaceobserver) adds a class +to the `body` when the fonts have loaded. (see [`app.js`](../../app/app.js#L26-L36) +and [`App/styles.css`](../../app/containers/App/styles.css)) + +### Adding a new font + +1. Either add the `@font-face` declaration to `App/styles.css` or add a `` + tag to the [`index.html`](../../app/index.html). (Don't forget to remove the `` + for Open Sans from the [`index.html`](../../app/index.html)!) + +2. In `App/styles.css`, specify your initial `font-family` in the `body` tag + with only web-save fonts. In the `body.jsFontLoaded` tag, specify your + `font-family` stack with your web font. + +3. In `app.js` add a `Observer` for your font. + +## Image optimization + +Images often represent the majority of bytes downloaded on a web page, so image +optimization can often be a notable performance improvement. Thanks to Webpack's +[`image-loader`](https://github.com/tcoopman/image-webpack-loader), every PNG, JPEG, GIF and SVG images +is optimized. + +See [`image-loader`](https://github.com/tcoopman/image-webpack-loader) to customize optimizations options. diff --git a/docs/general/commands.md b/docs/general/commands.md new file mode 100644 index 0000000..6b234f9 --- /dev/null +++ b/docs/general/commands.md @@ -0,0 +1,149 @@ +# Command Line Commands + +## Initialization + +```Shell +npm run setup +``` + +Initializes a new project with this boilerplate. Deletes the `react-boilerplate` +git history, installs the dependencies and initializes a new repository. + +> Note: This command is self-destructive, once you've run it the init script is +> gone forever. This is for your own safety, so you can't delete your project's +> history irreversibly by accident. + +## Development + +```Shell +npm run start +``` + +Starts the development server running on `http://localhost:3000` + +## Cleaning + +```Shell +npm run clean +``` + +Deletes the example app, replacing it with the smallest amount of boilerplate +code necessary to start writing your app! + +> Note: This command is self-destructive, once you've run it you cannot run it +> again. This is for your own safety, so you can't delete portions of your project +> irreversibly by accident. + +## Generators + +```Shell +npm run generate +``` + +Allows you to auto-generate boilerplate code for common parts of your +application, specifically `component`s, and `container`s. You can +also run `npm run generate ` to skip the first selection. (e.g. `npm run generate container`) + +## Server + +### Development + +```Shell +npm start +``` + +Starts the development server and makes your application accessible at +`localhost:3000`. Changes in the application code will be hot-reloaded. + +### Production + +```Shell +npm run start:production +``` + +- Runs tests (see `npm test`) +- Builds your app (see `npm run build`) +- Starts the production server (see `npm run start:prod`) + +The app is built for optimal performance: assets are +minified and served gzipped. + +### Host and Port + +To change the host and/or port the app is accessible at, pass the `--host` and/or `--port` option to the command +with `--`. E.g. to make the app visible at `my-local-hostname:5000`, run the following: +`npm start -- --host my-local-hostname --port 5000` + +## Building + +```Shell +npm run build +``` + +Preps your app for deployment (does not run tests). Optimizes and minifies all files, piping them to the `build` folder. + +Upload the contents of `build` to your web server to +see your work live! + +## Testing + +See the [testing documentation](../testing/README.md) for detailed information +about our testing setup! + +## Unit testing + +```Shell +npm test +``` + +Tests your application with the unit tests specified in the `**/tests/*.js` files +throughout the application. +All the `test` commands allow an optional `-- [string]` argument to filter +the tests run by Jest. Useful if you need to run a specific test only. + +```Shell +# Run only the Button component tests +npm test -- Button +``` + +### Watching + +```Shell +npm run test:watch +``` + +Watches changes to your application and re-runs tests whenever a file changes. + +### Remote testing + +```Shell +npm run start:tunnel +``` + +Starts the development server and tunnels it with `ngrok`, making the website +available worldwide. Useful for testing on different devices in different locations! + +### Dependency size test + +```Shell +npm run analyze +``` + +This command will generate a `stats.json` file from your production build, which +you can upload to the [webpack analyzer](https://webpack.github.io/analyse/) or [Webpack Visualizer](https://chrisbateman.github.io/webpack-visualizer/). This +analyzer will visualize your dependencies and chunks with detailed statistics +about the bundle size. + +## Linting + +```Shell +npm run lint +``` + +Lints your JavaScript and your CSS. + +```Shell +npm run lint:eslint:fix -- . +``` + +Lints your code and tries to fix any errors it finds. diff --git a/docs/general/components.md b/docs/general/components.md new file mode 100644 index 0000000..b4f2996 --- /dev/null +++ b/docs/general/components.md @@ -0,0 +1,84 @@ +# Extracting components + +One of the most compelling arguments for the self-contained components +architecture is the ability to easily reuse each component in other projects. +Since all the files kept in the same folder, this should be a breeze. + +## When? + +Often when working on a project, you find you've created a component that you +could use in other upcoming projects. You would like to extract that +component to its own git repository and npm package since keeping the version +histories separate makes a lot of sense. + +You're not finished with the component, but would like to continue working on it +in parallel alongside your main project. + +## How? + +Since all the files are kept in the same place, its simply a matter of moving +the folder to its own directory, setting up the `package.json` for your new +package, and including it in your main project. + +### Npm + +Npm has a great feature that allows this kind of parallel development of +packages - `npm link` (read more [here](https://docs.npmjs.com/cli/link)). After +setting up your new package, you can link it into your main package like this: + +1. `cd` into your new package directory +2. Run `npm link` +3. `cd` into your main project directory +4. Run `npm link ` + +### Configuration + +#### Specifying dependencies + +Linking the packages won't save the package as a dependency in your main project +`package.json`, so you'll have to do that manually. + +```json +"dependencies": { + "": "*", +} +``` + +## Gotchas + +As well as this approach works for development, there are some things you need +to watch out for when building and publishing your new package or project. + +### Publishing to npm registry + +In your new package, you will most likely have a build task to transpile from +ES6 into ES5. You probably keep your ES6 code in a `src/` directory and your +transpiled code in a `lib/` directory. + +In your `package.json`, you probably have something like this: + +```json + "main": "lib/index.js" +``` + +This is what you want when you publish to the registry, but during development +you probably want to change this to + +```json + "main": "src/index.js" +``` + +This will make sure that your main project always includes your most recent +code. You've just got to remember to change it back to `lib/` before publishing +to the npm registry. + +You can, of course, go down the `lib/` path, but that requires you to +rebuild your package and transpile it to ES5 whenever you introduce a change, +which can be a pain. + +### Building + +Building the package can be a little bit tricky due to how webpack handles +symlinks. We've found it easiest to remove the symlink and replace it with the +actual files, either by copying the package to `node_modules` or running +`npm install` if you've published your package to the npm registry. diff --git a/docs/general/debugging.md b/docs/general/debugging.md new file mode 100644 index 0000000..686d486 --- /dev/null +++ b/docs/general/debugging.md @@ -0,0 +1,77 @@ +# Debugging + +- [Debugging with Visual Studio Code](#debugging-with-visual-studio-code) +- [Debugging with WebStorm](#debugging-with-webstorm) + - [Troubleshooting](#troubleshooting) + - [Enable ESLint](#enable-eslint) + +## Debugging with Visual Studio Code + +You can super charge your React debugging workflow via VS Code and Chrome. Here are the steps: + +1. Install the [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) extension in VS Code. +2. Add the `Launch Chrome` option to your `launch.json` config: + +```json +{ + "version": "0.2.0", + "configurations": [ + { + "type": "chrome", + "request": "launch", + "name": "Launch Chrome", + "url": "http://localhost:3000", + "webRoot": "${workspaceRoot}/app", + "sourceMapPathOverrides": { + "webpack:///./app/*": "${webRoot}/*", + "webpack:///app/*": "${webRoot}/*" + } + } + ] +} +``` + +3. Start your dev server with `npm run start`. +4. Launch the VS Code Debugger with the `Launch Chrome` configuration. + +You can then set breakpoints directly from inside VS Code, use stepping with the Chrome or VS Code buttons and more. + +Read all about it in the [Debugger for Chrome page](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome). + +**Note**: There's currently a [known problem](https://github.com/react-boilerplate/react-boilerplate/pull/1698) with source maps and VS Code. You can change your Webpack dev config to use `inline-source-map` instead of `eval-source-map` and the issue should be resolved. + +## Debugging with WebStorm + +WebStorm is a powerful IDE, and why not also use it as debugger tool? Here are the steps: + +1. [Install JetBrain Chrome Extension](https://chrome.google.com/webstore/detail/jetbrains-ide-support/hmhgeddbohgjknpmjagkdomcpobmllji) +2. [Setting up the PORT](https://www.jetbrains.com/help/webstorm/2016.1/using-jetbrains-chrome-extension.html) +3. Change WebPack devtool config to `source-map` [(This line)](https://github.com/react-boilerplate/react-boilerplate/blob/56eb5a0ec4aa691169ef427f3a0122fde5a5aa24/internals/webpack/webpack.dev.babel.js#L65) +4. Run web server (`npm run start`) +5. Create Run Configuration (Run > Edit Configurations) +6. Add new `JavaScript Debug` +7. Setting up URL +8. Start Debug (Click the green bug button) +9. Edit Run Configuration Again +10. Mapping Url as below picture + - Map your `root` directory with `webpack://.` (please note the last dot) + - Map your `build` directory with your root path (e.g. `http://localhost:3000`) +11. Hit OK and restart debugging session + +![How to debug using WebStorm](webstorm-debug.png) + +### Troubleshooting + +1. You miss the last `.` (dot) in `webpack://.` +2. The port debugger is listening tool and the JetBrain extension is mismatch. + +### Enable ESLint + +ESLint helps developers on a team follow the same coding format. It's highly recommended to set it up in your IDE to avoid failing the linting step in tests. + +1. Go to WebStorm Preferences +2. Search for `ESLint` +3. Click `Enable` + +![Setting up ESLint](webstorm-eslint.png) + diff --git a/docs/general/deployment.md b/docs/general/deployment.md new file mode 100644 index 0000000..6631975 --- /dev/null +++ b/docs/general/deployment.md @@ -0,0 +1,121 @@ +# Deployment + +## Heroku + +### Easy 3-Step Deployment Process + +_Step 1:_ Create a _Procfile_ with the following line: `web: npm run start:prod`. We do this because Heroku runs `npm run start` by default, so we need this setting to override the default run command. + +_Step 2:_ Install the Node.js buildpack for your Heroku app by running the following command: `heroku buildpacks:set https://github.com/heroku/heroku-buildpack-nodejs#v133 -a [your app name]`. Make sure to replace `#v133` with whatever the latest buildpack is, which you can [find here](https://github.com/heroku/heroku-buildpack-nodejs/releases). + +_Step 3:_ Follow the standard Heroku deploy process: + +1. `git add .` +2. `git commit -m 'Made some epic changes as per usual'` +3. `git push heroku master` + +## AWS S3 + +### Easy 7-Step Deployment Process + +_Step 1:_ Run `npm install` to install dependencies, then `npm run build` to create the `./build` folder. + +_Step 2:_ Navigate to [AWS S3](https://aws.amazon.com/s3) and login (or sign up if you don't have an account). Click on `Services` followed by `S3` in the dropdown. + +_Step 3:_ Click on `Create Bucket` and fill out both your `Bucket Name` and `Region` (for the USA we recommend `US Standard`). Click `Create` to create your bucket. + +_Step 4:_ Open the `Permissions` accordion on the right (under the `Properties` tab) after selecting your new bucket. Click `Add more permissions`, set the `Grantee` to `Everyone` (or whoever you want to be able to access the website), and give them `View Permissions`. Click `Save`. + +_Step 5:_ Click on the `Static Website Hosting` accordion where you should see the URL (or _endpoint_) of your website (ie. example.s3-website-us-east-1.amazonaws.com). Click `Enable website hosting` and fill in both the `Index document` and `Error document` input fields with `index.html`. Click `Save`. + +_Step 6:_ Click on your new S3 bucket on the left to open the bucket. Click `Upload` and select all the files within your `./build` folder. Click `Start Upload`. Once the files are done, select all of the files, right-click on the selected files (or click on the `Actions` button) and select `Make Public`. + +_Step 7:_ Click on the `Properties` tab, open `Static Website Hosting`, and click on the _Endpoint_ link. The app should be running on that URL. + +## Deploying in a subfolder of an existing server + +Suppose you want users to access the app on `https:///web-app` + +_Step 1:_ Configure webpack to inject necessary environment variables into the app + +- Changes below are made to `internals/webpack/webpack.base.babel.js` file. + +```diff ++ const BUILD_FOLDER_PATH = process.env.BUILD_FOLDER_PATH || 'build'; ++ const PUBLIC_PATH = process.env.PUBLIC_PATH || '/'; +``` + +```diff +- path: path.resolve(process.cwd(), 'build'), +- publicPath: '/', ++ path: path.resolve(process.cwd(), BUILD_FOLDER_PATH), ++ publicPath: PUBLIC_PATH, +``` + +```diff +# inside EnvironmentPlugin ++ PUBLIC_PATH: '/', +``` + +_Step 2:_ add `basename` to the history + +- Changes below are made to `app/utils/history.js` file. + +```diff +- const history = createHistory(); ++ const basename = process.env.PUBLIC_PATH; ++ const history = createHistory({ basename }); +``` + +_Step 3:_ Run `PUBLIC_PATH='/web-app/' BUILD_FOLDER_PATH='build/web-app' npm run build`, to save production build inside `./build/web-app` folder. + +_Step 4:_ Upload/Place the created `web-app` folder in your server's web-root folder + +_Endpoint_ The app should be accessible on `https:///web-app`. + +_NOTE_ that this has been tested on both APACHE and NGINX servers. + +## AWS Elastic Beanstalk + +Please refer to to issue [#2566](https://github.com/react-boilerplate/react-boilerplate/issues/2566) for more explanation. + +### Pre-requisites + +1. Create an account on [AWS console](https://console.aws.amazon.com/) +2. Install EB CLI ([AWS documentation](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install.html?icmpid=docs_elasticbeanstalk_console#eb-cli3-install.cli-only)) +3. Create your [AWS EB profile](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-configuration.html#eb-cli3-profile). + In case you are using a continous deployment tool, you can create another user + for your CD tool as well. +4. Create your Elastic Beanstalk [application](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/applications.html) and [environment](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features.managing.html) (either via CLI or web console) +5. [Configure your EB CLI](https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-configuration.html). You should have a `.elasticbeanstalk/config.yml` if properly configured + +### Configuration + +_Step 1:_ Add AWS EB start scripts in _package.json_: `"aws-eb:prod": "npm run build && npm run start:prod"` + +_Step 2:_ Create a `.ebextensions/aws.config` file: + +```yaml +# Check https://github.com/react-boilerplate/react-boilerplate/issues/2566 for details +option_settings: + aws:elasticbeanstalk:container:nodejs: + NodeCommand: 'npm run aws-eb:prod' + aws:elasticbeanstalk:application:environment: + NPM_USE_PRODUCTION: false +``` + +In the likely case of multiple environment, remove the `NodeCommand` entry and +manually configure it per environment in the web console: _Configuration > Software > Node command_. + +_Step 3:_ Create a `.npmrc` file: + +``` +# Check https://github.com/react-boilerplate/react-boilerplate/issues/2566 for details +unsafe-perm=true +``` + +_Step 4:_ commit your changes and deploy via EB CLI: + +```sh +eb deploy {target environment name} +``` diff --git a/docs/general/editor.md b/docs/general/editor.md new file mode 100644 index 0000000..792749a --- /dev/null +++ b/docs/general/editor.md @@ -0,0 +1,40 @@ +# Setting Up Your Editor + +You can edit React Boilerplate using any editor or IDE, but there are a few extra steps that you can take to make sure your coding experience is as good as it can be. + +## VS Code + +To get the best editing experience with [VS Code](https://code.visualstudio.com), create a [`jsconfig.json`](https://code.visualstudio.com/Docs/languages/javascript#_javascript-projects-jsconfigjson) file at the root of your project: + +```json +{ + "compilerOptions": { + "baseUrl": "app", + "module": "commonjs", + "target": "es2016", + "jsx": "react" + }, + "exclude": ["node_modules", "**/node_modules/*"] +} +``` + +This `jsconfig.json` file tells VS Code to treat all JS files as part of the same project, improving IntelliSense, code navigation, and refactoring. You can configure project wide settings in using the `jsconfig.json`, such as only allowing functions from the ES5 standard library, or even enable [more advanced type checking for JS files](https://code.visualstudio.com/docs/languages/javascript#_type-checking) + +# ESLint + Prettier integration + +You can also get VSCode to understand your project's static code analysis setup. If you do this: + +- You'll see any warnings or errors directly within VSCode +- VSCode can also automatically fix or format your code for you + +To make this happen, install both the ESLint and Prettier extensions for VSCode and add the following to either your User or Workspace Settings: + +```json +{ + "editor.formatOnSave": true, + "prettier.eslintIntegration": true, + "eslint.run": "onSave" +} +``` + +Here's also a detailed video on the topic: [How to Setup VS Code + Prettier + ESLint](https://www.youtube.com/watch?v=YIvjKId9m2c) diff --git a/docs/general/faq.md b/docs/general/faq.md new file mode 100644 index 0000000..b2ade57 --- /dev/null +++ b/docs/general/faq.md @@ -0,0 +1,260 @@ +# Frequently Asked Questions + +- [Where are Babel, Prettier and ESLint configured?](#where-are-babel-prettier-and-eslint-configured) +- [Where are the files coming from when I run `npm start`?](#where-are-the-files-coming-from-when-i-run-npm-start) +- [How do I fix `Error: listen EADDRINUSE 127.0.0.1:3000`?](#how-do-i-fix-error-listen-eaddrinuse-1270013000) + - [OS X / Linux:](#os-x--linux) + - [Windows](#windows) +- [Issue with local caching when running in production mode (F5 / ctrl+F5 / cmd+r weird behavior)](#issue-with-local-caching-when-running-in-production-mode-f5--ctrlf5--cmdr-weird-behavior) + - [Quick fix on your local browser:](#quick-fix-on-your-local-browser) + - [Full in-depth explanation](#full-in-depth-explanation) +- [Local webfonts not working for development](#local-webfonts-not-working-for-development) +- [Non-route containers](#non-route-containers) + - [Where do I put the reducer?](#where-do-i-put-the-reducer) +- [Use CI with bitbucket pipelines](#use-ci-with-bitbucket-pipelines) +- [How to keep my project up-to-date with `react-boilerplate`?](#how-to-keep-my-project-up-to-date-with-react-boilerplate) +- [How to turn off Webpack performance warnings after production build?](#how-to-turn-off-webpack-performance-warnings-after-production-build) +- [Styles getting overridden?](#styles-getting-overridden) +- [Have another question?](#have-another-question) + +## Where are Babel, Prettier and ESLint configured? + +ESLint, Babel and Prettier all have their own config files in the root of the project. Same for Jest and stylelint. + +## Where are the files coming from when I run `npm start`? + +In development Webpack compiles your application runs it in-memory. Only when +you run `npm run build` will it write to disk and preserve your bundled +application across computer restarts. + +## How do I fix `Error: listen EADDRINUSE 127.0.0.1:3000`? + +This simply means that there's another process already listening on port 3000. +The fix is to kill the process and rerun `npm start`. + +### OS X / Linux: + +1. Find the process id (PID): + + ```Shell + ps aux | grep node + ``` + + > This will return the PID as the value following your username: + > + > ```Shell + > janedoe 29811 49.1 2.1 3394936 356956 s004 S+ 4:45pm 2:40.07 node server + > ``` + > + > Note: If nothing is listed, you can try `lsof -i tcp:3000` + +2. Then run + ```Shell + kill -9 YOUR_PID + ``` + > e.g. given the output from the example above, `YOUR_PID` is `29811`, hence + > that would mean you would run `kill -9 29811` + +### Windows + +1. Find the process id (PID): + + ```Shell + netstat -a -o -n + ``` + + > This will return a list of running processes and the ports they're + > listening on: + > + > ``` + > Proto Local Address Foreign Address State PID + > TCP 0.0.0.0:25 0.0.0.0:0 Listening 4196 + > ... + > TCP 0.0.0.0:3000 0.0.0.0:0 Listening 28344 + > ``` + + ``` + + ``` + +1. Then run + ```Shell + taskkill /F /PID YOUR_PID + ``` + > e.g. given the output from the example above, `YOUR_PID` is `28344`, hence + > that would mean you would run `taskkill /F /PID 28344` + +## Issue with local caching when running in production mode (F5 / ctrl+F5 / cmd+r weird behavior) + +Your production site isn't working? You update the code and nothing changes? It drives you insane? + +#### Quick fix on your local browser: + +To fix it on your local browser, just do the following. (Suited when you're testing the production mode locally) + +`Chrome dev tools > Application > Clear Storage > Clear site data` _(Chrome)_ + +#### Full in-depth explanation + +Read more at https://github.com/NekR/offline-plugin/blob/master/docs/updates.md + +## Local webfonts not working for development + +In development mode CSS sourcemaps require that styling is loaded by blob://, +resulting in browsers resolving font files relative to the main document. + +A way to use local webfonts in development mode is to add an absolute +output.publicPath in webpack.dev.babel.js, with protocol. + +```javascript +// webpack.dev.babel.js + +output: { + publicPath: 'http://127.0.0.1:3000/', + /* … */ +}, +``` + +## Non-route containers + +> Note: Container will always be nested somewhere below a route. Even if there's dozens of components +> in between, somewhere up the tree will be route. (maybe only "/", but still a route) + +### Where do I put the reducer? + +While you can include the reducer statically in `reducers.js`, we don't recommend this as you lose +the benefits of code splitting. Instead, add it as a _composed reducer_. This means that you +pass actions onward to a second reducer from a lower-level route reducer like so: + +```JS +// Main route reducer + +function myReducerOfRoute(state, action) { + switch (action.type) { + case SOME_OTHER_ACTION: + return someOtherReducer(state, action); + } +} +``` + +That way, you still get the code splitting at route level, but avoid having a static `combineReducers` +call that includes all of them by default. + +_See [this and the following lesson](https://egghead.io/lessons/javascript-redux-reducer-composition-with-arrays?course=getting-started-with-redux) of the egghead.io Redux course for more information about reducer composition!_ + +## Use CI with bitbucket pipelines + +Your project is on bitbucket? Take advantage of the pipelines feature (Continuous Integration) by creating a 'bitbucket-pipelines.yml' file at the root of the project and use the following code to automatically test your app at each commit: + +```YAML +image: gwhansscheuren/bitbucket-pipelines-node-chrome-firefox + +pipelines: + default: + - step: + script: + - node --version + - npm --version + - npm install + - npm test +``` + +## How to keep my project up-to-date with `react-boilerplate`? + +While it's possible to keep your project up-to-date or "in sync" with `react-boilerplate`, it's usually +very difficult and is therefore **_at your own risk_** and not recommended. You should not need to do it either, as +every version you use will be amazing! There is a long term goal to make this much easier but no ETA at the moment. + +## How to turn off Webpack performance warnings after production build? + +Webpack recommends having those performance hints turned off in development but to keep them on in production. If you still want to disable them, add the next lines to the config in `webpack.prod.babel.js`: + +```js +performance: { + hints: false; +} +``` + +You can find more information about the `performance` option (how to change maximum allowed size of a generated file, how to exclude some files from being checked and so on) in the [Webpack documentation](https://webpack.js.org/configuration/performance/). + +## Styles getting overridden? + +There is a strong chance that your styles are getting imported in the wrong order. Confused? +Let me try and explain with an example! + +```javascript +// MyStyledComponent.js +const MyStyledComponent = styled.div` + background-color: green; +`; +``` + +```css +/* styles.css */ +.alert { + background-color: red; +} +``` + +```javascript +// ContrivedExample.js +import MyStyledComponent from './MyStyledComponent'; +import './styles.css'; + +const ContrivedExample = props => ( + {props.children} +); +``` + +With the magic of [webpack](https://webpack.js.org/), both `MyStyledComponent.js` and `styles.css` +will each generate a stylesheet that will be injected at the end of `` and applied to `` +via the [`class` attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes#attr-class). + +So, will `` have a green background or a red background? + +Applying the rules of [specificity](https://developer.mozilla.org/en/docs/Web/CSS/Specificity), you +may think red as `styles.css` was imported last. Unfortunately, at the time of writing +an open issue ["CSS resolving order"](https://github.com/webpack/webpack/issues/215) +means you cannot control the order in which the stylesheets are injected. So, with this contrived +example, the background could be either green or red. + +To resolve the issue, you can either: + +**1) Increase the specificity of the CSS you want to win** + +```css +/* styles.css (imported css to win) */ +.alert.alert { + background-color: red; +} +``` + +```javascript +// MyStyledComponent.js (styled-component css to win) +const MyStyledComponent = styled.div` + && { + background-color: green; + } +`; +``` + +**2) Import the CSS in the `` of your `index.html` manually** + +This is a good choice if you are having issues with third-party styles + +```javascript +// Import bootstrap style (e.g. move this into the of index.html) +import 'bootstrap/dist/css/bootstrap.min.css'; +``` + +**3) Change the position of `` in the rendering of ``** + +You can do that inside `containers/App/index.js`. + +More information is available in the [official documentation](https://github.com/styled-components/styled-components/blob/master/docs/existing-css.md). + +## Have another question? + +Submit an [issue](https://github.com/react-boilerplate/react-boilerplate/issues), +hop onto the [Spectrum chat](https://spectrum.chat/react-boilerplate) +or contact Max direct on [twitter](https://twitter.com/mxstbr)! diff --git a/docs/general/files.md b/docs/general/files.md new file mode 100644 index 0000000..ce9e0d4 --- /dev/null +++ b/docs/general/files.md @@ -0,0 +1,34 @@ +# Configuration: A Glossary + +A guide to the configuration files for this project: where they live and what +they do. + +## The root folder + +- `.editorconfig`: Sets the default configuration for certain files across editors. (e.g. indentation) + +- `.gitattributes`: Normalizes how `git`, the version control system this boilerplate uses, handles certain files. + +- `.gitignore`: Tells `git` to ignore certain files and folders which don't need to be version controlled, like the build folder. + +- `.travis.yml` and `appveyor.yml`: Continuous Integration configuration
+ This boilerplate uses [Travis CI](https://travis-ci.com) for Linux environments + and [AppVeyor](https://www.appveyor.com/) for Windows platforms, but feel free + to swap either out for your own choice of CI. + +- `package.json`: Our `npm` configuration file has three functions: + + 1. It's where Babel and ESLint are configured + 1. It's the API for the project: a consistent interface for all its controls + 1. It lists the project's package dependencies + + Baking the config in is a slightly unusual set-up, but it allows us to keep + the project root as uncluttered and grokkable-at-a-glance as possible. + +## The `./internals` folder + +This is where the bulk of the tooling configuration lives, broken out into +recognisable units of work. + +Feel free to change anything you like but don't be afraid to [ask upfront](https://spectrum.chat/react-boilerplate) +whether you should: build systems are easy to break! diff --git a/docs/general/gotchas.md b/docs/general/gotchas.md new file mode 100644 index 0000000..c36912a --- /dev/null +++ b/docs/general/gotchas.md @@ -0,0 +1,114 @@ +# Gotchas + +These are some things to be aware of when using this boilerplate. + +- [Special images in HTML files](#special-images-in-html-files) +- [Load reducers optimistically](#load-reducers-optimistically) +- [Exclude modules from Babel processing](#exclude-modules-from-babel-processing) +- [Running tests in `watch` mode](#running-tests-in-watch-mode) +- [When in doubt, re-install!](#when-in-doubt-re-install) +- [Cleaning up Jest cache](#cleaning-up-jest-cache) +- [Using short_name in Web App manifest](#using-short_name-in-web-app-manifest) + +## Special images in HTML files + +If you specify your images in the `.html` files using the `` tag, everything +will work fine. The problem comes up if you try to include images using anything +except that tag, like meta tags: + +```HTML + +``` + +The webpack `html-loader` does not recognise this as an image file and will not +transfer the image to the build folder. To get webpack to transfer them, you +have to import them with the file loader in your JavaScript somewhere, e.g.: + +```JavaScript +import 'file?name=[name].[ext]!../img/yourimg.png'; +``` + +Then webpack will correctly transfer the image to the build folder. + +## Load reducers optimistically + +If you have containers that should be available throughout the app, like a `NavigationBar` (they aren't route specific), you need to add their respective reducers to the root reducer with the help of `combineReducers`. + +```js +// In app/reducers.js + +... +import { combineReducers } from 'redux'; +... + +import navigationBarReducer from 'containers/NavigationBar/reducer'; + +export default function createReducer(injectedReducers = {}) { + const rootReducer = combineReducers({ + global: globalReducer, + language: languageProviderReducer, + router: connectRouter(history), + navigationBar: navigationBarReducer, + ...injectedReducers, + }); + + return rootReducer; +} +``` + +## Exclude modules from Babel processing + +You need to exclude packages which are not intended to be processed by babel. For e.g. Server packages such as 'express' or a CSS file. Just add the package name to `exclude` array in `internals/config.js` and you're all set! + +```js +// in internals/config.js + +exclude: [ + 'chalk', + 'compression', + 'cross-env', + 'express', + 'ip', + 'minimist', + 'sanitize.css', + 'your-unwanted-package', <- add your-unwanted-package + ... +] +``` + +## Running tests in `watch` mode + +If you are unable to run tests in watch mode, you may have to install `watchman` for this to work. If you're using a Mac, simply run `brew install watchman` + +You can also install `watchman` from source. Please visit their [official guide](https://facebook.github.io/watchman/docs/install.html) for more information. + +## When in doubt, re-install! + +If you're facing any inexplicable problems while installing dependencies, building your project or running tests, try reinstalling dependencies. It works for most cases. Run the following commands in the exact order given: + +Remove node_modules + +- `rm -rf node_modules` + +Clear cache + +- `npm cache clean` + +Re-install dependencies + +- `npm install` + +Build project + +- `npm run build` + +## Cleaning up Jest cache + +By default, Jest caches transformed modules, which may lead to faulty coverage reports. To prevent this, you'll have to clear the cache by running `npm run test -- --no-cache` as pointed out in [Jest docs](https://facebook.github.io/jest/docs/cli.html#cache) + +## Using short_name in Web App manifest + +When there's insufficient space to display an app's full name it is truncated. +This happens with app launcher and new tab in Chrome for Android. +The `short_name` field allows a _12 character or less abbreviation_. +It also addresses any problems in testing the PWA in Lighthouse. diff --git a/docs/general/introduction.md b/docs/general/introduction.md new file mode 100644 index 0000000..1dc2919 --- /dev/null +++ b/docs/general/introduction.md @@ -0,0 +1,219 @@ +# The Hitchhiker's Guide to `react-boilerplate` + +The [`README.md`](https://github.com/react-boilerplate/react-boilerplate#features) gives you adequate information on how to clone boilerplate files, install dependencies and launch the example app. + +Once you've done that, this document is intended to give you a taste of how `react-boilerplate` works. It still assumes basic knowledge of React, Redux and `react-router`. **If you're completely new to React, please refer to https://github.com/petehunt/react-howto instead!** + +This is a production-ready boilerplate, and as such optimized for browsers, not for beginners. It includes tools to help you manage performance, asynchrony, styling, everything you need to build a _real_ application. Before you get your hands dirty with the source code, we'd like you to go through a checklist that will help you determine whether or not you're ready to use this boilerplate. It's not because we're _holier-than-thou_, but rather because we genuinely want to save you the frustration. + +Opening an issue is the fastest way to draw the attention of the team, but please make it a point to read the [docs](https://github.com/react-boilerplate/react-boilerplate/tree/master/docs) and [contribution instructions](https://github.com/react-boilerplate/react-boilerplate/blob/master/.github/CONTRIBUTING.md) before you do. The issues section is specifically used for pointing out defects and suggesting enhancements. If you have a question about one of the tools please refer to StackOverflow instead. + +## Tech Stack + +Here's a curated list of packages that you should be at least familiar with before starting your awesome project. However, the best way to see a complete list of the dependencies is to check [package.json](https://github.com/react-boilerplate/react-boilerplate/blob/master/package.json). + +### Core + +- [ ] [React](https://facebook.github.io/react/) +- [ ] [React Router](https://github.com/ReactTraining/react-router) +- [ ] [Redux](http://redux.js.org/) +- [ ] [Redux Saga](https://redux-saga.github.io/redux-saga/) +- [ ] [Reselect](https://github.com/reactjs/reselect) +- [ ] [Immer](https://github.com/mweststrate/immer) +- [ ] [Styled Components](https://github.com/styled-components/styled-components) + +### Unit Testing + +- [ ] [Jest](http://facebook.github.io/jest/) +- [ ] [react-testing-library](https://github.com/kentcdodds/react-testing-library) + +### Linting + +- [ ] [ESLint](http://eslint.org/) +- [ ] [Prettier](https://prettier.io/) +- [ ] [stylelint](https://stylelint.io/) + +Note that while `react-boilerplate` includes a lot of features, many of them are optional and you can find instructions in the docs on how to remove... + +- [`redux-saga` or `reselect`](https://github.com/react-boilerplate/react-boilerplate/blob/master/docs/js/remove.md) +- [offline-first, add to homescreen, performant web font loading and image optimisation](https://github.com/react-boilerplate/react-boilerplate/blob/master/docs/general/remove.md) +- [`sanitize.css`](https://github.com/react-boilerplate/react-boilerplate/blob/master/docs/css/remove.md) +- [i18n (i.e. `react-intl`)](https://github.com/react-boilerplate/react-boilerplate/blob/0f88f55ed905f8432c3dd7b452d713df5fb76d8e/docs/js/i18n.md#removing-i18n-and-react-intl) + +## Project Structure + +Let's start with understanding why we have chosen our particular structure. It has been an [evolving discussion](https://github.com/react-boilerplate/react-boilerplate/issues/27), and if you have an afternoon or two we recommend you read the full thread. + +In any case, here's the TL;DR: + +- You will write your app in the `app` folder. This is the folder you will spend most, if not all, of your time in. +- Configuration, generators and templates are in the `internals` folder. +- The `server` folder contains development and production server configuration files. + +### `app/` + +We use the [container/component architecture](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.4rmjqneiw). `containers/` contains React components which are connected to the redux store. `components/` contains dumb React components which depend on containers for data. **Container components care about how things work, while components care about how things look.** + +We've found that for many applications treating single pages (e.g. the LoginPage, the HomePage, etc.) as containers and their small parts (e.g. the Login form, the Navigation bar) as components works well, but there are no rigid rules. **Bend the architecture to the needs of your app, nothing is set in stone!** + +### `internals/` + +You can call this area the "engine" of your app. Your source code cannot be executed as-is in the web browser. It needs to pass through webpack to get converted into a version of Javascript that web browsers understand. While it's certainly helpful to understand what's happening here, for real world usage, you won't have to mess around with this folder much. + +- `internals/webpack`: You'll most probably use ECMAScript 6 or ECMAScript 7 to write the source code of your app. webpack takes care of making it compatible with a majority of browsers. + +> ([ECMAScript](http://stackoverflow.com/a/33748400/5241520) is the standard for JavaScript. Most people are still using browsers which understand ECMAScript 5. So your code must be [transpiled](https://scotch.io/tutorials/javascript-transpilers-what-they-are-why-we-need-them) into browser-understandable code. To apply the transpiler to your source code, you will use webpack. Feeling the jitters already? [Don't worry](https://hackernoon.com/how-it-feels-to-learn-javascript-in-2016-d3a717dd577f#.d2uasw2n6). Take a tea-break and then read on.) + +- `internals/generators`: This folder has the code to scaffold out new components, containers and routes. Read [more about scaffolding](https://github.com/react-boilerplate/react-boilerplate/tree/master/docs/general#quick-scaffolding) in the docs. + +- `internals/mocks`: This folder contains mocks which Jest uses when testing your app, e.g. for images. + +The other folders are mostly for the maintainers and/or the setup, and you should absolutely never need to touch them so we are going skip them for the sake of brevity. + +### `server/` + +As the name suggests, this folder contains development and production server configuration. + +## Basic Building Blocks + +These days when musicians produce music, they record different parts of the song separately. So vocals, drums, guitar, bass may be played in separate sessions and when they're satisfied with their work, the sessions are combined into a beautiful song. In a similar fashion, let's understand the role of different technologies and in the end, we'll see how everything converges into a single application. + +You can launch the example app by running `npm start`. To fully understand its inner workings, you'll have to understand multiple technologies and how they interact. From this point, we're going into an overdrive of implementation details. We'll simplify the technical jargon as much as we can. Please bear with us here. + +### How does the application boot up? + +Like any other webpage your app starts with the [`app/index.html`](https://github.com/react-boilerplate/react-boilerplate/blob/master/app/index.html) file. React will render your application into `div#app` . + +But how do we include all of your react components into a single HTML file? That's where webpack comes into the picture. webpack will literally pack your application into small javascript files. These files will be injected into the `index.html` as ` + - - Devilbox + devilbox diff --git a/src/app/index.tsx b/src/app/index.tsx index 5fd2c66..6d1b0d8 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -1,8 +1,18 @@ import React from 'react'; import { Helmet } from 'react-helmet-async'; import { Switch, Route, BrowserRouter } from 'react-router-dom'; -import { Container, CssBaseline } from '@material-ui/core'; +import { + Container, + CssBaseline, + BottomNavigation, + BottomNavigationAction, +} from '@material-ui/core'; import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; +import { + BugReport as BugReportIcon, + SupervisedUserCircle as SupervisedUserCircleIcon, +} from '@material-ui/icons'; +import { createStyles, makeStyles } from '@material-ui/core/styles'; import { GlobalStyle } from 'styles/global-styles'; @@ -18,29 +28,69 @@ const darkTheme = createMuiTheme({ }, }); -const App = () => ( - - - - - - - - -
- - - - - - - - - - - - - +const useStyles = makeStyles(() => + createStyles({ + stickToBottom: { + width: '100%', + position: 'fixed', + bottom: 0, + }, + customBottomNavigationAction: { + minWidth: 80, + display: 'flex', + alignItems: 'center', + }, + }), ); +const App = () => { + const classes = useStyles(); + + console.log((window as any).pageLoadStart); + + return ( + + + + + + + + +
+ + + + + + + + + + + +
+ {window && (window as any).pageLoadStart + ? `${new Intl.NumberFormat('en-US', { + style: 'decimal', + maximumFractionDigits: 2, + }).format( + (new Date().getTime() - (window as any).pageLoadStart) / 1000, + )} s` + : 0} +
+ + } + /> + } /> +
+ + + + + ); +}; + export default App; From 5b5f6e3b3e28fa4abf6aa8cc488e1c99c95d6c75 Mon Sep 17 00:00:00 2001 From: Tobias Winkler Date: Tue, 30 Jun 2020 01:36:20 +0200 Subject: [PATCH 19/70] moved footer into own folder Signed-off-by: Tobias Winkler --- src/app/components/Footer/index.tsx | 49 +++++++++++++++ src/app/index.tsx | 93 +++++++---------------------- 2 files changed, 72 insertions(+), 70 deletions(-) create mode 100644 src/app/components/Footer/index.tsx diff --git a/src/app/components/Footer/index.tsx b/src/app/components/Footer/index.tsx new file mode 100644 index 0000000..1824bce --- /dev/null +++ b/src/app/components/Footer/index.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { BottomNavigation, BottomNavigationAction } from '@material-ui/core'; +import { + BugReport as BugReportIcon, + SupervisedUserCircle as SupervisedUserCircleIcon, +} from '@material-ui/icons'; +import { createStyles, makeStyles } from '@material-ui/core/styles'; + +const useStyles = makeStyles(() => + createStyles({ + stickToBottom: { + width: '100%', + position: 'fixed', + bottom: 0, + }, + customBottomNavigationAction: { + minWidth: 80, + display: 'flex', + alignItems: 'center', + }, + }), +); + +const Footer = () => { + const classes = useStyles(); + + return ( + +
+ {window && (window as any).pageLoadStart + ? `${new Intl.NumberFormat('en-US', { + style: 'decimal', + maximumFractionDigits: 2, + }).format( + (new Date().getTime() - (window as any).pageLoadStart) / 1000, + )} s` + : 0} +
+ + } + /> + } /> +
+ ); +}; + +export default Footer; diff --git a/src/app/index.tsx b/src/app/index.tsx index 6d1b0d8..24e8d28 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -1,18 +1,8 @@ import React from 'react'; import { Helmet } from 'react-helmet-async'; import { Switch, Route, BrowserRouter } from 'react-router-dom'; -import { - Container, - CssBaseline, - BottomNavigation, - BottomNavigationAction, -} from '@material-ui/core'; +import { Container, CssBaseline } from '@material-ui/core'; import { createMuiTheme, ThemeProvider } from '@material-ui/core/styles'; -import { - BugReport as BugReportIcon, - SupervisedUserCircle as SupervisedUserCircleIcon, -} from '@material-ui/icons'; -import { createStyles, makeStyles } from '@material-ui/core/styles'; import { GlobalStyle } from 'styles/global-styles'; @@ -21,6 +11,7 @@ import MailsPage from './pages/Mails/Loadable'; import VhostsPage from './pages/Vhosts/Loadable'; import NotFoundPage from './pages/NotFound/Loadable'; import Header from './components/Header'; +import Footer from './components/Footer'; const darkTheme = createMuiTheme({ palette: { @@ -28,69 +19,31 @@ const darkTheme = createMuiTheme({ }, }); -const useStyles = makeStyles(() => - createStyles({ - stickToBottom: { - width: '100%', - position: 'fixed', - bottom: 0, - }, - customBottomNavigationAction: { - minWidth: 80, - display: 'flex', - alignItems: 'center', - }, - }), -); - -const App = () => { - const classes = useStyles(); - - console.log((window as any).pageLoadStart); +const App = () => ( + + + + - return ( - - - - + + - - +
-
+ + + + + + + + - - - - - - - - +