пятница, 16 марта 2018 г.

Browser XMLHttpRequest and Node Server

Файл server.js

var http = require('http')
    , fs = require('fs')
    , path = require('path')
    , url = require('url')
    , querystring = require('querystring');

var server = http.createServer();

server.on('request', function (request, response) {
    if (request.method === 'POST' && url.parse(request.url).path === '/ajax') {
        var data = [];
        request.on('data', function (chunk) {data.push(chunk)});
        request.on('end', function () {
            setTimeout(function () {
                response.writeHead(200, {'Content-Type': 'text/plain'});
                var query = querystring.parse(data.join());
                response.end(query.data);
            }, 1000);
        });
    } else {
        fs.readFile(path.resolve(path.join(__dirname, 'index.html')), function (error, indexHTML) {
            if (error) {throw error;}
            response.writeHead(200, {'Content-Type': 'text/html'});
            response.end(indexHTML);
        });
    }
});

server.listen(80, '127.0.0.1', function (error) {
    if (error) {throw error;}
    console.log('Server started at 127.0.0.1:80');
});

Файл index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>XMLHttpRequest</title>
</head>
<body>
    <div id="server-response"></div>
    <script type="text/javascript">
        setTimeout(function () {
            var request = new XMLHttpRequest();
            if (request.readyState === 0) {
                console.log('readyState 0 UNSENT: ' + (request.readyState === request.UNSENT));
            }
            request.open('POST', '/ajax', true, 'username', 'password');
            if (request.readyState === 1) {
                console.log('readyState 1 OPENED: ' + (request.readyState === request.OPENED));
            }
            request.onreadystatechange = function () {
                if (request.readyState === 2) {
                    console.log('readyState 2 HEADERS_RECEIVED: ' + (request.readyState === request.HEADERS_RECEIVED));
                }
                if (request.readyState === 3) {
                    console.log('readyState 3 LOADING: ' + (request.readyState === request.LOADING));
                }
                if (request.readyState === 4) {
                    console.log('readyState 4 DONE: ' + (request.readyState === request.DONE));
                }
                if (request.readyState === 4) {
                    var response = this;
                    if (response.status === 200) {
                        document.getElementById('server-response').innerHTML = (
                               '<p>RESPONSE STATUS:</p>'
                            + '<p>' + response.status + '</p>'
                            + '<p>RESPONSE STATUS TEXT:</p>'
                            + '<p>' + response.statusText + '</p>'
                            + '<p>HEADERS:</p>'
                            + '<p>' + response.getAllResponseHeaders() + '</p>'
                            + '<p>HEADER CONTENT_TYPE:</p>'
                            + '<p>' + response.getResponseHeader('Content-Type') + '</p>'
                            + '<p>RESPONSE URL:</p>'
                            + '<p>' + response.responseURL + '</p>'
                            + '<p>RESPONSE:</p>'
                            + '<p>' +response.response + '</p>'
                            + '<p>RESPONSE TEXT:</p>'
                            + '<p>' + response.responseText + '</p>'
                        );
                    } else {
                        document.getElementById('server-response').innerHTML = 'Error. Status code: ' + response.status + ', status text: ' + response.statusText;
                    }
                }
            };
            request.timeout = 2000;
            request.ontimeout = function () {document.getElementById('server-response').innerHTML = 'Timeout'};
            request.onabort = function () {document.getElementById('server-response').innerHTML = 'Abort'};
            request.onerror = function (event) {document.getElementById('server-response').innerHTML = 'Error. Server is not available. Status code: ' + event.target.status;};
            if (request.overrideMimeType) {request.overrideMimeType('text/plain', 'x-user-defined');}
            request.setRequestHeader('My-Header', 'abcdef');
            request.withCredentials = true;
            request.responseType = 'text';
            request.send('data=123&value=456');
            setTimeout(function () {request.abort();}, 500);
        }, 5000);
    </script>
</body>
</html>

четверг, 15 марта 2018 г.

new XMLHttpRequest()

var xhr = new XMLHttpRequest();

xhr.open('POST', 'http://www.site.com/', true, 'username', 'password');

xhr.withCredentials = true;

xhr.timeout = 120000;

xhr.setRequestHeader('My-Header', '123');

xhr.overrideMimeType('text/plain; charset=x-user-defined');

xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
        if (xhr.status === 200 || xhr.status === 0) {
            console.log('status: ' + xhr.status === 1223 ? 204 : xhr.status);
            console.log('statusText: ' + xhr.status === 1223 ? 'No Content' : xhr.statusText);
            console.log('getAllResponseHeaders: ' + xhr.getAllResponseHeaders());
            console.log('getResponseHeader: ' + xhr.getResponseHeader('Content-Type'));
            console.log('responseText: ' + xhr.responseText);
        } else {
            console.log('Error in request.');
        }
    }
};

