js

  • ES6+ functional programming

  • React localized application

    Language Manager :

    https://github.com/helabenkhalfallah/news_kit_frontend/tree/master/app-settings/language

     

    Localized Strings :

    a. Dico.js => contains used strings inside application in the different supported localization.

    b. Localizations.js => contains supported localizations.

    c. LocalizedString.js => a localized string object : { key, language, value }. We access to a string value by (key, language).

    d. LocalizedStringUtils.js => contains utils methods for localized strings.

    https://github.com/helabenkhalfallah/news_kit_frontend/tree/master/app-settings/localized-strings

     

    Provider :

    https://github.com/helabenkhalfallah/news_kit_frontend/blob/master/pages/_app.js

     

    Consumer :

    https://github.com/helabenkhalfallah/news_kit_frontend/blob/master/pages/mocks/mock-page.jsx

     

  • graphql server (express) with passport & jwt authentication and authorization

    graphql server (express) with passport & jwt authentication and authorization :
    https://github.com/helabenkhalfallah/graphql-server

  • apollo server + mongo (mongoose) + psql (Sequelize)

    A basic project for apollo server + mongo (mongoose) + psql (Sequelize) :
    https://github.com/helabenkhalfallah/apollo-graphql-server-sqlize

    With apollo server we don't need express or any others configurations, just apollo-server and graphql.
    From mongoose to psql, essentially we must changes : models and graphql resolve.


    For more details on how to use sequelize for queries and CRUD :
    https://github.com/helabenkhalfallah/node-express-mongoose-sqlize

  • node + express + mongo (mongoose) + psql (Sequelize)

    A basic project for node + express + mongo (mongoose) + psql (Sequelize) :
    https://github.com/helabenkhalfallah/node-express-mongoose-sqlize

    Routes : / routes
    dbs configs, connections and models : /db 
    CRUD : find, finOne, findById, add only if not exist, edit only if exist, delete only if exist ...

     

    Sequelize more details and documentation :

    http://docs.sequelizejs.com/manual/installation/getting-started.html

    http://javasampleapproach.com/node-js/sequelize-orm-build-crud-restapis-with-nodejs-express-sequelize-mysql

    https://stackoverflow.com/questions/36906500/avoid-created-at-and-updated-at-being-auto-generated-by-sequelize

  • JS - Training examples

    HArray : es6 array new concepts

    ES6 Array

    HAsynAwait: es6 async await concept

    ES6 AsynAwait

    HPromises: es6 async promise concept

    ES6 Promise

    HClasses: es6 class concept

    ES6 Classes

    HDestructing: es6 descruting

    ES6 Destructing

    HGenerators: es6 generators concept

    ES6 Generators

    HIterables: es6 iterables concept

    ES6 Iterables

    HMaps: es6 map/weakmap/set concept

    ES6 Maps

    HMutability: es6 mutability concept

    ES6 Mutability

    HNumbers: es6 numbers concept

    ES6 Numbers

    HParameters: es6 parameters concept

    ES6 Pure Impure

    HSpread: es6 spread concept

    ES6 Spread

    HString: es6 strings concept

    ES6 String

  • How to create a graphql-server

     

    You can find the source code here : 

    https://github.com/helabenkhalfallah/graphql-server

     

    # graphql-server template

    1. install dependencies : 
    npm install graphql express express-graphql --save

    2. configure lint :
    npm install eslint --save-dev
    ./node_modules/.bin/eslint --init

    3. add a /server/server.js file
    in this file we will configure our gql server.
    we start by configure a simple express server

    ```
    //express config 
    const express = require('express')
    const expressGraphQL = require('express-graphql')

    // Create an express instance
    const app = express()

    // Connect with graphql and the graphiql panel
    const gqlPath = process.env.GRAPHQL_APP_PATH || '/graphql'
    console.log('gqlPath : ', gqlPath)
    app.use(gqlPath, expressGraphQL({
      graphiql: true
    }))

    // Start server
    const portNumber = process.env.GRAPHQL_APP_PORT || 4000
    console.log('portNumber : ', portNumber)
    app.listen(portNumber, () => {
      console.log('Server is running...')
    })
    ```

    4. configure dotenv :
    npm install dotenv --save
    in index.js file and before any load :

    ```
    //dot env configuration
    var dotenv = require('dotenv')
    dotenv.load()
    console.log('Your environment variable GRAPHQL_APP_PATH has the value: ', process.env.GRAPHQL_APP_PATH)

    //launch server after loading env var
    require('./server/server.js')
    ```

    5. add cors, mongoose and bluebird
    npm install cors mongoose bluebird --save

    6. add models folder which will contains all mongoose schema.
    7. add graphql folder which will contains all gql schema & CRUD.
    8. all models defined on models are exported on a single module inside index.js.
    9. all schem & CRUD defined on graphql are exported on a single module inside index.js.
    10. Define all constant inside .env file.
    11. add babel to run ES6
    npm install --save-dpev babel-cli
    npm install --save-dev babel-preset-es2015
    npm install --save-dev babel-preset-stage-0

    12. add  .babelrc

    ```
    {
      "presets": ["es2015", "stage-0"]
    }
    ```

    13. modify package.json to run with babel
    14. add nodemon so that it will automatically reload the app on everychange
    npm install --save-dev nodemon
    https://javierfernandes.gitbooks.io/rest-api-babel-express/content/nodeapp.html

    15. mongo database preparation :
    https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/
    https://stackoverflow.com/questions/2518127/how-do-i-reload-bashrc-without-logging-out-and-back-in

    16. install Robomongo
    17. customize logger file
    npm install morgan winston winston-daily-rotate-file --save
    18. Test express default route - create a route file : AppRouter.js.
    19. Test express default route - modify server.js :

    ```
    //routes
    app.use('/users', AppRouter) 
    app.use('/photos', AppRouter)

    //route index
    app.get('/', (req, res) => {
      res.send('Invalid endpoint!')
    })
    ```

    20. prepare graphql types
    21. link mongoose schema to graphql types and mongoose models using queries and mutation.
    22. modify server.js for gql endpoint :

    ```
    app.use('/graphql', cors(), expressGraphQL({
      schema: UsergqlProvider.UserQueries.UsersListQuery,
      rootValue: global,
      graphiql: true
    }))
    ```

    A single endpoint, every things is handled internaly inside gql : queries and mutations !

    23. I found an issue firstly when calling find, I got an empty result.
    I resolved this by adding collection name on mongoose models :

    ```
    let userSchema = mongoose.Schema(
      {
        first_name: String,
        last_name: String,
        birthdaye: String,
        job: String,
      },
      {
        collection: 'User'
      })
    ```

    ```
    let photoSchema = mongoose.Schema(
      {
        url: String,
        description: String,
        date: String,
      },
      {
        collection: 'Photo'
      })
    ```

  • Best practices snippets

    Replacing switch statements or multiple if with Object literals

    Bad way - switch :

    switch(type) {
    case 'coke':
      drink = 'Coke';
      break;
    case 'pepsi':
      drink = 'Pepsi';
      break;
    default:
      drink = 'Unknown drink!';
    }

     

    Bad way - multiple If :

    function getDrink (type) {
      if (type === 'coke') {
        type = 'Coke';
      } else if (type === 'pepsi') {
        type = 'Pepsi';
      } else if (type === 'mountain dew') {
        type = 'Mountain Dew';
      } else if (type === 'lemonade') {
        type = 'Lemonade';
      } else if (type === 'fanta') {
        type = 'Fanta';
      } else {
        // acts as our "default"
        type = 'Unknown drink!';
      }
      return 'You\'ve picked a ' + type;
    }

     

    Better way :

    function getDrink (type) {
      var drinks = {
        'coke': 'Coke',
        'pepsi': 'Pepsi',
        'lemonade': 'Lemonade',
        'default': 'Default item'
      };
      return 'The drink I chose was ' + (drinks[type] || drinks['default']);
    }

     

    Null, Undefined, Empty Checks Shorthand

    This  code :

    let variable1 = "";
    let variable2 = "12";
    if (variable1 !== null && variable1 !== undefined && variable1 !== "") {
      variable2 = variable1;
    }
    console.log({ variable1, variable2 });

     

    Can be replaced simply by :

    let variable1 = "";
    let variable2 = variable1 || "default";
    console.log({ variable1, variable2 });

     

    Clone an Object Using Spread

    let user = {
      first: "chris",
      last: "burgin"
    }
    let userCopy = {...user}; // new object, not by ref

  • Best practices snippets

    Never Bind in Render

    <MyComponent onClick={(id) => this.onClick(id)} />  

    Issue :

    By binding your event handlers like this, you create brand new functions every time React calls your component’s render.

    Solution : bind functions outside of render.

     

    Unnecessary render

    <Component {...props}>

    Issue :

    When container state change : all childs will been rendered (shouldComponentUpdate return true). Unnecessary render.

    Solution : pass only necessary props :

    <Component necessary={props} >

     

    Never define style in Render

    <MyComponent style={ { margin: 0 } } />  

    Issue :

    New object with margin zero is created on every render.

    New object → new reference.

    Solution : define constants outside of render :

    const myStyle = {margin : 0}; →  outside of render.
    <MyComponent style={myStyle} />

     

    PureComponent

    React.PureComponent is similar to React.Component. 
    The difference between them is that React.Component doesn’t implement shouldComponentUpdate(), but React.PureComponent implements it with a shallow prop and state comparison.

    React.PureComponent’s shouldComponentUpdate() only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences.

    Only extend PureComponent when you expect to have simple props and state.

    https://reactjs.org/docs/react-api.html#reactpurecomponent

     

    React/Redux performance tip - Dan Abramov‏ -

    Component separation can make a much bigger difference than manual shouldComponentUpdate() everywhere.

     

    Smarter updates

    shouldComponentUpdate give better control over the component’s update cycle by comparing the upcoming props and state from the current ones.

    Whatever you do inside shouldComponentUpdate, do it fast. Avoid expensive operations and go directly to shallow comparisons.

  • JS - Best Practices (let, const and var)

     

    let and const are block scoped.

    Therefore, referencing block-scoped identifiers before they are defined will produce a ReferenceError.

    console.log(x); // ReferenceError: x is not defined
    let x = 'hi';

    // const and let only exist in the blocks they are defined in.
    {
    let a = 1;
    const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError

     

    Use const for all references; avoid using var.
    If you must reassign references, use let instead of var.
    let is block-scoped rather than function-scoped like var.

    Bad :

    var count = 1;
    if (true) {
    count += 1;
    }

    Good :

    // good, use the let.     
    let count = 1;
    if (true) {
         count += 1;
    }

     
    Read More :

  • Arrow functions

     

    One of the most anticipated new features in the ES6 Javascript standard was the Arrow Function Expression.

    It promises a shorter syntax than it's predecessor the Function Expression.


    Exemple : get length of each string inside an array

    let celebrities = ['Steve Jobs','Albert Einsten','Nicolas Tesla'];     

    //ES5

    const lengthES5 = celebrities.map(function(celebrity) {

      return celebrity.length;

    });

    console.log(lengthES5); //[ 10, 14, 13 ]


    //ES6
    const lengthES6 = celebrities.map(celebrity => {

      return celebrity.length;

    });

    console.log(lengthES6); //[ 10, 14, 13 ]


    //ES6 much better [ 10, 14, 13 ]
    celebrities.map(celebrity => celebrity.length);

     
    Sandbox :

    Arrow Functions lexically bind their context so this actually refers to the originating context :


    /* Function Object Context */
    var sciences = ['Physics','Chemistry','Math'];
    var searchedScience = 'Math';
    console.log(sciences)
    console.log(searchedScience)

    /* ES5 Function Object Context */
    //solution 1
    var self = this;
    this.sciences.forEach(function(science) {
        if(self.searchedScience === science){
              console.log('Founded Science 1: ', science)
        }else{
              console.log('Not Searched Science 1: ', science)
       }
    });

    //solution 2
    this.sciences.forEach(function(science) {
       if(self.searchedScience === science){
           console.log('Founded Science 2: ', science)
       }else{
           console.log('Not Searched Science 2: ', science)
       }
    }, this);

    //solution 3
    this.sciences.forEach(function(science) {
         if(self.searchedScience === science){
           console.log('Founded Science 3: ', science)
         }else{
           console.log('Not Searched Science 3: ', science)
        }
    }.bind(this));

    /* ES6 Function Object Context */
    this.sciences.forEach((science) => {
       if(this.searchedScience === science){
          console.log('ES6 Founded Science: ', science)
       }else{
          console.log('ES6 Not Searched Science: ', science)
      }
    });

  • JS - Best Practices (Importing/Exporting in ES6)

    Importing with ES6 :

    ES6 provides us with various flavors of importing :

    We can import an entire file :

    import 'underscore';


    Named imports :

    import { sumTwo, sumThree } from 'math/addition';

     

    Rename the named imports :

    import {
    sumTwo as addTwoNumbers,
    sumThree as sumThreeNumbers 
    } from 'math/addition';

     

    Import all the things (also called namespace import) :

    import * as util from 'math/addition';

     

    Import a list of values from a module :

    import * as additionUtil from 'math/addition';
    const { sumTwo, sumThree } = additionUtil;

     

    Exporting with ES6 :

    With ES6, we have various flavors of exporting :

    Named Exports :

    export let name = 'David';
    export let age = 25;​​

     

    Exporting a list :

    function sumTwo(a, b) {
        return a + b;
    }

    function sumThree(a, b, c) {
       return a + b + c;
    }

    export { sumTwo, sumThree }; 

     

    Export functions, objects and values (etc.) simply by using the export keyword :

    export function sumTwo(a, b) {
         return a + b;
    }

    export function sumThree(a, b, c) {
        return a + b + c;
    }

     

    Export default bindings :

    function sumTwo(a, b) {
        return a + b;
    }

    function sumThree(a, b, c) {
       return a + b + c;
    }

    let api = {
      sumTwo,
      sumThree
    };


    export default api;

    /* Which is the same as

    export { api as default };

    */

     

    Always use the export default method at the end of the module. It makes it clear what is being exported, and saves time by having to figure out what name a value was exported as.

     

  • JS - Best Practices (String)

     

    Use single quotes '' for strings.

    // bad
    const name = "My String";

    // bad - template literals should contain interpolation or newlines
    let text = `This string contains "double quotes" which don't need to be escaped anymore.`;     

    // good
    const name = 'My String';

     

    .includes( )

    Instead of checking for a return value > -1 to denote string containment, we can simply use .includes() which will return a boolean:

    const string = 'food';
    const substring = 'foo';
    console.log(string.includes(substring)); // true  

     

    .repeat( )

    // String.repeat(numberOfRepetitions)
    'meow'.repeat(3); // 'meowmeowmeow'  

     

  • JS - Best Practices (Destructuring)

     

    Destructuring allows to extract values from arrays and objects (even deeply nested) and store them in variables with a more convenient syntax.

     

    Destructuring Arrays :

    Old :

    var arr = [1, 2, 3, 4];
    var a = arr[0];
    var b = arr[1];
    var c = arr[2];
    var d = arr[3];

    ES6:

    let [a, b, c, d] = [1, 2, 3, 4];   

    console.log(a); // 1
    console.log(b); // 2

     

    Destructuring Objects :

    Old :

    var luke = { occupation: 'jedi', father: 'anakin' };       
    var occupation = luke.occupation; // 'jedi'
    var father = luke.father; // 'anakin'

    ES6:

    let luke = { occupation: 'jedi', father: 'anakin' };
    let {occupation, father} = luke;

    console.log(occupation); // 'jedi'
    console.log(father); // 'anakin'

     
    Read More:
     

  • JS - Best Practices (Shortcut Notations)

     

    Bad :

    var lunch = new Array();
    lunch[0]='Dosa';
    lunch[1]='Roti';
    lunch[2]='Rice';
    lunch[3]='what the heck is this?';

    Good :

    let lunch = [
    'Dosa',
    'Roti',
    'Rice',
    'what the heck is this?'
    ];

     

    Bad :

    if(v){

       var x = v;

    } else {

       var x =10;

    }

    Good :

    let x = v || 10;     

     

    Bad :

    var direction;
    if(x > 100){
    direction = 1;
    } else {
    direction = -1;
    }

    Good :

    let direction = (x > 100) ? 1 : -1;

     

  • JS - Best Practices (Encapsulate conditionals)

     

    Bad :

    if (fsm.state === 'fetching' && isEmpty(listNode)) {
          // ...
    }

    Correct :

    function shouldShowSpinner(fsm, listNode) {
          return fsm.state === 'fetching' && isEmpty(listNode);
    }

    if (shouldShowSpinner(fsmInstance, listNodeInstance)) {  
         // ...
    }

     

  • JS - Best Practices (Side effects)

    Accidentally modifying global variable :

    Bad :

    // Global variable referenced by following function.
    // If we had another function that used this name, now it'd be an array and it could break it.
    let name = 'Ryan McDermott';

    function splitIntoFirstAndLastName() {
        name = name.split(' ');
    }

    splitIntoFirstAndLastName();
    console.log(name); // ['Ryan', 'McDermott'];

    Correct :

    function splitIntoFirstAndLastName(name) {
         return name.split(' ');
    }

    const name = 'Ryan McDermott';
    const newName = splitIntoFirstAndLastName(name);

    console.log(name); // 'Ryan McDermott';
    console.log(newName); // ['Ryan', 'McDermott'];

     

    In JavaScript, primitives are passed by value and objects/arrays are passed by reference :

    Bad :

    //any other function that uses that cart array will be affected by this addition.
    const addItemToCart = (cart, item) => {
          cart.push({ item, date: Date.now() });
    };

    Correct :

    //clone the cart, edit it, and return the clone
    const addItemToCart = (cart, item) => {
         return [...cart, { item, date: Date.now() }];
    };

     

  • JS - Best Practices (Async Code)

     

    Use Promises whenever you can : instead of writing nested callbacks, you can have chainable Promise calls.

    Avoid :

    asyncFunc1((err, result1) => {
      asyncFunc2(result1, (err, result2) => {  
        asyncFunc3(result2, (err, result3) => {   
          console.lor(result3) })
    }) })


    Prefer :

    asyncFuncPromise1()
    .then(asyncFuncPromise2)
    .then(asyncFuncPromise3)
    .then((result) => console.log(result))
    .catch((err) => console.error(err))

     

    You can use async/await also :

    var foo = async (function() {
    var resultA = await (firstAsyncCall());
    var resultB = await (secondAsyncCallUsing(resultA));
    var resultC = await (thirdAsyncCallUsing(resultB));
           return doSomethingWith(resultC);
    });

     

×