среда, 24 апреля 2013 г.

Импортирование модулей Node.js

В каждом файле может быть описан только один модуль, как в Require JS.
Модули лучше записывать в каталоги node_modules.
Поиск модулей происходит в каталогах node_modules, идя вверх по уровням вложенности папок до корня
файловой системы /.

Импортирование модулей.

Файл mymodule.js

var count = 0;

exports.next = function(){
    return count++;
}

exports.foo = 'one';
exports.bar = 'two';

Файл main.js

var s = require('./mymodule');

s.next(); // 0
s.next(); // 1
s.next(); // 2
s.next(); // 3

s.foo; // one
s.bar; // two

package.json для модулей

{
    name: 'myModule',
    main: '.lib/my_module.js'
}

При таком файле package.json команда require('myModule') найдет этот каталог и загрузит файл
/path/to/node_modules/myModule/lib/my_module.js

Если файла package.json нет, то Node будет вместо него искать файл index.js, то есть загрузит файл
/path/to/node_modules/myModule/index.js

Команды Grunt

Типичный состав файла Gruntfile.js

module.exports = function(grunt) {

  // Configuration goes here
  grunt.initConfig({
   
    // Configure the copy task to move files from the development to production folders
    copy: {
      target: {
        files: {
          'prod/': ['dev/**']
        }
      }
    },
  });

  // Load plugins here
  grunt.loadNpmTasks('grunt-contrib');

  // Define your tasks here
  grunt.registerTask('default', ['copy']);

};

Список доступных команд Grunt и установленных плагинов Grunt-contrib

grunt --help

Запуск тасков по дефолту

grunt

Запус какого-то отдельного таска, например jshint, вместе со всеми его таргетами

grunt jshint

Запуск отдельного таска с конкретным таргетом

grunt concat:foo

Определение своего собственного таска в файле Gruntfile.js

module.exports = function(grunt) {

    // A very basic default task.
    grunt.registerTask('default', 'Log some stuff.', function(){
        grunt.log.write('Logging some stuff...').ok();
    });

};

Формат работы с файлами

grunt.initConfig({
  jshint: {
    foo: {
      src: ['src/aa.js', 'src/aaa.js']
    },
  },
  concat: {
    bar: {
      src: ['src/bb.js', 'src/bbb.js'],
      dest: 'dest/b.js',
    },
  },
});

Фильтрация файлов

grunt.initConfig({
  clean: {
    foo: {
      src: ['tmp/**/*'],
      filter: function(filepath) {
        return (grunt.file.isDir(filepath) && require('fs').readdirSync(filepath).length === 0);
      },
    },
  },
});

Импортирование данных в формате JSON и YAML

pkg: grunt.file.readJSON('package.json');
pkg: grunt.file.readYAML('');

---------------------------------------------------------------

grunt.initConfig({
  pkg: grunt.file.readJSON('package.json'),
  uglify: {
    options: {
      banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
    },
    dist: {
      src: 'src/<%= pkg.name %>.js',
      dest: 'dist/<%= pkg.name %>.min.js'
    }
  }
});

grunt.loadNpmTasks('grunt-uglify');

grunt.registerTask('default', ['uglify']);

Список плагинов Grunt

grunt-contrib-uglify
grunt-contrib-qunit
grunt-contrib-concat
grunt-contrib-jshint
grunt-contrib-watch

Установка всех плагинов

npm install grunt-contrib-uglify --save-dev
npm install grunt-contrib-qunit --save-dev
npm install grunt-contrib-concat --save-dev
npm install grunt-contrib-jshint --save-dev
npm install grunt-contrib-watch --save-dev

Загрузка всех плагинов в файле Gruntfile.js

grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-concat');

Регистрация всех таксов, запускаемых по умолчанию

grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);

Запуск вотчера

grunt watch

Шаблоны как в Ruby on Rails

<%= pkg.name %> - вывод значения переменной

