Learn web development

Учебник Express часть 2: Создание скелета сайта

Перевод не завершен. Пожалуйста, помогите перевести эту статью с английского.

Эта вторая статья в нашем учебнике Express показывает, как вы можете создать «скелет» проекта веб-сайта, который затем можно будет заполнить с помощью маршрутов сайта, шаблонов/представлений и вызовов базы данных.

Необходимые знания: Установить среду разработки Node. Просмотреть обзорно учебник Express.
Задача: Научиться запускать свои проекты используя Express Application Generator.

Обзор

В этой статье показано как вы можете создать "скелет" сайта с помощью инструмента Express Application Generator, который затем можно будет заполнить с помощью маршрутов сайта, шаблонов/представлений и вызовов базы данных. В этом случае мы будем использовать инструмент для создания основы для нашего сайта Local Library, к которому мы добавим весь другой код необходимый сайту. Процесс чрезвычайно прост, требуется только, чтобы вы вызвали генератор в командной строке с новым именем проекта, опционально также определяя механизм шаблона сайта и генератор CSS.

В следующих разделах показано, как вызвать генератор приложений, и даётся небольшое объяснение различных вариантов просмотра/CSS. Мы также объясним, как структурирован скелет веб-сайта. В конце мы покажем, как вы можете запустить веб-сайт, чтобы убедиться, что он работает.

Замечание: Express Application Generator генератор не только для Express приложений, и генерирование проекта не единственный способ организации для ваших файлов и директорий. Однако созданный сайт имеет модульную структуру, которую легко расширить и понять. Для информации о минимальном Express приложении, смотрите Hello world example (документация Express).

Использование генератора приложений

Вы уже должны были устанавливать генератор в статье установка среды разработки Node. Для быстрого напоминания, вы установили генератор используя пакетный менеджер NPM, следующим образом:

npm install express-generator -g

Генератор имеет несколько параметров, которые вы можете просмотреть в командной строке с помощью команды --help (или -h):

