From 1867a5b48fcd3b8d54ddd3a07cddf5ececc36c91 Mon Sep 17 00:00:00 2001 From: Derek Pollard Date: Tue, 5 May 2020 15:42:52 -0400 Subject: [PATCH 01/18] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20fix=20ty?= =?UTF-8?q?po=20in=20toolkit.tsx=20comment=20(#18)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/@reduxjs/toolkit.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/@reduxjs/toolkit.tsx b/src/utils/@reduxjs/toolkit.tsx index b3cce48..9b72197 100644 --- a/src/utils/@reduxjs/toolkit.tsx +++ b/src/utils/@reduxjs/toolkit.tsx @@ -5,7 +5,7 @@ import { CreateSliceOptions, } from '@reduxjs/toolkit'; -/* Wrap createClice with stricter Name options */ +/* Wrap createSlice with stricter Name options */ /* istanbul ignore next */ export const createSlice = < From fb9860defd9704d2941a2ef7bdb9c13ed462786b Mon Sep 17 00:00:00 2001 From: Abdallah Hemedah Date: Sat, 9 May 2020 18:37:13 +0200 Subject: [PATCH 02/18] =?UTF-8?q?docs:=20=F0=9F=93=9Aadd=20netlify=20deplo?= =?UTF-8?q?yment=20(#23)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/deployment/netlify.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/deployment/netlify.md b/docs/deployment/netlify.md index 3b74da6..d7cbf33 100644 --- a/docs/deployment/netlify.md +++ b/docs/deployment/netlify.md @@ -1,3 +1,39 @@ # Deploy to Netlify -This docs is still awaiting help 😢If you want to help with this documenation please contact to us +### Easy 5-Step Deployment Process + +_Step 1:_ Create a `netlifty.toml` file in the root directory of your project and copy this code below. Edit these settings if you did not follow the boilerplate structure. More settings available here (https://docs.netlify.com/configure-builds/file-based-configuration/#sample-file) + +``` +[build] + # Directory to change to before starting a build. + # This is where we will look for package.json/.nvmrc/etc. + base = "/" + + # Directory (relative to root of your repo) that contains the deploy-ready + # HTML files and assets generated by the build. If a base directory has + # been specified, include it in the publish directory path. + publish = "./build" + + # Default build command. + command = "npm run build" + +# The following redirect is intended for use with most SPAs that handle routing internally. +[[redirects]] + from = "/*" + to = "/index.html" + status = 200 +``` + +_Step 2:_ Commit your code and push your latest updates to a GitHub repository. + +_Step 3:_ Register or Login in at Netlify (https://app.netlify.com/). + +_Step 4:_ In your account | team page click `New site from git` then chose your repository. + +_Step 5:_ Click deploy. + + +> Note: No need to change any setting in the last step as `netlify.toml` overwrites these settings. + +Now your code will be deployed automatically to netlify on every push to the default branch of your repository.🥳🥳 From a4a4f5076abc31d9cad612c0c4daab7d37b753b4 Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Mon, 11 May 2020 20:04:30 +0300 Subject: [PATCH 03/18] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20fix=20ty?= =?UTF-8?q?po?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #25 --- internals/startingTemplate/src/locales/i18n.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internals/startingTemplate/src/locales/i18n.ts b/internals/startingTemplate/src/locales/i18n.ts index 6bea839..045c25e 100644 --- a/internals/startingTemplate/src/locales/i18n.ts +++ b/internals/startingTemplate/src/locales/i18n.ts @@ -13,7 +13,7 @@ const translationsJson = { }; export type TranslationResource = typeof en; -export type LanguageKeys = keyof TranslationResource; +export type LanguageKey = keyof TranslationResource; export const translations: ConvertedToFunctionsType = {} as any; From 4ed9ed555e6d3c5363819af3f5eebf7800ec6046 Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sat, 16 May 2020 13:04:29 +0300 Subject: [PATCH 04/18] =?UTF-8?q?chore:=20=F0=9F=94=A7=20added=20script=20?= =?UTF-8?q?for=20creating=20changelog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .versionrc.js | 2 +- internals/scripts/create-changelog.script.ts | 21 ++++++++++++++++++++ package.json | 1 + 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 internals/scripts/create-changelog.script.ts diff --git a/.versionrc.js b/.versionrc.js index c8552e7..bc83f86 100644 --- a/.versionrc.js +++ b/.versionrc.js @@ -29,6 +29,6 @@ module.exports = { { type: 'style', section: internalSection, hidden: false }, ], skip: { - commit: true, + changelog: true, }, }; diff --git a/internals/scripts/create-changelog.script.ts b/internals/scripts/create-changelog.script.ts new file mode 100644 index 0000000..f8e7fac --- /dev/null +++ b/internals/scripts/create-changelog.script.ts @@ -0,0 +1,21 @@ +import shell from 'shelljs'; + +interface Options {} + +export function createChangeLog(opts: Options = {}) { + const changes1 = shell.exec(`git diff package.json`, { silent: true }); + const changes2 = shell.exec(`git diff package-lock.json`, { silent: true }); + if (changes1.stdout.length > 0 || changes2.stdout.length > 0) { + console.error('Error: Unstaged files'); + process.exit(1); + } + shell.exec(`npx standard-version --skip.commit --skip.tag`, { + silent: false, + }); + + // Revert the bumbped version + shell.exec(`git checkout -- package-lock.json`, { silent: true }); + shell.exec(`git checkout -- package.json`, { silent: true }); +} + +createChangeLog(); diff --git a/package.json b/package.json index af42f5d..4c080ce 100755 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "create:cra-app": "rm -rf generated-cra-app && npm run create:npm-package && npx create-react-app generated-cra-app --template file:.cra-template-rb && rm -rf .cra-template-rb", "// ---PUBLISHING---": "", "publish:github": "cross-env PUBLIC_URL='/react-boilerplate-cra-template' npm run build && gh-pages -d build", + "changelog": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/create-changelog.script.ts", "release": "standard-version", "publish:npm": "npm run create:npm-package && npm publish .cra-template-rb" }, From 5f5e4133b85f5a7c6bbbbae24fd0c6361ad9e151 Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sat, 16 May 2020 13:22:09 +0300 Subject: [PATCH 05/18] =?UTF-8?q?docs:=20=F0=9F=93=9A=EF=B8=8F=20added=20e?= =?UTF-8?q?xample=20repo=20to=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index c49dff0..2d92944 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,14 @@ with a focus on Tests Status + + Release Status + Coverage - - +
@@ -44,15 +45,19 @@ The official [Create React App](https://github.com/facebook/create-react-app) te Start your `create-react-app` projects in seconds with the best, industry-standard tools and practices made ready for you. -**📝 Documentation:** [Gitbook](https://cansahin.gitbook.io/react-boilerplate-cra-template/) +**📚Documentation:** [Gitbook](https://cansahin.gitbook.io/react-boilerplate-cra-template/) + +**🎨Explore the Example Application:** [Example Application](https://react-boilerplate.github.io/react-boilerplate-cra-template/) + +**💡Examples & Tutorials of commonly needed **`'How to'`**'s:** [Collection of examples & tutorials](https://github.com/react-boilerplate/cra-template-examples) + +> Feel free to contribute with your `how to do this and that` examples and guides. **📦 Package:** [npm](https://www.npmjs.com/package/cra-template-rb) ![version](https://img.shields.io/npm/v/cra-template-rb) ![version](https://img.shields.io/npm/dm/cra-template-rb) -**👁️ Explore the Example Application:** [Example Application](https://react-boilerplate.github.io/react-boilerplate-cra-template/) - --- ## Install & Start From f6a0350dc5c6203a1b1c47d2b420245b7251bd05 Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sat, 16 May 2020 16:34:43 +0300 Subject: [PATCH 06/18] =?UTF-8?q?fix:=20=F0=9F=90=9B=20removing=20`connect?= =?UTF-8?q?ed-react-router`=20(#28)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/building-blocks/README.md | 8 +++--- docs/building-blocks/routing.md | 27 +++---------------- docs/misc/gotchas.md | 1 - internals/startingTemplate/src/app/index.tsx | 6 ++--- internals/startingTemplate/src/index.tsx | 17 +++++------- .../store/__tests__/configureStore.test.ts | 8 +++--- .../src/store/__tests__/reducer.test.ts | 13 ++++----- .../src/store/configureStore.ts | 19 +++---------- .../startingTemplate/src/store/reducers.ts | 18 ++++++------- .../startingTemplate/src/types/RootState.ts | 2 -- .../src/utils/@reduxjs/toolkit.tsx | 2 +- ...redux-injectors.tsx => redux-injectors.ts} | 0 .../src/utils/types/injector-typings.ts | 2 +- package-lock.json | 8 ------ package.json | 1 - .../__snapshots__/index.test.tsx.snap | 4 +-- src/app/index.tsx | 6 ++--- src/index.tsx | 21 ++++++--------- src/store/__tests__/configureStore.test.ts | 8 +++--- src/store/__tests__/reducer.test.ts | 13 ++++----- src/store/configureStore.ts | 20 ++++---------- src/store/reducers.ts | 18 ++++++------- src/types/RootState.ts | 2 -- src/utils/__tests__/history.test.ts | 14 ++++++++++ template.json | 1 - 25 files changed, 91 insertions(+), 148 deletions(-) rename internals/startingTemplate/src/utils/{redux-injectors.tsx => redux-injectors.ts} (100%) create mode 100644 src/utils/__tests__/history.test.ts diff --git a/docs/building-blocks/README.md b/docs/building-blocks/README.md index d04c86d..0e29711 100644 --- a/docs/building-blocks/README.md +++ b/docs/building-blocks/README.md @@ -9,9 +9,8 @@ First we have to look at what is happening when react starts its life with out ` It is one of the biggest files of the boilerplate. It contains all the global setup to make sure your app runs smoothly. Let's break its contents down: - `react-app-polyfill` is imported to enable compatibility with many browsers and cool stuff like generator functions, Promises, etc. -- A `history` object is created, which remembers all the browsing history for your app. This is used by the ConnectedRouter to know which pages your users visit. (Very useful for analytics, by the way.) - A redux `store` is instantiated. -- `ReactDOM.render()` not only renders the [root react component](https://github.com/react-boilerplate/react-boilerplate/blob/master/app/containers/App/index.js) called ``, of your application, but it renders it with ``, ``. +- `ReactDOM.render()` not only renders the [root react component](https://github.com/react-boilerplate/react-boilerplate/blob/master/app/containers/App/index.js) called ``, of your application, but it renders it with ``. - Hot module replacement is set up via [Webpack HMR](https://webpack.js.org/guides/hot-module-replacement/) that makes all the reducers, injected sagas, components, containers, and i18n messages hot reloadable. - i18n internationalization support setup. - `` connects your app with the redux `store`. @@ -40,10 +39,9 @@ The store is created with the `createStore()` factory, which accepts three param 2. **Initial state:** The initial state of your app as determined by your reducers. 3. **Middleware/enhancers:** Middlewares are third party libraries which intercept each redux action dispatched to the redux store and then... do stuff. For example, if you install the [`redux-logger`](https://github.com/evgenyrodionov/redux-logger) middleware, it will listen to all the actions being dispatched to the store and print previous and next state in the browser console. It's helpful to track what happens in your app. -In our application we are using two such middleware. +In our application we are using a single middleware. -1. **Router middleware:** Keeps your routes in sync with the redux `store`. -2. **Redux saga:** Used for managing _side-effects_ such as dispatching actions asynchronously or accessing browser data. +1. **Redux saga:** Used for managing _side-effects_ such as dispatching actions asynchronously or accessing browser data. ### Redux-Toolkit diff --git a/docs/building-blocks/routing.md b/docs/building-blocks/routing.md index 2b3d721..5735065 100644 --- a/docs/building-blocks/routing.md +++ b/docs/building-blocks/routing.md @@ -1,12 +1,10 @@ # Routing `react-router` is the de-facto standard routing solution for react applications. -The thing is that with redux and a single state tree, the URL is part of that -state. `connected-react-router` takes care of synchronizing the location of our -application with the application state. -(See the [`connected-react-router` FAQ](https://github.com/supasate/connected-react-router/blob/master/FAQ.md) -for more information) +## Why not using [connected-react-router](https://github.com/supasate/connected-react-router)? + +There is detailed explanation [here](https://reacttraining.com/react-router/web/guides/redux-integration/deep-integration). In short, it is not suggested to integrate route with redux, simply because it shouldn't be needed. There are other ways of navigating as explained there. ## Usage @@ -20,25 +18,6 @@ Top level routes are located in `src/app/index.tsx`. If you want your route component (or any component for that matter) to be loaded asynchronously, use container or component generator with 'Do you want to load resources asynchronously?' option activated. -To go to a new page use the `push` function by `connected-react-router`: - -```ts -import { push } from 'connected-react-router'; - -dispatch(push('/path/to/somewhere')); -``` - -You can do the same thing in a saga: - -```ts -import { push } from 'connected-react-router'; -import { put } from 'redux-saga/effects'; - -export function* mySaga() { - yield put(push('/home')); -} -``` - ## Child Routes For example, if you have a route called `about` at `/about` and want to make a child route called `team` at `/about/our-team`, follow the example diff --git a/docs/misc/gotchas.md b/docs/misc/gotchas.md index 3823a5f..4fb3b80 100644 --- a/docs/misc/gotchas.md +++ b/docs/misc/gotchas.md @@ -20,7 +20,6 @@ import navigationBarReducer from 'containers/NavigationBar/reducer'; export function createReducer(injectedReducers: InjectedReducersType = {}) { const rootReducer = combineReducers({ navigationBar: navigationBarReducer, - router: connectRouter(history) as Reducer, ...injectedReducers, }); diff --git a/internals/startingTemplate/src/app/index.tsx b/internals/startingTemplate/src/app/index.tsx index b1c8d52..5efcaff 100644 --- a/internals/startingTemplate/src/app/index.tsx +++ b/internals/startingTemplate/src/app/index.tsx @@ -8,7 +8,7 @@ import * as React from 'react'; import { Helmet } from 'react-helmet-async'; -import { Switch, Route } from 'react-router-dom'; +import { Switch, Route, BrowserRouter } from 'react-router-dom'; import { GlobalStyle } from 'styles/global-styles'; @@ -17,7 +17,7 @@ import { NotFoundPage } from './components/NotFoundPage/Loadable'; export function App() { return ( - <> + - + ); } diff --git a/internals/startingTemplate/src/index.tsx b/internals/startingTemplate/src/index.tsx index 149b2de..35a1868 100755 --- a/internals/startingTemplate/src/index.tsx +++ b/internals/startingTemplate/src/index.tsx @@ -11,9 +11,7 @@ import 'react-app-polyfill/stable'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; -import { ConnectedRouter } from 'connected-react-router'; import * as serviceWorker from 'serviceWorker'; -import { history } from 'utils/history'; import 'sanitize.css/sanitize.css'; // Import root app @@ -26,8 +24,7 @@ import { configureAppStore } from 'store/configureStore'; // Initialize languages import './locales/i18n'; -// Create redux store with history -const store = configureAppStore(history); +const store = configureAppStore(); const MOUNT_NODE = document.getElementById('root') as HTMLElement; interface Props { @@ -35,13 +32,11 @@ interface Props { } const ConnectedApp = ({ Component }: Props) => ( - - - - - - - + + + + + ); const render = (Component: typeof App) => { diff --git a/internals/startingTemplate/src/store/__tests__/configureStore.test.ts b/internals/startingTemplate/src/store/__tests__/configureStore.test.ts index 0d23426..d90f780 100644 --- a/internals/startingTemplate/src/store/__tests__/configureStore.test.ts +++ b/internals/startingTemplate/src/store/__tests__/configureStore.test.ts @@ -1,5 +1,4 @@ import { configureAppStore } from '../configureStore'; -import { history } from '../../utils/history'; describe('configureStore', () => { it('should return a store with injected enhancers', () => { @@ -11,11 +10,10 @@ describe('configureStore', () => { injectedSagas: expect.any(Object), }), ); - expect(store.getState().router).toBeDefined(); }); - it('should return a store with router in state', () => { - const store = configureAppStore(history); - expect(store.getState().router).toBeDefined(); + it('should return an empty store', () => { + const store = configureAppStore(); + expect(store.getState()).toBeUndefined(); }); }); diff --git a/internals/startingTemplate/src/store/__tests__/reducer.test.ts b/internals/startingTemplate/src/store/__tests__/reducer.test.ts index b07403f..f8fd159 100644 --- a/internals/startingTemplate/src/store/__tests__/reducer.test.ts +++ b/internals/startingTemplate/src/store/__tests__/reducer.test.ts @@ -2,12 +2,6 @@ import { createReducer } from '../reducers'; import { Reducer } from '@reduxjs/toolkit'; describe('reducer', () => { - it('should include router in reducer', () => { - const reducer = createReducer({}) as Reducer; - const state = reducer({}, ''); - expect(state.router).toBeDefined(); - }); - it('should inject reducers', () => { const dummyReducer = (s = {}, a) => 'dummyResult'; const reducer = createReducer({ test: dummyReducer } as any) as Reducer< @@ -17,4 +11,11 @@ describe('reducer', () => { const state = reducer({}, ''); expect(state.test).toBe('dummyResult'); }); + + it('should return identity reducers when empty', () => { + const reducer = createReducer() as Reducer; + const state = { a: 1 }; + const newState = reducer(state, ''); + expect(newState).toBe(state); + }); }); diff --git a/internals/startingTemplate/src/store/configureStore.ts b/internals/startingTemplate/src/store/configureStore.ts index 9a66013..92a6af6 100644 --- a/internals/startingTemplate/src/store/configureStore.ts +++ b/internals/startingTemplate/src/store/configureStore.ts @@ -2,30 +2,19 @@ * Create the store with dynamic reducers */ -import { - configureStore, - getDefaultMiddleware, - Middleware, -} from '@reduxjs/toolkit'; -import { routerMiddleware } from 'connected-react-router'; +import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'; import { createInjectorsEnhancer, forceReducerReload } from 'redux-injectors'; import createSagaMiddleware from 'redux-saga'; -import { History } from 'history'; import { createReducer } from './reducers'; -export function configureAppStore(history?: History) { +export function configureAppStore() { const reduxSagaMonitorOptions = {}; const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions); const { run: runSaga } = sagaMiddleware; - // Create the store with two middlewares - // 1. sagaMiddleware: Makes redux-sagas work - // 2. routerMiddleware: Syncs the location/URL path to the state - const middlewares = [sagaMiddleware] as Middleware[]; - if (history) { - middlewares.push(routerMiddleware(history)); - } + // Create the store with saga middleware + const middlewares = [sagaMiddleware]; const enhancers = [ createInjectorsEnhancer({ diff --git a/internals/startingTemplate/src/store/reducers.ts b/internals/startingTemplate/src/store/reducers.ts index 10a1f1c..e88a330 100644 --- a/internals/startingTemplate/src/store/reducers.ts +++ b/internals/startingTemplate/src/store/reducers.ts @@ -2,20 +2,20 @@ * Combine all reducers in this file and export the combined reducers. */ -import { combineReducers, Reducer, AnyAction } from '@reduxjs/toolkit'; -import { connectRouter, RouterState } from 'connected-react-router'; +import { combineReducers } from '@reduxjs/toolkit'; -import { history } from 'utils/history'; import { InjectedReducersType } from 'utils/types/injector-typings'; /** * Merges the main reducer with the router state and dynamically injected reducers */ export function createReducer(injectedReducers: InjectedReducersType = {}) { - const rootReducer = combineReducers({ - ...injectedReducers, - router: connectRouter(history) as Reducer, - }); - - return rootReducer; + // Initially we don't have any injectedReducers, so returning identity function to avoid the error + if (Object.keys(injectedReducers).length === 0) { + return state => state; + } else { + return combineReducers({ + ...injectedReducers, + }); + } } diff --git a/internals/startingTemplate/src/types/RootState.ts b/internals/startingTemplate/src/types/RootState.ts index 3024ce2..c369041 100644 --- a/internals/startingTemplate/src/types/RootState.ts +++ b/internals/startingTemplate/src/types/RootState.ts @@ -1,4 +1,3 @@ -import { RouterState } from 'connected-react-router'; // [IMPORT NEW CONTAINERSTATE ABOVE] < Needed for generating containers seamlessly /* @@ -6,6 +5,5 @@ import { RouterState } from 'connected-react-router'; You have to declare them here manually */ export interface RootState { - router?: RouterState; // [INSERT NEW REDUCER KEY ABOVE] < Needed for generating containers seamlessly } diff --git a/internals/startingTemplate/src/utils/@reduxjs/toolkit.tsx b/internals/startingTemplate/src/utils/@reduxjs/toolkit.tsx index b3cce48..9b72197 100644 --- a/internals/startingTemplate/src/utils/@reduxjs/toolkit.tsx +++ b/internals/startingTemplate/src/utils/@reduxjs/toolkit.tsx @@ -5,7 +5,7 @@ import { CreateSliceOptions, } from '@reduxjs/toolkit'; -/* Wrap createClice with stricter Name options */ +/* Wrap createSlice with stricter Name options */ /* istanbul ignore next */ export const createSlice = < diff --git a/internals/startingTemplate/src/utils/redux-injectors.tsx b/internals/startingTemplate/src/utils/redux-injectors.ts similarity index 100% rename from internals/startingTemplate/src/utils/redux-injectors.tsx rename to internals/startingTemplate/src/utils/redux-injectors.ts diff --git a/internals/startingTemplate/src/utils/types/injector-typings.ts b/internals/startingTemplate/src/utils/types/injector-typings.ts index 0536ee6..54105c6 100644 --- a/internals/startingTemplate/src/utils/types/injector-typings.ts +++ b/internals/startingTemplate/src/utils/types/injector-typings.ts @@ -1,7 +1,7 @@ import { RootState } from 'types'; -import { Reducer, AnyAction } from 'redux'; import { Saga } from 'redux-saga'; import { SagaInjectionModes } from 'redux-injectors'; +import { Reducer, AnyAction } from '@reduxjs/toolkit'; type RequiredRootState = Required; diff --git a/package-lock.json b/package-lock.json index 60d7fca..6655884 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5291,14 +5291,6 @@ "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", "dev": true }, - "connected-react-router": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/connected-react-router/-/connected-react-router-6.8.0.tgz", - "integrity": "sha512-E64/6krdJM3Ag3MMmh2nKPtMbH15s3JQDuaYJvOVXzu6MbHbDyIvuwLOyhQIuP4Om9zqEfZYiVyflROibSsONg==", - "requires": { - "prop-types": "^15.7.2" - } - }, "console-browserify": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", diff --git a/package.json b/package.json index 4c080ce..9130bb5 100755 --- a/package.json +++ b/package.json @@ -95,7 +95,6 @@ }, "dependencies": { "@reduxjs/toolkit": "1.3.2", - "connected-react-router": "6.8.0", "fontfaceobserver": "2.1.0", "history": "4.10.1", "i18next": "19.3.4", diff --git a/src/app/__tests__/__snapshots__/index.test.tsx.snap b/src/app/__tests__/__snapshots__/index.test.tsx.snap index cd89ead..aa39234 100644 --- a/src/app/__tests__/__snapshots__/index.test.tsx.snap +++ b/src/app/__tests__/__snapshots__/index.test.tsx.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[` should render and match the snapshot 1`] = ` - + should render and match the snapshot 1`] = ` /> - + `; diff --git a/src/app/index.tsx b/src/app/index.tsx index 6b7ea89..ffef470 100644 --- a/src/app/index.tsx +++ b/src/app/index.tsx @@ -8,7 +8,7 @@ import * as React from 'react'; import { Helmet } from 'react-helmet-async'; -import { Switch, Route } from 'react-router-dom'; +import { Switch, Route, BrowserRouter } from 'react-router-dom'; import { GlobalStyle } from '../styles/global-styles'; @@ -17,7 +17,7 @@ import { NotFoundPage } from './containers/NotFoundPage/Loadable'; export function App() { return ( - <> + - + ); } diff --git a/src/index.tsx b/src/index.tsx index 5801e3c..7f642db 100755 --- a/src/index.tsx +++ b/src/index.tsx @@ -11,10 +11,8 @@ import 'react-app-polyfill/stable'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; -import { ConnectedRouter } from 'connected-react-router'; import FontFaceObserver from 'fontfaceobserver'; import * as serviceWorker from 'serviceWorker'; -import { history } from 'utils/history'; import 'sanitize.css/sanitize.css'; @@ -38,8 +36,7 @@ openSansObserver.load().then(() => { document.body.classList.add('fontLoaded'); }); -// Create redux store with history -const store = configureAppStore(history); +const store = configureAppStore(); const MOUNT_NODE = document.getElementById('root') as HTMLElement; interface Props { @@ -47,15 +44,13 @@ interface Props { } const ConnectedApp = ({ Component }: Props) => ( - - - - - - - - - + + + + + + + ); diff --git a/src/store/__tests__/configureStore.test.ts b/src/store/__tests__/configureStore.test.ts index 0d23426..d90f780 100644 --- a/src/store/__tests__/configureStore.test.ts +++ b/src/store/__tests__/configureStore.test.ts @@ -1,5 +1,4 @@ import { configureAppStore } from '../configureStore'; -import { history } from '../../utils/history'; describe('configureStore', () => { it('should return a store with injected enhancers', () => { @@ -11,11 +10,10 @@ describe('configureStore', () => { injectedSagas: expect.any(Object), }), ); - expect(store.getState().router).toBeDefined(); }); - it('should return a store with router in state', () => { - const store = configureAppStore(history); - expect(store.getState().router).toBeDefined(); + it('should return an empty store', () => { + const store = configureAppStore(); + expect(store.getState()).toBeUndefined(); }); }); diff --git a/src/store/__tests__/reducer.test.ts b/src/store/__tests__/reducer.test.ts index b07403f..f8fd159 100644 --- a/src/store/__tests__/reducer.test.ts +++ b/src/store/__tests__/reducer.test.ts @@ -2,12 +2,6 @@ import { createReducer } from '../reducers'; import { Reducer } from '@reduxjs/toolkit'; describe('reducer', () => { - it('should include router in reducer', () => { - const reducer = createReducer({}) as Reducer; - const state = reducer({}, ''); - expect(state.router).toBeDefined(); - }); - it('should inject reducers', () => { const dummyReducer = (s = {}, a) => 'dummyResult'; const reducer = createReducer({ test: dummyReducer } as any) as Reducer< @@ -17,4 +11,11 @@ describe('reducer', () => { const state = reducer({}, ''); expect(state.test).toBe('dummyResult'); }); + + it('should return identity reducers when empty', () => { + const reducer = createReducer() as Reducer; + const state = { a: 1 }; + const newState = reducer(state, ''); + expect(newState).toBe(state); + }); }); diff --git a/src/store/configureStore.ts b/src/store/configureStore.ts index a7cb0f6..0d97cb1 100644 --- a/src/store/configureStore.ts +++ b/src/store/configureStore.ts @@ -1,27 +1,16 @@ -import { - configureStore, - getDefaultMiddleware, - Middleware, -} from '@reduxjs/toolkit'; -import { routerMiddleware } from 'connected-react-router'; +import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'; import { createInjectorsEnhancer, forceReducerReload } from 'redux-injectors'; import createSagaMiddleware from 'redux-saga'; -import { History } from 'history'; import { createReducer } from './reducers'; -export function configureAppStore(history?: History) { +export function configureAppStore() { const reduxSagaMonitorOptions = {}; const sagaMiddleware = createSagaMiddleware(reduxSagaMonitorOptions); const { run: runSaga } = sagaMiddleware; - // Create the store with two middlewares - // 1. sagaMiddleware: Makes redux-sagas work - // 2. routerMiddleware: Syncs the location/URL path to the state - const middlewares = [sagaMiddleware] as Middleware[]; - if (history) { - middlewares.push(routerMiddleware(history)); - } + // Create the store with saga middleware + const middlewares = [sagaMiddleware]; const enhancers = [ createInjectorsEnhancer({ @@ -34,6 +23,7 @@ export function configureAppStore(history?: History) { reducer: createReducer(), middleware: [...getDefaultMiddleware(), ...middlewares], devTools: + /* istanbul ignore next line */ process.env.NODE_ENV !== 'production' || process.env.PUBLIC_URL.length > 0, enhancers, diff --git a/src/store/reducers.ts b/src/store/reducers.ts index 10a1f1c..e88a330 100644 --- a/src/store/reducers.ts +++ b/src/store/reducers.ts @@ -2,20 +2,20 @@ * Combine all reducers in this file and export the combined reducers. */ -import { combineReducers, Reducer, AnyAction } from '@reduxjs/toolkit'; -import { connectRouter, RouterState } from 'connected-react-router'; +import { combineReducers } from '@reduxjs/toolkit'; -import { history } from 'utils/history'; import { InjectedReducersType } from 'utils/types/injector-typings'; /** * Merges the main reducer with the router state and dynamically injected reducers */ export function createReducer(injectedReducers: InjectedReducersType = {}) { - const rootReducer = combineReducers({ - ...injectedReducers, - router: connectRouter(history) as Reducer, - }); - - return rootReducer; + // Initially we don't have any injectedReducers, so returning identity function to avoid the error + if (Object.keys(injectedReducers).length === 0) { + return state => state; + } else { + return combineReducers({ + ...injectedReducers, + }); + } } diff --git a/src/types/RootState.ts b/src/types/RootState.ts index e37e048..44910ea 100644 --- a/src/types/RootState.ts +++ b/src/types/RootState.ts @@ -1,4 +1,3 @@ -import { RouterState } from 'connected-react-router'; import { GithubRepoFormState } from 'app/containers/GithubRepoForm/types'; import { ThemeState } from 'styles/theme/types'; // [IMPORT NEW CONTAINERSTATE ABOVE] < Needed for generating containers seamlessly @@ -10,7 +9,6 @@ import { ThemeState } from 'styles/theme/types'; So, not available always */ export interface RootState { - router?: RouterState; theme?: ThemeState; githubRepoForm?: GithubRepoFormState; // [INSERT NEW REDUCER KEY ABOVE] < Needed for generating containers seamlessly diff --git a/src/utils/__tests__/history.test.ts b/src/utils/__tests__/history.test.ts new file mode 100644 index 0000000..5c6242b --- /dev/null +++ b/src/utils/__tests__/history.test.ts @@ -0,0 +1,14 @@ +import { history } from '../history'; + +describe('history', () => { + it('get browser history', () => { + expect(history).toEqual( + expect.objectContaining({ + action: expect.any(String), + location: expect.any(Object), + push: expect.any(Function), + replace: expect.any(Function), + }), + ); + }); +}); diff --git a/template.json b/template.json index f6456c6..183faeb 100755 --- a/template.json +++ b/template.json @@ -45,7 +45,6 @@ }, "dependencies": { "@reduxjs/toolkit": "1.3.2", - "connected-react-router": "6.8.0", "fontfaceobserver": "2.1.0", "history": "4.10.1", "i18next": "19.3.4", From a1a64f22e25b65fcb95f60a5c4ef111b21546a3e Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sat, 16 May 2020 19:18:56 +0300 Subject: [PATCH 07/18] =?UTF-8?q?chore:=20=F0=9F=94=A7=20removed=20useless?= =?UTF-8?q?=20pre-commit=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 9130bb5..d73cd9e 100755 --- a/package.json +++ b/package.json @@ -51,7 +51,6 @@ "test:coverage": "npm run test:all -- --coverage", "test:cra": "npm run create:cra-app && cd generated-cra-app && npm run test:generators && npm run lint && npm run checkTs && npm run cleanExampleApp && npm run lint && npm run checkTs", "// ---BUILDING TEMPLATE---": "", - "delete:cra-app": "rm -rf generated-cra-app", "create:npm-package": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/create-npm-package.script.ts", "create:cra-app": "rm -rf generated-cra-app && npm run create:npm-package && npx create-react-app generated-cra-app --template file:.cra-template-rb && rm -rf .cra-template-rb", "// ---PUBLISHING---": "", @@ -70,7 +69,7 @@ }, "husky": { "hooks": { - "pre-commit": "npm run delete:cra-app && npm run checkTs && lint-staged", + "pre-commit": "npm run checkTs && lint-staged", "prepare-commit-msg": "devmoji -e", "commit-msg": "if git-branch-is dev; then commitlint -E HUSKY_GIT_PARAMS; fi" } From 47d81b311e7c7d2a1f68e55af6d7e10e37526759 Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sat, 16 May 2020 19:48:53 +0300 Subject: [PATCH 08/18] =?UTF-8?q?docs:=20=F0=9F=93=9A=EF=B8=8F=20added=20F?= =?UTF-8?q?AQ?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/SUMMARY.md | 2 +- docs/misc/faq.md | 36 ++++++++++++++++++++++++++++++++++++ docs/misc/gotchas.md | 28 ---------------------------- 3 files changed, 37 insertions(+), 29 deletions(-) create mode 100644 docs/misc/faq.md delete mode 100644 docs/misc/gotchas.md diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 3907143..e9038a5 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -30,4 +30,4 @@ ## Misc -- [Gotchas & Tips](misc/gotchas.md) +- [FAQ](misc/faq.md) diff --git a/docs/misc/faq.md b/docs/misc/faq.md new file mode 100644 index 0000000..d2071d2 --- /dev/null +++ b/docs/misc/faq.md @@ -0,0 +1,36 @@ +# FAQ + +- [Using global reducers instead of injecting](#load-reducers-optimistically) +- [Keeping up-to-date with the template](keeping-up-to-date-with-the-template) +- [Are there any examples or tutorials?](examples-and-tutorials) + +## Using 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`. + +```ts +// In src/store/reducers.ts + +... +import { combineReducers } from '@reduxjs/toolkit'; +... + +import navigationBarReducer from 'containers/NavigationBar/reducer'; + +export function createReducer(injectedReducers: InjectedReducersType = {}) { + const rootReducer = combineReducers({ + navigationBar: navigationBarReducer, + ...injectedReducers, + }); + + return rootReducer; +} +``` + +## Keeping up-to-date with the template + +Eventhough the template is an npm package it's not possible for you to **just update** the package, since you start CRA with this template initially. The suggested way to keep an eye on the [CHANGELOG](../../CHANGELOG.md) file. All the changes that **concerns** the template user will be displayed there, like bug fixes, documentation updates, new features etc... You can check each change's commits and file changes and see what has been changed. Then, the decision is yours if you want to apply those to your code. + +## Examples & Tutorials + +Take a look our [another 'how to' repo](https://github.com/react-boilerplate/cra-template-examples) for examples and common web app implementations & patterns diff --git a/docs/misc/gotchas.md b/docs/misc/gotchas.md deleted file mode 100644 index 4fb3b80..0000000 --- a/docs/misc/gotchas.md +++ /dev/null @@ -1,28 +0,0 @@ -# Gotchas - -These are some things to be aware of when using this boilerplate. - -- [Load reducers optimistically](#load-reducers-optimistically) - -## 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`. - -```ts -// In src/store/reducers.ts - -... -import { combineReducers } from '@reduxjs/toolkit'; -... - -import navigationBarReducer from 'containers/NavigationBar/reducer'; - -export function createReducer(injectedReducers: InjectedReducersType = {}) { - const rootReducer = combineReducers({ - navigationBar: navigationBarReducer, - ...injectedReducers, - }); - - return rootReducer; -} -``` From 765a8972733a556bd39b414cbbe1ff9458864f6a Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sat, 16 May 2020 19:49:38 +0300 Subject: [PATCH 09/18] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20updated?= =?UTF-8?q?=20readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2d92944..579f679 100644 --- a/README.md +++ b/README.md @@ -47,11 +47,9 @@ Start your `create-react-app` projects in seconds with the best, industry-standa **📚Documentation:** [Gitbook](https://cansahin.gitbook.io/react-boilerplate-cra-template/) -**🎨Explore the Example Application:** [Example Application](https://react-boilerplate.github.io/react-boilerplate-cra-template/) +**🎨 Check the example app:** [Boilerplate Example Application](https://react-boilerplate.github.io/react-boilerplate-cra-template/) -**💡Examples & Tutorials of commonly needed **`'How to'`**'s:** [Collection of examples & tutorials](https://github.com/react-boilerplate/cra-template-examples) - -> Feel free to contribute with your `how to do this and that` examples and guides. +**🚑 Collection of `'HOW TO'`s:** [Examples & Tutorials for common patterns](https://github.com/react-boilerplate/cra-template-examples) **📦 Package:** [npm](https://www.npmjs.com/package/cra-template-rb) @@ -62,15 +60,22 @@ Start your `create-react-app` projects in seconds with the best, industry-standa ## Install & Start +Create React App with the template + ```shell -# Create React App with the template npx create-react-app --template cra-template-rb my-app +``` + +Start and check our example app, if you want -# Check the example app +```shell cd my-app npm start +``` -# Remove the example app and start your project! +Remove the example app to start your project! + +```shell npm run cleanExampleApp ``` From 57895a3ca97acc7e6dda2a14b093d669d3be4e9e Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sun, 17 May 2020 13:51:57 +0300 Subject: [PATCH 10/18] =?UTF-8?q?fix:=20=F0=9F=90=9B=20supporting=20css=20?= =?UTF-8?q?prop=20in=20styled-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes #27 --- src/react-app-env.d.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts index 6431bc5..afa73d4 100644 --- a/src/react-app-env.d.ts +++ b/src/react-app-env.d.ts @@ -1 +1,4 @@ /// + +// To solve the issue: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31245 +/// From e6f805435b332587875f045f327e97c43b0b49bf Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sun, 17 May 2020 14:00:14 +0300 Subject: [PATCH 11/18] =?UTF-8?q?chore:=20=F0=9F=94=A7=20moved=20creation?= =?UTF-8?q?=20of=20the=20test=20CRA=20to=20a=20script=20to=20avoid=20husky?= =?UTF-8?q?=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internals/scripts/create-cra-app.script.ts | 43 +++++ package-lock.json | 195 +++++++++++++++++++++ package.json | 3 +- 3 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 internals/scripts/create-cra-app.script.ts diff --git a/internals/scripts/create-cra-app.script.ts b/internals/scripts/create-cra-app.script.ts new file mode 100644 index 0000000..6edf348 --- /dev/null +++ b/internals/scripts/create-cra-app.script.ts @@ -0,0 +1,43 @@ +import shell from 'shelljs'; +import { createNpmPackage, removeNpmPackage } from './create-npm-package'; +import replace from 'replace-in-file'; +import fs from 'fs'; + +interface Options {} + +export function createCRA(opts: Options = {}) { + const app_name = 'generated-cra-app'; + shell.exec(`rm -rf ${app_name}`); + + const template = createNpmPackage(); + shell.exec(`npx create-react-app ${app_name} --template file:${template}`, { + silent: false, + fatal: true, + }); + + removeNpmPackage(); + + fixHuskyBug(); +} + +function fixHuskyBug() { + // husky changes directory to the example folder which we don't want + // https://github.com/typicode/husky#monorepos + // https://github.com/typicode/husky/issues/677 + const huskyLocalPath = '.git/hooks/husky.local.sh'; + if (!fs.existsSync(huskyLocalPath)) { + return; + } + const options = { + files: '.git/hooks/husky.local.sh', + from: /cd.*/g, + to: `cd "."`, + }; + try { + replace.sync(options); + } catch (error) { + console.error('Error occurred:', error); + } +} + +createCRA(); diff --git a/package-lock.json b/package-lock.json index 6655884..2d700ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18012,6 +18012,201 @@ "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", "dev": true }, + "replace-in-file": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/replace-in-file/-/replace-in-file-6.0.0.tgz", + "integrity": "sha512-vMmJekpRgju0GA0UvRxauDbQ645wGXxasVZfw5l5HKk58OlAI1tMmXNcV+YAUKrS/XFdBPla5qgvjI5Tqvshvg==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "glob": "^7.1.6", + "yargs": "^15.3.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "chalk": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", + "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.1" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", diff --git a/package.json b/package.json index d73cd9e..cd0eee1 100755 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "test:cra": "npm run create:cra-app && cd generated-cra-app && npm run test:generators && npm run lint && npm run checkTs && npm run cleanExampleApp && npm run lint && npm run checkTs", "// ---BUILDING TEMPLATE---": "", "create:npm-package": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/create-npm-package.script.ts", - "create:cra-app": "rm -rf generated-cra-app && npm run create:npm-package && npx create-react-app generated-cra-app --template file:.cra-template-rb && rm -rf .cra-template-rb", + "create:cra-app": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/create-cra-app.script.ts", "// ---PUBLISHING---": "", "publish:github": "cross-env PUBLIC_URL='/react-boilerplate-cra-template' npm run build && gh-pages -d build", "changelog": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/create-changelog.script.ts", @@ -151,6 +151,7 @@ "prettier": "2.0.1", "react-scripts": "3.4.1", "react-test-renderer": "16.13.0", + "replace-in-file": "6.0.0", "rimraf": "3.0.2", "serve": "11.3.0", "shelljs": "0.8.3", From 86fd72d3fd9d6ff16f59349c2eaca629cdc4f98f Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sun, 17 May 2020 14:16:56 +0300 Subject: [PATCH 12/18] =?UTF-8?q?chore:=20=F0=9F=94=A7=20fixed=20changelog?= =?UTF-8?q?=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internals/scripts/create-changelog.script.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/internals/scripts/create-changelog.script.ts b/internals/scripts/create-changelog.script.ts index f8e7fac..5209f38 100644 --- a/internals/scripts/create-changelog.script.ts +++ b/internals/scripts/create-changelog.script.ts @@ -9,9 +9,12 @@ export function createChangeLog(opts: Options = {}) { console.error('Error: Unstaged files'); process.exit(1); } - shell.exec(`npx standard-version --skip.commit --skip.tag`, { - silent: false, - }); + shell.exec( + `npx standard-version --skip.commit --skip.tag --skip.changelog=0`, + { + silent: false, + }, + ); // Revert the bumbped version shell.exec(`git checkout -- package-lock.json`, { silent: true }); From c776cdd7e55295d304268cc0821779c9720f0fdd Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sun, 17 May 2020 15:41:53 +0300 Subject: [PATCH 13/18] =?UTF-8?q?feat:=20=E2=9C=A8=20added=20media=20query?= =?UTF-8?q?=20utility?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/building-blocks/css.md | 18 ++++++ .../startingTemplate/src/styles/media.ts | 62 +++++++++++++++++++ src/styles/media.ts | 62 +++++++++++++++++++ 3 files changed, 142 insertions(+) create mode 100644 internals/startingTemplate/src/styles/media.ts create mode 100644 src/styles/media.ts diff --git a/docs/building-blocks/css.md b/docs/building-blocks/css.md index 2be2fc8..7237f4d 100644 --- a/docs/building-blocks/css.md +++ b/docs/building-blocks/css.md @@ -61,3 +61,21 @@ _(The CSS rules are automatically vendor prefixed, so you don't have to think ab 🧙**Tips:** Importing from `styled-components/macro` will enable some features you can [see here](https://styled-components.com/docs/tooling#babel-macro) {% endhint %} + +## Media queries + +Type-safe media queries can be complicated if you haven't mastered the typescript. Therefore we include a [media utility file](../../src/styles/media.ts) to make things easier for you. + +### Example Usage + +```ts +import { media } from 'styles/media'; + +const SomeDiv = styled.div` + display: flex; + .... + ${media.medium` + display: block + `}; +`; +``` diff --git a/internals/startingTemplate/src/styles/media.ts b/internals/startingTemplate/src/styles/media.ts new file mode 100644 index 0000000..b331b37 --- /dev/null +++ b/internals/startingTemplate/src/styles/media.ts @@ -0,0 +1,62 @@ +/* + * Media queries utility + */ + +import { + css, + DefaultTheme, + CSSObject, + InterpolationFunction, + ThemedStyledProps, + Interpolation, + FlattenInterpolation, +} from 'styled-components/macro'; + +/* + * Taken from https://github.com/DefinitelyTyped/DefinitelyTyped/issues/32914 + */ + +// Update your breakpoints if you want +const sizes = { + small: 600, + medium: 1024, + large: 1440, + xlarge: 1920, +}; + +// Iterate through the sizes and create a media template +export const media = (Object.keys(sizes) as Array).reduce( + (acc, label) => { + acc[label] = (first: any, ...interpolations: any[]) => css` + @media (min-width: ${sizes[label]}px) { + ${css(first, ...interpolations)} + } + `; + + return acc; + }, + {} as { [key in keyof typeof sizes]: MediaFunction }, +); + +/* + * @types/styled-component is not working properly as explained in the github issue referenced above. + * We must overcome this with custom typings, however, this might not work in time as the styled-components update. + * Be carefull and keep an eye on the issue and the possible improvements + */ +type MediaFunction =

( + first: + | TemplateStringsArray + | CSSObject + | InterpolationFunction>, + ...interpolations: Array>> +) => FlattenInterpolation>; + +/* Example +const SomeDiv = styled.div` + display: flex; + .... + ${media.medium` + display: block + `} +`; +*/ diff --git a/src/styles/media.ts b/src/styles/media.ts new file mode 100644 index 0000000..b331b37 --- /dev/null +++ b/src/styles/media.ts @@ -0,0 +1,62 @@ +/* + * Media queries utility + */ + +import { + css, + DefaultTheme, + CSSObject, + InterpolationFunction, + ThemedStyledProps, + Interpolation, + FlattenInterpolation, +} from 'styled-components/macro'; + +/* + * Taken from https://github.com/DefinitelyTyped/DefinitelyTyped/issues/32914 + */ + +// Update your breakpoints if you want +const sizes = { + small: 600, + medium: 1024, + large: 1440, + xlarge: 1920, +}; + +// Iterate through the sizes and create a media template +export const media = (Object.keys(sizes) as Array).reduce( + (acc, label) => { + acc[label] = (first: any, ...interpolations: any[]) => css` + @media (min-width: ${sizes[label]}px) { + ${css(first, ...interpolations)} + } + `; + + return acc; + }, + {} as { [key in keyof typeof sizes]: MediaFunction }, +); + +/* + * @types/styled-component is not working properly as explained in the github issue referenced above. + * We must overcome this with custom typings, however, this might not work in time as the styled-components update. + * Be carefull and keep an eye on the issue and the possible improvements + */ +type MediaFunction =

( + first: + | TemplateStringsArray + | CSSObject + | InterpolationFunction>, + ...interpolations: Array>> +) => FlattenInterpolation>; + +/* Example +const SomeDiv = styled.div` + display: flex; + .... + ${media.medium` + display: block + `} +`; +*/ From a3d05f8faa49cffbdb3e82fe53a9024db8f2170b Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sun, 17 May 2020 20:12:24 +0300 Subject: [PATCH 14/18] =?UTF-8?q?chore:=20=F0=9F=94=A7=20improved=20cleani?= =?UTF-8?q?ng=20script?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #29 --- internals/scripts/clean.ts | 33 ++++++++++++++++++++++++++++++--- template.json | 5 +++-- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/internals/scripts/clean.ts b/internals/scripts/clean.ts index 0b7f6bc..bd97ae1 100644 --- a/internals/scripts/clean.ts +++ b/internals/scripts/clean.ts @@ -1,12 +1,15 @@ import shell from 'shelljs'; import path from 'path'; import chalk from 'chalk'; +import replace from 'replace-in-file'; +import fs from 'fs'; +const packageJson = require('../../package.json'); interface Options {} process.chdir(path.join(__dirname, '../..')); -export function cleanExampleApp(opts: Options = {}) { +export function cleanAndSetup(opts: Options = {}) { if (!shell.test('-e', 'internals/startingTemplate')) { shell.echo('The example app has already deleted.'); shell.exit(1); @@ -25,9 +28,33 @@ export function cleanExampleApp(opts: Options = {}) { shell.exec('npm run prettify -- src/*', { silent: true }); - shell.echo(chalk.green('Example App removed. Happy Coding!!!')); + cleanPackageJsonFile(); + + shell.echo( + chalk.green('Example app removed and setup completed. Happy Coding!!!'), + ); +} + +function cleanPackageJsonFile() { + delete packageJson['eslintConfig']; + delete packageJson['dependencies']['replace-in-file']; + delete packageJson['scripts']['cleanAndSetup']; + + fs.writeFileSync('./package.json', JSON.stringify(packageJson)); + shell.exec('npm run prettify -- package.json', { silent: true }); + + try { + // Remove explanation from husky to enable it + replace.sync({ + files: 'package.json', + from: /"husky\((.*?)\)"/g, + to: '"husky"', + }); + } catch (error) { + console.error('Couldnt clean husky:', error); + } } (function () { - cleanExampleApp(); + cleanAndSetup(); })(); diff --git a/template.json b/template.json index 183faeb..63c8637 100755 --- a/template.json +++ b/template.json @@ -20,7 +20,7 @@ "*.{ts,tsx,js,jsx}": ["npm run eslint -- --fix"], "*.{md,json}": ["prettier --write"] }, - "husky": { + "husky(remove-everything-in-these-parentheses.See-the-issue-#29)": { "hooks": { "pre-commit": "npm run checkTs && lint-staged" } @@ -93,7 +93,8 @@ "plop": "2.6.0", "serve": "11.3.0", "shelljs": "0.8.3", - "husky": "4.2.3" + "husky": "4.2.3", + "replace-in-file": "6.0.0" } } } From 3cedb9494d242cc48fc605c2002d1cf173c14c55 Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Sun, 17 May 2020 20:13:01 +0300 Subject: [PATCH 15/18] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20updated?= =?UTF-8?q?=20clean=20script=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yaml | 2 +- .github/workflows/release.yml | 2 +- README.md | 2 +- docs/quick-start.md | 2 +- docs/tools/commands.md | 4 ++-- package.json | 4 ++-- template.json | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 61332a7..71e8c01 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -37,7 +37,7 @@ jobs: - run: npm run lint - run: npm run checkTs - run: npm run test - - run: npm run cleanExampleApp + - run: npm run cleanAndSetup - run: npm run build - run: npm run test:generators - run: npm run lint diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 71d75a6..1d3a66b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -23,7 +23,7 @@ jobs: - run: npm run test:generators - run: npm run lint - run: npm run checkTs - - run: npm run cleanExampleApp + - run: npm run cleanAndSetup - run: npm run build - run: npm run test:generators - run: npm run lint diff --git a/README.md b/README.md index 579f679..77cba68 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ npm start Remove the example app to start your project! ```shell -npm run cleanExampleApp +npm run cleanAndSetup ``` ## Features diff --git a/docs/quick-start.md b/docs/quick-start.md index e3e1ee4..3cd4711 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -18,7 +18,7 @@ npm start **3)** When you are done examining the sample application. Clean it and start your own app!! ```shell -npm run cleanExampleApp +npm run cleanAndSetup ``` {% hint style="success" %} diff --git a/docs/tools/commands.md b/docs/tools/commands.md index 20bdce7..39a1192 100644 --- a/docs/tools/commands.md +++ b/docs/tools/commands.md @@ -3,11 +3,11 @@ ## Cleaning ```Shell -npm run cleanExampleApp +npm run cleanAndSetup ``` Removes the example app, replacing it with the smallest amount of boilerplate -code necessary to start writing your app! +code necessary to start writing your app! Also, it makes some necessary changes to your setup to give you a clean and working start {% hint style="warning" %} diff --git a/package.json b/package.json index cd0eee1..2c32b42 100755 --- a/package.json +++ b/package.json @@ -44,12 +44,12 @@ "lint:fix": "npm run eslint -- --fix src", "lint:css": "stylelint src/**/*.css", "generate": "cross-env TS_NODE_PROJECT='./internals/ts-node.tsconfig.json' plop --plopfile internals/generators/plopfile.ts", - "cleanExampleApp": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/clean.ts", + "cleanAndSetup": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/clean.ts", "prettify": "prettier --write", "// ---TESTING TEMPLATE---": "", "test:all": "npm run test -- --watchAll=false", "test:coverage": "npm run test:all -- --coverage", - "test:cra": "npm run create:cra-app && cd generated-cra-app && npm run test:generators && npm run lint && npm run checkTs && npm run cleanExampleApp && npm run lint && npm run checkTs", + "test:cra": "npm run create:cra-app && cd generated-cra-app && npm run test:generators && npm run lint && npm run checkTs && npm run cleanAndSetup && npm run lint && npm run checkTs", "// ---BUILDING TEMPLATE---": "", "create:npm-package": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/create-npm-package.script.ts", "create:cra-app": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/create-cra-app.script.ts", diff --git a/template.json b/template.json index 63c8637..f954e26 100755 --- a/template.json +++ b/template.json @@ -13,7 +13,7 @@ "lint:fix": "npm run eslint -- --fix src", "lint:css": "stylelint src/**/*.css", "generate": "cross-env TS_NODE_PROJECT='./internals/ts-node.tsconfig.json' plop --plopfile internals/generators/plopfile.ts", - "cleanExampleApp": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/clean.ts", + "cleanAndSetup": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/clean.ts", "prettify": "prettier --write" }, "lint-staged": { From 3f2d9c991e8af4914dcd899d6a346dceae0a9463 Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Mon, 18 May 2020 18:31:57 +0300 Subject: [PATCH 16/18] =?UTF-8?q?test:=20=F0=9F=9A=A8=20added=20media=20ut?= =?UTF-8?q?ility=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/styles/__tests__/media.test.ts | 14 ++++++++++++++ internals/startingTemplate/src/styles/media.ts | 2 +- src/styles/__tests__/media.test.ts | 14 ++++++++++++++ src/styles/media.ts | 2 +- 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 internals/startingTemplate/src/styles/__tests__/media.test.ts create mode 100644 src/styles/__tests__/media.test.ts diff --git a/internals/startingTemplate/src/styles/__tests__/media.test.ts b/internals/startingTemplate/src/styles/__tests__/media.test.ts new file mode 100644 index 0000000..b1d0c0d --- /dev/null +++ b/internals/startingTemplate/src/styles/__tests__/media.test.ts @@ -0,0 +1,14 @@ +import { media, sizes } from '../media'; +import { css } from 'styled-components/macro'; + +describe('media', () => { + it('should return media query in css', () => { + const mediaQuery = media.small`color:red;`.join(''); + const cssVersion = css` + @media (min-width: ${sizes.small}px) { + color: red; + } + `.join(''); + expect(mediaQuery).toEqual(cssVersion); + }); +}); diff --git a/internals/startingTemplate/src/styles/media.ts b/internals/startingTemplate/src/styles/media.ts index b331b37..bd7cc02 100644 --- a/internals/startingTemplate/src/styles/media.ts +++ b/internals/startingTemplate/src/styles/media.ts @@ -17,7 +17,7 @@ import { */ // Update your breakpoints if you want -const sizes = { +export const sizes = { small: 600, medium: 1024, large: 1440, diff --git a/src/styles/__tests__/media.test.ts b/src/styles/__tests__/media.test.ts new file mode 100644 index 0000000..b1d0c0d --- /dev/null +++ b/src/styles/__tests__/media.test.ts @@ -0,0 +1,14 @@ +import { media, sizes } from '../media'; +import { css } from 'styled-components/macro'; + +describe('media', () => { + it('should return media query in css', () => { + const mediaQuery = media.small`color:red;`.join(''); + const cssVersion = css` + @media (min-width: ${sizes.small}px) { + color: red; + } + `.join(''); + expect(mediaQuery).toEqual(cssVersion); + }); +}); diff --git a/src/styles/media.ts b/src/styles/media.ts index b331b37..bd7cc02 100644 --- a/src/styles/media.ts +++ b/src/styles/media.ts @@ -17,7 +17,7 @@ import { */ // Update your breakpoints if you want -const sizes = { +export const sizes = { small: 600, medium: 1024, large: 1440, From e0240c83f1f5d0a7fd370759c6114b25bdb5044c Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Mon, 18 May 2020 19:34:01 +0300 Subject: [PATCH 17/18] =?UTF-8?q?chore:=20=F0=9F=94=A7=20added=20commit=20?= =?UTF-8?q?hook=20verify=20startingTemplate=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../verify-startingTemplate-changes.ts | 34 +++++++++++++++++++ package.json | 3 +- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 internals/scripts/verify-startingTemplate-changes.ts diff --git a/internals/scripts/verify-startingTemplate-changes.ts b/internals/scripts/verify-startingTemplate-changes.ts new file mode 100644 index 0000000..3a1b24a --- /dev/null +++ b/internals/scripts/verify-startingTemplate-changes.ts @@ -0,0 +1,34 @@ +import shell from 'shelljs'; +import fs from 'fs'; + +interface Options {} + +/* + * Check if the changed files are also updated if they are in the startingTemplate + */ +export function verifyStartingTemplateChanges(opts: Options = {}) { + const gitDiff = shell.exec(`git diff --staged --name-only`, { silent: true }); + const changedFiles = gitDiff.stdout.split('\n'); + for (const file of changedFiles) { + if (file.startsWith(pathInTemplate(''))) { + continue; + } + if (fileIsInStartingTemplate(file)) { + const fileNotChangedInStartingTemplate = + changedFiles.find(f => f === pathInTemplate(file)) === undefined; + if (fileNotChangedInStartingTemplate) { + console.error(`File: ${file} must be updated in the startingTemplate`); + process.exit(1); + } + } + } +} + +function fileIsInStartingTemplate(file: string) { + const path = pathInTemplate(file); + return fs.existsSync(path) && !fs.statSync(path).isDirectory(); +} + +const pathInTemplate = (file: string) => `internals/startingTemplate/${file}`; + +verifyStartingTemplateChanges(); diff --git a/package.json b/package.json index 2c32b42..e823dbd 100755 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "cleanAndSetup": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/clean.ts", "prettify": "prettier --write", "// ---TESTING TEMPLATE---": "", + "verify-startingTemplate-changes": "ts-node --project=./internals/ts-node.tsconfig.json ./internals/scripts/verify-startingTemplate-changes.ts", "test:all": "npm run test -- --watchAll=false", "test:coverage": "npm run test:all -- --coverage", "test:cra": "npm run create:cra-app && cd generated-cra-app && npm run test:generators && npm run lint && npm run checkTs && npm run cleanAndSetup && npm run lint && npm run checkTs", @@ -69,7 +70,7 @@ }, "husky": { "hooks": { - "pre-commit": "npm run checkTs && lint-staged", + "pre-commit": "npm run verify-startingTemplate-changes && npm run checkTs && lint-staged", "prepare-commit-msg": "devmoji -e", "commit-msg": "if git-branch-is dev; then commitlint -E HUSKY_GIT_PARAMS; fi" } From b93ca6647ae2f9dd8441bf69a9e9708ff94248c6 Mon Sep 17 00:00:00 2001 From: Can Sahin Date: Mon, 18 May 2020 19:35:17 +0300 Subject: [PATCH 18/18] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20added=20?= =?UTF-8?q?missing=20things=20in=20startingTemplate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internals/startingTemplate/src/react-app-env.d.ts | 3 +++ .../startingTemplate/src/utils/redux-injectors.ts | 13 ++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/internals/startingTemplate/src/react-app-env.d.ts b/internals/startingTemplate/src/react-app-env.d.ts index 6431bc5..afa73d4 100644 --- a/internals/startingTemplate/src/react-app-env.d.ts +++ b/internals/startingTemplate/src/react-app-env.d.ts @@ -1 +1,4 @@ /// + +// To solve the issue: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31245 +/// diff --git a/internals/startingTemplate/src/utils/redux-injectors.ts b/internals/startingTemplate/src/utils/redux-injectors.ts index 7161480..3aeb104 100644 --- a/internals/startingTemplate/src/utils/redux-injectors.ts +++ b/internals/startingTemplate/src/utils/redux-injectors.ts @@ -10,13 +10,12 @@ import { /* Wrap redux-injectors with stricter types */ -export function useInjectReducer({ - key, - reducer, -}: InjectReducerParams) { - return useReducer({ key, reducer }); +export function useInjectReducer( + params: InjectReducerParams, +) { + return useReducer(params); } -export function useInjectSaga({ key, saga, mode }: InjectSagaParams) { - return useSaga({ key, saga, mode }); +export function useInjectSaga(params: InjectSagaParams) { + return useSaga(params); }