<% console.log('Здесь можно писать любой JavaScript-код'); %> - выполнение любого кода

Пример полного файла Gruntfile.js со всеми плагинами

module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      options: {
        separator: ';'
      },
      dist: {
        src: ['src/**/*.js'],
        dest: 'dist/<%= pkg.name %>.js'
      }
    },
    uglify: {
      options: {
        banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
      },
      dist: {
        files: {
          'dist/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
        }
      }
    },
    qunit: {
      files: ['test/**/*.html']
    },
    jshint: {
      files: ['gruntfile.js', 'src/**/*.js', 'test/**/*.js'],
      options: {
        // options here to override JSHint defaults
        globals: {
          jQuery: true,
          console: true,
          module: true,
          document: true
        }
      }
    },
    watch: {
      files: ['<%= jshint.files %>'],
      tasks: ['jshint', 'qunit']
    }
  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-concat');

  grunt.registerTask('test', ['jshint', 'qunit']);

  grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglify']);

};

Регистрация различных тасков

grunt.registerTask('default', ['jshint', 'qunit', 'concat', 'uglife']);
grunt.registerTask('dist', ['concat:dits', 'uglify:dist']);

Регистрация собственного таска

grunt.initConfig({
  log: {
    foo: [1, 2, 3],
    bar: 'hello world',
    baz: false
  }
});

grunt.registerMultiTask('log', 'Log stuff.', function() {
  grunt.log.writeln(this.target + ': ' + this.data);
});

grunt.registerTask('foo', 'A sample task that logs stuff.', function(arg1, arg2) {
  if (arguments.length === 0) {
    grunt.log.writeln(this.name + ", no args");
  } else {
    grunt.log.writeln(this.name + ", " + arg1 + " " + arg2);
  }
});

Выполнение собственного таска

grunt log:foo

или с подстановкой аргументов 'testing' и '123'

grunt foo:testing:123

Внутри регистрации тасков можно запускать другие таски

grunt.registerTask('foo', 'My task.', function() {
  grunt.task.run('bar', 'baz');
});

Таски могут быть асинхронными

grunt.registerTask('asyncfoo', 'My async task.', function() {

  // Force task into async mode and grab a handle to the "done" function.
  var done = this.async();

  // Run some sync stuff.
  grunt.log.writeln('Processing task...');

  // And some async stuff.
  setTimeout(function() {
    grunt.log.writeln('All done!');
    done();
  }, 1000);

});

Таски имеют доступ к своему имени и аргументам, которые могут использоваться в коде

grunt.registerTask('foo', 'My task.', function(a, b) {
  grunt.log.writeln(this.name, a, b);
});

В случае возникновения ошибки такс можно прервать программным способом

grunt.registerTask('foo', 'My task.', function() {

  if (failureOfSomeKind) {
    grunt.log.error('This is an error message.');
  }

  // Fail by returning false if this task had errors
  if (ifErrors) { return false; }

  grunt.log.writeln('This is the success message');

});

Если таск провалится, то все последующие таски будут прерваны, если при запуске не указана опиция --force

grunt --force

grunt.registerTask('foo', 'My "foo" task.', function() {
  // Fail synchronously.
  return false;
});

grunt.registerTask('bar', 'My "bar" task.', function() {
  var done = this.async();
  setTimeout(function() {
    // Fail asynchronously.
    done(false);
  }, 1000);
});

Выполнение тасков может быть зависимым от результатов выполнения других тасков

grunt.registerTask('foo', 'My "foo" task.', function() {
  return false;
});

grunt.registerTask('bar', 'My "bar" task.', function() {
  // Fail task if "foo" task failed or never ran.
  grunt.task.requires('foo');
  // This code executes if the "foo" task ran successfully.
  grunt.log.writeln('Hello, world.');
});

Таск может провалиться, если требуемая конфигурация grunt.config свойств не существует

