Monthly Archives: August 2018

Java and MongoDB 4.0 Support for Multi-Document ACID Transactions

By Maxime Beugnet

MongoDB 4.0 adds support for multi-document ACID transactions.

But wait… Does that mean MongoDB did not support transactions until now? No, actually MongoDB has always supported transactions in the form of single document transactions. MongoDB 4.0 extends these transactional guarantees across multiple documents, multiple statements, multiple collections, and multiple databases. What good would a database be without any form of transactional data integrity guarantee?

Before we dive into this blog post, you can find all the code and try multi-document ACID transactions here.

Quick start

Step 1: Start MongoDB

Start a single node MongoDB ReplicaSet in version 4.0.0 minimum on localhost, port 27017.

If you use Docker:

  • You can use start-mongo.sh.
  • When you are done, you can use stop-mongo.sh.
  • If you want to connect to MongoDB with the Mongo Shell, you can use connect-mongo.sh.

If you prefer to start mongod manually:

  • mkdir /tmp/data && mongod --dbpath /tmp/data --replSet rs
  • mongo --eval 'rs.initiate()'

Step 2: Start Java

This demo contains two main programs: ChangeStreams.java and Transactions.java.

  • Change Steams allow you to be notified of any data changes within a MongoDB collection or database.
  • The Transaction process is the demo itself.

You need two shells to run them.

If you use Docker:

First shell:

./compile-docker.sh
./change-streams-docker.sh

Second shell:

./transactions-docker.sh

If you do not use Docker, you will need to install Maven 3.5.X and a JDK 10 (or JDK 8 minimum but you will need to update the Java versions in the pom.xml):

First shell:

./compile.sh
./change-streams.sh

Second shell:

./transactions.sh

Let’s compare our existing single document transactions with MongoDB 4.0’s ACID compliant multi-document transactions and see how we can leverage this new feature with Java.

Prior to MongoDB 4.0

Even in MongoDB 3.6 and earlier, every write operation is represented as a transaction scoped to the level of an individual document in the storage layer. Because the document model brings together related data that would otherwise be modeled across separate parent-child tables in a tabular schema, MongoDB’s atomic single-document operations provide transaction semantics that meet the data integrity needs of the majority of applications.

Every typical write operation modifying multiple documents actually happens in several independent transactions: one for each document.

Let’s take an example with a very simple stock management application.

First of all, I need a MongoDB Replica Set so please follow the instructions given above to start MongoDB.

Now let’s insert the following documents into a product collection:

MongoDB Enterprise rs:PRIMARY> db.product.insertMany([
    { "_id" : "beer", "price" : NumberDecimal("3.75"), "stock" : NumberInt(5) }, 
    { "_id" : "wine", "price" : NumberDecimal("7.5"), "stock" : NumberInt(3) }
])

Let’s imagine there is a sale on and we want to offer our customers a 20% discount on all our products.

But before applying this discount, we want to monitor when these operations are happening in MongoDB with Change Streams.

Execute the following in Mongo Shell:

cursor = db.product.watch([{$match: {operationType: "update"}}]);
while (!cursor.isExhausted()) {
    if (cursor.hasNext()) {
    print(tojson(cursor.next()));
    }
}

Keep this shell on the side, open another Mongo Shell and apply the discount:

PRIMARY> db.product.updateMany({}, {$mul: {price:0.8}})
{ "acknowledged" : true, "matchedCount" : 2, "modifiedCount" : 2 }
PRIMARY> db.product.find().pretty()
{
    "_id" : "beer",
    "price" : NumberDecimal("3.00000000000000000"),
    "stock" : 5
}
{
    "_id" : "wine",
    "price" : NumberDecimal("6.0000000000000000"),
    "stock" : 3
}

As you can see, both documents were updated with a single command line but not in a single transaction. Here is what we can see in the Change Stream shell:

{
    "_id" : {
        "_data" : "825B4637290000000129295A1004374DC58C611E4C8DA4E5EDE9CF309AC5463C5F6964003C62656572000004"
    },
    "operationType" : "update",
    "clusterTime" : Timestamp(1531328297, 1),
    "ns" : {
        "db" : "test",
        "coll" : "product"
    },
    "documentKey" : {
        "_id" : "beer"
    },
    "updateDescription" : {
        "updatedFields" : {
            "price" : NumberDecimal("3.00000000000000000")
        },
        "removedFields" : [ ]
    }
}
{
    "_id" : {
        "_data" : "825B4637290000000229295A1004374DC58C611E4C8DA4E5EDE9CF309AC5463C5F6964003C77696E65000004"
    },
    "operationType" : "update",
    "clusterTime" : Timestamp(1531328297, 2),
    "ns" : {
        "db" : "test",
        "coll" : "product"
    },
    "documentKey" : {
        "_id" : "wine"
    },
    "updateDescription" : {
        "updatedFields" : {
            "price" : NumberDecimal("6.0000000000000000")
        },
        "removedFields" : [ ]
    }
}

As you can see the cluster times (see the clusterTime key) of the two operations are different: the operations occurred during the same second but the counter of the timestamp has been incremented by one.

Thus here each document is updated one at a time and even if this happens really fast, someone else could read the documents while the update is running and see only one of the two products with the discount.

Most of the time, it is something you can tolerate in your MongoDB database because, as much as possible, we try to embed tightly linked, or related data in the same document. As a result, two updates on the same document happen within a single transaction :