xhr.onabort = function () {
    if (!xhr) {return;}
    xhr = null;
    console.log('Aborted.');
};

xhr.ontimeout = function () {
    xhr = null;
    console.log('Timeout.');
};

xhr.onerror = function (error) {
    xhr = null;
    console.log('Error.');
    console.log(error.message);
};

xhr.send(JSON.stringify({a: 1, b: 2}));

setTimeout(function () {
    if (xhr) {xhr.abort();}
}, 1000);

понедельник, 5 марта 2018 г.

AJAX загрузка картинок

<html>
<body>
<script language="javascript" type="text/javascript">
    function send_with_ajax ( ) {
        if (window.XMLHttpRequest || window.ActiveXObject) {
            if (window.ActiveXObject) {
                try {
                    xhr = new ActiveXObject("Msxml2.XMLHTTP");
                } catch(exception) {
                    xhr = new ActiveXObject("Microsoft.XMLHTTP");
                }
            } else {
              xhr = new XMLHttpRequest();
            }
        } else {
            alert("Your browser does not support XMLHTTP Request...!");
        }

        xhr.open("GET", "300x300.gif", true);   // Make sure file is in same server
        xhr.overrideMimeType('text/plain; charset=x-user-defined');
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4){
                if ((xhr.status == 200) || (xhr.status == 0)){
                    var image = document.getElementById("get_img");
                    image.src = "data:image/gif;base64," + encode64(xhr.responseText);
                }else{
                    alert("Something misconfiguration : " +
                        "\nError Code : " + xhr.status +
                        "\nError Message : " + xhr.responseText);
                }
            }
        };
        xhr.send(null);
    }

    function encode64 (inputStr) {
       var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
       var outputStr = "";
       var i = 0;
     
       while (i> 2;
          var enc2 = ((byte1 & 3) << 4) | (byte2 >> 4);
         
          var enc3, enc4;
          if (isNaN(byte2)){
            enc3 = enc4 = 64;
          } else{
            enc3 = ((byte2 & 15) << 2) | (byte3 >> 6);
            if (isNaN(byte3)){
               enc4 = 64;
            } else {
                enc4 = byte3 & 63;
            }
          }
          outputStr +=  b64.charAt(enc1) + b64.charAt(enc2) + b64.charAt(enc3) + b64.charAt(enc4);
       }
       return outputStr;
    }
</script>

<button onClick="send_with_ajax()">Get Image</button><br />
<img id="get_img" />
</body>
</html>

пятница, 2 марта 2018 г.

Node.js - Краткая шпаргалка по работе с файлами

const fs = require('fs');

// Создать, переименовать или переместить, прочитать содержимое, удалить директорию.

fs.mkdir('test-dir', 0o777, function (error) {if (error) {throw error;}
    fs.rename('./test-dir', './other-dir', function (error) {if (error) {throw error;}
        fs.readdir('./other-dir', {encoding: 'utf8'}, function (error, files) {if (error) {throw error;}
            console.log(files);
            fs.rmdir('./other-dir', function (error) {if (error) {throw error;}});
        });
    });
});

// Создать или записать, дописать, обрезать, прочитать содержимое, переименовать или переместить, скопировать, удалить файл.

fs.writeFile('test-file.txt', 'Hello world', {encoding: 'utf8', mode: 0o666, flag: 'w'}, function (error) {if (error) {throw error;}
    fs.appendFile('./test-file.txt', ' and home', {encoding: 'utf8', mode: 0o666, flag: 'a'}, function (error) {if (error) {throw error;}
        fs.truncate('./test-file.txt', 5, function (error) {if (error) {throw error;}
            fs.readFile('./test-file.txt', {encoding: 'utf8', flag: 'r'}, function (error, data) {if (error) {throw error;}
                console.log(data);
                fs.rename('./test-file.txt', './other-file.txt', function (error) {if (error) {throw error;}
                    fs.link('./other-file.txt', './test-file.txt', function (error) {if (error) {throw error;}
                        fs.unlink('./other-file.txt', function (error) {if (error) {throw error;}
                        });
                    });
                });
            });
        });
    });
});

// Изменить права доступа, узнать время создания и изменения, изменить время создания и изменения, узнать полный путь файла.

fs.chmod('./test-file.txt', 0o777, function (error) {if (error) {throw error;}
    fs.access('./test-file.txt', fs.constants.R_OK | fs.constants.W_OK, function (error) {
        if (error) {console.log('No access!');} else {console.log('Can read | write');}
        fs.stat('./test-file.txt', function (error, stat) {if (error) {throw error;}
            console.log(stat.birthtime);
            fs.utimes('./test-file.txt', (new Date().getTime() + 20000) / 1000, (new Date().getTime() + 50000) / 1000, function (error) {if (error) {throw error;}
                fs.realpath('./test-file.txt', {encoding: 'utf8'}, function (error, resolvedPath) {if (error) {throw error;}
                    console.log(resolvedPath);
               });
            });
        });
    });
});