> express --help

  Usage: express [options] [dir]

  Options:

    -h, --help           output usage information
        --version        output the version number
    -e, --ejs            add ejs engine support
        --pug            add pug engine support
        --hbs            add handlebars engine support
    -H, --hogan          add hogan.js engine support
    -v, --view <engine>  add view <engine> support (ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
    -c, --css <engine>   add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
        --git            add .gitignore
    -f, --force          force on non-empty directory

Вы можете просто указать express для создания проекта в текущем каталоге с использованием механизма просмотра Jade и обычного CSS (если вы укажете имя каталога, тогда проект будет создан в подпапке с этим именем).

express

Вы также можете выбрать механизм просмотра (шаблона), используя --view и/или механизм генерации CSS с помощью --css.

Заметка: Другие опции для выбора шаблонизатора (такие как --hogan, --ejs, --hbs и пр.) устарели. Используйте --view (или -v)!

Какой шаблонизатор я могу использовать?

Экспресс генератор приложений позволяет вам сконфигурировать несколько популярных движков, включая EJS, Hbs, Pug (Jade), Twig, и Vash, тем не менее Jade выбран поумолчанию. Экспресс сам по себе может поддерживать большое количество шаблонизаторов из коробки.

Заметка: Если вы хотите использовать шаблонизатор, который не поддерживается генератором, тогда смотрите Использование шаблонных движков с Экспресс (Экспресс документация) и документацию для вашего шабонизатора.

Одним словом вы должны выбрать шаблонизатор, который имеет весь необходимый вам функционал и позволяет вам стать производительным как можно быстрее - другими словами, так же как вы выбираете любой другой компонент! Некоторые критерии для сравнения шаблонизаторов:

  • Время до производительности — Если ваша команда уже имела дело с шаблонизатором, в таком случае скорей всего продуктивнее будет использовать этот шаблонизатор. Если нет, тогда вам нужно рассмотреть все относительные сложности изучения для кандидатов в шаблонизаторы.
  • Популярность и активность — Проверьте популярность движка, возможно у него есть активное сообщество. Это очень важно иметь поддержку для движка, когда у вас возникают проблемы в течении жизни вебсайта.
  • Стиль — Некоторые шаблонизаторы используют специфическую разметку для отображения вставленного контента внутри "обычного" HTML, пока другие строят  HTML используя разный синтаксис (например, используя отступы или блочные имена).
  • Производительность/время интерпретации.
  • Особенности — вы должны выбирать движок  по наличию следующих особенностей:
    • Наследование макета: позволяет вам определить базовый шаблон и затем наследовать только те части, которые отличаются для конкретной страницы. Это, как правило, лучший подход, чем создание шаблонов путём включения нескольких необходимых компонентов или создания шаблона с нуля каждый раз.
    • Поддержка «Include»: позволяет создавать шаблоны, включая другие шаблоны.
    • Краткий синтаксис управления переменными и циклами.
    • Возможность фильтровать значения переменных на уровне шаблона (например, делать переменные в верхнем регистре или форматировать значение даты).
    • Возможность создавать выходные форматы, отличные от HTML (например, JSON или XML).
    • Поддержка асинхронных операций и потоковой передачи. Может использоваться как на клиенте, так и на сервере. Если на клиенте можно использовать шаблонный движок, это позволяет использовать данные и выполнять всю или большую часть рендеринга на стороне клиента.

Совет: В интернете множество ресурсов, которые могут оказать помощь в сравнении различных опций!

Для этого проекта мы будем использовать Pug в качестве шаблонизатора (в прошлом назывался Jade), так как это один из наиболее популярных Express/JavaScript шаблонизаторов, который поддерживается генератором без дополнительных настроек.

Какие шаблонизаторы CSS я могу использовать?

Express Application Generator позволяет вам создавать проекты, сконфигурированные для использования шаблонизаторов CSS: LESS, SASS, Compass, Stylus.

Заметка: CSS имеет некоторые ограничения, которые затрудняют выполнение задач. Шаблонизаторы CSS позволяют вам использовать более эффективный синтаксис для создании таблиц стилей CSS, после чего компилирует файлы шаблонизатора таблиц стилей в стандартный CSS для его восприятия браузером.

Как и в случае с шаблонизатором сайта вы должны использовать шаблонизатор, позволяющий вам и вашей команде работать более продуктивно. Для этого проекта мы будем использовать обычный CSS (по умолчанию), поскольку наши требования к CSS недостаточно сложны, чтобы оправдать использование чего-либо еще.

Какую базу данных я могу использовать?

Сгенерированный код не использует/включает в себя какую-либо базу данных. Express может использовать любой механизм взаимподействия с базой данных, который поддерживается Node (Express не предъявляет каких-либо специфичных требований к базе данных).

Мы будем обсуждать взаимодействие с базой данных в следующей статье.

Создание проекта

For the sample Local Library app we're going to build, we'll create a project named express-locallibrary-tutorial using the Pug template library and no CSS stylesheet engine.

Для начала перейдите в в директорию, которая будем использована для создания нового проекта и запустите Express Application Generator командой, указанной нижеin the command prompt as shown:

express express-locallibrary-tutorial --view=pug

Генератор создаст (и выведет списоком) проектные файлы.

   create : express-locallibrary-tutorial
   create : express-locallibrary-tutorial/package.json
   create : express-locallibrary-tutorial/app.js
   create : express-locallibrary-tutorial/public/images
   create : express-locallibrary-tutorial/public
   create : express-locallibrary-tutorial/public/stylesheets
   create : express-locallibrary-tutorial/public/stylesheets/style.css
   create : express-locallibrary-tutorial/public/javascripts
   create : express-locallibrary-tutorial/routes
   create : express-locallibrary-tutorial/routes/index.js
   create : express-locallibrary-tutorial/routes/users.js
   create : express-locallibrary-tutorial/views
   create : express-locallibrary-tutorial/views/index.pug
   create : express-locallibrary-tutorial/views/layout.pug
   create : express-locallibrary-tutorial/views/error.pug
   create : express-locallibrary-tutorial/bin
   create : express-locallibrary-tutorial/bin/www

   install dependencies:
     > cd express-locallibrary-tutorial && npm install

   run the app:
     > SET DEBUG=express-locallibrary-tutorial:* & npm start

После списка созданных объектов генератор выведет инструкции для установки зависимостей (которые указаны в файле package.json) и запуска приложения (указанные выше инструкции предназначены для Windows; для Linux/Mac OS X они могут слегка отличаться).

Запускаем скелет сайта

На данный момент у нас есть готовый скелет проект. Сайт на самом деле пока ничего не делает, но его стоит запустить для демонстрации его работы.

  1. Для начала установите зависимости (команда install запросит все пакеты зависимостей, указанных в файле package.json).
    cd express-locallibrary-tutorial
    npm install
  2. Затем запустите приложение.
    • В Windows используйте эту команду:
      SET DEBUG=express-locallibrary-tutorial:* & npm start
    • В Mac OS X или Linux, используйте эту комманду:
      DEBUG=express-locallibrary-tutorial:* npm start
      
  3. Откройте http://localhost:3000/ в вашем браузере для получения доступа к сайту.

Вы можете увидеть страницу, выглядящую так:

Browser for default Express app generator website

У вас есть веб-приложение на базе Express, работающее по адресу localhost:3000.

Заметка: Вы можете также запустить приложение с помощью команды npm start. Переменная DEBUG, указанная в примере, включает логгирование в консоль для дальнейшей отладки. К примеру, при посещении страницы веб-приложения, вы увидите похожий вывод в консоль:

>SET DEBUG=express-locallibrary-tutorial:* & npm start

> express-locallibrary-tutorial@0.0.0 start D:\express-locallibrary-tutorial
> node ./bin/www

  express-locallibrary-tutorial:server Listening on port 3000 +0ms
GET / 200 288.474 ms - 170
GET /stylesheets/style.css 200 5.799 ms - 111
GET /favicon.ico 404 34.134 ms - 1335

Enable server restart on file changes

Any changes you make to your Express website are currently not visible until you restart the server. It quickly becomes very irritating to have to stop and restart your server every time you make a change, so it is worth taking the time to automate restarting the server when needed.

One of the easiest such tools for this purpose is nodemon. This is usually installed globally (as it is a "tool"), but here we'll install and use it locally as a developer dependency, so that any developers working with the project get it automatically when they install the application. Use the following command in the root directory for the skeleton project:

npm install --save-dev nodemon

If you open your project's package.json file you'll now see a new section with this dependency:

  "devDependencies": {
    "nodemon": "^1.11.0"
  }

Because the tool isn't installed globally we can't launch it from the command line (unless we add it to the path) but we can call it from an NPM script because NPM knows all about the installed packages. Find the the scripts section of your package.json. Initially it will contain one line, which begins with "start". Update it by putting a comma at the end of that line, and adding the "devstart" line seen below:

  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www"
  },

