shaman-online-meeting v0.0.1
#Install
- Copy
src/config.json.dist
tosrc/config.json
- Run
npm install
#Production
- Copy
src/config.json.dist
tosrc/config.json
- Run
npm run clean && npm run build
#Development
- Configure IDE
* If you use IDE by JetBrains, you can import settings for auto formatting code. File to import
docs/IDEA_JS_airbnb.xml
- To start development:
Use
npm start
, it run webpack dev server in watch mode. Webpack in watch mode will recompile project whenever one of files changes. Wait until webpack compile project. Project been available at localhost:YOUR_PORT Default port for development server is 3000, if you want change it usenpm start -- --port YOUR_PORT
#Npm scripts
To run script use npm run SCRIPT_NAME
.
Available scripts:
- clean - remove all files from dist folder
- start - run webpack dev server
- test - run karma tests
- build - build project for production
- js-lint - run ESLint
- js-lint-fix - run ESLint in fix mode
- sort-styles - sort styles
- style-lint - run Stylelint
- all-lint - run all linters
- all-test - run tests and all linters
#Redux
Actions
- We use redux-actions for create actions, it create actions in accordance FSA
- We use helpers for create AJAX and CRUD actions see
actions/helpers
file for details
Middlewares
List of used middlewares:
- stringifyQueryParams - use for stringify queryParam
q
- tokens - add token from state (
app.token
) toAPI_CALL
actions
##Services
- url - service for generate full url`s
- api - service for send AJAX requests
- schemas - schemas description for normalize data via
normalizr
##AJAX API
###Ajax api data flow
###How send AJAX request and process response
- Create action with
API_CALL
key
#!javascript
import { API_READ, API_CALL } from 'services/api';
import { SCHEMA } from 'services/schemas'
const actionsTypes = {
'SUCCESS':'MY_TEST_ACTION_SUCCESS', // with this action type will called if request ok
'FAILURE':'MY_TEST_ACTION_FAILURE', // with this action type will called if request failure
};
//in general you should use action creators for that, but we consider clear action
const action = {
type:'MY_TEST_ACTION_REQUEST'
payload:{
[API_CALL]: { // you should use API_CALL imported from services/api
method: API_READ, // for more methods see services/api
endpoint: '/test_url',
actions: actionsTypes,
schema: SCHEMA, //data from success response will normalized in accordance this schema
// you can use queryParams, body and etc
},
}
}
- Call
store.dispatch(action)
- Action pass through reducers, if you want, you can create reducer which will change state in accordance action(for example isInProgress flag)
- Action will processing
sagas/api
saga will create request to server viaservices/api
services/api
send request to server(if action hasschema
key, response data will be normalized) * if response ok - saga dispatch actionMY_TEST_ACTION_SUCCESS
, elseMY_TEST_ACTION_FAILURE
- If you want, you can create reducers for
MY_TEST_ACTION_SUCCESS
orMY_TEST_ACTION_FAILURE
, response from server will be available inpayload.response
Normalize data
We use Normalizr for normalize data from server.
This will make it easier to follow Redux principle "Single source of truth"
See normalizr
docs for details
##Notify API TODO
#JS
- We use Airbnb JavaScript Style Guide with some exceptions (see .eslintrc.json for details)
- Check your code with ESlint, to run ESLint use
npm run js-lint
. ESLint can fix some problems, for do this runnpm run js-lint-fix
- We comment code with JSDoc. Use
@typedef
for comment reusable types, if your type - global, store it indocs/types
#CSS
- Use kebab-case for selectors names
- We use SCSS preprocessor
- We use React CSS Modules to isolate components class names from each other.
This means what all selectors in your CSS(SCSS) will transform with hash, for example:
my-cool-selector -> my_cool-selector_jhsd_3
. To work with that selectors useCSSModules
decorator, andstyleName
attribute insteadclassName
Prefers class based selector instead tag name based selectors. Why? You may rewrite styles in child components, because tag name based selectors is not transformed. - We use Autoprefixer to automatic add vendor prefixes to CSS rules. Forget about
display: -ms-flexbox
write justdisplay: flex
and Autoprefixer will all work done for you - We use PostCSS Sorting to sort rules content with specified order. Run
npm run sort-styles
to sort styles before push commits to server - Check your styles with Stylelint, to run Stylelint use
npm run style-lint
.
#Tests
- We use Karma as test runner, this allows testing app in different environments
- We use Power-assert as assertion library, it makes errors output much more convenient
- We use SinonJs for mocks, spyes, stubs and etc.
- For start test use
npm test
, this run run Karma in watch mode, Karma executing the tests whenever one of files changes. Set NODE_ENV=CI if you want run tests in CI - All tests files:
must have the ending
.test.js
. for examplemyFirstTest.test.js
must be in directory__tests__
*__tests__
directory must be on the same level with the test file - To tests Redux middlewares use helpers
middlewares/__tests__/helpers
to dispatch your actions with fake store
Best practices )))
UI Components
Sometimes we need reusable UI components which:
- Stores data in global store during lifetime
- Clean up store when destroy
- Can dispatch actions, specified for this UI component
For example consider create LoginForm component. It should be able:
- Send data to API server
- Show spinner until request finished
- Show error message if auth failed
###Actions Actions for ui components store in actions/ui.
Create two actions in actions/ui/loginForm
- UI_LOGIN_FORM_ACTIVATE - will fire when component mount to DOM
- UI_LOGIN_FORM_DEACTIVATE - will fire when component unmount from DOM
Reducer
Reduces for ui components store in reducers/ui.
Create reducer in reducers/ui/loginForm
, It will do:
- Fill init state when
UI_LOGIN_FORM_ACTIVATE
- Clean state when
UI_LOGIN_FORM_DEACTIVATE
- Set
isInProgress
whenLOGIN_START_REQUEST
- Unset
isInProgress
whenLOGIN_START_SUCCESS
- Unset
isInProgress
and fillerrorMessage
whenLOGIN_START_FAILED
###Containers
Create container component in containers
. Connect it to state with following options:
- actionCreators: uiActivate uiDeactivate * startLogin(this action send ajax request to server)
- slice from state
ui.loginForm
###Result As result we will have component which incapsulate all the functionality in one place, and does not pollute global state
4 years ago