// Открыть, записать, закрыть файл.

fs.open('./test-file.txt', 'w', 0o666, function (error, fd) {if (error) {throw error;}
    const dataBuffer = Buffer.from('abcdefghijklmnopqrstuvwxyz');
    const dataBufferSize = dataBuffer.length;
    let chunkBufferSize = 2; // in bytes
    let chunkBuffer = dataBuffer.slice(0, chunkBufferSize);
    let totalBytesWritten = 0;
    const offset = 0;
    function writeDataToFile () {
        if (totalBytesWritten < dataBufferSize) {
            fs.write(fd, chunkBuffer, offset, chunkBufferSize, totalBytesWritten, function (error, chunkBufferBytesWritten, buffer) {if (error) {throw error;}
                totalBytesWritten += chunkBufferSize;
                if ((totalBytesWritten + chunkBufferSize) > dataBufferSize) {
                    chunkBufferSize = dataBufferSize - totalBytesWritten;
                }
                chunkBuffer = dataBuffer.slice(totalBytesWritten, totalBytesWritten + chunkBufferSize);
                writeDataToFile();
            });
        } else {
            fs.close(fd, function (error) {if (error) {throw error;}
            });
        }
    }
    writeDataToFile();
});

// Открыть, прочитать, закрыть файл.

fs.open('./test-file.txt', 'r', function (error, fd) {if (error) {throw error;}
    fs.fstat(fd, function (error, stat) {if (error) {throw error;}
        const fileSize = stat.size;
        let fileBuffer = Buffer.alloc(fileSize);
        let chunkBufferSize = 2; // in bytes
        let totalBytesRead = 0;
        function readDataFromFile () {
            if (totalBytesRead < fileSize) {
                if ((totalBytesRead + chunkBufferSize) > fileSize) {
                    chunkBufferSize = fileSize - totalBytesRead;
                }
                fs.read(fd, fileBuffer, totalBytesRead, chunkBufferSize, totalBytesRead, function (error, chunkBytesRead, buffer) {if (error) {throw error;}
                    totalBytesRead += chunkBufferSize;
                    console.log(buffer.toString('utf8'));
                    readDataFromFile();
                });
            } else {
                fs.close(fd, function (error) {if (error) {throw error;}
                });
            }
        }
        readDataFromFile();
    });
});

// Поток записи в файл.

const writeStream = fs.createWriteStream('./test-file.txt', {encoding: 'utf8', mode: 0o666, flags: 'w', fd: null, autoClose: true});
writeStream.on('error', function (error) {throw error;});
writeStream.on('open', function () {console.log('writeFile opened');});
writeStream.on('close', function () {
    console.log('bytesWritten: ' + writeStream.bytesWritten + ' | path: ' + writeStream.path);
    console.log('writeFile closed');
});
writeStream.write('some');
writeStream.write(' data');
writeStream.end();

// Поток чтения из файла.

const readStream = fs.createReadStream('./test-file.txt', {encoding: 'utf8', mode: 0o666, flags: 'r', fd: null, autoClose: true});
readStream.on('error', function (error) {throw error;});
readStream.on('open', function () {console.log('readStream open');});
readStream.on('data', function (data) {console.log(data + ' | bytesRead: ' + readStream.bytesRead + ' | path: ' + readStream.path);});
readStream.on('end', function (data) {console.log(data + ' | readStream end');});
readStream.on('close', function () {console.log('readStream closed');});

// Отслеживать изменения в файле.

// Первый способ.

function watchHandler (current, previous) {
    console.log('Current mtime:' + current.mtime + ' | Previous mtime: ' + previous.mtime);
}
fs.watchFile('./test-file.txt', {persistent: true, interval: 5007}, watchHandler);
fs.unwatchFile('./test-file.txt', watchHandler);

// Второй способ.

const watcher = fs.watch('./test-file.txt', {encoding: 'utf8', persistent: true, recursive: true});
watcher.on('error', function (error) {throw error;});
watcher.on('change', function (eventType, filename) {
    console.log(eventType);
    if (filename) {console.log(filename);}
    watcher.close();
});

понедельник, 26 февраля 2018 г.

Webpack 4 - Краткий конфиг с комментариями

Файл webpack.config.js

const webpack = require('webpack') // Загружаем Webpack для использования встроенных в него плагинов.
        , CleanWebpackPlugin = require('clean-webpack-plugin')
        , ExtractWebpackTextPlugin = require("extract-text-webpack-plugin") // Загружаем отдельный плагин для Webpack, установленный через NPM.
        , path = require('path'); // Загружаем модуль "path" для прописывания абсолютных путей от диска "C" до файлов.