grunt.registerTask('foo', 'My "foo" task.', function() {
  // Fail task if "meta.name" config prop is missing.
  grunt.config.requires('meta.name');
  // Also fails if "meta.name" config prop is missing.
  grunt.config.requires(['meta', 'name']);
  // Log... conditionally.
  grunt.log.writeln('This will only log if meta.name is defined in the config.');
});

Таск может получать доступ к содержимому grunt.config

grunt.registerTask('foo', 'My "foo" task.', function() {
  // Log the property value. Returns null if the property is undefined.
  grunt.log.writeln('The meta.name property is: ' + grunt.config('meta.name'));
  // Also logs the property value. Returns null if the property is undefined.
  grunt.log.writeln('The meta.name property is: ' + grunt.config(['meta', 'name']));
});   

Команды NPM - Node Package Manager

Node package manager

Показать документацию по Node package manager

npm help

Показать справку по конкретной команде Node package manager

npm help <command>

Показать документацию по структуре файла package.json

npm help json

Простейшая структура файла package.json

{
    name: 'packageName',
    version: '1.0',
    main: 'myModuleName', // Внимание! Значение main подставляется в URL-адреса и названия команд!
    modules: {
        'mod1': 'lib/mod1',
        'mod2': 'lib/mod2'
    }
}

Модуль можно загрузать в коде череза require('myModuleName')

Проверка наличия модуля в репозитории по адресу http://search.npmjs.org

npm search myModuleName

Указание зависимостей модуля от других модулей

dependecies: {
    foo: '1.0.0 - 2.9999.9999',
    bar: '>= 1.0.2 < 2.1.2'
}

Сведения об авторе модуля

description: 'My first super module.',
homepage: 'http://www.mysite.com',
author: 'Dmitry'

Командные скрипты модуля

bin: {
    'nodeload.js': './nodeload.js',
    'nl.js': './nl.js'
}

Получить подсказку по скриптовым командам модуля

npm help scripts

Структура папок внутри модуля

direcotories: {
    lib: './lib',
    bin: './bin'
}

Показать список установленных модулей

npm list

Показать список установленных модулей в более удобном виде в виде адресов к папкам

npm set parseable=true
npm list

Установка модуля

npm install moduleName

Модуль устанавливается в локальную папку node_modules

Для установки модуля в глобальную папку node_modules Node.js необходимо использовать флаг -g

npm install -g moduleName

Установка определенной версии модуля

npm install moduelName@2.3.1

Установка самой последней стабильной версии модуля

npm install moduleName@stable

Определить куда был установлен Node.js

which node

Установка правила устававливать все модули глобально

npm set global=true

Показать занчение параметра global

npm get global

Поиск модулей производится на сайте http://npmjs.org или http://search.npmjs.org
или командой

npm search moduleName

Вывод содержимого файла package.json любого (даже не скаченного) модуля в командную строку

npm view moduleName

Вывод любого значения из файла package.json модуля

npm view moduleName homepage

Вывод версии модуля

npm view moduleName version

Вывод зависимостей модуля

npm view moduleName dependecies

Запуск тестов модуля, если они есть

npm test moduleName

Если отредактировать содержимое модуля, то после этого необходимо его перестроить, набрав команду

npm rebuild moduleName

Проверка даты обновления модуля в репозитории

npm outdated

Обновление устаревших модулей

npm update moduleName

Удалени установленного модуля

npm uninstall moduleName

Создание модуля

0) Создание и переход в папку будущего модуля

mkdir myModule
cd myModule

1) Создание файла package.json

npm  init

2) Создание кода модуля

3) Заведение аккаунта в публияном репозитории

npm adduser

4) Публикация модуля в публичном репозитории

npm publish

5) Поиск своего модуля на сайте http://search.npmjs.org

6) Удаление своего модуля из публичного репозитория при необходимости

npm unpublish

Команды конфигурации Node package manager