PRIMARY> db.product.update({_id: "wine"},{$inc: {stock:1}, $set: {description : "It's the best wine on Earth"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
PRIMARY> db.product.findOne({_id: "wine"})
{
    "_id" : "wine",
    "price" : NumberDecimal("6.0000000000000000"),
    "stock" : 4,
    "description" : "It's the best wine on Earth"
}

However, sometimes, you cannot model all of your related data in a single document, and there are a lot of valid reasons for choosing not to embed documents.

MongoDB 4.0 with multi-document ACID transactions

Multi-document ACID transactions in MongoDB are very similar to what you probably already know from traditional relational databases.

MongoDB’s transactions are a conversational set of related operations that must atomically commit or fully rollback with all-or-nothing execution.

Transactions are used to make sure operations are atomic even across multiple collections or databases. Thus, with snapshot isolation reads, another user can only see all the operations or none of them.

Let’s now add a shopping cart to our example.

For this example, 2 collections are required because we are dealing with 2 different business entities: the stock management and the shopping cart each client can create during shopping. The lifecycle of each document in these collections is different.

A document in the product collection represents an item I’m selling. This contains the current price of the product and the current stock. I created a POJO to represent it : Product.java.

{ "_id" : "beer", "price" : NumberDecimal("3"), "stock" : NumberInt(5) }

A shopping cart is created when a client adds its first item in the cart and is removed when the client proceeds to checkout or leaves the website. I created a POJO to represent it : Cart.java.

{
    "_id" : "Alice",
    "items" : [
        {
            "price" : NumberDecimal("3"),
            "productId" : "beer",
            "quantity" : NumberInt(2)
        }
    ]
}

The challenge here resides in the fact that I cannot sell more than I possess: if I have 5 beers to sell, I cannot have more than 5 beers distributed across the different client carts.

To ensure that, I have to make sure that the operation creating or updating the client cart is atomic with the stock update. That’s where the multi-document transaction comes into play. The transaction must fail in the case someone tries to buy something I do not have in my stock. I will add a constraint on the product stock:

db.createCollection("product", {
    validator: {
        $jsonSchema: {
            bsonType: "object",
            required: [ "_id", "price", "stock" ],
            properties: {
            _id: {
                bsonType: "string",
                description: "must be a string and is required"
            },
            price: {
                bsonType: "decimal",
                minimum: 0,
                description: "must be a positive decimal and is required"
            },
            stock: {
                bsonType: "int",
                minimum: 0,
                description: "must be a positive integer and is required"
            }
            }
        }
    }
})

Node that this is already included in the Java code.

To monitor our example, we are going to use MongoDB Change Streams that were introduced in MongoDB 3.6.

In each of the threads of this process called ChangeStreams.java, I am going to monitor one of the 2 collections and print each operation with its associated cluster time.

// package and imports

public class ChangeStreams {

    private static final Bson filterUpdate = Filters.eq("operationType", "update");
    private static final Bson filterInsertUpdate = Filters.in("operationType", "insert", "update");
    private static final String jsonSchema = "{ $jsonSchema: { bsonType: "object", required: [ "_id", "price", "stock" ], properties: { _id: { bsonType: "string", description: "must be a string and is required" }, price: { bsonType: "decimal", minimum: 0, description: "must be a positive decimal and is required" }, stock: { bsonType: "int", minimum: 0, description: "must be a positive integer and is required" } } } } ";

    public static void main(String[] args) {
        MongoDatabase db = initMongoDB(args[0]);
        MongoCollection<Cart> cartCollection = db.getCollection("cart", Cart.class);
        MongoCollection<Product> productCollection = db.getCollection("product", Product.class);
        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.submit(() -> watchChangeStream(productCollection, filterUpdate));
        executor.submit(() -> watchChangeStream(cartCollection, filterInsertUpdate));
        ScheduledExecutorService scheduled = Executors.newSingleThreadScheduledExecutor();
        scheduled.scheduleWithFixedDelay(System.out::println, 0, 1, TimeUnit.SECONDS);
    }

    private static void watchChangeStream(MongoCollection<?> collection, Bson filter) {
        System.out.println("Watching " + collection.getNamespace());
        List<Bson> pipeline = Collections.singletonList(Aggregates.match(filter));
        collection.watch(pipeline)
                    .fullDocument(FullDocument.UPDATE_LOOKUP)
                    .forEach((Consumer<ChangeStreamDocument<?>>) doc -> System.out.println(
                            doc.getClusterTime() + " => " + doc.getFullDocument()));
    }

    private static MongoDatabase initMongoDB(String mongodbURI) {
        getLogger("org.mongodb.driver").setLevel(Level.SEVERE);
        CodecRegistry providers = fromProviders(PojoCodecProvider.builder().register("com.mongodb.models").build());
        CodecRegistry codecRegistry = fromRegistries(MongoClient.getDefaultCodecRegistry(), providers);
        MongoClientOptions.Builder options = new MongoClientOptions.Builder().codecRegistry(codecRegistry);
        MongoClientURI uri = new MongoClientURI(mongodbURI, options);
        MongoClient client = new MongoClient(uri);
        MongoDatabase db = client.getDatabase("test");
        db.drop();
        db.createCollection("cart");
        db.createCollection("product", productJsonSchemaValidator());
        return db;
    }

    private static CreateCollectionOptions productJsonSchemaValidator() {
        return new CreateCollectionOptions().validationOptions(
                new ValidationOptions().validationAction(ValidationAction.ERROR).validator(BsonDocument.parse(jsonSchema)));
    }
}

In this example we have 5 beers to sell. Alice wants to buy 2 beers but we are not going to use the new MongoDB 4.0 multi-document transactions for this. We will observe in the change streams two operations : one creating the cart and one updating the stock at 2 different cluster times.

Then Alice adds 2 more beers in her cart and we are going to use a transaction this time. The result in the change stream will be 2 operations happening at the same cluster time.

Finally, she will try to order 2 extra beers but the jsonSchema validator will fail the product update and result in a rollback. We will not see anything in the change stream. Here is the Transaction.java source code:

// package and import

public class Transactions {

    private static MongoClient client;
    private static MongoCollection<Cart> cartCollection;
    private static MongoCollection<Product> productCollection;

    private final BigDecimal BEER_PRICE = BigDecimal.valueOf(3);
    private final String BEER_ID = "beer";

    private final Bson stockUpdate = inc("stock", -2);
    private final Bson filterId = eq("_id", BEER_ID);
    private final Bson filterAlice = eq("_id", "Alice");
    private final Bson matchBeer = elemMatch("items", eq("productId", "beer"));
    private final Bson incrementBeers = inc("items.$.quantity", 2);

    public static void main(String[] args) {
        initMongoDB(args[0]);
        new Transactions().demo();
    }

    private static void initMongoDB(String mongodbURI) {
        getLogger("org.mongodb.driver").setLevel(Level.SEVERE);
        CodecRegistry codecRegistry = fromRegistries(MongoClient.getDefaultCodecRegistry(), fromProviders(
                PojoCodecProvider.builder().register("com.mongodb.models").build()));
        MongoClientOptions.Builder options = new MongoClientOptions.Builder().codecRegistry(codecRegistry);
        MongoClientURI uri = new MongoClientURI(mongodbURI, options);
        client = new MongoClient(uri);
        MongoDatabase db = client.getDatabase("test");
        cartCollection = db.getCollection("cart", Cart.class);
        productCollection = db.getCollection("product", Product.class);
    }

    private void demo() {
        clearCollections();
        insertProductBeer();
        printDatabaseState();
        System.out.println("#########  NO  TRANSACTION #########");
        System.out.println("Alice wants 2 beers.");
        System.out.println("We have to create a cart in the 'cart' collection and update the stock in the 'product' collection.");
        System.out.println("The 2 actions are correlated but can not be executed on the same cluster time.");
        System.out.println("Any error blocking one operation could result in stock error or beer sale we don't own.");
        System.out.println("---------------------------------------------------------------------------");
        aliceWantsTwoBeers();
        sleep();
        removingBeersFromStock();
        System.out.println("####################################n");
        printDatabaseState();
        sleep();
        System.out.println("n######### WITH TRANSACTION #########");
        System.out.println("Alice wants 2 extra beers.");
        System.out.println("Now we can update the 2 collections simultaneously.");
        System.out.println("The 2 operations only happen when the transaction is committed.");
        System.out.println("---------------------------------------------------------------------------");
        aliceWantsTwoExtraBeersInTransactionThenCommitOrRollback();
        sleep();
        System.out.println("n######### WITH TRANSACTION #########");
        System.out.println("Alice wants 2 extra beers.");
        System.out.println("This time we do not have enough beers in stock so the transaction will rollback.");
        System.out.println("---------------------------------------------------------------------------");
        aliceWantsTwoExtraBeersInTransactionThenCommitOrRollback();
        client.close();
    }

    private void aliceWantsTwoExtraBeersInTransactionThenCommitOrRollback() {
        ClientSession session = client.startSession();
        try {
            session.startTransaction(TransactionOptions.builder().writeConcern(WriteConcern.MAJORITY).build());
            aliceWantsTwoExtraBeers(session);
            sleep();
            removingBeerFromStock(session);
            session.commitTransaction();
        } catch (MongoCommandException e) {
            session.abortTransaction();
            System.out.println("####### ROLLBACK TRANSACTION #######");
        } finally {
            session.close();
            System.out.println("####################################n");
            printDatabaseState();
        }
    }

    private void removingBeersFromStock() {
        System.out.println("Trying to update beer stock : -2 beers.");
        try {
            productCollection.updateOne(filterId, stockUpdate);
        } catch (MongoCommandException e) {
            System.out.println("#####   MongoCommandException  #####");
            System.out.println("##### STOCK CANNOT BE NEGATIVE #####");
            throw e;
        }
    }

    private void removingBeerFromStock(ClientSession session) {
        System.out.println("Trying to update beer stock : -2 beers.");
        try {
            productCollection.updateOne(session, filterId, stockUpdate);
        } catch (MongoCommandException e) {
            System.out.println("#####   MongoCommandException  #####");
            System.out.println("##### STOCK CANNOT BE NEGATIVE #####");
            throw e;
        }
    }

    private void aliceWantsTwoBeers() {
        System.out.println("Alice adds 2 beers in her cart.");
        cartCollection.insertOne(new Cart("Alice", Collections.singletonList(new Cart.Item(BEER_ID, 2, BEER_PRICE))));
    }

    private void aliceWantsTwoExtraBeers(ClientSession session) {
        System.out.println("Updating Alice cart : adding 2 beers.");
        cartCollection.updateOne(session, and(filterAlice, matchBeer), incrementBeers);
    }

    private void insertProductBeer() {
        productCollection.insertOne(new Product(BEER_ID, 5, BEER_PRICE));
    }

    private void clearCollections() {
        productCollection.deleteMany(new BsonDocument());
        cartCollection.deleteMany(new BsonDocument());
    }

    private void printDatabaseState() {
        System.out.println("Database state:");
        printProducts(productCollection.find().into(new ArrayList<>()));
        printCarts(cartCollection.find().into(new ArrayList<>()));
        System.out.println();
    }

    private void printProducts(List<Product> products) {
        products.forEach(System.out::println);
    }

    private void printCarts(List<Cart> carts) {
        if (carts.isEmpty())
            System.out.println("No carts...");
        else
            carts.forEach(System.out::println);
    }

    private void sleep() {
        System.out.println("Sleeping 3 seconds...");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            System.err.println("Oups...");
            e.printStackTrace();
        }
    }
}

Here is the console of the Change Stream :

$ ./change-streams.sh 

Watching test.cart
Watching test.product

Timestamp{value=6570052721557110786, seconds=1529709604, inc=2} => Cart{id='Alice', items=[Item{productId=beer, quantity=2, price=3}]}

Timestamp{value=6570052734442012673, seconds=1529709607, inc=1} => Product{id='beer', stock=3, price=3}

Timestamp{value=6570052764506783745, seconds=1529709614, inc=1} => Product{id='beer', stock=1, price=3}
Timestamp{value=6570052764506783745, seconds=1529709614, inc=1} => Cart{id='Alice', items=[Item{productId=beer, quantity=4, price=3}]}

As you can see here, we only get four operations because the two last operations were never committed to the database, and therefore the change stream has nothing to show.

You can also note that the two first cluster times are different because we did not use a transaction for the two first operations, and the two last operations share the same cluster time because we used the new MongoDB 4.0 multi-document transaction system, and thus they are atomic.

Here is the console of the Transaction java process that sum up everything I said earlier.

$ ./transactions.sh 
Database state:
Product{id='beer', stock=5, price=3}
No carts...

#########  NO  TRANSACTION #########
Alice wants 2 beers.
We have to create a cart in the 'cart' collection and update the stock in the 'product' collection.
The 2 actions are correlated but can not be executed on the same cluster time.
Any error blocking one operation could result in stock error or a sale of beer that we can't fulfill as we have no stock.
---------------------------------------------------------------------------
Alice adds 2 beers in her cart.
Sleeping 3 seconds...
Trying to update beer stock : -2 beers.
####################################

Database state:
Product{id='beer', stock=3, price=3}
Cart{id='Alice', items=[Item{productId=beer, quantity=2, price=3}]}

Sleeping 3 seconds...

######### WITH TRANSACTION #########
Alice wants 2 extra beers.
Now we can update the 2 collections simultaneously.
The 2 operations only happen when the transaction is committed.
---------------------------------------------------------------------------
Updating Alice cart : adding 2 beers.
Sleeping 3 seconds...
Trying to update beer stock : -2 beers.
####################################

Database state:
Product{id='beer', stock=1, price=3}
Cart{id='Alice', items=[Item{productId=beer, quantity=4, price=3}]}

Sleeping 3 seconds...

######### WITH TRANSACTION #########
Alice wants 2 extra beers.
This time we do not have enough beers in stock so the transaction will rollback.
---------------------------------------------------------------------------
Updating Alice cart : adding 2 beers.
Sleeping 3 seconds...
Trying to update beer stock : -2 beers.
#####   MongoCommandException  #####
##### STOCK CANNOT BE NEGATIVE #####
####### ROLLBACK TRANSACTION #######
####################################

Database state:
Product{id='beer', stock=1, price=3}
Cart{id='Alice', items=[Item{productId=beer, quantity=4, price=3}]}

Next Steps

Thanks for taking the time to read my post – I hope you found it useful and interesting. As a reminder, all the code is available on this Github repository for you to experiment.

If you are looking for a very simple way to get started with MongoDB, you can do that in just 5 clicks on our MongoDB Atlas database service in the cloud.

Also, multi-document ACID transactions is not the only new feature in MongoDB 4.0, so feel free to take a look at our free course on MongoDB University M040: New Features and Tools in MongoDB 4.0 and our guide to what’s new in MongoDB 4.0 where you can learn more about native type conversions, new visualization and analytics tools, and Kubernetes integration.

Source:: scotch.io

Behind the scenes of my latest book on JavaScript

By Dr. Axel Rauschmayer

This blog post takes you behind the scenes of my latest book, “JavaScript for impatient programmers” (which I’ll henceforth abbreviate as “Impatient JS”). It describes:

  • How I chose what to write about.
  • My techniques for explaining topics.
  • Tools I used for creating ebooks and other artifacts.
  • How I unit-tested the code shown in the book and in its quizzes.

Source:: 2ality

Getting Started with Component Transitions in Vue

By Chris Nwamba

Vue Transition Diagram

When we build applications, we aim to make them easy on the eye. We want our users to have a smooth experience using it, and to feel our application flowing from one point to another, rather than just jump between screens.

If we switch components without transitions, we see a sharp change every time a new component is called up. This is not ideal and can result in our users having a poor experience with our application.

In this tutorial, we will look at how to improve the flow of our application using component transitions in Vue.

Prerequisites

  1. Vue CLI 3 for installing Vue
  2. Knowledge of JavaScript
  3. Knowledge of Vue.js

Setup Our Application

To begin, we will create a Vue application. Run the following command:

$ vue create component-transitions
$ cd component-transitions

Once we are done creating the application, we need to define a component we will use for the transitions.

Update The App Component
When we create a new Vue application, the CLI creates an App.vue file inside the ./src directory. Open the file and update the style section as follows:

[...]
<style>
    [...] 
    h3 {
        margin: 40px 0 0;
    }
    ul {
        list-style-type: none;
        padding: 0;
    }
    li {
        display: inline-block;
        margin: 0 10px;
    }
    a {
        color: #42b983;
    }
</style>

We created global styles we wish to share across all our components. This way, we will not have to add styles per component again.

Update The HelloWorld Component
Our Vue application also comes with a HelloWorld.vue file in located in ./src/components directory. Open the file and edit as follows:

<template>
    <div class="hello">
        <h1>{{ msg }}</h1>
    </div>
</template>

<script>
    export default {
        name: 'HelloWorld',
        props: {
            msg: String
        }
    }
</script>

Create The About Component
We are going to create a new component About.vue inside the ./src/components directory. Open the file and add the following:

<template>
    <div>
        <h1>{{ msg }}</h1>
    </div>
</template>

<script>
    export default {
        name: 'About',
        props: {
            msg: String
        }
    }
</script>

Create Another Component
We are going to create another component Extra.vue inside the ./src/components directory. Open the file and add the following:

<template>
    <div>
        <h1>{{ intro }}</h1>
    </div>
</template>

<script>
    export default {
        name: 'Extra',
        props: {
            msg: String
        },
        data(){
            return {
                intro : "Extra"
            }
        },
        watch: {
            msg : {
                immediate: true, 
                handler(val, oldval) {
                    //
                }
            }
        }
    }
</script>

For our extra component, we have added a watch method to track the updates to the msg prop. When the message prop updates, we want to update the intro property.

We defined it this way to allow us to use transitions on the component.

Rendering Our Components

Vue provides a variety of ways to apply transition effects when items in a component are updated or when components themselves are changed. It ranges from applying CSS classes for transitions and animations to using 3rd party JavaScript libraries for transition effects.

The first set of transitions we will define will be on change of components. We will use conditional rendering to display the components we created and apply transition as they render.

Import The Components
We need to import the components we created into our App.vue component. Open the file and edit as follows:

[...]
<script>
    import HelloWorld from './components/HelloWorld.vue'
    import About from './components/About.vue'
    import Extra from './components/Extra.vue'

    export default {
        name: 'app',
        components: {
            HelloWorld, About, Extra
        }
    }
</script>

Use The Components
Now that we have imported the components, let us use it in our App component. Edit the App.vue file as follows:

<template>
    <div id="app">
        <img src="./assets/logo.png">
        <HelloWorld msg="Welcome to your Vue.js application"/>
        <Extra :msg="extra"/>
        <About msg="This is the About page"/>
        <button @click="changeExtra">Update Extra</button>
    </div>
</template>

We defined a function changeExtra to listen for button clicks and also bound the msg prop for the Extra component to extra attribute. Now, let’s create the extra attribute and changeExtra method. We will just leave the Vue.js logo there so the page doesn’t feel empty ?

Edit the file as follows:

[...]
export default {
    name: 'app',
    components: {
        HelloWorld, About, Extra
    },
    data(){
        return {
            extra : "Extra"
        }
    },
    methods : {
        changeExtra(){
            this.extra = "This is extra"
        }
    },
}
[...]

Define Links For Switching Components
We are going to show one component at a time. To do this, we will have a simple set of links that would allow us to state which component to use at a certain time.

Open the App.vue file and add the following:

<template>
    <div id="app">
        [...]
        <div>
            <ul>
                <li @click="showHome">Home</li>
                <li @click="showAbout">About</li>
                <li @click="showExtra">Extra</li>
            </ul>
        </div>
    </div>
</template>

Then add the methods we used above:

[...]
methods : {
    [...]
    showHome(){
        this.displayHome = true
        this.displayAbout = false
        this.displayExtra = false
    },
    showAbout(){
        this.displayHome = false
        this.displayAbout = true
        this.displayExtra = false
    },
    showExtra(){
        this.displayHome = false
        this.displayAbout = false
        this.displayExtra = true
    }
},
[...]

Finally, we define the properties — displayHome, displayAbout, displayExtra.

[...]
data(){
    return {
        extra : "Extra",
        displayHome : true,
        displayAbout : false,
        displayExtra : false
    }
},
[...]

We set displayHome to true so that anytime we load our application, it shows up first. The rest is false so they do not show up.

Conditional Rendering Of Our Components
Now that we have defined links for showing our components, let’s render them based on certain conditions.
Still in the App.vue file, edit it as follows:

<template>
    <div id="app">
        <img src="./assets/logo.png">
        <HelloWorld msg="Welcome to your Vue.js application" v-if="displayHome"/>
        <About msg="This is the About page" v-if="displayAbout"/>
        <div v-if="displayExtra">
            <Extra :msg="extra"/>
            <button @click="changeExtra">Update Extra</button>
        </div>
        [...]
    </div>
</template>

So, we have completely rendered all of our components, now we can add transitions to it. Hurray!!!

Defining Transitions On Data Change

We will modify Extra component. We want to add a simple transition effect when we update the data inside of it. Open the Extra.vue file in the ./src/components/ directory and edit as follows:

<template>
    <div>
        <transition name="fade">
            <h1 v-if="!msg">{{ intro }}</h1>
        </transition>
        <transition name="fade">
            <h1 v-if="msg">{{ msg }}</h1>
        </transition>
    </div>
</template>
[...]
<style scoped>
   .fade-enter-active{
        transition: opacity 1.5s;
    }
    .fade-leave-active {
        opacity: 0;
    }
    .fade-enter, .fade-leave-to {
        opacity: 0;
    }
</style>

This is a simple component. When we click the Update Extra button, we will notice a slide fading transition occur. The transition is very noticeable, so our users must see it.

We are able to achieve the transition by wrapping our element in a Vue transition element and then defining the effect we want the transition element to use. In our case, we used opacity to make the component appear and disappear.

For data change transitions, you might want to use state transition as it provides a more robust experience. Read more about State Transitions.

Vue provides hooks at different stages of the transition cycle that we can hook into and define how we want the transition to be. I’ve added an image below from Vue.js website to illustrate this:

v represents the name of our transition. In the case of the Extra component, we replace v with fade to have fade-enter in place of v-enter and so on.

Defining Transitions On Component Change

Define Transition On The HelloWorld Component
Now, to the App component where we will explore different other ways to implement transitions. Let’s define the transition on the HelloWorld component. Open the App.vue file and edit as follows:

<transition name="welcome">
    <HelloWorld msg="Welcome to your Vue.js application" v-if="displayHome"/>
</transition>

Our transition will be named “welcome”. Now, add the transition classes to get your desired effect:

<style scoped>
    /* Welcome Styles */
    .welcome-enter {
        transform: translateX(10px);
        opacity: 0;
    }
    .welcome-enter-active {
        transition: all .8s cubic-bezier(1.0, 0.5, 0.8, 1.0);
    }
    .welcome-leave-active, .welcome-leave-to {
        opacity: 0;
    }
</style>

Now, every time we click the Home link, there will be a little shaking ? as our component it shows.

PS: We created a new style element and added ‘scoped` to it.

Define Transition On The About Component
We will take a similar step with what we did for the HelloWorld component. Open the file and add the following:

[...]
<transition name="about">
    <About msg="This is the About page" v-if="displayAbout"/>
</transition>
[...]

Then add the transition effect:

<style scoped>
    [...]
    /* About Styles */
    .about-enter {
        width: 30%;
        opacity: 0;
    }
    .about-enter-active {
        transition: all 2s ease-in-out;
    }
    .about-leave-active, .about-leave-to {
        opacity: 0;
    }
    .about-enter-to {
        width:100%;
        opacity: 1;
        margin-left: auto;
    }
</style>

Define The Transition On Extra Component
Finally, let’s also add a transition for enter and exit of the extra component:

[...]
<transition name="extra">
    <div v-if="displayExtra">
        <Extra :msg="extra"/>
        <button @click="changeExtra">Update Extra</button>
    </div>
</transition>
[...]

Then add the styles for the transition:

<style scoped>
    [...]
    /* Extra Styes */
    .extra-enter {
        transform: translateX(-200px);
        opacity: 0;
    }
    .extra-enter-to {
        transform: translateX(0px);
    }
    .extra-enter-active {
        transition: all 1s cubic-bezier(1.0, 0.5, 0.8, 1.0);
    }
    .extra-leave-active, .extra-leave-to {
        opacity: 0;
    }
</style>

And that’s it for component transitions.

Run The Application

Now that we are done defining transitions for our various components, let’s run the application and see what it looks like.

From your terminal, run the following command:

$ npm run serve

Then visit the application on the url that appears.

See A Demo

Conclusion

We have looked at vue component transitions in this tutorial. We saw how easy it is to add transitions to our application. I have to admit we kind of overdid the transition thing and used effects we may not want to use in a real application. The entire goal was to show that anything is possible.

Try to use different CSS transitions for your components and see what you can come up with.

Source:: scotch.io

​DDoS Protection Mastery Starts Here

By SergiuHKR

We’re very excited to announce the launch of the online DDoS Protection Bootcamp. Built for IT security and network ops professionals, this one-of-a-kind online training portal offers an unprecedented selection of free courses and challenging quizzes that test and improve your DDoS protection skills.

Jointly prepared by Imperva Incapsula and DDoS testing firm NimbusDDoS, the DDoS Protection Bootcamp leverages the domain expertise of both companies to offer in-depth technical training in DDoS protection. Until now, you literally had to work for a security company to have access to this level of knowledge.

Unlike other training sites, the DDoS Protection Bootcamp is uniquely designed to combine rich educational content with a fun online quiz-based format that lets you measure your knowledge as you progress through the topics. Each quiz question comes with a complete explanation of the right answer so you can learn from your mistakes.

What You’ll Learn at the DDoS Protection Bootcamp

Recent studies indicate that almost 75 percent of organizations have suffered at least one DDoS attack over the past 12 months. This is not a problem that’s going away. The DDoS Protection Bootcamp gives trainees the technical knowledge and skills to identify and block different types of DDoS attacks.

This comprehensive course covers the following topics:

  • Introduction to DDoS
  • Volumetric Attacks
  • Protocol Attacks
  • Application Level (Layer 7) Attacks
  • Reflection Attacks
  • Understanding Risks
  • Mitigation Techniques
  • DDoS Trends

The training is divided into Basic and Advanced levels so you can choose the courses that best match your needs and proceed at your own pace. As noted, the educational content for each topic is followed by a quiz whose level of difficulty depends on the course level. The course concludes with a final exam covering all eight topics.

Get started today

If you’re ready to step up your game, the DDoS Protection Bootcamp is a great way to get into top professional shape.

Check it out today — It’s absolutely free and no registration is required. You’re also more than welcome to invite a friend or colleague to join you.

Like any new training course, your feedback is invaluable. Let us know what you liked, what you didn’t like and where we can improve. Enjoy!

Source:: scotch.io

Create Web Notifications Using Laravel and Pusher Channels

By Neo Ighodaro

When building web applications, it is not uncommon to find some sort of in-app notification system that will notify you instantly when someone carries out an action related to you or your account. On Facebook, you will be notified when someone likes your status, or when someone comments on your profile. We will replicate this feature by creating a web notifications system using Laravel and Pusher.

To follow this tutorial, you need to have PHP and Laravel installed on your machine.

What we would be building

After this tutorial we would demonstrate how we can have a small web application show notifications using Laravel and Pusher. It would be similar to how websites like Facebook show notifications. Here is a preview of what we would be building:

Setting up your Pusher application

Create a Pusher account, if you have not already, and then set up your application as seen in the screenshot below.

how-to-create-web-notifications-using-laravel-and-pusher-1

Setting up your Laravel application

You can create a new Laravel application by running the command below in your terminal:

laravel new laravel-web-notifications

After that, we will need to install the Pusher PHP SDK, you can do this using Composer by running the command below:

composer require pusher/pusher-php-server

When Composer is done, we will need to configure Laravel to use Pusher as its broadcast driver, to do this, open the .env file that is in the root directory of your Laravel installation. Update the values to correspond with the configuration below:

    PUSHER_APP_ID=322700
    BROADCAST_DRIVER=pusher

    // Get the credentials from your pusher dashboard
    PUSHER_APP_ID=XXXXX
    PUSHER_APP_KEY=XXXXXXX
    PUSHER_APP_SECRET=XXXXXXX

Important Note: If you’re using the EU or AP Cluster, make sure to update the options array in your config/broadcasting.php config since Laravel defaults to using the US Server. You can use all the options the Pusher PHP Library supports.

Open config/app.php and uncomment the AppProvidersBroadcastServiceProvider::class .

Creating our Laravel and Pusher application

Now that we are done with configuration, let us create our application. First we would create an Event class that would broadcast to Pusher from our Laravel application. Events can be fired from anywhere in the application.

php artisan make:event StatusLiked

This will create a new StatusLiked class in the app/Events directory. Open the contents of the file and update to the following below:

<?php

namespace AppEvents;

use IlluminateQueueSerializesModels;
use IlluminateFoundationEventsDispatchable;
use IlluminateBroadcastingInteractsWithSockets;
use IlluminateContractsBroadcastingShouldBroadcast;

class StatusLiked implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $username;

    public $message;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($username)
    {
        $this->username = $username;
        $this->message  = "{$username} liked your status";
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return Channel|array
     */
    public function broadcastOn()
    {
        return ['status-liked'];
    }
}

Above, we have implemented the ShouldBroadcast interface and this tells Laravel that this event should be broadcasted using whatever driver we have set in the configuration file.

We also have a constructor that accepts two parameters, username and verb. We will get back to this later on. We assigned these variables to class properties named the same way. It is important to set the visibility of the properties to public; if you don’t, the property will be ignored.

Lastly, we set the channel name to broadcast on.

Creating the application views

We will keep it simple and create a single view where you can see a navigation bar with a notification icon. The icon will be updated when new notifications are available without the need to refresh the page. The notifications are ephemeral in this tutorial by design; you can extend the functionality and make it last longer after the page reloads if you so desire.

Open the welcome.blade.php file and replace it with the HTML below.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Demo Application</title>
    <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
    <link rel="stylesheet" type="text/css" href="/css/bootstrap-notifications.min.css">
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <nav class="navbar navbar-inverse">
      <div class="container-fluid">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-9" aria-expanded="false">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Demo App</a>
        </div>

        <div class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li class="dropdown dropdown-notifications">
              <a href="#notifications-panel" class="dropdown-toggle" data-toggle="dropdown">
                <i data-count="0" class="glyphicon glyphicon-bell notification-icon"></i>
              </a>

              <div class="dropdown-container">
                <div class="dropdown-toolbar">
                  <div class="dropdown-toolbar-actions">
                    <a href="#">Mark all as read</a>
                  </div>
                  <h3 class="dropdown-toolbar-title">Notifications (<span class="notif-count">0</span>)</h3>
                </div>
                <ul class="dropdown-menu">
                </ul>
                <div class="dropdown-footer text-center">
                  <a href="#">View All</a>
                </div>
              </div>
            </li>
            <li><a href="#">Timeline</a></li>
            <li><a href="#">Friends</a></li>
          </ul>
        </div>
      </div>
    </nav>

    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src="//js.pusher.com/3.1/pusher.min.js"></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

    <script type="text/javascript">
      var notificationsWrapper   = $('.dropdown-notifications');
      var notificationsToggle    = notificationsWrapper.find('a[data-toggle]');
      var notificationsCountElem = notificationsToggle.find('i[data-count]');
      var notificationsCount     = parseInt(notificationsCountElem.data('count'));
      var notifications          = notificationsWrapper.find('ul.dropdown-menu');

      if (notificationsCount <= 0) {
        notificationsWrapper.hide();
      }

      // Enable pusher logging - don't include this in production
      // Pusher.logToConsole = true;

      var pusher = new Pusher('API_KEY_HERE', {
        encrypted: true
      });

      // Subscribe to the channel we specified in our Laravel Event
      var channel = pusher.subscribe('status-liked');

      // Bind a function to a Event (the full Laravel class)
      channel.bind('AppEventsStatusLiked', function(data) {
        var existingNotifications = notifications.html();
        var avatar = Math.floor(Math.random() * (71 - 20 + 1)) + 20;
        var newNotificationHtml = `
          <li class="notification active">
              <div class="media">
                <div class="media-left">
                  <div class="media-object">
                    <img src="https://api.adorable.io/avatars/71/`+avatar+`.png" class="img-circle" alt="50x50" style="width: 50px; height: 50px;">
                  </div>
                </div>
                <div class="media-body">
                  <strong class="notification-title">`+data.message+`</strong>
                  <!--p class="notification-desc">Extra description can go here</p-->
                  <div class="notification-meta">
                    <small class="timestamp">about a minute ago</small>
                  </div>
                </div>
              </div>
          </li>
        `;
        notifications.html(newNotificationHtml + existingNotifications);

        notificationsCount += 1;
        notificationsCountElem.attr('data-count', notificationsCount);
        notificationsWrapper.find('.notif-count').text(notificationsCount);
        notificationsWrapper.show();
      });
    </script>
  </body>
</html>

This is mostly a lot of Bootstrap noise so we will isolate the important parts, mostly Javascript. We include the Pusher javascript library, and then we added the javascript block that does the magic. Let us look at some snippets of the javascript block:

// Enable pusher logging - don't include this in production
// Pusher.logToConsole = true;

// Initiate the Pusher JS library
var pusher = new Pusher('API_KEY_HERE', {
    encrypted: true
});

// Subscribe to the channel we specified in our Laravel Event
var channel = pusher.subscribe('status-liked');

// Bind a function to a Event (the full Laravel class)
channel.bind('AppEventsStatusLiked', function(data) {
    // this is called when the event notification is received...
});

PROTIP: By default, Laravel will broadcast the event using the event’s class name. However, you may customize the broadcast name by defining a broadcast as method on the event:
public function broadcastAs() {
return ‘event-name’;
}

The code above just initializes the Pusher JS library and subscribes to a channel. It then sets a callback to call when the event broadcasted is received on that channel.

Testing our set up

Finally to test our set up, we will create a route that manually calls the event. If everything works as expected, we will get a new notification anytime we hit the route. Let’s add the new route:

Route::get('test', function () {
    event(new AppEventsStatusLiked('Someone'));
    return "Event has been sent!";
});

Now we can start a PHP server using Laravel so we can test our code to see if it works.

$ php artisan serve

Conclusion

In this article we have been able to leverage the power of Pusher to create a modern web notifications system and it was very easy. This is just scratching the surface of what can be really done using Pusher. The example was just to show you the possibilities.

The code is available on GitHub, you can star, fork and play around with it.

Source:: scotch.io

My Top 8 Visual Studio Code Tips and Features

By Chris Ganga

Visual Studio Code has become one of the most used and loved Text Editors in recent years. Here are some statistics from the 2018 Stackoverflow Survey:- Most Popular Development Environments.

Source: https://insights.stackoverflow.com/survey/2018/

1. Visual Studio Code CLI

Visual Studio Code comes with an inbuilt Command Line Interface. Once you’ve installed Visual Studio Code, and have it open, press ⇧⌘P to open the command palette for Mac, or just ⌘P and the press > button.

Next, type in shell command, select Install Code Command in PATH, and press enter.

Now if you type in code, Visual Studio Code will open, and code , Visual Studio Code will open with the directory represented by Path.

To see the command line interface however, type in code -h.

code -h
Visual Studio Code 1.25.1

Usage: code [options] [paths...]

To read from stdin, append '-' (e.g. 'ps aux | grep code | code -')

Options:
  -d, --diff <file> <file>           Compare two files with each other.
  -a, --add <dir>                    Add folder(s) to the last active window.
  -g, --goto <file:line[:character]> Open a file at the path on the specified line and character position.
  -n, --new-window                   Force to open a new window.
  -r, --reuse-window                 Force to open a file or folder in an already opened window.
  -w, --wait                         Wait for the files to be closed before returning.
  --locale <locale>                  The locale to use (e.g. en-US or zh-TW).
  --user-data-dir <dir>              Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.
  -v, --version                      Print version.
  -h, --help                         Print usage.

I’ve truncated the output above, but there’s more to it. You can read through the commands and what they do, but you can see there are some very useful and handy tools in there. We’ll look at one --diff.

Ever wanted to see the difference between two files, Let’s look at an example. Here are two files with a slight difference in them.

app1.js

 var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue 1!'
  }
})

app2.js

 var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Vue 2!'
  }
})

This is a small file, and we can see the diff right away. But for demonstration purposes, we’ll type in the following in the command line.

code --diff app1.js app2.js

This opens Visual Studio Code with the following View.

We can see where the diff in the two files is. This is the same view that’s available when you are looking at Git Diff, with the integrated Git Support in Visual Studio Code.

2. Git Integration

Sometimes using Git can be fun or hard, but Visual Studio Code comes with integrated Git that allows for Adding, Committing, Pulling and Pushing Changes to a remote Git repository using a simple GUI.

Let’s go through a simple workflow that will involve the following steps.

  1. Create a project with git initialized.
  2. Make some changes
  3. Commit the changes

We have the two files we created app1.js and app2.js. Let’s initialize a git repository in this directory. And then open Visual Studio Code with this directory.

git init
code .

Where . represents the current directory your terminal is in.

You’ll immediately notice that Git is active in the left most pane. It has a badge with 2 on it.

The two files have a U in on their right, which means they are untracked. If you click on the git Icon with a badge of 2, you get this view. Hover over the first file app1.js, and these icons appear

The + sign is an equivalent of git add command. click it. and the view changes to this.

We can now see a Staged Changes section, with the file we’ve added, and the status has changed to A which represents Index Added.

Next, click on the Open File Icon on the file app1.js in the Staged Changes, and open the file. Edit the file to this. Replace message.

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello Scotch!'
  }
})

Now, there’s a new entry in Changes section with the same file. When you click on the file app1.js in the Changes Section, you will see a diff displayed, like we saw in topic 1.

You can then click on the + sign to stage the changes. Committing the file to git is as simple as typing in the commit message at the top section with the Message (Press..., and pressing CMD + Enter or Ctrl + Enter. Below, I wrote Initial Commit
.

Pressing CMD + Enter, changes the view back to Changes only for the files we did not add.
.

Other helpful features that are git related include

  • A helpful Context Menu: – When you click on the menu icon ... within the Git Panel, this is what you see.

We see useful commands that are sometimes quite hard to grasp.

At the bottom of Visual Studio Code, in the status bar, you can also see the branch you are currently in. Clicking on that branch allows you to select any other branches that exist.

When you click on that, a list of branches appears in the search panel, with the first option being the ability to create a new branch

3. Debugging

Visual Studio Code has a rich API for enabling debugging tools, Here are some articles here in scotch referencing them.

  1. https://scotch.io/tutorials/debugging-javascript-in-google-chrome-and-visual-studio-code
  2. https://scotch.io/tutorials/debugging-node-code-in-vs-code
  3. https://scotch.io/@chenster/debugging-php-in-visual-studio-code205

Debugging is a large topic, and is usually language/stack specific. Depending on the language you are using, there are available plugins that enable support for debugging, and you’ll be able to use breakpoints to debug your code when developing.

4. Live Share

Visual Studio Code Live Share is a feature that enables you to share your VS Code instance, and allow someone remote to control and run other things such as debuggers.

Live Share is published as a plugin, and is currently in Preview.

All that is required is for you to install the plugin, and the status bar will enable you share any working session by getting a link, once you are signed in.

Here’s a Video, showing Visual Studio Code in action.

5. Split Views, Zen Mode

If you like working on multiple open editors in the same project, you will find this feature really interesting. You can press OPT, and click on a file, or right click on a file and choose Open to the Side, to open more the file in a split view like shown below.
.

There are a couple of built in Editor Layouts that you can view by going to the View > Editor Layout menu.

Below shows the 2×2 Grid Option

Zen Mode: Sometimes you want minimal distractions from everything, and only want to focus on your code. Below shows the zen mode, which can be accessed through the View > Toggle Zen Mode, or by opening the Command Palette, and typing in >Zen

Below shows the zen mode. Notice my code has been centered, and all other VS Code visuals removed.

6. Helpers (Intellisense, Context Menus..)

I decide to call this section helpers because it consists of little things that are quite helpful when writing code.

Here’s a simple JavaScript file we’ll use to demonstrate these features.

function name() {
  return "scotch"
}

function age() {
  return 8
}

function nameAndAge() {
  return {
    name: name(),
    age: age(),
  }
}
console.log(name())
console.log(age())
console.log(nameAndAge())
  • Peek Definition – this allows you to see the definition of a function/variable, without navigating to the it, even if it’s in a different file. It works with multiple languages, though sometimes you need to install the relevant plugins. To access it, right click in the line console.log(nameAndAge()), and click on peek definition in the context menu.
    .
    VS Code will find the function, and give you an overlayed editor to peek on what’s going on.

    You can also select Go To Definition, and you will be taken directly to where the function/variable is defined.
  • Find All References – This works pretty similar to Peek Definition. Right click on the function nameAndAge, and select Find All References.

    On the right of the overlayed editor, you will see a list of all the places the function has been referenced. This is useful in giving you an overview of how much a piece of code affects your whole codebase.
  • Rename Symbol – Also found in the context Menu, this allows you to rename a function or variable, and it will be changed everywhere it is referenced in the codebase.
  • Refactor – Currently, this works mainly for TypeScript and JavaScript, but it allows you to refactor code. e.g move a function into a file. In our example, if you right click on the nameAndAge function and click on refactor, one option will be Move To New File, and when you click on that, the function is removed, and put into a new file called nameAndAge.js
function nameAndAge() {
  return {
    name: name(),
    age: age(),
  };
}
  • Intellisense – Intellisense usually allows you to list members of a struct, class or object, and even get required parameters for functions, that makes writing code faster and less error prone. This is supported by default for JavaScript and TypeScript, but you may have to install language specific plugins to support the language you are using.

    You can also hover over anything:- variables, functions and see a pop up telling you more about them. Below is a hover over the log function in console
  • NPM Scripts – This sounds like it should be a feature in its own, but I’ll just put it here. NPM Scripts are usually commands that we put in the scripts section of the file package.json.
"scripts": {
    "start": "node index.js"
  }

VS Code has a couple of helpers for NPM. First of all, when you are creating the scripts, there’s beautiful intellisense and you can just select the script you want.

Next, there’s a NPM SCRIPTS panel on the left, usually at the bottom, which will list the package.json file, and within it the scripts. Right clicking on the file, gives you an option to run npm install
.
And Hovering over the particular script displays a Play button which will allow you run the script.

  • Outline – Outline was released recently, and I can’t believe how much I use it. It essentially gives you an overview of your code, and navigates to sections you click on.

Take for instance the piece of code we had earlier, if you open the file, and go to the Outline section on the left pane, you’ll see this

We see an outline of the main blocks of our code, and clicking on any of them, takes the editor focus to that section of the code.

These are just a few features and tips I didn’t know hot to categories. 😉

7. Integrated Terminal

Most of the time when running code, there’s usually a terminal open either to the side, or somewhere in your machine.

Visual Studio Code comes with an Integrated Terminal accessible through View > Integrated Terminal, and configurable through the settings: "terminal.external.osxExec": "iTerm.app",. The terminal usually opens by default in the workspace you are in, and can also have split views.

8. Plugins and Themes

Visual Studio Code has a rich plugin API, and this has enabled developers to create really awesome plugins. I’ll list a few common ones which I’ve used, but to get a comprehensive list, you can look at the Visual Studio Code Marketplace. Themes can be found here

  • Linters
    • ESLint – This enables us lint JavaScript ES code based on eslint rules we provide.
    • TSLint – This enables us link Typescript code based on tslint rules we provide
    • Prettier – Prettier is a common code formatter with growing popularity and enables linting of JavaScript, Typescript and CSS.
  • Language Support :- Visual Studio Code has syntax support for most common languages, but to get full language feature and tools, you will find yourself downloading language plugins. Since I write mostly JavaScript and Golang I have the vscode-go tools installed. You can see a list of language plugins here
  • Git – There are many plugins that add more support for Git, but the most common one is Git Lense. Here’s an example feature:

    Whenever you click on a line of code, it shows you who edited it, and a little more info about it. You can read more in the GitLense Documentation
  • Settings – The most common settings plugin is called Settings Sync, and allows you to sync your VS Code installations on different devices.
  • Docker – Developing with Docker can sometimes mean running complex docker commands, and monitoring things. Installing this Docker Extensions adds some helpful docker tools, such as generating docker files, docker files intellisense, and even monitoring. Here’s an example of my running containers in VS Code right now.

    Also comes with a useful context menu.

    If you are familiar with docker, you’ll find this plugin quite helpful.
  • NPM – I’ve already explained the inbuilt npm tools above. Here are a few plugins that make my npm work easier.
    • Version Lense – Easily manage versions of your npm packages.
    • Import Cost – Easily see the bytes every package import brings in your codebase.
  • Markdown All in One – this allows you to edit markdown as though you were writing a word document, and many other features. Useful if you write a lot of markdown.
  • Frameworks – I work mainly with VueJS and Golang, but there are a couple of plugins that support the various javascript frameworks.
    • Vetur – This gives support for VueJS
    • Angular Essentials – For Angular Developers.
    • React developers, please leave a comment, I’ll edit the article ;-).

Conclusion: Visual Studio Code can do that.

Visual Studio Code is a good Editor, that can adapt to many languages and technologies out there, and discovering these little helpers can sometimes take time.

Lucky for us, two awesome developers, @burkeholland and @sarah_edo created Visual Studio Code Can Do That site, that lists some awesome features and things you can do with Visual Studio Code.

Feel free to go through them.

Happy Coding!

Source:: scotch.io