module.exports = [ // Webpack может принимать массив конфигов и выполнять их все сразу.
    { // Конфиг сборки Webpack.

        // Входные файлы для сборки.
    /*
          entry: path.resolve(__dirname, 'src/polyfills.js') // Одиночный стартовый файл, который будет помещен в итоговый файл. Имя выходного файла будет main.js, если задан output.filename: '[name].js'
    */

          entry: { // Набор входных файлов, помещаемых в итоговый файл сборки и выполняемых в нём согласно порядку их следования в этом массиве.
              'bundle': [ // Имя выходного файла сборки, если задан output.filename: '[name].js'
                  path.resolve(__dirname, 'src/polyfills.js') // Файл с полифилами помещается в итоговый файл сборки первым и выполняется в нём первым.
                , path.resolve(__dirname, 'src/vendors.js') // Файл с вендорами помещается в итоговый файл сборки вторым и выполняется в нём вторым.
                , path.resolve(__dirname, 'src/index.js') // Главный стартовый файл помещается в итоговый файл сборки третьим и выполняется в нём третьим.
              ]
          }

    /*
          entry: { // Набор отдельных входных файлов, помещаемых в такие же отдельные выходные файлы с теми же именами. Обязательно должен быть задан output.filename: '[name].js'
              'polyfills': path.resolve(__dirname, 'src/polyfills.js') // Отдельный входной файл.
            , 'vendors': path.resolve(__dirname, 'src/vendors.js') // Отдельный входной файл.
            , 'index': path.resolve(__dirname, 'src/index.js') // Отдельный входной файл.
          }
    */
        // Итоговые файлы сборки.
        , output: { // Описание итогового файла сборки.
              path: path.resolve(__dirname, 'dist') // В какую папку записать итоговые файлы сборки, картинки и CSS-файлы.
             , filename: 'bundle.js' // Если написано так, то все входные файлы из массива или одиночный входной файл будут помещены в один общий итоговый файл с данным именем.
            // , filename: '[name].js' // Если написано так, то исходные файлы передаются по отдельности и итоговых файлов сборки будет несколько.
            // Из каждого файла объекта "entry" будет сформирован отдельный итоговый файл, согласно его названию:
            // dist/polyfills.js
            // dist/vendor.js
            // dist/index.js
            // При этом каждый итоговый файл придется загружать в файле "index.html" по отдельности через <script> или через загрузчик JavaScript-файлов.
            , publicPath: 'dist/' // Базовый путь.
            // При обычной сборке он подставляет этот путь в URL картинок и шрифтов в CSS-файлах.
            // При запуске через "webpack-dev-server" он указывает тому путь на папку "dist" с итоговыми файлами сборки, шрифтами и картинками относительно расположения файла index.html.
            // Влияет на переписывание путей до картинок в CSS-файлах. Лучше вместо его указания использовать "CopyWebpackPlugin" для копирования файла "index.html" в папку "dist".
            // , chunkFilename: '[name].bundle.js' // Используется для выделения файлов из изсходных файлов в файлы, которые согласно коду будут импортироваться динамически по ходу его выполнения.
            // Пример динамического импорта файла внутри исходника:
            // return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {......}).catch(error => 'An error occurred while loading the component');
            // В результате в папке "dist" будет создан файл: lodash.bundle.js, который потом будет загружаться динамически.
            }

        , target: 'web' // Тип собираемого итогового файла.

        , resolve: {
              alias: { // Синонимы путей до файлов. Импорт модулей в исходных файлах можно делать по указанным синонимам, как модули из папки "node_modules". Это удобно, так как можно не указывать пути файлов относительно друг друга.
                  'inner-file': path.resolve(__dirname, 'src/inner/inner.js')
              }
          }

        , externals: { // Модули, которые надо из итогового файла сборки исключить. Они будут загружаться отдельно.
              'polyfills': 'polyfills'
            , 'lodash': '_' // Заменить импорт модуля на имя этой глобальной перемеменной: require('lodash') --> var _ В итоговый файл попадет: {1: function (...) {module.exports = _;}}
            , 'jquery': 'jQuery' // Заменить импорт модуля на имя этой глобальной перемеменной: require('jquery') --> var jQuery В итоговый файл попадет: {1: function (...) {module.exports = jQuery;}}
          }

        , module: {
            rules: [ // Набор используемых загрузчиков для различных типов файлов.
                  { // Загрузчик файлов, импортируемых в коде через import или require().
                      test: /\.css$/ // Регулярное выражение для поиска файлов данного типа.
                    , include: path.resolve(__dirname, 'src') // применять загрузчик только в файлам, находящимся в этой папке.
                    , use: ExtractWebpackTextPlugin.extract({ // Использование плагина для помещения всех загружаемых CSS-файлов в один общий итоговый выходной CSS-файл.
                              publicPath: '/dist' // Путь до картинок и шрифтов в CSS-файлах.
                            , fallback: 'style-loader' // Название используемого загрузчика.
                            , use: [ // Массив используемых загрузчиков. Загрузчики выполняются начиная с конца.
                                {
                                    loader: 'css-loader' // Название используемого загрузчика.
                                }
                            ]
                      })
                  }
                , { // Загрузчик файлов, импортируемых в коде через import или require().
                      test: /\.(png|jpg|gif)$/ // Регулярное выражение для поиска файлов данного типа.
                    , use: [ // Массив используемых загрузчиков. Загрузчики выполняются начиная с конца.
                          {
                              loader: 'url-loader' // Название используемого загрузчика.
                            , options: { // Опции загрузчика.
                                  limit: 1 // 8192
                              }
                          }
                    ]
                  }
            ]
          }

        , plugins: [ // Набор плагинов, которые обрабатывают итоговый файл после его сборки согласно порядку их следования в этом массиве. Порядок следования плагинов имеет значение.
              new CleanWebpackPlugin(['dist'])  // Плагин, удаляющий сборочную папку "dist".
            // , new webpack.optimize.UglifyJsPlugin() // Плагин, сжимающий итоговый файл сборки "bundle.js".
            , new webpack.optimize.CommonsChunkPlugin({ // Плагин, который находит общий для нескольких файлов код, например импорт библиотек, и помещает его в отдлеьный итоговый общий файл.
                  name: 'common' // Имя итогового файлы, в который будет помещен код, являющияйся общим для нескольких входных файлов.
              })
            , new ExtractWebpackTextPlugin('bundle.css') // Плагин, помещающий все входные файлы CSS в один общий итоговый выходной CSS-файл.
            , new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify('production')}) // Плагин для вставки различных переменных в итоговый файл сборки.
            , new webpack.NamedModulesPlugin() // Плагин для того, чтобы видеть для каких модулей произошла горячая замена HMR - Hot Module Replace.
            , new webpack.HotModuleReplacementPlugin() // Плагин для активации функции горячей замены модулей HMR - Hot Module Replace.
          ]

        , devServer: { // Настройки разработческого сервера. Адрес сервера по умолчанию: localhost:8080
              host: '127.0.0.1' // Хост, на котором будет запущен сервер.
            , port: 8080 // Порт, на котором будет запущен сервер.
            // , https: { // Настройки ключей для создания HTTPS сервера.
            //       key: fs.readFileSync('/path/to/server.key')
            //     , cert: fs.readFileSync('/path/to/server.crt')
            //     , ca: fs.readFileSync('/path/to/ca.pem')
            //   }
            , contentBase: '.' // Путь до папки, в которой находится файл index.html.
            // , publicPath: 'dist/' // Путь до папкм, в которой находится итоговый файл сборки.
            , hot: true // Включен режим горячей замены модулей HMR - Hot Module Replace.
                            // Пример кода горячего обновление модуля.
                            // import printMe from './print.js';
                            // printMe();
                            // if (module.hot) {
                            //     module.hot.accept('./print.js', function () { // Данный код будет выполнен при обновлении кода модуля print.js.
                            //         console.log('Accepting the updated printMe module!');
                            //         printMe();
                            //     });
                            // }
            , proxy: {
                  '/api': 'http://localhost:3000/api' // Проксирование запроса по этому адресу на другой сервер.
              }
            , headers: {
                  'X-Custom-Foo': 'bar' // Добавить данный заголовок ко всем ответам сервера.
              }
          }

        , devtool: 'inline-source-map' // Куда помещать source map.
        , bail: true // Не собирать итоговый файл, если во время сборки возникла хотя бы одна ошибка.
    }
];