npm config set color true --global
npm config get color
npm config delete color

npm config list
npm config edit

npm get color
npm set color true --global

Конфигурационные параметры можно помещать в следующие файлы
$HOME/.npmrc
Инсталляционный каталог Node/etc/npmrc

Конфигурационный файл Node package manager содержит пары name=value и обновляется командой

npm config set

Номера версия модуля

version: 'X.Y.Z', где
X - основной номер (0 - совершеннно нестабилен, 1 и далее - внесены несовместимые изменения)
Y - дополнительный номер (тут добален новый функционал)
Z - номер исправления (тут исправлены только ошибки)

Команды Node.js

Подсказки по командам

node --help
node --v8-options

Запуск интерпретатора Node.js

node
> console.log('Hello, world!');

Выход из интерпретатора Node.js

Два раза нажмите сочетание клавиш Ctrl + C

Запуск файла в Node.js

node myscript.js

Пример содержимого файла myscript.js

var fs = require('fs');
var files = fs.readdirSync('.');
for (file in files) {
    console.log(files[file]);
}

Данный код выведет список файлов и директорий в текущей папке.

Запуск файла в Node.js с передачей аргументов файлу через командную строку

node myscript.js ../

Переданные файлу через командную строку аргументы содержатся в глобальном массиве
process.argv

Посмотрим пример работы с аргументами командной строки в файле myscript.js

var fs = require('fs'); // Загружаем модуль fs для работы с файлами и папками
var dir = '.';              // Текущая папка

if (process.argv[2]) {
    dir = process.argv[2];
}

var files = fs.readdirSync(dir);
for (file in files) {
    console.log(files);
}

Запуск простейшего сервера на Node.js

Создадим файл app.js

var http = require('http');
http.createServer(function(request, response){
    response.writeHead(200, {'Content-Type': 'text/plain'});
    response.end('Hello, World!\n');
}).listen(8124, '127.0.0.1');

console.log('Server is running at http://127.0.0.1:8124');

Перейдя в браузере по ссылке http://127.0.0.1:8124 вы увидете на странице сообщение

Hello, World!

Чтобы остановить сервер нажмите сочетание клавиш Ctrl + C

Установка Grunt в Ubuntu после установки Node.js

0. Проверка установлен ли Grunt в системе

grunt --version

1. Удаление Grunt из операционной системы, если ранее он был установлен

npm uninstall -g grunt

2. Установка Grunt CLI

sudo npm install -g grunt-cli

3. Создаем папку, в которой будем использовать Grunt

cd /home/dovsyannikkov
mkdir GruntProject

4. Переходим в созданную папку, где будем использовать Grunt

cd GruntProject

5. Создаем файл package.json для указания модулей, используемых в проекте для их инсталяции

npm init

6. Заполним созданный файл package.json следующим кодом

{
  "name": "GruntProject",
  "author": "Dmitry Ovsyannikov",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-jshint": "~0.1.1"
  }
}

Необязательная команда

npm install grunt-contrib --save-dev

установит все плагины и обновит package.json до такого состояния

{
  "name": "GruntProject",
  "author": "Dmitry Ovsyannikov",
  "version": "0.1.0",
  "devDependencies": {
    "grunt": "~0.4.1",
    "grunt-contrib-jshint": "~0.1.1",
    "grunt-contrib": "~0.6.1"
  }
}

7. Установим Grunt и JSHint в эту папку GruntProject, согласно перечисленным в файле package.json плагинам

npm install

8. Проверим установку Grunt и Grunt CLI

grunt --version

9. Создадим файл Gruntfile.js, в котором будет находится код для Grunt

touch Gruntfile.js

10. Заполняем файл Gruntfile.js следующим кодом

