Forum

Methodology

Toolbox

Platform

Community

Dynamic projects with BEM

Introduction

Many of today's applications require dynamic capabilities, such as data exchange in real time followed by complete or partial reloading of the current page.

The purpose of this document is to show how to develop dynamic BEM projects using full stack development.

We'll look at the process of creating a dynamic app called Social Services Search Robot (SSSR). This is an app for searching for recent tweets and videos by keyword.

The project development uses:

After reading this, you will be able to develop your own BEM projects for use with dynamic data.

Note: To be able to use the examples given here, you need basic skills in:

  • HTML

  • CSS

  • JavaScript

  • BEM

Important: This document doesn't cover issues with layout and the client JavaScript.

You will need to install:

Important: Windows users must additionally install Git Bash.

All the code samples provided in this document were tested in the following versions:

  • Node.js — 4.7.0.

  • npm — 4.5.0.

Note: npm is the package manager that is included in Node.js.

Notation

This document uses the following notation:

  • folder — directory

  • file — file

  • add folder — create a directory

  • add file — create a file

  • edit file — edit a file

Technologies

The full BEM technology stack includes:

  • BEMDECL — Technology for describing declarations in BEM.

  • DEPS — Technology for describing dependencies in BEM.

  • BEMTREE — Template engine that transforms data to BEMJSON.

  • BEMHTML — Template engine that transforms BEMJSON to HTML.

  • i-bem.js — JavaScript framework for BEM.

More information about the BEMJSON format for input data.

BEMDECL

Forms a list of BEM entities that are used on the page.

In BEM, this list is called a declaration. The purpose of the declaration is to define what to include in the build and in what order.

Declarations are defined in files with the .bemdecl.js extension.

Example of a declaration from the Hello World application:

// `desktop.bundles/index/index.bemdecl.js`
exports.blocks = [
    { name: 'root' }
];  

As the example shows, the index.bemdecl.js file only defines the root block.

When using DEPS, the declaration defines the BEM entity to start the project build on.

You should treat the root block as the central "entry point" when working with a project. All the other BEM entities are included in the build by dependencies.

Example of a project build from dependencies:

root(DECL)
|
└──> root(DEPS)
     |
     └──> page(DEPS)
          |
          ├──> header(DEPS)
          |    |
          |    └──> ...
          |
          ├──> body(DEPS)
          |    |
          |    └──> ...
          |
          └──> footer(DEPS)
               |
               └──> ...

More information about the BEMDECL technology.

DEPS

Defines the dependencies between BEM entities that are spread out across the project's file system and not listed in the declaration.

Dependencies are defined as JavaScript objects in files with the .deps.js extension.

Example of dependencies for the root block from the Hello World application:

// `common.blocks/root/root.deps.js`
({
    shouldDeps: 'page'
})

More information about DEPS.

BEMTREE

Part of the bem-xjst template engine that transforms data to BEMJSON.

Templates are defined in BEMJSON format in files with the .bemtree.js extension.

Input and output of the template engine:

BEMTREE

More information about BEMTREE.

BEMHTML

Part of the bem-xjst template engine that transforms BEMJSON to HTML.

Templates are defined in files with the .bemhtml.js extension.

Input and output of the template engine:

BEMHTML

More information about BEMHTML.

i-bem.js

Client JavaScript framework for web development using the BEM methodology.

The JavaScript code is described in files with the .js extension.

It allows you to:

  • Develop a web interface in terms of blocks, elements, modifiers.

  • Describe the block's logic in declarative style as a set of states.

  • Easily integrate the JavaScript code with BEMHTML templates and CSS.

  • Flexibly redefine the behavior of library blocks.

More information about i-bem.js.

Hello World application

Programmers have a tradition of starting out programming in a new language or framework with the Hello, World! program. The program usually prints the words "Hello, World!" to the output stream to show that it runs and can perform input/output operations.

You cancreate this application and then extend it to the desired SSSR.

To do this, you'll need a local copy of the bem-express template repository. You can use Git to make a copy.

Note: For OS X or Linux users, all commands are run in the terminal. Windows users need Git Bash. Make sure that you run Git Bash as the administrator.

Template repository

The bem-express template repository was created for tasks involving the development of dynamic applications using BEM. It contains the essential config files and solves an entire set of problems such as building a project, configuring linters, connecting libraries, and others.

The main BEM libraries are integrated in bem-express by default:

Quick start