Файл server.js

const express = require('express')
        , webpack = require('webpack')
        , webpackDevMiddleware = require('webpack-dev-middleware')
        , webpackConfig = require('./webpack.config.js');

const server = express();

server.use(webpackDevMiddleware(webpack(webpackConfig), {
    publicPath: webpackConfig[0].output.publicPath
}));

server.listen(3000, function () {
    console.log('Server is listening on 127.0.0.1:3000');
});

Файл package.json

{
      "name": "test"
    , "version": "1.0.0"
    , "dependencies": {
          "webpack": "2.7.0"
        , "webpack-dev-server": "2.11.1"
        , "webpack-dev-middleware": "2.0.5"
        , "css-loader": "0.28.9"
        , "style-loader": "0.20.1"
        , "file-loader": "1.1.6"
        , "url-loader": "0.6.2"
        , "clean-webpack-plugin": "0.1.18"
        , "extract-text-webpack-plugin": "2.1.2"
        , "express": "4.16.2"
        , "typescript": "2.7.1"
    }
}

Файл index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="dist/bundle.css">
    <title>Webpack App</title>
  </head>
  <body>
    <script src="dist/bundle.js"></script>
  </body>
</html>

Файл src/polyfills.js

console.log(1);

Файл src/vendors.js

console.log(2);