module.exports = function(grunt) {

  // Configuration goes here
  grunt.initConfig({

    // Some typical JSHint options and globals
    jshint: {
        all: [
            'main.js'
        ],
        options: {
            devel: false,
           
            camelcase: true,
            curly: true,
            eqeqeq: false,
            immed: true,
            indent: 4,
            latedef: true,
            newcap: true,
            noarg: true,
            quotmark: 'single',
            undef: true,
            unused: true,
            strict: false,
            trailing: true,

            eqnull: true,
            laxcomma: true,

            browser: true,
            jquery: true,
            node: true,
            nonstandard: true,
            worker: true,

            white: false,

            //nomen: true,

            //boss: true,
            maxlen: 130,

            globals: {
                require: true,
                define: true,

                underscore: true,
                '_': true
            }
        }
    }

  });

  // Load plugins here
  grunt.loadNpmTasks('grunt-contrib-jshint');

  // Define your tasks here
  grunt.registerTask('default', ['jshint']);

};

11. В папке GruntProject создаем файл main.js

touch main.js

12. Файл main.js заполняем кодом, который будем тестировать через JSHint

/**
 * Searches a keyword and shows formatted results
 *
 * @class pages/search/main
 */

define([
    'jquery'
  , 'app.config'
  , 'repo/utils/xss'

  , 'text!./templates/list-results.html'

  , 'underscore'
], function(
    $
  , appConfig
  , xss

  , tplSocialButtons
) {

    var CSS_FORM_NAME = 'js-form'

      , $query
      , $form
      , $searchButton;

    function init() {
        updateVars();
        bindEvents();
    }

    function updateVars() {
        $query = $( '.js-query' );
        $form = $( '.' + CSS_FORM_NAME );
        $searchButton = $( '.js-search' );
    }

    function bindEvents() {
        $searchButton.click( search );
    }

    function search() {
        var query = $query.val();

        $.ajax({
            type: 'GET'
          , url: appConfig.urls.search
          , data: query
          , success: redrawView
        });
    }

    /**
     * Sends form data and shows a result
     *
     * @param {Object} json Object with news
     * @method redrawView
     * @public
     */
    function redrawView( json ) {
        var data = xss.clear( json )
          , html = _.template( tplSocialButtons, { data: data } );

        $form.html( html );
    }
   
    return {
        init: init
      , redrawView: redrawView
    };
});

13. Запускаем Grunt для тестирования кода в файле main.js через JSHint, код которого описан в файле Gruntfile.js

grunt

Установка Node.js в Ubuntu

0. Проверяем наличие в операционной системы необходимых для работы библиотек

python --version
g++ --version
curl --version
locate libssl
openssl version
git --version

1. Устанавливаем необходимые пакеты и библиотеки в случае их отсутствия

по отдельности

sudo apt-get install python
sudo apt-get install g++
sudo apt-get install curl
sudo apt-get install libssl-dev
sudo apt-get install openssl-devel
sudo apt-get install git

сразу все вместе

sudo apt-get install python g++ curl libssl-dev openssl-devel git

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

cd /home/dovsyannikkov
mkdir NodeSourceCode

3. Переходим в созданную папку, где будем храним исходники Node.js

cd NodeSourceCode

4. И клонируем последнюю версию Node.js из официального репозитория Git

git clone https://github.com/joyent/node.git

6. Переходим в автоматически созданную папку node

cd node

4. Выбираем для скачивания последнюю стабильную версию Node.js

git checkout v0.10.4-release

5. Компилируем и устанавливаем Node.js из исходных кодов

./configure
make
sudo make install

6. Проверяем результат установки Node.js и пакетного менеджера npm

node --version
npm --version

Если по обеим командам получили номер версии, то всё установлено правильно

Хорошая подборка книг по JavaScript

— JavaScript: The Definitive Guide, 5th Edition By David Flanagan
— Pro JavaScript Techniques by John Resig
— Pro JavaScript Design Patterns by Dustin Diaz and Ross Harmes
— JavaScript: The Good Parts by Douglas Crockford