We can now start the server in almost exactly the same way as previously, but with the devstart command specified:

SET DEBUG=express-locallibrary-tutorial:* & npm run devstart

Now if you edit any file in the project the server will restart (or you can restart it by typing rs on the command prompt at any time). You will still need to reload the browser to refresh the page.

Note: We now have to call "npm run <scriptname>" rather than just npm start, because "start" is actually an NPM command that is mapped to the named script. We could have replaced the command in the start script but we only want to use nodemon during development, so it makes sense to create a new script command.

The generated project

Let's now take a look at the project we just created.

Directory structure

The generated project, now that you have installed dependencies, has the following file structure (files are the items not prefixed with "/"). The package.json file defines the application dependencies and other information. It also defines a startup script that will call the application entry point, the JavaScript file /bin/www. This sets up some of the application error handling and then loads app.js to do the rest of the work. The app routes are stored in separate modules under the routes/ directory. The templates are stored under the /views directory.

/express-locallibrary-tutorial
    app.js
    /bin
        www
    package.json
    /node_modules
        [about 4,500 subdirectories and files]
    /public
        /images
        /javascripts
        /stylesheets
            style.css
    /routes
        index.js
        users.js
    /views
        error.pug
        index.pug
        layout.pug
    

The following sections describe the files in a little more detail.

package.json

The package.json file defines the application dependencies and other information:

{
  "name": "express-locallibrary-tutorial",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.15.2",
    "cookie-parser": "~1.4.3",
    "debug": "~2.2.0",
    "express": "~4.14.0",
    "morgan": "~1.7.0",
    "pug": "~2.0.0-beta6",
    "serve-favicon": "~2.3.0"
  },
  "devDependencies": {
    "nodemon": "^1.11.0"
  }
}

The dependencies include the express package and the package for our selected view engine (pug). In addition, we have the following packages that are useful in many web applications:

  • body-parser: This parses the body portion of an incoming HTTP request and makes it easier to extract different parts of the contained information. For example, you can use this to read POST parameters.
  • cookie-parser: Used to parse the cookie header and populate req.cookies (essentially provides a convenient method for accessing cookie information).
  • debug: A tiny node debugging utility modelled after node core's debugging technique.
  • morgan: An HTTP request logger middleware for node.
  • serve-favicon: Node middleware for serving a favicon (this is the icon used to represent the site inside the browser tab, bookmarks, etc.).

The scripts section defines a "start" script, which is what we are invoking when we call npm start to start the server. From the script definition you can see that this actually starts the JavaScript file ./bin/www with node. It also defines a "devstart" script, which we invoke when calling npm run devstart instead. This starts the same ./bin/www file, but with nodemon rather than node.

  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www"
  },

www file

The file /bin/www is the application entry point! The very first thing this does is require() the "real" application entry point (app.js, in the project root) that sets up and returns the express() application object.

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');