Файл src/index.js

import './index.css';

import a from './module.js';
import b from 'inner-file';

console.log(3);
console.log(a);
console.log(b);

var div = document.createElement('div');
div.id = 'my';
div.innerHTML = 'Привет.';
document.getElementsByTagName('body')[0].appendChild(div);

// Горячее обновление модуля.

import printMe from './print.js';

printMe();

if (module.hot) {
    module.hot.accept('./print.js', function () { // Данный код будет выполнен при обновлении кода модуля print.js.
        console.log('Accepting the updated printMe module!');
        printMe();
    });
}

Файл src/index.css

#my {
    width: 100px;
    height: 100px;
    background: url(image.png) no-repeat 0 0;
}

Файл src/print.js

export default function printMe() {
    console.log('I get called from print.js!');
    // console.log('Updating print.js...');
}

Файл src/module.js

var a = 4;

export default a;

Файл src/inner/inner.js

var b = 5;

export default b;

среда, 14 февраля 2018 г.

TypeScript - Понятный tsconfig.json с комментариями.

// Файл "tsconfig.json":
// - устанавливает корневой каталог проекта TypeScript;
// - выполняет настройку параметров компиляции;
// - устанавливает файлы проекта.
// Присутствие файла "tsconfig.json" в папке указывает TypeScript, что это корневая папка проекта.
// Внутри "tsconfig.json" указываются настройки компилятора TypeScript и корневые файлы проекта.
// Программа компилятора "tsc" ищет файл "tsconfig.json" сначала в папке, где она расположена, затем поднимается выше и ищет в родительских папках согласно их вложенности друг в друга.
// Команда "tsc --project C:\path\to\my\project\folder" берет файл "tsconfig.json" из папки, расположенной по данному пути.
// Файл "tsconfig.json" может быть полностью пустым, тогда компилятор скомпилирует все файлы с настройками заданными по умолчанию.
// Опции компилятора, перечисленные в командной строке перезаписывают собой опции, заданные в файле "tsconfig.json".
{
      "extends": "./configs/base" // Загрузить другой конфигурационный файл "tsconfig.json", взятый за основу, и перезаписать его значениями из секций ниже.
    , "compileOnSave": true // При значении true указывает используемой редактору кода производить компиляцию при каждом сохранении файлов TypeScript. Поддерживается не всеми редакторами кода.
    , "compilerOptions": { // Настраивает параметры компиляции. Параметры называются также, как и в командной строке.

        // Основные настройки.
        // Настройки путей для создания выходных файлов.
          "module": "amd" // Определяет тип импорта кода в итоговом файле, прописанном в "outFile". Необходимо задавать при использовании опции "outFile".
        , "outFile": "./build/bundle.js" // Имя единого итогового выходного файла, в который будут помещен код из всех найденных TypeScript-файлов.
        , "outDir": "./build" // Поместить все скомпилированные файлы в данную папку, согласно их вложенности в исходниках. Если задана опция "outFile", то опция "outDir" будет проигнорирована.
                                    // Если "outFile" и "outDir" не заданы, то выходные файлы будут созданы рядом со своими исходниками.
        // Настройки для поиска @types
        , "typeRoots" : [ // По умолчанию все видимые в проекте пакеты "@types", расположенные в папках "node_modules" на всех уровнях вложенности, используются при компиляции.
                                // Но, если указан массив "typeRoots", тогда при компиляции будут использованы только описания типов, найденные в папках, расположенных по перечисленным в нем путях.
                                // При этом описания типов, находящихся в других папках использованы не будут.
                                // Папки с пакетами описаний типов обычно содержат внутри себя файл "index.d.ts" или "package.json" со свойством "types".
              "./typings" // При компиляции будут использованы только файлы описания типов ".d.ts" находящиеся в этой папке.
          ]
        , "types" : ["node", "lodash", "express"] // Если указан параметр "types", то из всех найденных будут использованы только те описания типов, что указаны в его массиве, а именно: "./typings/node", "./typings/lodash", "./typings/express".
                                                                 // Другие найденные типы использоваться не будут.
                                                                 // Задание "types": [] приведет к отключению автоматического использования описаний типов из папок "@types".
        , "rootDir": "../src" // Путь до папки с которой надо начинать поиск входных файлов. Обычно корневая директория вычисляется по списку входных файлов. Данная опция необходима для проверки, что все найденные TypeScript-файлы находятся внутри корневой папки.
        , "rootDirs": [  // Список корневых папок, совокупный контент которых представляет структуру проекта для компиляции.
              "src/views"
            , "generated/templates/views"
        ]
        , "baseUrl": "." // Путь до базовой папки для поиска не относительных путей до файлов.
        , "paths": {  // Укажите сопоставление маршрутов для вычисления по сравнению с параметром baseUrl.
              "jquery": ["node_modules/jquery/dist/jquery"] // Путь относительно "baseUrl".
          }
        , "lib": ["es5", "es6", "es2015.promise", "es2016.array.include"] // Набор библиотечных файлов полифилов, которые будут включены в итоговый выходной файл.
        , "target": "es3" // Тип кода создаваемого итогового файла.
        , "jsx": "react" // Включать ли поддержку ".tsx" файлов?
        , "jsxFactory": "React.createElement" // Укажите фабричную функцию JSX, чтобы использовать, когда таргетинг реагирует на обработку JSX, например: 'React.createElement' или 'h'. Требуется TypeScript версии 2.1 или новее.
        , "allowJs": false // Разрешать компилировать файлы с JavaScript-кодом?
        , "checkJs": false // Сообщить об ошибках в .js-файлах? Используйте совместно с "allowJs".
        , "downlevelIteration": false // Обеспечьте полную поддержку итераций для for - in, ..., деструктуризации при настройке на ES5 или ES3?
        , "noEmitOnError": true // Не создавать итоговый файл, если во время компиляции произошла ошибка.
        , "noEmitHelpers": false // Не помещать в код итогового файла функции хелперы.
        , "importHelpers": false // Имортировать созданные хелперы (__extends, __rest и так далее) из "tslib".
        , "noUnusedLocals": true // Показывать ошибку, если где-то найдены неиспользуемые локальные значения.
        , "noUnusedParameters": true // Показывать ошибку, если где-то найдены неиспользуемые параметры.
        , "strictNullChecks": false // Значения "null" и "undefined" могут быть присвоены только значениям данного типа и значениям только с типом "any"?
        , "noImplicitUseStrict": false // Не записывать 'use strict' в итоговый выходной файл?
        , "alwaysStrict":  // Компилировать ли каждый файл в строгом режиме и создавать ли 'use strict' для каждого выходного файла? Требуется TypeScript версии 2.1 или новее.
        , "strict": false // Включить ли все строги проверки типов сразу: noImplicitAny, noImplicitThis, alwaysStrict, strictNullChecks, strictFunctionTypes, strictPropertyInitialization?
        , "removeComments": true // Удалить все комментарии из итогового файла.
        , "sourceMap": true // Создавать ли соответствующие source map файлы ".map"?
        , "pretty": true // Окрашивать в терминале сообщения об ошибках.
        , "watch": true // Запустить компилятор в режиме отслеживания изменений во входных файлах и их повторной компиляции?

        // Дополнительные настройки.
        , "charset": "utf8" // Кодировка входных файлов.
        , "declaration": false // Создавать ли соответствующие файлы ".d.ts"?
        , "declarationDir": "." // Путь до папки, в которую будут записаны созданные соответствующие файлы ".d.ts".
        , "diagnostics": false // Показывать ли диагностическую информацию?
        , "emitBOM": false // Записывать ли UTF-8 Byte Order Mark (BOM) в начало итогового файла?
        , "inlineSourceMap": false // Помещать ли source map в итоговый файл, вместо того чтобы иметь отдельный файл с source map?
        , "inlineSources": false // Помещать ли source в итоговый файл рядом с source map?
        , "listFiles": false // Печатать ли имена файлов при компиляции?
        , "mapRoot": "." // Путь до папки, в которой дебаггер браузера должен будет искать файлы с source map.
        , "newLine": "CRLF" // Определяет тип завершения строк в итоговом файле.
        , "noEmit": false // Не создавать итоговый файл.
        , "noImplicitAny": false // Показывать ошибку, если где-то задан тип "any".
        , "noImplicitThis": false // Показывать ошибку на "this", если где-то задан тип "any".
        , "noLib": false // Не использовать стандартный библиотечный файл по умолчанию (lib.d.ts).
        , "noResolve": false // Не добавлять "/// <reference path="..." />" в список скомпилированных файлов.
        , "noStrictGenericChecks": false // Отключить строгую проверку типов джинериков в типах функций?
        , "skipDefaultLibCheck": false // Пропустить проверку типов из стандартной библиотеки по умолчанию?
        , "skipLibCheck": false // Не проверять типы, заданные во всех файлах описания типов (*.d.ts)?
        , "preserveConstEnums": false // Не удалять объявления const enum из итогового файла.
        , "preserveSymlinks": false // Не заменять символические ссылки на их реальный путь, обрабатывать символический файл как реальный.
        , "isolatedModules": false // Обрабатывать каждый файл, как отдельный изолированный модуль.
        , "sourceRoot": "." // Путь до папки, в которой дебаггер должен искать исходные source файлы.
        , "suppressExcessPropertyErrors": false // Подавлять избыточные проверки свойств для объектных литералов?
        , "suppressImplicitAnyIndexErrors": false // Подавлять "noImplicitAny" ошибки для индексирования объектов, не имеющих индексных подписей.
        , "stripInternal": false // Не создавать объявления для кода, который имеет аннотацию JSDoc /** @internal */.
        , "experimentalDecorators": false // Включить экспериментальную поддержку декораторов EcmaScript?
        , "emitDecoratorMetadata": false // Создавать метаданные для объявлений декораторов в исходном коде?
        , "moduleResolution": "classic" // Определить способ поиска модулей в папках: как в Node.js или классический, как в TypeScript 1.5 и ниже.
        , "allowUnusedLabels": false // Не создавать сообщений об ошибках, если в коде найдены неиспользуемые метки label?
        , "noImplicitReturns": false // Сообщить об ошибке, когда не все пути кода в функции возвращают значение?
        , "noFallthroughCasesInSwitch": false // Сообщить об ошибке в случае обнаружения проваливания в конструкции switch-case?
        , "allowUnreachableCode": false // Сообщить об ошибке в случае обнаружения кода, который никогда не будет выполнен?
        , "forceConsistentCasingInFileNames": false // Запретить несогласованные ссылки на один и тот же файл?
        , "plugins": [] // Список плагинов для сервера языка TypeScript для загрузки. Требуется TypeScript версии 2.3 или новее.
        , "traceResolution": false // Выводить в логи сообщения о нахождении путей до модулей.
        , "allowSyntheticDefaultImports": false // Разрешить импортировать модули не имеющие внутри себя "import default"?
        , "listEmittedFiles": false // Печатать список всех выходных файлов при компиляции. Требуется TypeScript версии 2.0 или новее.
        , "disableSizeLimit": false // Отключить ограничение размера в проекте JavaScript.
        , "maxNodeModuleJsDepth": 0 // Максимальная глубина поиска зависимостей внутри node_modules и загрузки файлов JavaScript. Применяется только вместе с заданной опцией "allowJs".
        , "strictFunctionTypes": false // Отключить проверку бивариантных параметров для типов функций.
        , "strictPropertyInitialization": false // Убедитесь, что свойства класса, имеющие значения undefined, получают новые значения внутри конструктора.
        , "esModuleInterop": false // Создать хелперы __importStar и __importDefault для обеспечения совместимости с экосистемой Babel и включить allowSyntheticDefaultImports для совместимости с системой типов.

      }
    , "files": [ // Список относительных или абсолютных путей до конкретных исходных файлов, которые обязательно надо скомпилировать.
                   // Если секция "files" не указана, то компилятор по умолчанию включает все файлы с расширением *.ts и *.tsx, которые находятся в корневой папке и внутренних подпапках проекта.
                   // Если секция "files" указана, то скомпилируются файлы, которые в ней перечислены.
                   // Все файлы, на которые есть ссылки в файлах из секции "files", также скомпилируются.
          "core.ts"
        , "app.ts"
      ]
      // Вместе с компиляцией только конкретных исходных файлов можно компилировать только файлы в заданных папках, которые будут найдены через регулярные выражения, которые принимают только следующие значения:
      // - букву или цифру;
      // - * - ноль или более любых символов, не включая разделители директорий "/" и "\";
      // - ? - один любой символ, не включая разделители директорий "/" и "\";
      // - **/ - рекурсивно включить любую подпапку.
      // Если путь до папки заканчивается так "*" или так ".*", тогда в ней будут скомплированы все файлы с расширениями .ts, .tsx, .d.ts, а также .js и .jsx, если опция "allowJs" будет равна true.
    , "include": [ // Секция "include" позволяет скомпилировать все файлы, находящиеся в заданных папках.
                       // Если секция "files" и секция "include" заданы вместе, то будут скомпилированы только файлы, перечисленные в обеих секциях.
                       // Все файлы, на которые есть ссылки во включенных файлах из секции "files" и секции "include", также скомпилируются.
          "src/**/*"
      ]
    , "exclude": [ // Секция "exclude" позволяет исключить при компиляции определенные файлы, которые находятся в заданных папках секции "include" или в папках всего проекта, если секция "include" не задана.
                       // Компилятор не будет учитывать перечисленные в секции "exclude" файлы TypeScript, которые находятся в папках из секции "include".
                       // Однако файлы, заданные в секции "files" будут обязательно скомпилированы.
                       // Если секция "exclude" не указана, то по умолчанию будут исключаться из компиляции все файлы из папок:
                       // - node_modules,
                       // - bower_components,
                       // - jspm_packages,
                       // - файлы из папки, указанной в опции компилятора "outDir".
          "src/**/*.spec.ts"
        , "node_modules"
      ]
}

вторник, 30 января 2018 г.

Разница между nextTick и setImmediate

Функция process.nextTick() помещается в начало очереди следующего цикла event loop и должна называться process.sendThisToTheStartOfTheQueue().

А setImmediate() помещается в конец очереди следующего цикла event loop и должна называться sendThisToTheEndOfTheQueue().