To create the Hello World application, follow these steps:

  • Clone bem-express:

    git clone https://github.com/bem/bem-express.git sssr-project
    

    Note: This example uses bem-express version 2.00.

  • Go to the project directory:

    cd sssr-project
    
  • Delete the versioning history for the source repository:

    rm -rf .git
    
  • Initialize your own Git repository:

    git init
    
  • Set dependencies:

    npm install
    

    Note: Don't use root superuser permissions when setting npm dependencies.

  • Build the project and start the server:

    npm run dev
    

    Note: ENB is responsible for the project build.

    When the application starts, the terminal shows a message that the server is running on port 3000:

    Server is listening on 3000.

    Note: If port 3000 is being used by another program, you can reassign the port. For example, set it to 8000:

    Method 1. Change the value at application launch.

    PORT=8000 npm run dev
    

    Method 2. Change the default value in the server/config.js file.

    defaultPort: 8000
    

    The following starts on the computer:

    • Server — Responsible for processing dynamic data.

    • nodemon — Monitors changes in the file system and restarts the server.

    • chokidar — Monitors changes in files in the *.blocks/ directories and rebuilds the project structure.

    • livereload — Refreshes the page in the browser.

  • Open the browser and enter the address localhost:3000.

    It should open a page with the following content:

    Index page content
    footer content
    

    Note: If you run the application in Windows and you get a Firewall notification:

    • Disable the

      Public Network
      option.

    • Enable the

      Private Network
      option.

    • Allow access.

  • Open the server/index.js file and make the following changes to the code that starts with the line app.get('/', function(req, res) (see the comments):

    /**
     * The function handles all GET requests from the application's main page
     * @function
     * @param {object} req - Request.
     * @param {object} res - Response.
     */
    app.get('/', function(req, res) {
        var hello = 'Hello';                  // Initialize the `hello` variable
        var world = 'World';                  // Initialize the `world` variable
        render(req, res, {
            view: 'page-index',
            title: 'Main page',
            meta: {
                description: 'Page description',
                og: {
                    url: 'https://site.com',
                    siteName: 'Site name'
                }
            },
            hello: hello,                     // Pass the `hello` variable to `this.data.hello`
            world: world                      // Pass the `world` variable to `this.data.world`
        })
    });
    
  • Open the common.blocks/page-index/page-index.bemtree.js file and replace the contents with the following:

    block('page-index').content()(function() {
        // Receive data from the `this` global object
        var data = this.data;
        // Return the received data: `data.hello: 'Hello'`, `data.world: 'World'`
        return data.hello + ', ' + data.world;
    });
    

    After saving, the server automatically restarts and the page content changes to:

    Hello, World
    footer content
    

The Hello, World application is ready.

Did something go wrong?

If you had trouble creating the application, look for a solution in the forum. If you can't find an answer there, submit a question to the forum experts.

File system

After setting all the dependencies, the file system of the Hello World application should look like this:

sssr-project/
    .enb/                 # Config files for the ENB compiler
    common.blocks/        # Basic implementations of blocks
    desktop.bundles/      # Directories of project bundles
    development.blocks/   # Blocks that are integrated during development
    node_modules/         # Installed Node modules (packages)
    server/               # Directory with server code
    static/               # Root directory for distribution of static files
    .bemhint.js           # Bemhint linter configuration
    .borschik             # Borschik compiler configuration
    .eslintignore         # Excluding files and directories in ESLint
    .eslintrc             # ESLint configuration
    .gitignore            # Excluding files and directories in Git
    .stylelintrc          # Stylelint configuration
    .travis.yml           # Automatically starting linters in Continuous Integration
    nodemon.json          # Nodemon package configuration
    package.json          # Describing a project for npm
    README.md             # Text description of the project

Let's look at some of the main directories in more detail:

.enb

Contains the configuration of the ENB compiler.

The build performs the following tasks:

  • Combines source files that are spread out across the project's file structure.

  • Includes just the necessary blocks, elements, and modifiers in the project.

  • Follows the order for including entities.

  • Processes the source code during the build process (for example, transforms LESS code into CSS code).

The build algorithm is described in the .enb/make.js file.

More information about building BEM projects.

common.blocks

Contains implementations of all the project's BEM entities.

The names of files and directories follow the naming convention. The code is divided into independent parts for ease of working with individual blocks.

common.blocks/
    body/                 # Directory for the body block
    footer/               # Directory for the footer block
    header/               # Directory for the header block
    page/                 # Directory for the page block
        _view/            # Subdirectory for the page_view modifier
        page.bemtree.js   # BEMTREE implementation of the page block
        page.deps.js      # DEPS implementation of the page block
    page-index/           # Directory for the page-index block
    root/                 # Directory for the root block

Before being sent to the browser, the files are compiled and optimized.

desktop.bundles

Contains the files received as the result of the build. These files are called bundles in the BEM methodology.

Each bundle directory corresponds to a single page of the project:

desktop.bundles/
    index/                # Bundles for the index page
        index.bemdecl.js  # Declaration for the index page
        index.bemhtml.js  # BEMHTML bundle for the index page
        index.bemtree.js  # BEMTREE bundle for the index page
        index.css         # CSS bundle for the index page
        index.deps.js     # DEPS bundle for the index page
        index.js          # JS bundle for the index page
        ...

Note: The only file in the index directory that isn't generated automatically is the index.bemdecl.js file. More information about the BEMDECL technology is provided below.

server

Contains the Node modules that listen for web requests and generate the page.

File system for the directory:

server/
    config.js             # Application configuration
    index.js              # Application entry point
    rebuild.js            # Rebuilding the application
    render.js             # HTML rendering

Modules and their functions:

  • index.js — Module for initializing and launching the application. It connects Express.js and various modules that provide middleware support.

  • config.js — Module with the application's configuration data. It detects the application's default configuration (the port, the directory for storing static files, and the session's secret key).

  • rebuild.js — Module for automatically rebuilding the project. It monitors changes in files and directories (in the *.blocks and static directories), and rebuilds and restarts the project.

  • render.js — Module for HTML rendering. It receives BEMJSON as input, completes it with the necessary data, and generates HTML.

static

Contains static files that can be accessed externally:

static/
    favicon.ico           # Favicon
    index.min.css         # Symbolic link to desktop.bundles/index/index.min.css
    index.min.js          # Symbolic link to desktop.bundles/index/index.min.js

More information about symbolic links.

Social Services Search Robot application

Demo

SSSR is a service for searching for tweets and videos that match a specified set of parameters. The search parameters are transmitted to the Twitter Search API and the YouTube Data API in the form of an HTTP GET request. The APIs form a response as a JSON document.

The purpose of developing this application is to show you:

  • How to tie the data and the interface together.

  • Which technologies are used and what they do.

You can use this infrastructure (the SSSR application) as the basis of a wide variety of dynamic BEM projects for solving specific tasks.

Note. To develop the application, you need to install some specific Node modules.

Application flow

The application flow can be visualized as follows:

Chart of Social Services Search Robot

Step 1. Submitting a query

The user sends a query to the server.

Step 2. Receiving data

The application sends a request for data to the Twitter Search API and the YouTube Data API according to the query received from the user.

Note: Generating the request and preparing the received data for templating are covered in detail below.

Step 3. BEMTREE templating

The application passes the received data to the BEMTREE template engine, which transforms the data to BEMJSON.

Step 4. BEMHTML templating

The application passes the BEMJSON to the BEMHTML template engine, which transforms the BEMJSON to HTML.

Step 5. Sending results to the user

The application returns the results (the HTML page) to the user.

Note: Either the entire page can be updated, or just the content of a specific block.

Node modules used

Let's take a closer look at the concept of a Node module and the main modules that the application needs.

Important: This section doesn't cover all the modules that are used. For more information about a specific module, see the npm site. It includes a list of all the Node modules and a search feature.

The basic Node implementation is kept as simple as possible. Rather than directly embedding all the possible components in Node, the develpers provide additional functionality as separate modules (packages).

The modular system for Node is modeled after the CommonJS system, which is a solution for creating interactive modules. The system relies on a contract that must be fulfilled by developers in order for their modules to interact correctly with each other.

All packages that are installed using the npm package manager are located in the node_modules directory.

Use the require command to enable modules. If a package is installed using npm, you don't need to specify the path. Just specify the name:

var express = require('express');

If you are enabling a custom local module, specify the path:

var someModule = require('./somefolder/somemodule');

Any module that you enable must be designed for Node interaction. To meet this requirement, the module must be exported using module.exports:

module.exports = {
    // some module
};

The application requires the following modules:

Note: You can install the required modules using a single command:

npm install express passport passport-youtube-v3 twitter googleapis moment --save

express

Provides most of the functionality that the developer needs for building a web application.

Install:

npm install express --save

The Express documentation provides a basic application called Hello World Express. It demonstrates the basic steps:

var express = require('express');
var app = express();

app.get('/', function (req, res) {
  res.send('Hello World!')
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
});

passport

Provides various authentication strategies for Node.js applications.

Install:

npm install passport --save

Example of OAuth 2.0 authorization:

var passport = require('passport'),
    OAuth2Strategy = require('passport-oauth').OAuth2Strategy;

/**
 * This function integrates the appropriate authorization strategy
 * @function
 * @param {string} provider — For example, Facebook, Twitter, Google, or others
 * @param {object} strategy — Authorization strategy
 */
passport.use('provider', new OAuth2Strategy({
    authorizationURL: 'https://www.provider.com/oauth2/authorize',
    tokenURL: 'https://www.provider.com/oauth2/token',
    clientID: SERVICE_APP_ID,
    clientSecret: SERVICE_APP_SECRET,
    callbackURL: 'https://www.example.com/auth/provider/callback'
}));

Note: OAuth 2.0 is an open authorization protocol that makes it possible to grant a third party limited access to a user's protected resources, without sharing the user's credentials.

passport-youtube-v3

Provides a mechanism for authentication on YouTube via the YouTube account and OAuth 2.0 tokens.

Install:

npm install passport-youtube-v3 --save

Example

var passport = require('passport'),
    YoutubeV3Strategy = require('passport-youtube-v3').Strategy;
/**
 * This function integrates the YoutubeV3Strategy
 * @function
 * @param {object} strategy — Strategy
 */
passport.use(new YoutubeV3Strategy({
    clientID: YOUTUBE_APP_ID,
    clientSecret: YOUTUBE_APP_SECRET,
    callbackURL: '/auth/youtube/callback',
    scope: ['https://www.googleapis.com/auth/youtube.readonly']
}, verify));

More information about how to get OAuth tokens.

twitter

Client library for working with the Twitter REST API.

Install:

npm install twitter --save

Example

var Twitter = require('twitter');
// Creating an instance of the Twitter object
var client = new Twitter({
  consumer_key: '',
  consumer_secret: '',
  bearer_token: ''
});

var params = {q: 'bem'};
/**
 * Search function. Searches for tweets that match the specified parameters.
 * @function
 * @param {object} params - Search parameters.
 * @param {function} callback - Receives the tweet results.
 */
client.get('search/tweets', params, function(error, tweets, response) {
  if (!error) {
    console.log(tweets);
  }
});

googleapis

Client library for working with the Google REST API.

Install:

npm install googleapis --save

Example

var google = require('googleapis'),
    OAuth2 = google.auth.OAuth2;
// Creating an instance of the OAuth2 object
var oauth2Client = new OAuth2(
  YOUR_CLIENT_ID,
  YOUR_CLIENT_SECRET,
  YOUR_REDIRECT_URL
);
// Setting credentials for outgoing calls
oauth2Client.setCredentials({
  access_token: 'ACCESS TOKEN HERE',
  refresh_token: 'REFRESH TOKEN HERE'
});
// Logging in
var youtube = google.youtube({
    version: 'v3',
    auth: this.oauth2Client
});

var params = {q: 'bem'};
/**
 * Search function. Searches for videos that match the specified parameters.
 * @function
 * @param {object} params - Search parameters.
 * @param {function} callback - Receives the video results.
 */
youtube.search.list(params, function(error, video, response) {
  if (!error) {
    console.log(video);
  }
});

moment

JavaScript library for parsing, validating, and formatting dates.

Install:

npm install moment --save

Example

var moment = require('moment');

moment().startOf('day').fromNow();             // 17 hours ago

Preparing the project structure

Before you begin writing code, you need to make a few changes to the structure that you got from the Hello World application.

Changes for:

Changes for static files

static

static directory

  • Create the images subdirectory.

  • Move the favicon to the images subdirectory.

common.blocks directory

server directory

  • Edit index.js.

    Change:

    .use(favicon(path.join(staticFolder, 'favicon.ico')))
    

    To:

    .use(favicon(path.join(staticFolder, '/images/favicon.ico')))
    

    Complete code for index.js.

When all these steps have been completed, the file structure in the static directory should look like this:

static/
    images/
        favicon.ico
index.min.css
index.min.js

Changes for server code

server-changes

server directory

  • Create these subdirectories:

    • controllers

    • helpers

    • middleware

  • Create empty JS files for the future modules:

    • app.js — Module for integrating middleware (makes it accessible in the application).

    • auth.js — Module for authentication on YouTube.

    • routes.js — Module for routing web requests.

  • Add this code to the app.js file.

  • Add this code to the routes.js file.

  • Change the extension of the config file:

    config.js —> config.json

  • Edit the config.json file

    Change:

    module.exports = {
        staticFolder: 'static',
        defaultPort: 3000,
        cacheTTL: 30000,
        sessionSecret: 'REPLACE_ME_WITH_RANDOM_STRING'
    };
    

    To:

    {
      "staticFolder": "static",
      "defaultPort": 3000,
      "cacheTTL": 30000,
      "sessionSecret": "REPLACE_ME_WITH_RANDOM_STRING"
    }
    
  • Change the current content of the index.js file to this.

    Note: The index.js file will only contain the functionality for starting the application and listening for requests on the port.

controllers directory

  • Create an empty JS file:

    • index.js — Controller for processing requests and rendering HTML.

  • Add this code to the index.js file.

helpers directory

  • Create empty JS files:

    • index.js — Entry point for helpers.

    • twitter.js — Helper module for working with the Twitter Search API.

    • youtube.js — Helper module for working with the YouTube Data API.

middleware directory

  • Create an empty JS file:

    • auth.js — Module for checking authentication on YouTube.

When all these steps have been completed, the file structure in the server directory should look like this:

server/
    controllers/
        index.js          # Controller for processing requests and rendering HTML
    helpers/
        index.js          # Entry point for helper modules (empty)
        twitter.js        # Helper module for working with the Twitter Search API (empty)
        youtube.js        # Helper module for working with the YouTube Data API (empty)
    middleware/
        auth.js           # Module for checking authentication on YouTube (empty)
    app.js                # Module for middleware integration
    auth.js               # Module for YouTube authentication (empty)
    config.json           # Application configuration
    index.js              # Starting the application and listening for requests on the port
    rebuild.js            # Module for tracking changes and retstarting the server
    render.js             # HTML rendering
    routes.js             # Router

Obtaining OAuth tokens

Twitter and Google store various user data such as tweets, YouTube videos, email messages, photos, and so on. To make it easy to access this data from other apps or third-party services, they use the OAuth 2.0 open authorization protocol.

The protocol requires the developer to register the application on the OAuth server and request access to specific data. The authorized user either grants or denies access.

Obtaining an OAuth token for Twitter

Twitter allows applications to make authenticated requests on behalf of the application itself.

How to get started

Note: You need Postman in order to make the POST request to receive the OAuth token in exchange for the code obtained using the Base64 method.

How do I encode a string?

To encode a string using Base64:

  • Create a string in the format Consumer Key:Consumer Secret.

    Example

    xvz1evFS4wEEPTGEFPHBog:L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg

    Note: To get the Consumer Key and Consumer Secret, go to the Keys and Access Tokens tab in your application.

  • Start the terminal or Git Bash.

  • Run the command echo -n "xvz1evFS4wEEPTGEFPHBog:L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg" | base64.

  • Copy the code you receive.

    Example

    eHZ6MWV2RlM0d0VFUFRHRUZQSEdFS2hab2xHQzB2SldMdzhpRUo4OERSZHlPZw==

Note: If you run into problems, consult the online resource base64encode.org.

How do I exchange the code for an OAuth token?

To receive a token in exchange for the code:

  • Start Postman.

    Note: By default, a tab opens where you need to form a POST request to the Twitter OAuth server.

  • Choose POST for the request type.

  • Enter the server address https://api.twitter.com/oauth2/token.

  • Go to the Headers tab.

  • In the Key field, enter the Authorization header with Value set to Basic <encoded Consumer Key:Consumer Secret string>.

    Example

    Authorization: Basic eHZ6MWV2RlM0d0VFUFRHRUZQSEdFS2hab2xHQzB2SldMdzhpRUo4OERSZHlPZw==

    Note: Basic indicates the basic authorization method.

  • Enter a second Content-Type header with the value application/x-www-form-urlencoded;charset=UTF-8.

    Example

    Content-Type: application/x-www-form-urlencoded;charset=UTF-8

  • Go to the Body tab.

  • Choose the option x-www-form-urlencoded.

  • In the Key field, enter the grant_type request body with the value client_credentials.

  • Click Send.

    The OAuth server returns the token in JSON:

    {
      "token_type": "bearer",
      "access_token": "AAAAAAAAAAAAAAAAAAAAAA%2FAAAAAAAAAA%3DAAAAAAAAAAAAAAAAAA"
    }
    

    Important: Save the token and keys that you receive (Consumer Key and Consumer Secret). You need them for the application's config file.

Obtaining an OAuth token for Google

Google allows applications to make authenticated requests on behalf of the application itself.

Note: The passport-youtube-v3 module is responsible for receiving and updating the OAuth token in exchange for the authorization code using a POST request.

How to get started

  • Read the documentation.

  • Register your application and receive the Client ID and Client Secret.

  • Set the callback URL (in our case, it is http://localhost:3000) in your application's account.

  • Use the Client ID and Client Secret that you received in requests that you send to the YouTube Data API.

Important: Save the keys that you receive (Client ID and Client Secret). You need them for the application's config file.

Application configuration

After you have received all the keys and tokens, you need to add them to the application's config file:

  • Add them to the server/config.json file in the services field.

    "services": {
      "twitter": {
        "consumer_key": "",
        "consumer_secret": "",
        "bearer_token": ""
      },
      "youtube": {
        "client_id": "",
        "client_secret": "",
        "redirect_url": "http://localhost:3000"
      }
    }
    

    Complete code for config.json.

  • Fill in the appropriate fields with the received data.

  • Hide the server/config.json file from the Git version control system so you don't accidentally add private keys to the file repository.

    # .gitignore file
    server/config.json
    

    Complete code for .gitignore.

Working with the Twitter Search API

The Twitter Search API lets you find recent or popular tweets that have been published on Twitter.com over the last 7 days.

More information:

API access

To successfully make calls to the API, you need:

  • The appropriate URL for the request.

  • An OAuth token issued to your application for accessing the API.

  • The twitter module.

API calls

Changes for working with the Twitter Search API:

twitter-changes

controllers directory

  • Change the current content of the index.js file to this.

helpers directory

  • Add the following content to the index.js file:

    module.exports = {
        twitter: require('./twitter')
    };
    
  • Add this code to the twitter.js file.

Working with the YouTube Data API

The YouTube Data API allows you to find videos that are published on Youtube.com. By default, the search results include videos, channels, and playlists.

More information:

API access

To successfully make calls to the API, you need:

  • The appropriate URL for the request.

  • An OAuth token issued to your application for accessing the API.

  • The googleapis module.

API calls

Changes for working with the YouTube Data API:

youtube-changes

server directory

  • Add this code to the auth.js file.

  • Edit routes.js.

    Change:

    var router = require('express').Router(),
        controllers = require('./controllers');
    
    router
        .get('/ping/', function(req, res) {
            res.send('ok');
        })
        .get('/', controllers.getContent);
    
    module.exports = router;
    

    To:

    var router = require('express').Router(),
        controllers = require('./controllers'),
        passportYouTube = require('./auth'),
        middleware = require('./middleware/auth'),
        isAuthenticated = middleware.isAuthenticated;
    
    router
        .get('/auth/youtube', passportYouTube.authenticate('youtube'))
        .get('/auth/youtube/callback', passportYouTube.authenticate('youtube', { failureRedirect: '/error', failureFlash: true }), (req, res) => {
            res.redirect('/');
        })
        .get('/', isAuthenticated, controllers.getContent);
    
    module.exports = router;
    

controllers directory

  • Change the current content of the index.js file to this.

helpers directory

  • Add the following content to the index.js file (see the note):

    module.exports = {
        twitter: require('./twitter'),
        youtube: require('./youtube')        // Connecting the `youtube.js` module
    };
    
  • Add this code to the youtube.js file.

middleware directory

  • Add the following content to the auth.js file:

    module.exports = {
        isAuthenticated: function(req, res, next) {
            if (req.isAuthenticated()) return next();
    
            return res.redirect('/auth/youtube');
        }
    };
    

Layout

This document focuses primarily on interaction between BEM technologies, so it doesn't cover layout and the JavaScript client. Describing layout issues would make this document unreasonably large.

To prepare the layout, follow these steps:

  • Delete all the blocks from the common.blocks directory.

  • Clone these blocks to the common.blocks directory.

  • Add logo.svg to the static/images directory.

  • Restart the server: npm run dev.

The Social Services Search Robot application is ready.

Did something go wrong?

If you had trouble creating the application, look for a solution in the forum. If you can't find an answer there, submit a question to the forum experts.

If you notice a mistake or want something to supplement the article, you can always write to us at GitHub, or correct an article using prose.io.