Note: require() is a global node function that is used to import modules into the current file. Here we specify app.js module using a relative path and omitting the optional (.js) file extension.

The remainder of the code in this file sets up a node HTTP server with app set to a specific port (defined in an environment variable or 3000 if the variable isn't defined), and starts listening and reporting server errors and connections. For now you don't really need to know anything else about the code (everything in this file is "boilerplate"), but feel free to review it if you're interested.

app.js

This file creates an express application object (named app, by convention), sets up the application with various settings and middleware, and then exports the app from the module. The code below shows just the parts of the file that create and export the app object:

var express = require('express');
var app = express();
...
module.exports = app;

Back in the www entry point file above, it is this module.exports object that is supplied to the caller when this file is imported.

Lets work through the app.js file in detail. First we import some useful node libraries into the file using require(), including express, serve-favicon, morgan, cookie-parser and body-parser that we previously downloaded for our application using NPM; and path, which is a core Node library for parsing file and directory paths.

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

Then we require() modules from our routes directory. These modules/files contain code for handling particular sets of related "routes" (URL paths). When we extend the skeleton application, for example to list all books in the library, we will add a new file for dealing with book-related routes.

var index = require('./routes/index');
var users = require('./routes/users');

Note: At this point we have just imported the module; we haven't actually used its routes yet (this happens just a little bit further down the file).

Next we create the app object using our imported express module, and then use it to set up the view (template) engine. There are two parts to setting up the engine. First we set the 'views' value to specify the folder where the templates will be stored (in this case the sub folder /views). Then we set the 'view engine' value to specify the template library (in this case "pug").

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

The next set of functions call app.use() to add the middleware libraries into the request handling chain. In addition to the 3rd party libraries we imported previously, we use the Express.static middleware to get Express to serve all the static files in the directory /public in the project root.

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

Now that all the other middleware is set up, we add our (previously imported) route-handling code to the request handling chain. The imported code will define particular routes for the different parts of the site:

app.use('/', index);
app.use('/users', users);

Note: The paths specified above ('/' and '/users') are treated as a prefix to routes defined in the imported files. So for example if the imported users module defines a route for /profile, you would access that route at /users/profile. We'll talk more about routes in a later article.

The last middleware in the file adds handler methods for errors and HTTP 404 responses.

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

The Express application object (app) is now fully configured. The last step is to add it to the module exports (this is what allows it to be imported by /bin/www).

module.exports = app;

Routes

The route file /routes/users.js is shown below (route files share a similar structure, so we don't need to also show index.js). First it loads the express module, and uses it to get an express.Router object. Then it specifies a route on that object, and lastly exports the router from the module (this is what allows the file to be imported into app.js).

var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.send('respond with a resource');
});

module.exports = router;

The route defines a callback that will be invoked whenever an HTTP GET request with the correct pattern is detected. The matching pattern is the route specified when the module is imported ('/users') plus whatever is defined in this file ('/'). In other words, this route will be used when an URL of /users/ is received.

Tip: Try this out by running the server with node and visiting the URL in your browser: http://localhost:3000/users/. You should see a message: 'respond with a resource'.

One thing of interest above is that the callback function has the third argument 'next', and is hence a middleware function rather than a simple route callback. While the code doesn't currently use the next argument, it may be useful in the future if you add want to add multiple route handlers to the '/' route path.

Views (templates)

The views (templates) are stored in the /views directory (as specified in app.js) and are given the file extension .pug. The method Response.render() is used to render a specified template along with the values of named variables passed in an object, and then send the result as a response. In the code below from /routes/index.js you can see how that route renders a response using the template "index" passing the template variable "title".

/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', { title: 'Express' });
});

The corresponding template for the above route is given below (index.pug). We'll talk more about the syntax later. All you need to know for now is that the title variable (with value 'Express') is inserted where specified in the template.

extends layout

block content
  h1= title
  p Welcome to #{title}

Challenge yourself

Create a new route in /routes/users.js that will display the text "You're so cool" at URL /users/cool/. Test it by running the server and visiting http://localhost:3000/users/cool/ in your browser

Summary

You have now created a skeleton website project for the Local Library and verified that it runs using node. Most important, you also understand how the project is structured, so you have a good idea where we need to make changes to add routes and views for our local library.

Next we'll start modifying the skeleton so that works as a library website.

See also

Метки документа и участники

Внесли вклад в эту страницу: Maxim_Tovchenko, maxno62, ozeep, temenb, daviys
Обновлялась последний раз: Maxim_Tovchenko,