четверг, 29 июня 2017 г.

Шпаргалка по Node.js: HTTP Server, Socket, TLS, UDP, WebSocket, Path, Files, Stream, Spawn, MySQL

http для браузера
socket для telnet
udp для передачи видео
tls для защищенных соединений

// Server and Client

var fs = require('fs');

var writeStream = fs.createWriteStream('client-logs.txt');

var http = require('http');

var server = http.createServer();

server.on('request', function (request, response) {
    console.log(request.method);
    console.log(request.url);
    console.log(request.headers);
    request.on('data', function (data) {
        writeStream.write(data);
    });
    request.on('end', function () {
        writeStream.end();
    });
    response.setHeader('Content-Length', '1000');
    response.removeHeader('Max-Length', '10');
    response.writeHead(200, 'OK', {'Content-Type': 'text/html'});
    response.write('Hi');
    response.end('Bye');
    server.close();
});

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

var options = {
    host: "www.google.com",
    port: 80,
    path: "/upload",
    method: "POST",
    agent: new Agent({
        maxSockets: 10
    })
};

var request = http.request(options);

request.on('response', function (response) {
    console.log('STATUS:', response.statusCode);
    console.log('HEADERS:', response.headers);
    console.log(response.httpVersion);
    response.setEncoding('utf8');
    response.on('data', function (chunk) {console.log(chunk);});
    response.on('end', function (chunk) {console.log('END');});
});

request.on('socket', function (socket) {
    socket.emit('agentRemove');
});

request.write('data');
request.end();

// Transmission control protocol TCP Server - Use with command line Telnet

// socket умеет и читать данные и писать данные,
// то есть и принимать их on('data'), on('end')
// и отсылать write(data), end(data)

require('net').createServer(function (socket) { // new connection
    socket.on('data', function(data) {
        // got data
    });
    socket.on('end', function(data) {
        // connection closed
    });
    socket.write('Some string');
}).listen(4001);

// telnet 127.0.0.1 4001

var server = require('net').createServer();

var connections = []; // Request connections

server.on('connection', function (socket) {

    connections.push(socket);

    socket.setEncoding('utf8');

    socket.on('data', function(data) {
        // got data
        console.log('got:', data.toString());

        connections.forEach(function(otherSocket) {
            if (otherSocket !== socket) {
                otherSocket.write(data);
            }
        });

        if (data.trim().toLowerCase() === 'quit') {
            socket.write('Bye bye!');
            socket.end();
        } else {
            socket.write(data);
        }
    });

    socket.on('end', function(data) {
        // connection closed
        console.log('Client connection ended');
    });

    socket.on('close', function() {
        console.log('connection closed');
        var index = connections.indexOf(socket);
        connections.splice(index, 1); // remove closed socket connections
    });

    socket.on('error', function(error) {
        console.log(error);
    });

    socket.pause();
    socket.resume();

    socket.write('Some string');
    socket.end('Bye');
});

// socket.setKeepAlive(true) periodically sends an empty packet to keep the connection alive
// whereas socket.setTimeout() is used to define a local inactivity timeout

server.setKeepAlive(true, 10000); // keep the connection alive on both peers, delay 10 seconds before next send

server.setTimeout(60000); // servert timeout 1 minute
server.on('timeout', function() {
    server.write('idle timeout, disconnecting, bye!');
    server.end();
});

// socket.setTimeout(60000, function() { // альтернативная запись таймаута
//     socket.end('idle timeout, disconnecting, bye!');
// });

server.setNoDelay(true); // force data to be sent immediately after each write command socket.write()

server.on('error', function (error) {
    throw error;
});

server.on('close', function () {
    console.log('Server is now closed');
});

server.on('listening', function () {
    console.log('Server started at 127.0.0.1:4001');
});

server.listen(4001, '127.0.0.1');

setTimeout(function () {
    server.close();
}, 5000);


// telnet localhost 4001

var ws = require('fs').createWriteStream('mysocketdump.txt');
require('net').createServer(function(socket) {
    socket.pipe(ws); // Write data from telnet into file
}).listen(4001);

// telnet localhost 4001

require('net').createServer(function(socket) {
    var rs = require('fs').createReadStream('mysocketdump.txt');
    rs.pipe(socket); // Send text from file to telnet
}).listen(4001);

// Transmission control protocol TCP Client

var net = require('net');

var host = "www.google.com";
var port = 4000;

var client = net.createConnection(port, host, function (response) {
    console.log('We have a new connection');
});

client.once('connect', function (response) {
    console.log('We have a new connection');
    response.setEncoding('base64');
    response.on('data', function (data) {
        console.log('some data has arrived:', data);
    });
});

client.on('error', function (error) {
    console.error('this error happened:' + error.message + ', code: ' + error.code);
});

client.on('close', function() {
    console.log('connection got closed, will try to reconnect');
});

client.write('here is a string for you!');
client.end();

// Datagram Server

// node udp_server_1.js
// echo hello | nc -u 0.0.0.0 4000
// This call sends a UDP packet with hello to the local host port 4000.
// Server output that’s something like the following:
// server got message: hello

var dgram = require('dgram');

var server = dgram.createSocket('udp4'); // UDP over IPv4

server.on('message', function (message, rinfo) { // rinfo - information about message sender (remote info)
    console.log('server got message: ' + message + ' from ' + rinfo.address + ':' + rinfo.port);
    server.send(message, 0, message.length, rinfo.port, rinfo.address, function() {
        // you can reuse the message buffer
    }); // Send message to message to a specifi c address and port.
});

server.on('listening', function() {
    var address = server.address();
    console.log('server listening on ' + address.address + ':' + address.port);
});

var port = 4000;

server.bind(port);

// Datagram Client

var dgram = require('dgram');

var client = dgram.createSocket('udp4'); // UDP over IPv4

client.on('message', function(message) {
    console.log('Got message back from server:', message.toString());
});

var port = 8000;

client.bind(port);

var message = new Buffer('this is a message');

client.send(message, 0, message.length, 4000, 'localhost', function(error, bytes) {
    if (error) {throw error;}
    client.close();
});

// Datagram Multicast Server

// Message multicasting can be useful when you don’t need to know the address of all peers. Peers just have to "tune in" and listen to that channel.
// For instance, you could have an event logging server listening on multiple "channels".
// When another process needs to log in to a "channel", it would multicast a message containing the event details into that "channel".
// Nodes can report their interest in listening to certain multicast channels by
// tuning in to that channel. In IP addressing, a space is reserved for multicast addresses.
// In IPv4 the range is between 224.0.0.0 and 239.255.255.255, but some of these are reserved.

// ./udp_client.js 230.1.2.3 4000

var server = require('dgram').createSocket('udp4');

server.on('message', function(message, rinfo) {
    console.log('server got message: ' + message + ' from ' + rinfo.address + ':' + rinfo.port);
});

server.bind(4000);

server.addMembership('230.1.2.3');

// Tells the kernel that this UDP socket should receive multicast messages for the multicast address 230.1.2.3.

// Sending Multicast Messages

var dgram = require('dgram');

var client = dgram.createSocket('udp4');

var message = new Buffer('this is a multicast message');

client.bind(4000);

client.setMulticastTTL(10); // Set the multicast time-to-live (TTL) to 10.

// This TTL tells the network how many hops (routers) the datagram can travel through before it is discarded.
// Every time a UDP packet travels through a hop, the TTL counter is decremented, and if 0 is reached, the packet is discarded.

client.send(message, 0, message.length, 4000, '230.1.2.3');

client.close();

// TLS SSL Server

var tls = require('tls');
var fs = require('fs');

var serverOptions = {
    key: fs.readFileSync('./my_key.pem'),
    cert: fs.readFileSync('./my_certificate.pem'),
    ca: [fs.readFileSync('fake_ca.pem')],
    requestCert: true, // asks the client to send over the certificate
    rejectUnauthorized: true // reject certificates that are not validated by the Certificate Authority chain
};

var server = tls.createServer(serverOptions);

server.on('secureConnection', function (clientStream) {
    console.log('got a new connection');
    console.log('client authorized:', clientStream.authorized);
    clientStream.on('data', function (data) {
        console.log('got some data from the client:', data);
        clientStream.write('Hey Hello Client!');
        if (data.toString().trim().toLowerCase() === 'quit') {
            clientStream.end('Bye bye!');
        }
    });
});

server.listen(4001);

// TLS SSL Client

var tls = require('tls');
var fs = require('fs');

var options = {
    key: fs.readFileSync('/path/to/my/private_key.pem'),
    cert: fs.readFileSync('/path/to/my/certificate.pem')
};

var client = tls.connect(4001, '127.0.0.1', options, function() {
    console.log('connected');
    console.log('authorized: ' + client.authorized);
    if (! client.authorized) {
        console.log('client denied access:', client.authorizationError);
    } else {
        // ...
    }
    client.on('data', function (data) {
        console.log('got some data from the server:', data);
        client.write('Hey, hello Server!');
        client.end('Bye bye!');
    });
});

// TLS chat server

var tls = require('tls');
var fs = require('fs');

var port = 4001;

var clients = [];

var options = {
    key: fs.readFileSync('server_key.pem'),
    cert: fs.readFileSync('server_cert.pem')
};

var server = tls.createServer(options, function(client) {
    clients.push(client);
    client.on('data', function(data) {
        var socket = client.socket;
        clients.forEach(function(clientFromArray) {
            if (clientFromArray !== client) {
                clientFromArray.write(socket.remoteAddress + ':' + socket.remotePort + ' said: ' + data);
            }
        });
    });
    client.on('close', function() {
        console.log('closed connection');
        clients.splice(clients.indexOf(client), 1);
    });
});

server.listen(port, function() {
    console.log('listening on port', server.address().port);
});

// HTTPS Server

var fs = require('fs');
var https = require('https');

var options = {
    key: fs.readFileSync('server_key.pem'),
    cert: fs.readFileSync('server_cert.pem'),
    requestCert: true, // asks the client to send over the certificate
    rejectUnauthorized: true // reject certificates that are not validated by the Certificate Authority chain
};

var server = https.createServer(options, function(request, response) {
    console.log('authorized:', request.socket.authorized);
    console.log('client certificate:', request.socket.getPeerCertificate());
    response.writeHead(200, {'Content-Type': 'text/plain'});
    response.end('Hello World!');
});

server.listen(4001, '192.168.1.100', function() {
    console.log('Server is listening now on port', server.address().port);
});

// HTTPS Client

var fs = require('fs');
var https = require('https');

var options = {
    host: '0.0.0.0',
    port: 4001,
    method: 'GET',
    path: '/'
};

var request = https.request(options, function (response) {
    console.log('response statusCode:', response.statusCode);
    console.log('server authorized:', response.socket.authorized);
    console.log('server certificate: ' + response.socket.getPeerCertificate());
    response.on('data', function (data) {
        console.log('got some data back from the server:', data);
    });
});

request.write('Hey!');
request.end();

// WebSocket Server

var ioserver = require('socket.io')

ioserver.sockets.on('connection', function (socket) {
    socket.on('my event', function (content) {
        console.log(content);
    });
    socket.on('clientMessage', function(content) {
        socket.emit('serverMessage', 'You said: ' + content);
        socket.get('username', function(err, username) {
            if (! username) {username = socket.id;}
            socket.get('room', function(error, room) {
                if (error) {throw error;}
                var broadcast = socket.broadcast;
                var message = content;
                if (room) {
                    broadcast.to(room);
                }
                broadcast.emit('serverMessage', username + ' said: ' + message);
            });
        });
    });
    socket.on('join', function(room) {
        socket.get('room', function(err, oldRoom) {
            if (error) {throw error;}
            socket.set('room', room, function(error) {
                if (error) {throw error;}
                socket.join(room);
                if (oldRoom) {socket.leave(oldRoom);}
                socket.get('username', function(err, username) {
                    if (! username) {username = socket.id;}
                });
                socket.emit('serverMessage', 'You joined room ' + room);
                socket.get('username', function(err, username) {
                    if (! username) {username = socket.id;}
                    socket.broadcast.to(room).emit('serverMessage', 'User ' + username + ' joined this room');
                });
            });
        });
    });
    socket.on('disconnect', function() {
        socket.get('username', function(err, username) {
            if (! username) {username = socket.id;}
            socket.broadcast.emit('serverMessage', 'User ' + username + ' disconnected');
        });
    });
    socket.on('login', function(username) {
        socket.set('username', username, function (error) {
            if (error) {throw error;}
            socket.emit('serverMessage', 'Currently logged in as ' + username);
            socket.broadcast.emit('serverMessage', 'User ' + username + ' logged in');
        });
    });
    socket.emit('login');
});

ioserver.listen(4000);

// Websocket Client

<html>
    <head>
        <title>Socket.IO example application</title>
        <script src="http://localhost:4000/socket.io/socket.io.js"></script>
        <script>
            var socket = io.connect('http://localhost:4000');
            socket.on('serverMessage', function(content) {
                console.log(content);
            });
            socket.on('login', function() {
                var username = prompt('What username would you like to use?');
                socket.emit('login', username);
            });
            socket.emit('my event', 'Hello world.');
        </script>
    </head>
    <body></body>
</html>

// WebSocket Server with Standart Server

var fs = require('fs');

var http = require('http');
var ioserver = require('socket.io');

var server = http.createServer();

server.on('request', function (request, response) {
    fs.readFile(__dirname + '/index.html', function(error, data) {
        if (error) {
            res.writeHead(500);
            res.end('Error loading index.html');
        } else {
            res.writeHead(200, 'OK');
            res.end(data);
        }
    });
});

ioserver.sockets.on('connection', function (socket) {
    socket.on('my event', function(content) {
        console.log(content);
    });
    socket.on('clientMessage', function (content) {
        socket.emit('serverMessage', 'You said: ' + content);
        socket.get('username', function(err, username) {
            if (! username) {username = socket.id;}
            socket.broadcast.emit('serverMessage', username + ' said: ' + content);
        });
    });
    socket.on('disconnect', function() {
        socket.get('username', function(err, username) {
            if (! username) {username = socket.id;}
            socket.broadcast.emit('serverMessage', 'User ' + username + ' disconnected');
        });
    });
    socket.on('login', function(username) {
        socket.set('username', username, function (error) {
            if (error) {throw error;}
            socket.emit('serverMessage', 'Currently logged in as ' + username);
            socket.broadcast.emit('serverMessage', 'User ' + username + ' logged in');
        });
    });
    socket.emit('login');
});

server.listen(4000);
ioserver.listen(4000);

// Path

path.normalize('/foo//bar//baz/asdf/quux/..'); // '/foo/bar/baz/asdf'
path.join('/foo', 'bar', 'baz/asdf'); // '/foo/bar/baz/asdf'
path.resolve('/foo/bar', '../baz'); // 'C:\foo\baz'
path.relative('/data/test/aaa', '/data/impl/bbb'); // '../bbb'

path.dirname('/foo/bar/baz/asdf/quux.txt'); // '/foo/bar/baz/asdf'
path.basename('/foo/bar/baz/asdf/quux.html'); // 'quux.html'

// Files

fs.exists('/does_not_exist', function (exists) {
    console.log('exists:', exists);
});

fs.stat('/etc/passwd', function(err, stats) {
    console.log(stats.isFile());
    console.log(stats.isDirectory());
    console.log(stats.isBlockDevice());
    console.log(stats.isCharacterDevice());
    console.log(stats.isSymbolicLink());
    console.log(stats.isFifo());
    console.log(stats.isSocket());
});

fs.open('./my_file.txt', 'r', function opened(err, fd) {
    if (err) { throw err }
    var readBuffer = new Buffer(1024),
        bufferOffset = 0,
        bufferLength = readBuffer.length,
        filePosition = 100;
    fs.read(fd, readBuffer, bufferOffset, bufferLength, filePosition, function read (err, readBytes) {
        if (err) { throw err; }
        console.log('just read ' + readBytes + ' bytes');
        if (readBytes > 0) {console.log(readBuffer.slice(0, readBytes));}
        fs.close(fd);
    });
});

fs.open('./my_file.txt', 'a', function opened(err, fd) {
    if (err) { throw err; }
    var writeBuffer = new Buffer('writing this string'),
        bufferPosition = 0,
        bufferLength = writeBuffer.length, filePosition = null;
    fs.write(fd, writeBuffer, bufferPosition, bufferLength, filePosition, function wrote(err, written) {
        if (err) { throw err; }
        console.log('wrote ' + written + ' bytes');
        fs.close(fd);
    });
});

// Streams

fs.open(path, 'r', function(err, fd) {
    fs.createReadStream(null, {fd: fd, encoding: 'utf8'});
    fd.on('data', function (chunk) {console.log(chunk);});
});

require('http').createServer(function(req, res) {
    var rs = fs.createReadStream('/path/to/big/file');
    rs.on('data', function(data) {
        var sent = res.write(data);
        if (!sent) {
            rs.pause();
        }
    });
    res.on('drain', function() {
        rs.resume();
    });
    rs.on('end', function() {
        res.end();
    });
}).listen(8080);

require('http').createServer(function(req, res) {
    var rs = fs.createReadStream('/path/to/big/file');
    rs.pipe(res, {end: false});
    rs.on('end', function() {
        res.write("And that's all, folks!");
        res.end();
    });
}).listen(8080);

require('http').createServer(function(req, res) {
    var rs = fs.createReadStream('/path/to/big/file');
    rs.pipe(res);
}).listen(8080);

// Process Swarm

node plus_one.js

// unpause the stdin stream
process.stdin.resume();
process.stdin.on('data', function( data) {
    var number;
    try {
        number = parseInt(data.toString(), 10); // parse the input data into a number
        number += 1; // increment by one
        process.stdout.write(number + "\n"); // output the number
    } catch (err) {
        process.stderr.write(err.message + "\n");
    }
});

node plus_one_test.js

var spawn = require('child_process').spawn;

var child = spawn('node', ['plus_one.js']); // Spawn the child with a node process executing the plus_one app

setInterval(function () { // Call this function every 1 second (1000 milliseconds):
    var number = Math.floor(Math.random() * 10000); // Create a random number smaller than 10.000
    child.stdin.write(number + "\n"); // Send that number to the child process:
    child.stdout.once('data', function (data) { // Get the response from the child process and print it:
        console.log('child replied to ' + number + ' with: ' + data);
    }); // Because you want to listen for data back from the child only once per number, you will use child.stdout.once and not child.stdout.on.
    // If you used the latter function, you would register multiple callback functions as time went by.
    // Each callback function would be called every time you got data from on the child stdout, which would end up printing the data multiple times and erroneously.
}, 1000);

child.stderr.on('data', function(data) {
    process.stdout.write(data);
});

child.on('exit', function(code, signal) {
    if (code) {
        console.log('child process terminated with code ' + code);
    } else if (signal) {
        console.log('child process terminated because of signal ' + signal);
    }
});

setTimeout(function() {
    child.kill();
}, 5000);


var spawn = require('child_process').spawn;
require('http').createServer(function(request, response) {
    var child = spawn('tail', ['-f', '/var/log/system.log']);
    child.stdout.pipe(res);
    res.on('end', function() {
        child.kill();
    });
}).listen(4000);

// Uncaught Exception

process.on('uncaughtException', function(err) {
    // do something
});

// MySQL

// npm install mysql

var mysql = require('mysql');

var client = mysql.createClient({
    host: 'localhost',
    user: 'root',
    password: 'root',
});

client.query('DROP DATABASE IF EXISTS node');

client.query('CREATE DATABASE node');

client.query('USE node');

client.query('CREATE TABLE test ' +
                 '(id INT(11) AUTO_INCREMENT, ' +
                 ' content VARCHAR(255), ' +
                 ' PRIMARY KEY(id))'
);

for (var i = 0; i < 10000; i++) {
    client.query('INSERT INTO test (content) VALUES (?)', ['content for row ' + (i + 1)]);
}

client.query('UPDATE test SET content = ? WHERE id >= ?', ['new content', 9000], function (err, info) {
    console.log('Changed content of ' + info.affectedRows + ' rows');
});

query = client.query('SELECT id, content FROM test WHERE id >= ? AND id <= ?', [8990, 9010]);

query.on('error', function(err) {throw err;});

query.on('row', function(row) {console.log('Content of row #' + row.id + ' is: "' + row.content + '"');});

query.on('end', function(result) {console.log('Finished retrieving results');});

client.end();

JavaScript - Convert Seconds to Days : Hours : Minutes : Seconds

var totalSeconds = 1 * 60 * 60 * 24 * 2 + 1 + 60 + 60 * 60 * 5;
var days = Math.floor(totalSeconds / 86400);
totalSeconds %= 86400;
var hours = Math.floor(totalSeconds / 3600);
totalSeconds %= 3600;
var minutes = Math.floor(totalSeconds / 60);
var seconds = totalSeconds % 60;
console.log(days + ' ' + hours + ':' + minutes + ':' + seconds);

среда, 28 июня 2017 г.

Webpack 2 и 3 API

------------------------------------------------------------------------
Webpack 2 API
------------------------------------------------------------------------
Комментарии
Файлы с модулями ищутся во всех директориях, перечисленных в массиве resolve.modules = []
С помощью объекта resolve.alias = {} можно указать альтернативный путь к файлу модуля, которые заменит его путь, указанный в импорте.
Если путь к файлу модулю указанный в импорте имеет расширение файла, то загружается сразу.
Если в пути расширение не указано, то проверяется перечень расширений файлов, указанных в массиве resolve.extensions = ['.js', '.jsx']
и загружается файл, соотвествующий первому найденному расширению.
Если путь в импорте указывает на директорию, то в ней ищется файл package.json, внутри которого ищутся пути указанные в resolve.mainFields,
если такой путь найден, то он берется, как путь до файла, в противном случае ищутся пути, указанные в resolve.mainFiles и, если такой путь найден,
то он становится путем до файла. Раширение файла берется из resolve.extensions.
Такой же принцип поиска файлов и у загрузчиков модулей.
module.preLoaders и module.postLoaders были удалены. Взамен их в rules надо указывать свойство enforce: "pre"
Плагин webpack.optimize.DedupePlugin был удален
Плагин BannerPlugin принимает теперь только 1 объект вместо 2-х параметров
Конфиги к лоадерам теперь надо указывать внутри rules:
  module: {
    rules: [{
      test: /\.tsx?$/,
      loader: 'ts-loader'
      options: {transpileOnly: false} // work with webpack 2
    }]
  },
  // does not work with webpack 2
  ts: {transpileOnly: false}
------------------------------------------------------------------------
Запуск сборки через package.json
npm start
"scripts": {
    "start": "webpack --progress --watch --config webpack.config.js webpack-dev-server --open"
}
// Dev Server start at http://localhost:8080
------------------------------------------------------------------------
const path = require('path');

const webpack = require('webpack'); // импорт wepack для получения  доступа к встроенным в Webpack плагинам

const HtmlWebpackPlugin = require('html-webpack-plugin'); // импорт отдельно установленного плагина для Webpack
------------------------------------------------------------------------
const config = {
------------------------------------------------------------------------
    context: path.join(__dirname, 'source'), // Базовая директория - абсолютный путь для поиска исходного главного файла entry и загрузчиков модулей
    // Абсолютный путь до папки с файлом указанным в entry. По умолчанию равно process.cwd(). А также исходная точка для поиска загрузчиков модулей module.rules.loader
------------------------------------------------------------------------
    entry: './index.js', // Исходный главный файл (string | object | array)
    entry: ['./library.js', './index.js'], // Последовательный набор, идущих друг за другом исходных файлов, которые будут объединены в 1 общий фыайл. Последний в списке файл главный и только он экспортируется в output.
    entry: { // Несколько разных исходных главных файлов
        page1: './index1.js', // Исходный главный файл для страницы 1
        page2: ['./library.js', './index2.js'] // Исходный главный файл для страницы 2
    },
------------------------------------------------------------------------
  output: {
    path: path.join(__dirname, '/home/proj/public/dist/[hash]'), // Только абсолютный путь до папки с итоговыми файлами. (string)
    publicPath: '/dist/[hash]', // Например "https://cdn.example.com/assets/" - Браузерный путь до папки, где лежат итоговый файлы. Предназначен для использования вместе с Webpack Dev Server. (string)
    publicPath: "https://cdn.example.com/assets/", // CDN (always HTTPS)
    publicPath: "//cdn.example.com/assets/", // CDN (same protocol)
    publicPath: "/assets/", // server-relative
    publicPath: "assets/", // relative to HTML page
    publicPath: "../assets/", // relative to HTML page
    publicPath: "", // relative to HTML page (same directory)
    pathinfo: true // Включить в сборку информацию откуда взялся каждый модуль
    filename: "[name].bundle.js", // Имя итогового файла (string)
                                              // [id] - идентификатор модуля
                                              // [name] - имя итогового файла
                                              // [hash] - хэш итогового файла
                                              // [chunkhash] - хэш части сборки итогового файла
                                              // [filebase] - базовое имя файла
                                              // [file] - имя файла
                                              // [query] - что-то что следует после ? в имени файла
    chunkFilename: "[id].bundle.js", // Имя итоговой части сборки
                                                  // [id] - идентификатор части сборки
                                                  // [name] - имя части сборки
                                                  // [hash] - хэш части сборки
                                                  // [chunkhash] - хэш части сборки
    sourceMapFilename: "[file].map" // Имя файлов source map, размещаемых в папке output.path
                                                  // [file] - имя итогового JavaScript-файла
                                                  // [id] - идентификатор части сборки
                                                  // [hash] хэш итогового файла
                                                  // [contenthash] заменен на hashфайла (в webpack 3.0.0).
    sourcePrefix: "\t" // Изменить префикс у каждой линии сборки итогового файла
    strictModuleExceptionHandling: false
    hashDigest: 'hex' // Используемый алгоритм для создания хэшей [hash]
    hashDigestLength: 20 // Длина создаваемых хэшей [hash]
    hashFunction: 'md5' // Используемая функция для создания хэшей [hash]
    hashSalt: '' // Соль для создания хэшей [hash]
    chunkLoadTimeout: 120000 // Число миллисекунд до того, как chunk устареет
    library: 'lib.js' // Если задано, то итоговая сборка будет экспортирована как отдельная библиотека с указанным именем. Используется только, если вы хотите собрать отдельную библиотеку. (string)
    libraryTarget: "var" // В каком формате написать экспорт содержимого библиотеки? var Library = ...library code...; (string)
    libraryExport: '' // Позволяет задать export для библиотеки
    umdNamedDefine: true // При указании libraryTarget: "umd" именует модуль UMD сборки
    crossOriginLoading: "anonymous" // Включить cross-origin loading для частей сборки
    devtoolModuleFilenameTemplate: "webpack:///[resource-path]?[loaders]" // Имя файла шаблона для генерируемых файлов source map
    devtoolFallbackModuleFilenameTemplate: "" // Имя файла шаблона когда происходит дублирование
    devtoolLineToLine: { // генерировать source map, привязанный линией к линии к исходному файлу Данная опция больше не используется
                test:  test: /\.js$/, // Регулярное выражение для поиска файлов, для которых будет произведено создание sourve map
                exclude: /node_modules/, // Регулярное выражение для поиска файлов, для которых не будет произведено создание sourve map
                include: ['/source/file2.js', '/source/file3.js'] // Массив путей до файлов, которые тоже нужно созданить source map
    }
    hotUpdateChunkFilename: "[id].[hash].hot-update.js" // Имя файла для частей с горячим обновлением, размещаемых в папке output.path
                                                   // [id] - идентификатор обновления
                                                   // [hash] - хэш обновления
    hotUpdateMainFilename: "[hash].hot-update.json" // имя главного файла с горячим обновлением, размещаемиого в папке output.path
                                                   // [hash] - хэш сборки
    hotUpdateFunction: "webpackHotUpdate" // Имя функци JSONP, используемой Webpack для асинхронной загрузки обновлений частей сборки
    jsonpFunction: '' // Используется только если установлена target: 'web' - имя функции для асинхронной загрузки chunks
  }
------------------------------------------------------------------------
    externals: { // Перечень модулей, которые не должны быть включены в итоговую сборку, а должны быть вынесены в отдельные файлы, которые будут загружаться отдельно через <script>
        "lodash": {
            commonjs: "lodash",
            commonjs2: "lodash",
            amd: "lodash",
            root: "_"
        }
        {
            a: false, // модуль a не будет вынесен во вне
            b: true, // модуль b будет вынесен во вне `module.exports = b`
            "./c": "c", // модуль "./c" будет вынесен во вне `module.exports = c`
            "./d": "var d", // модуль "./d" будет вынесен во вне `module.exports = ./d`  <-- здесь будет синтакическая ошибка
            "./f": "commonjs ./a/b", // модуль "./f"  будет вынесен во вне `module.exports = require("./a/b")`
            "./f": "this ./a/b" // модуль "./f" будет вынесен во вне `(function() { module.exports = this["./a/b"]; }())`
        },
        /^[a-z\-0-9]+$/, // Каждый модуль не входящий в это выражение будет вынесен во вне abc -> require("abc")
        function(context, request, callback) { // Какждый модуль, имеющий в своем имени префикс "global-" будет вынесен во вне "global-abc" -> abc
            if(/^global-/.test(request)) {return callback(null, "var " + request.substr(7));}
            callback();
        },
        "./e" // модуль "./e" будет вынесен во вне (require("./e"))
        subtract: ['./math', 'subtract']
    },
    -------------------------------------------
    externals: [
      'react',
      'react-dom'
      'library/A',
      'library/B',
      /^library\/.+$/ // everything that starts with "library/"
    ]
------------------------------------------------------------------------
  module: { // Объект со списком загрузчиков модулей
------------------------------------------------------------------------
    -------------------------------------------
    // Набор общих опций
    exprContextCritical: true,
    exprContextRecursive: true,
    exprContextRegExp: false,
    exprContextRequest: ".",
    unknownContextCritical: true,
    unknownContextRecursive: true,
    unknownContextRegExp: false,
    unknownContextRequest: ".",
    wrappedContextCritical: false
    wrappedContextRecursive: true,
    wrappedContextRegExp: /.*/,
    strictExportPresence: false // since webpack 2.3.0
------------------------------------------------------------------------
    resolveLoader: { // Где искать загрузчики модулей
        // Имеет такой же набор опций, что и resolve для файлов, но только для загрузчиков модулей
        moduleExtensions: ['-loader'] // Массив расширений загрузчиков модулей
        enforceExtension: true // Запретить указывать пути файлов без расширений файлов
        modules: [path.join(__dirname, 'src'), 'node_modules'] // Массив имен папок внутри данной директории, в которых надо искать загрузчикимодулей.
        enforceModuleExtension: true // Использовать расширения для модулей загрузчиков
        alias: { // Заменить имя загрузчика модуля на его полное имя
            txt: 'raw-loader'
        }
        aliasFields: ["browser"] // Указать поле, которое будет обработано парсером
        descriptionFiles: ["package.json"] // JSON файлы, которые будут использованы для descriptions
        mainFields: ["browser", "module", "main"] // искать пути к модулям в указанных полях файлов package.json: {...main: 'build/d3.Node.js', browser: 'build/d3.js', module: 'index', ...}
        mainFiles: ["index"] // Поиск фалов с данными исенами, если вместо пути к файлу указан путь к директории
        unsafeCache: true // Включить небезопасное кэширование модулей
        cachePredicate: function() { return true } // Функция определяющая стоит ли кэшировать запрос
        plugins: [new DirectoryNamedWebpackPlugin()] // Наборе плагинов для поиска файлов модулей
        symlinks: true // Искать файлы по ссылкам ярлыкам
    }
------------------------------------------------------------------------
    resolve: { // Где искать исходные файлы для сборки
        extensions: ['.ts', '.js', '.json'] // Массив расширений исходных файлов которые надо включать в сборку
        enforceExtension: true // Запретить указывать пути файлов без расширений файлов
        modules: [path.join(__dirname, 'src'), 'node_modules'] // Массив имен папок внутри данной директории, в которых надо искать исходные файлы.
        enforceModuleExtension: true // Использовать расширения для модулей загрузчиков
        alias: { // Заменить имя модуля в импорте на путь до файла
            jquery: "jquery/src/jquery"
        }
        aliasFields: ["browser"] // Указать поле, которое будет обработано парсером
        descriptionFiles: ["package.json"] // JSON файлы, которые будут использованы для descriptions
        mainFields: ["browser", "module", "main"] // искать пути к модулям в указанных полях файлов package.json: {...main: 'build/d3.Node.js', browser: 'build/d3.js', module: 'index', ...}
        mainFiles: ["index"] // Поиск фалов с данными исенами, если вместо пути к файлу указан путь к директории
        unsafeCache: true // Включить небезопасное кэширование модулей
        cachePredicate: function() { return true } // Функция определяющая стоит ли кэшировать запрос
        plugins: [new DirectoryNamedWebpackPlugin()] // Наборе плагинов для поиска файлов модулей
        symlinks: true // Искать файлы по ссылкам ярлыкам
    },
    noParse: [/\.ts$/, /\.tsx$/] // Не парсить перед сборкой файлы, перечисленные в данном массиве. Ожидается, что эти файлы сами ничего не импортирую. В них есть только экспорт exports и module.exports.
    rules: [ // Массив загрузчиков модулей загружающие файлы во время сборки итогового файла
                // Внимание! Webpack ищет загрузчики модулей относительно файла с конфигом. Если ваши загрузчики установлены в папке node_modules вне в родительской директории,
                // то Webpack не сможет их сам найти.
        {
            test: /\.txt$/, // Какие файлы должен загружать данный загрузчик модулей
            use: 'raw-loader' // Какой загрузчик модулей должен загружать данные файлы
            // loader: 'raw-loader' // Альтернатива use - Какой загрузчик модулей должен загружать данные файлы
            options: { // Набор опций для данного загрузчика модулей
              presets: ["es2015"]
            },
            include: [// Массив путей до файлов, которые тоже нужно загружать данным загрузчиком модулей
              path.resolve(__dirname, "app") // Только абсолютные пути
            ],
            exclude: [ // Массив путей до файлов, которые ненужно загружать данным загрузчиком модулей
              path.resolve(__dirname, "app/demo-files") // Только абсолютные пути
            ],
            issuer: { test, include, exclude }, // условия дляissuer (the origin of the import)
            enforce: "pre"  // Загрузчик модулей только для предварительной обработки перед сборкой взамен удаленных module.preLoaders и module.postLoaders
            enforce: "post", // Загрузчик модулей только для обработки после сборки взамен удаленных module.preLoaders и module.postLoaders
            parser: {
              amd: false, // disable AMD
              commonjs: false, // disable CommonJS
              system: false, // disable SystemJS
              harmony: false, // disable ES2015 Harmony import/export
              requireInclude: false, // disable require.include
              requireEnsure: false, // disable require.ensure
              requireContext: false, // disable require.context
              browserify: false, // disable special handling of Browserify bundles
              requireJs: false, // disable requirejs.*
              node: false, // disable __dirname, __filename, module, require.extensions, require.main, etc.
              node: {...} // reconfigure node layer on module level
            }
        }
        {
            test: /\.css$/,  // Регулярное выражение для поиска файлов, загружаемых данным загрузчиком модулей
            use: [ // Массив с перечнем модулей загрузчиков, используемых для загрузки данных типов файлов, и выполняющихся с конца в начало
                {
                    loader: 'style-loader' // Имя загрузчика модулей
                },
                {
                    loader: 'css-loader', // Имя загрузчика модулей
                    options: {// Опции для данного загрузчика модулей
                        modules: true
                    }
                }
            ]
        }
        {
          test: /\.js$/,
          exclude: /(node_modules)/,
          use: [{
            loader: 'babel-loader',
            options: {
              presets: [['es2015', {modules: false}]],
              plugins: [
                'syntax-async-functions',
                'syntax-dynamic-import',
                'transform-async-to-generator',
                'transform-regenerator',
                'transform-runtime'
              ]
            }
          }]
        }
        {
          resource: /filename/, // matches "/path/filename.js"
          resourceQuery: /^\?querystring$/, // matches "?querystring"
          issuer: /filename/, // matches "/path/something.js" if requested from "/path/filename.js"
        }
    ]
  }
------------------------------------------------------------------------
  plugins: [ // Массив плагинов, применяемых к итоговому файлу сборки
    new webpack.optimize.UglifyJsPlugin({ // Плагин для минимизации итогового файла сборки
      sourceMap: options.devtool && (options.devtool.indexOf("sourcemap") >= 0 || options.devtool.indexOf("source-map") >= 0)
    }),
    new HtmlWebpackPlugin({template: './src/index.html'}),
    new webpack.HotModuleReplacementPlugin() // Включить Hot Module Replacement (HMR)
    new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify('production')})
    new webpack.optimize.CommonsChunkPlugin({name: ['polyfills', 'vendor'].reverse()}),
    new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery'
      __assign: ['tslib', '__assign'],
      __extends: ['tslib', '__extends'],
    })
    function() {
      this.plugin("done", function(stats) { // save to file extracted from webpack compilation stats
        require("fs").writeFileSync(
          path.join(__dirname, "build", "stats.json"),
          JSON.stringify(stats.toJson()));
      });
    }
  ]
------------------------------------------------------------------------
    target: 'web' // Скомпилировать сборку для использования в браузере
------------------------------------------------------------------------
    bail: true // Прервать сборку при обнаружении хоть одной ошибки
------------------------------------------------------------------------
    profile: true // Получать информацию о времени сборки каждого модуля
------------------------------------------------------------------------
    recordsPath: path.join(__dirname, 'records.json') // Записывать в файл информации об изменении сборки каждого модуля между сборками
    recordsInputPath: path.join(__dirname, 'records.json'), // из какого файла читать последнюю информацию о сборке
    recordsOutputPath: path.join(__dirname, 'newRecords.json') // в какой файл записывать
------------------------------------------------------------------------
    cache: true // Кэшировать сборку для ускорения пересборки
------------------------------------------------------------------------
    watch: true // Отслеживать изменения файлов и запускать пересборку
------------------------------------------------------------------------
    watchOptions: { // Опции для процесса отслеживания изменений файлов для сборки
        ignored: "files/**/*.js" // Какие файлы не отслеживать для пересборки
        aggregateTimeout: 300, // Задержка перед запуском пересборки на случай если сейчас будут еще изменены файлы
        poll: 1000 // С каким интервалом проверять изменения в файлах
    }
------------------------------------------------------------------------
    devtool: 'inline-source-map' // В каком виде производить сборку source map
------------------------------------------------------------------------
    devServer: { // конфиг для webpack-dev-server
        hot: true, // Сказать dev-server, что мы испольлзуем Hot Module Replacement (HMR)
        lazy: true // Компилирует сборку только при запросе файлов из браузера. Не смотрит на изменения файлов watch
        filename: "bundle.js" // используется совместо с  lazy: true
        contentBase: [path.join(__dirname, "public"), path.join(__dirname, "assets")], // boolean | string | array, место расположения статичных файлов для загрузки
        staticOptions: { // Опции для загрузки статичных файлов
          redirect: false
        }
        watchContentBase: true // Остлеживать ли изменения статичных файлов и перезагружать ли после этого страницу браузера
        watchOptions: { // Опции для остлеживания процесса изменения файлов для сборки
          poll: true
        }
        https: false, // true для self-signed, объект для cert authority
        host: 'localhost', // (работает только в CLI)
        port: 7777, // (работает только в CLI)
        publicPath: "/assets/" // итоговая сборка будет доступна браузеру по указанному пути
        publicPath: "http://localhost:8080/assets/"
        allowedHosts: [ // Список разрешенных хостов
            'host.com',
            'subdomain.host.com',
            'subdomain2.host.com',
            'host2.com'
        ]
        proxy: { // прокси URL на backend development server
          '/api': 'http://localhost:3000'
          "/api": {
            target: "http://localhost:3000",
            pathRewrite: {"^/api" : ""}
          }
          "/api": {
            target: "http://localhost:3000",
            bypass: function(req, res, proxyOptions) {
              if (req.headers.accept.indexOf("html") !== -1) {
                console.log("Skipping proxy for browser request.");
                return "/index.html";
              }
            }
          }
        },
        headers: { // Добавить эти заголовки при ответе браузеру
          "X-Custom-Foo": "bar"
        }
        https: { // Сертификаты для HTTPS
          key: fs.readFileSync("/path/to/server.key"),
          cert: fs.readFileSync("/path/to/server.crt"),
          ca: fs.readFileSync("/path/to/ca.pem"),
        }
        historyApiFallback: { // true для index.html вплоть 404 или объект для множественных путей
          rewrites: [
            { from: /^\/$/, to: '/views/landing.html' },
            { from: /^\/subpage/, to: '/views/subpage.html' },
            { from: /./, to: '/views/404.html' }
          ]
        }
        noInfo: true, // только логи errors и warns при hot reload, остальная информация при сборке будет скрыта в консоли командной строки
        quiet: true // вся информация о сборке будет скрыта в консоли командной строки
        clientLogLevel: "none" //
        compress: true, // включить gzip compression
        stats: 'minimal', // Какую информацию о сборке выводить в консоль командной строки
        hotOnly: true // Включить Hot Module Replacement (работает только в CLI)
        inline: false // Включить вставку кода inline или в <iframe> (работает только в CLI)
        overlay: { // Показывать сообщения об ошибке сборки прямо на странице браузера, а не в консоли
          warnings: true,
          errors: true
        }
        progress: true // Показывать прогрессбар сборки (работает только в CLI)
        public: "myapp.test:80" // Указывается при проксирование через Nginx (работает только в CLI)
        setup: function (app) { // Собственная функция middleware для Express
          app.get('/some/path', function(req, res) {
            res.json({ custom: 'response' });
          });
        }
    }
------------------------------------------------------------------------
    performance: { // Конфигурирование как отражать информацию о производительности проведения сборки
        hints: "warning", // включить или выключить подсказки по производительности
        maxAssetSize: 200000, // int (in bytes), - при каких лимитах показывать подсказки по производительности
        maxEntrypointSize: 400000, // int (in bytes) - при каких лимитах показывать подсказки по производительности
        assetFilter: function (assetFilename) { // Какой файл использовать для оценки производительности сборки
            return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
        }
    },
------------------------------------------------------------------------
    stats: "errors-only", // Какую информацию о сборке показывать на экране консоли
    stats: {
      // Add asset Information
      assets: true,
      // Sort assets by a field
      assetsSort: "field",
      // Add information about cached (not built) modules
      cached: true,
      // Show cached assets (setting this to `false` only shows emitted files)
      cachedAssets: true,
      // Add children information
      children: true,
      // Add chunk information (setting this to `false` allows for a less verbose output)
      chunks: true,
      // Add built modules information to chunk information
      chunkModules: true,
      // Add the origins of chunks and chunk merging info
      chunkOrigins: true,
      // Sort the chunks by a field
      chunksSort: "field",
      // Context directory for request shortening
      context: "../src/",
      // `webpack --colors` equivalent
      colors: true,
      // Display the distance from the entry point for each module
      depth: false,
      // Display the entry points with the corresponding bundles
      entrypoints: false,
      // Add errors
      errors: true,
      // Add details to errors (like resolving log)
      errorDetails: true,
      // Exclude modules which match one of the given strings or regular expressions
      exclude: [],
      // Add the hash of the compilation
      hash: true,
      // Set the maximum number of modules to be shown
      maxModules: 15,
      // Add built modules information
      modules: true,
      // Sort the modules by a field
      modulesSort: "field",
      // Show dependencies and origin of warnings/errors (since webpack 2.5.0)
      moduleTrace: true,
      // Show performance hint when file size exceeds `performance.maxAssetSize`
      performance: true,
      // Show the exports of the modules
      providedExports: false,
      // Add public path information
      publicPath: true,
      // Add information about the reasons why modules are included
      reasons: true,
      // Add the source code of modules
      source: true,
      // Add timing information
      timings: true,
      // Show which exports of a module are used
      usedExports: false,
      // Add webpack version information
      version: true,
      // Add warnings
      warnings: true,
      // Filter warnings to be shown (since webpack 2.4.0),
      // can be a String, Regexp, a function getting the warning and returning a boolean
      // or an Array of a combination of the above. First match wins.
      warningsFilter: "filter" | /filter/ | ["filter", /filter/] | (warning) => ... return true|false
    };
------------------------------------------------------------------------
    node: { // Включать ли набор разных полифилов для кода Node.js
        console: false,
        global: true,
        process: true,
        __filename: "mock",
        __dirname: "mock",
        Buffer: true,
        setImmediate: true
        dns: "mock",
        fs: "empty",
        path: true,
        url: false
    }
------------------------------------------------------------------------
    amd: { // Установить значения для require.amd и define.amd для:
        jQuery: true
    }
------------------------------------------------------------------------
    loader: '' // Передать собственные значения в контекст модуля загрузчика
-----------------------------------------------------------------------
};
------------------------------------------------------------------------
// Компиляция через команду webpack
module.exports = config;
------------------------------------------------------------------------
или
------------------------------------------------------------------------
// Компиляция через Node.js короткий способ
------------------------------------------------------------------------
// Компиляция через Node.js короткий способ
webpack(config, function (error, stats) {
        console.log(error); // => fatal compiler error (rar)
        var json = stats.toJson() // => webpack --json
        console.log(json.errors); // => array of errors
        console.log(json.warnings); // => array of warnings
        console.log('Done');
    }
);
------------------------------------------------------------------------
или
------------------------------------------------------------------------
// Компиляция через Node.js длинный способ
const compiler = webpack(config);
compiler.run(function(error, stats) {
        console.log(stats.hasErrors());
        console.log(stats.hasWarnings());
        console.log(error); // => fatal compiler error (rar)
        var json = stats.toJson({chunks: false, hash: true ...}) // => webpack --json
        console.log(json.errors); // => array of errors
        console.log(json.warnings); // => array of warnings
        console.log(stats.toString({
            chunks: false, // Makes the build much quieter
            colors: true
        }));
        console.log('Done');
});
// или
const watchOptions = {
    aggregateTimeout: 300, // после внесения любого изменения в файл подождать 300 секунд перед началом сборки. Вдруг еще изменения будут.
    poll: true // использовать polling вместо native watchers
                  // можно передать число для установки polling interval
};
const watcher =  compiler.watch(watchOptions, function (error, stats) {
        console.log(error); // => fatal compiler error (rar)
        var json = stats.toJson() // => webpack --json
        console.log(json.errors); // => array of errors
        console.log(json.warnings); // => array of warnings
        console.log('Done');
    }
);
watcher.close(function () {console.log('Watcher stoped ');}); // Остановка отслеживания изменений в файлах
------------------------------------------------------------------------
// Полный контроль и запуск Dev Server через Express
------------------------------------------------------------------------
var express = require("express");
var webpackDevMiddleware = require("webpack-dev-middleware");
var webpack = require("webpack");
var webpackConfig = require("./webpack.config");

var app = express();
var compiler = webpack(webpackConfig);

app.use(webpackDevMiddleware(compiler, {
  publicPath: "/", // Same as "output.publicPath" in most cases.
  filename: "bundle.js", // Same as "output.filename" in most cases.
  lazy: true // lazy mode will only recompile on a request to the entry point.
}));

app.listen(3000, function () {
  console.log("Listening on port 3000!");
  console.log("Depending on what you've used in output.publicPath and output.filename, your bundle now available on http://localhost:3000/bundle.js");
});

понедельник, 26 июня 2017 г.

NodeJS HTTP Proxy

Файл http-proxy.js

var otherServerAnswer = Buffer.from(
      JSON.stringify(
          {data: [1, 2, 3]} // Ваши данные, которые вы хотите передать.
      )
    , 'utf-8'
);

var proxyURL = '/get/data' // null <-- Адрес, при запросе по которому, вы хотите передать ваши данные или null, если вам не нужна возврат ваших данных в ответ на запрос по указанном адресу.
    , proxyServerHostname = '127.0.0.5' // Адрес промежуточного сервера.
    , proxyServerPort = 80
    , otherServerHostname = '127.0.0.1' // Адрес целевого сервера.
    , otherServerPort = 8080;

var http = require('http')
    , url = require('url');

var proxyServer = http.createServer(function (browserRequest, proxyServerResponse) {

    console.log('Browser request: ' + browserRequest.method + ' ' + browserRequest.url);

    var browserURL = url.parse(browserRequest.url);

    var options = {
          headers: browserRequest.headers
        , method: browserRequest.method
        , hostname: otherServerHostname
        , port: otherServerPort
        , path: browserURL.path
    };

    var proxyServerRequest = http.request(options);

    browserRequest.on('data', function (chunk) {proxyServerRequest.write(chunk, 'binary');});
    browserRequest.on('end', function () {proxyServerRequest.end();});
    browserRequest.on('error', function (error) {console.log('Error with browser request: ' + error);});

    proxyServerRequest.on('response', function (otherServerResponse) {
        if (typeof browserRequest.url === 'string' && browserRequest.url === proxyURL) {
            otherServerResponse.headers['content-length'] = Buffer.byteLength(otherServerAnswer);
            proxyServerResponse.writeHead(otherServerResponse.statusCode, otherServerResponse.headers);
            proxyServerResponse.end(otherServerAnswer, 'binary');
        } else {
            var chunks = [];
            otherServerResponse.on('data', function (chunk) {
                // Закомментированные строки для проверки правильности передачи данных.
                // Конвертация из бинарных данных в строку и обратно.
                // chunk = chunk.toString('utf-8');
                // chunk = JSON.parse(chunk);
                // chunk = JSON.stringify(chunk);
                // chunk = Buffer.from(chunk, 'utf-8');
                // console.log(Buffer.byteLength(chunk));
                chunks.push(chunk);
            });
            otherServerResponse.on('end', function () {
                // console.log(Buffer.concat(chunks).toString('utf-8'));
                proxyServerResponse.writeHead(otherServerResponse.statusCode, otherServerResponse.headers);
                proxyServerResponse.end(Buffer.concat(chunks), 'binary');
            });
        }
        otherServerResponse.on('error', function (error) {console.log('Error with other server response: ' + error);});
    });
    proxyServerRequest.on('error', function (error) {console.log('Error with other proxy server request: ' + error);});

});

proxyServer.listen(proxyServerPort, proxyServerHostname, function (error) {
    if (error) {throw error;}
    console.log('Proxy server started at ' + proxyServerHostname + ':' + proxyServerPort);
});

////////////////////////////////////////////////////////////////////////////////
/* Пример кода целевого сервера для тестирования работы промежуточного сервера.
var otherServer = http.createServer(function (request, response) {
    response.writeHead(200, {'Content-Type': 'text/html'});
    response.write('OK');
    response.end('BYE');
});

otherServer.listen(otherServerPort, otherServerHostname, function (error) {
    if (error) {throw error;}
    console.log('Other server started at ' + otherServerHostname + ':' + otherServerPort);
});
*/

среда, 21 июня 2017 г.

Webpack API

------------------------------------------------------------------------
Webpack API
------------------------------------------------------------------------
const path = require('path');
const webpack = require('webpack');
------------------------------------------------------------------------
const config = {
------------------------------------------------------------------------
    context: path.join(__dirname, 'source'), // Абсолютный путь до папки с файлом указанным в entry. По умолчанию равно process.cwd().
------------------------------------------------------------------------
    entry: './index.js', // Исходный главный файл
    entry: ['./library.js', './index.js'], // Последовательный набор, идущих друг за другом исходных файлов. Последний в списке файл главный.
    entry: { // Несколько разных исходных главных файлов
        page1: './index1.js', // Исходный главный файл для страницы 1
        page2: ['./library.js', './index2.js'] // Исходный главный файл для страницы 2
    },
------------------------------------------------------------------------
    output: {
        path: path.join(__dirname, '/home/proj/public/dist/[hash]'), // // Абсолютный путь до папки с итоговыми файлами.
        publicPath: '/dist/[hash]', // Браузерный путь до папки, где лежат итоговый файлы. Предназначен для использования вместе с Webpack Dev Server.
        filename: "[name].bundle.js", // Имя итогового файла
                                                  // [name] - имя итогового файла
                                                  // [hash] - хэш итогового файла
                                                  // [chunkhash] - хэш части сборки итогового файла
        chunkFilename: "[id].bundle.js", // Имя итоговой части сборки
                                                      // [id] - идентификатор части сборки
                                                      // [name] - имя части сборки
                                                      // [hash] - хэш части сборки
                                                      // [chunkhash] - хэш части сборки
        sourceMapFilename: "[file].map" // Имя файлов source map, размещаемых в папке output.path
                                                      // [file] - имя итогового JavaScript-файла
                                                      // [id] - идентификатор части сборки
                                                      // [hash] хэш итогового файла
        pathinfo: false, // Включать ли в итоговую сборку комментарии синформацией о модулях: require(/* ./test */23)
        library: 'lib.js' // Если задано, то итоговая сборка будет экспортирована как отдельная библиотека с указанным именем. Используется только, если вы хотите собрать отдельную библиотеку.
        libraryTarget: "var" // В каком формате написать экспорт содержимого библиотеки? var Library = ...library code...;
        umdNamedDefine: false //Если указана output.libraryTarget и в ней установлено "umd" и указано output.library, тогда установка данного значения в true создаст имя AMD модуля
        sourcePrefix: "\t" // Записать перед каждой строчкой в итоговой сборке заданную строку
        crossOriginLoading: "anonymous" // Включить cross-origin loading для частей сборки
        devtoolModuleFilenameTemplate: "webpack:///[resource-path]?[loaders]" // Имяфайла шаблона для генерируемых файлов source map
        devtoolLineToLine: false // генерировать source map, привязанный линией к линии к исходному файлу
        hotUpdateChunkFilename: "[id].[hash].hot-update.js" // имя файла для частей с горячим обновлением, размещаемых в папке output.path
                                                       // [id] - идентификатор обновления
                                                       // [hash] - хэш обновления
        hotUpdateMainFilename: "[hash].hot-update.json" // имя главного ффайла с горячим обновлением, размещаемиого в папке output.path
                                                       // [hash] - хэш сборки
        jsonpFunction: "webpackJsonp" // Имя функци JSONP, используемой Webpack для асинхронной загрузки частей сборки
        hotUpdateFunction: "webpackHotUpdate" // Имя функци JSONP, используемой Webpack для асинхронной загрузки обновлений частей сборки
    },
------------------------------------------------------------------------
    externals: { // Перечень модулей, которые не должны быть включены в итоговую сборку, а должны быть вынесены в отдельные файлы
        {
            a: false, // модуль a не будет вынесен во вне
            b: true, // модуль b будет вынесен во вне `module.exports = b`
            "./c": "c", // модуль "./c" будет вынесен во вне `module.exports = c`
            "./d": "var d", // модуль "./d" будет вынесен во вне `module.exports = ./d`  <-- здесь будет синтакическая ошибка
            "./f": "commonjs ./a/b", // модуль "./f"  будет вынесен во вне `module.exports = require("./a/b")`
            "./f": "this ./a/b" // модуль "./f" будет вынесен во вне `(function() { module.exports = this["./a/b"]; }())`
        },
        /^[a-z\-0-9]+$/, // Каждый модуль не входящий в это выражение будет вынесен во вне abc -> require("abc")
        function(context, request, callback) { // Какждый модуль, имеющий в своем имени префикс "global-" будет вынесен во вне "global-abc" -> abc
            if(/^global-/.test(request)) {return callback(null, "var " + request.substr(7));}
            callback();
        },
        "./e" // модуль "./e" будет вынесен во вне (require("./e"))
    },
------------------------------------------------------------------------
    module: { // Как загружать модули JavaScript в сборку
        resolveLoader: { // Где искать загрузчики модулей
            // Имеет такой же набор опций, что и resolve для файлов, но только для загрузчиков модулей, кроме moduleTemplates, которого у resolve нет
            moduleTemplates: ["*-webpack-loader", "*-web-loader", "*-loader", "*"] // Массив с перечнем альтернативных имен для загрузчиков модулей
            extensions: ["", ".webpack-loader.js", ".web-loader.js", ".loader.js", ".js"], // Массив расширений загрузчиков модулей
            packageMains: ["webpackLoader", "webLoader", "loader", "main"]  // Просматривать перечисленные свойства в файлах package.json для поиска загрузчиков модулей
            root: path.join(__dirname, "node_modules") // Путь до папки в которой надо искать загрузчики модулей
            modulesDirectories: ["web_loaders", "web_modules", "node_loaders", "node_modules"], // Массив имен папок внутри данной директории, в которых надо искать загрузчики модулей.
                                                                                                                                        // Это подобие тому, как Node.js ищет папки с имене "node_modules". Обычно достаточно указать только область поиска в resolveLoader.root.
            fallback: [ // Массив с перечнем директорий в которых нужно искать загрузчики модулей, если Webpack не обнаружит нужные загрузчики модулей в папках указананнх в resolveLoader.root и resolveLoader.modulesDirectories.
                path.resolve('./some/modules'), // Все пути обязательно должны быть абсолютными!
                path.resolve('./other/modules')
            ]
            alias: { // Заменить имя загрузчика модуля на его полное имя
                txt: 'raw-loader'
            }
            packageAlias: "browser" // Найти в файле package.json свойства с указанным именем и использовать его содержимое вместо resolveLoader.alias
            unsafeCache: [/some.js/] // Включить небезопасное кэширование

        }
        resolve: { // Где искать исходные файлы для сборки
            extensions: ["", ".webpack.js", ".web.js", ".js", ".json", ".coffee"] // Массив расширений исходных файлов которые надо включать в сборку
            packageMains: ["webpack", "browser", "web", "browserify", ["jam", "main"], "main"] // Просматривать перечисленные свойства в файлах package.json для поиска исходных файлов для сборки
            root: [ // Массив с перечнем директорий в которых нужно искать исходные файлы.
                path.resolve('./app/modules'), // Все пути обязательно должны быть абсолютными!
                path.resolve('./vendor/modules')
            ]
            modulesDirectories: [ // Массив имен папок внутри данной директории, в которых надо искать исходные файлы.
                                           // Это подобие тому, как Node.js ищет папки с имене "node_modules". Обычно достаточно указать только область поиска в resolve.root.
                "web_modules",
                "node_modules"
            ]
            fallback: [ // Массив с перечнем директорий в которых нужно искать исходные файлы, если Webpack не обнаружит нужные исходные файлы в папках указананнх в resolve.root и resolve.modulesDirectories.
                path.resolve('./some/modules'), // Все пути обязательно должны быть абсолютными!
                path.resolve('./other/modules')
            ]
            alias: { // Заменить имя модуля в импорте на путь до файла
                main: "/absolute/path/to/file/main.js"
                sum: "/absolute/path/to/file/sum.js"
            }
            packageAlias: "browser" // Найти в файле package.json свойства с указанным именем и использовать его содержимое вместо resolve.alias
            unsafeCache: [/some.js/] // Включить небезопасное кэширование
        }
        noParse: [/\.ts$/, /\.tsx$/] // Не парсить перед сборкой файлы, перечисленные в данном массиве. Ожидается, что эти файлы сами ничего не импортирую. В них есть только экспорт exports и module.exports.
        preLoaders: [ // Массив с перечнем используемых загрузчиков модулей JavaScript для предварительной обработки перед сборкой
            test:  test: /\.js$/, // Регулярное выражение для поиска файлов, загружаемых данным загрузчиком модулей
            exclude: /node_modules/, // Регулярное выражение для поиска которые нельзя, загружаемых данным загрузчиком модулей
            include: ['/source/file2.js', '/source/file3.js'] // Массив путей до файлов, которые тоже нужно загружать данным загрузчиком модулей
            // Внимание! Webpack ищет загрузчики модулей относительно файла с конфигом. Если ваши загрузчики установлены в папке node_modules вне в родительской директории,
            // то Webpack не сможет их сам найти.
            // В этом случае необходимо добавить папку node_modules с модулями загрузчиками как абсолютный путь в опцию resolveLoader.root
            loader: 'style-loader?mimetype=image/png!css-loader?mimetype=image/png' // Строка с перечнем модулей загрузчиков, используемых для загрузки данных типов файлов, разделенных знаком "!", и выполняющихся справа налево
            query: { // Объект с перечнем настроек для loader, если он указан только один. В противном случае перечень настроек указывается внутри строки загрузчика.
                mimetype: 'image/png'
            }
            // Используется или loader или loaders
            loaders: [ // Массив с перечнем модулей загрузчиков, используемых для загрузки данных типов файлов, и выполняющихся с конца в начало
                'style-loader?mimetype=image/png',
                'css-loader?mimetype=image/png'
            ]
        ],
        loaders: [ // Массив с перечнем используемых загрузчиков модулей JavaScript в сборку
            test:  test: /\.js$/, // Регулярное выражение для поиска файлов, загружаемых данным загрузчиком модулей
            exclude: /node_modules/, // Регулярное выражение для поиска которые нельзя, загружаемых данным загрузчиком модулей
            include: ['/source/file2.js', '/source/file3.js'] // Массив путей до файлов, которые тоже нужно загружать данным загрузчиком модулей
            // Внимание! Webpack ищет загрузчики модулей относительно файла с конфигом. Если ваши загрузчики установлены в папке node_modules вне в родительской директории,
            // то Webpack не сможет их сам найти.
            // В этом случае необходимо добавить папку node_modules с модулями загрузчиками как абсолютный путь в опцию resolveLoader.root
            loader: 'style-loader?mimetype=image/png!css-loader?mimetype=image/png' // Строка с перечнем модулей загрузчиков, используемых для загрузки данных типов файлов, разделенных знаком "!", и выполняющихся справа налево
            query: { // Объект с перечнем настроек для loader, если он указан только один. В противном случае перечень настроек указывается внутри строки загрузчика.
                mimetype: 'image/png'
            }
            // Используется или loader или loaders
            loaders: [ // Массив с перечнем модулей загрузчиков, используемых для загрузки данных типов файлов, и выполняющихся с конца в начало
                'style-loader?mimetype=image/png',
                'css-loader?mimetype=image/png'
            ]
        ]
        postLoaders: [ // Массив с перечнем используемых загрузчиков модулей JavaScript для обработки после сборки
            test:  test: /\.js$/, // Регулярное выражение для поиска файлов, загружаемых данным загрузчиком модулей
            exclude: /node_modules/, // Регулярное выражение для поиска которые нельзя, загружаемых данным загрузчиком модулей
            include: ['/source/file2.js', '/source/file3.js'] // Массив путей до файлов, которые тоже нужно загружать данным загрузчиком модулей
            // Внимание! Webpack ищет загрузчики модулей относительно файла с конфигом. Если ваши загрузчики установлены в папке node_modules вне в родительской директории,
            // то Webpack не сможет их сам найти.
            // В этом случае необходимо добавить папку node_modules с модулями загрузчиками как абсолютный путь в опцию resolveLoader.root
            loader: 'style-loader?mimetype=image/png!css-loader?mimetype=image/png' // Строка с перечнем модулей загрузчиков, используемых для загрузки данных типов файлов, разделенных знаком "!", и выполняющихся справа налево
            query: { // Объект с перечнем настроек для loader, если он указан только один. В противном случае перечень настроек указывается внутри строки загрузчика.
                mimetype: 'image/png'
            }
            // Используется или loader или loaders
            loaders: [ // Массив с перечнем модулей загрузчиков, используемых для загрузки данных типов файлов, и выполняющихся с конца в начало
                'style-loader?mimetype=image/png',
                'css-loader?mimetype=image/png'
            ]
        ]
        // Отключить обработку неизвестных require
        unknownContextRegExp: /$^/,
        unknownContextCritical: false,
        // Отключить обработку require с единственным выражением
        exprContextRegExp: /$^/,
        exprContextCritical: false,
        // Предупредить о каждом обнаруженном выражении в require
        wrappedContextCritical: true
    },
------------------------------------------------------------------------
    plugins: [ // Массив с перечнем плагинов, вызываемых по очередние к содержимому итоговой сборки
        new webpack.IgnorePlugin(/file\.js$/),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            output: {
                comments: false
            }
        }),
        new ComponentPlugin()
    ]
------------------------------------------------------------------------
    target: 'web' // Скомпмилировать сборку для использования в браузере
------------------------------------------------------------------------
    bail: true // Прервать сборку при обнаружении хоть одной ошибки
------------------------------------------------------------------------
    profile: true // Получать информацию о времени сборки каждого модуля
------------------------------------------------------------------------
    cache: true // Кэшировать сборку для ускорения пересборки
------------------------------------------------------------------------
    debug: true // Переключить работу загрузчиков модулей в режим отладки
------------------------------------------------------------------------
    watch: true // Отслеживать изменения файлов и запускать пересборку
------------------------------------------------------------------------
    devtool: 'eval' // В какмо виде произовдить сборку source map
------------------------------------------------------------------------
    devServer: { // конфиг для webpack-dev-server
        contentBase: "./build",
    }
------------------------------------------------------------------------
    node: { // Включать ли набор разных полифилов для кода Node.js
        console: false,
        global: true,
        process: true,
        Buffer: true,
        __filename: "mock",
        __dirname: "mock",
        setImmediate: true
    }
------------------------------------------------------------------------
    amd: { // Установить значения для require.amd и define.amd для:
        jQuery: true
    }
------------------------------------------------------------------------
};
------------------------------------------------------------------------
// Компиляция через команду webpack
module.exports = config;
------------------------------------------------------------------------
или
------------------------------------------------------------------------
// Компиляция через Node.js короткий способ
webpack(config, function (error, stats) {
        console.log(error); // => fatal compiler error (rar)
        var json = stats.toJson() // => webpack --json
        console.log(json.errors); // => array of errors
        console.log(json.warnings); // => array of warnings
        console.log('Done');
    }
);
------------------------------------------------------------------------
или
------------------------------------------------------------------------
// Компиляция через Node.js длинный способ
const compiler = webpack(config);
compiler.run(function(error, stats) {
        console.log(stats.hasErrors());
        console.log(stats.hasWarnings());
        console.log(error); // => fatal compiler error (rar)
        var json = stats.toJson({chunks: false, hash: true ...}) // => webpack --json
        console.log(json.errors); // => array of errors
        console.log(json.warnings); // => array of warnings
        console.log(stats.toString({
            chunks: false, // Makes the build much quieter
            colors: true
        }));
        console.log('Done');
});
// или
const watchOptions = {
    aggregateTimeout: 300, // после внесения любого изменения в файл подождать 300 секунд перед началом сборки. Вдруг еще изменения будут.
    poll: true // использовать polling вместо native watchers
                  // можно передать число для установки polling interval
};
const watcher =  compiler.watch(watchOptions, function (error, stats) {
        console.log(error); // => fatal compiler error (rar)
        var json = stats.toJson() // => webpack --json
        console.log(json.errors); // => array of errors
        console.log(json.warnings); // => array of warnings
        console.log('Done');
    }
);
watcher.close(function () {console.log('Watcher stoped ');}); // Остановка отслеживания изменений в файлах
------------------------------------------------------------------------
// Dev Server
var WebpackDevServer = require("webpack-dev-server");
var webpack = require("webpack");
var fs = require("fs");

var compiler = webpack({
  // configuration
});
var server = new WebpackDevServer(compiler, {
  // webpack-dev-server options

  contentBase: "/path/to/directory",
  // Can also be an array, or: contentBase: "http://localhost/",

  hot: true,
  // Enable special support for Hot Module Replacement
  // Page is no longer updated, but a "webpackHotUpdate" message is sent to the content
  // Use "webpack/hot/dev-server" as additional module in your entry point
  // Note: this does _not_ add the `HotModuleReplacementPlugin` like the CLI option does.

  historyApiFallback: {
        rewrites: [
            // shows views/landing.html as the landing page
            { from: /^\/$/, to: '/views/landing.html' },
            // shows views/subpage.html for all routes starting with /subpage
            { from: /^\/subpage/, to: '/views/subpage.html' },
            // shows views/404.html on all other pages
            { from: /./, to: '/views/404.html' },
        ],
  },
  // Set this as true if you want to access dev server from arbitrary url.
  // This is handy if you are using a html5 router.

  compress: true,
  // Set this if you want to enable gzip compression for assets

  proxy: {
    "**": "http://localhost:9090"
  },
  // Set this if you want webpack-dev-server to delegate a single path to an arbitrary server.
  // Use "**" to proxy all paths to the specified server.
  // This is useful if you want to get rid of 'http://localhost:8080/' in script[src],
  // and has many other use cases (see https://github.com/webpack/webpack-dev-server/pull/127 ).

  setup: function(app) {
    // Here you can access the Express app object and add your own custom middleware to it.
    // For example, to define custom handlers for some paths:
    // app.get('/some/path', function(req, res) {
    //   res.json({ custom: 'response' });
    // });
  },

  // pass [static options](http://expressjs.com/en/4x/api.html#express.static) to inner express server
  staticOptions: {
  },

  clientLogLevel: "info",
  // Control the console log messages shown in the browser when using inline mode. Can be `error`, `warning`, `info` or `none`.

  // webpack-dev-middleware options
  quiet: false,
  noInfo: false,
  lazy: true,
  filename: "bundle.js",
  watchOptions: {
    aggregateTimeout: 300,
    poll: 1000
  },
  // It's a required option.
  publicPath: "/assets/",
  headers: { "X-Custom-Header": "yes" },
  stats: { colors: true },

  https: {
    cert: fs.readFileSync("path-to-cert-file.pem"),
    key: fs.readFileSync("path-to-key-file.pem"),
    cacert: fs.readFileSync("path-to-cacert-file.pem")
  }
});
server.listen(8080, "localhost", function() {});
// server.close();
------------------------------------------------------------------------
// Dev Server Middleware
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpack = require("webpack");

const compiler = webpack(config);

app.use(webpackDevMiddleware(compiler, {
    publicPath: config.output.publicPath
    filename: config.output.filename
    watchOptions: {
        aggregateTimeout: 300
        poll: true
    }
    noInfo: true
    quiet: false
    lazy: false
    stats: true
    headers: {
        "X-Custom-Header": "yes"
    }
}));
------------------------------------------------------------------------

==================================================================
==================================================================

const webpack = require('webpack');
const ComponentPlugin = require('component-webpack-plugin');

module.exports = {

==================================================================

    entry: './src/app.js',
    entry: {
        beep: './beep.js',
        boop: './boop.js',
    },

    entry: {
        app: './app.js',
        vendor: ['jquery', 'underscore', ...]
    },
    output: {
        filename: 'bundle.js'
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin(/* entry= */'vendor', /* filename= */'vendor.bundle.js')
    ]
    <script src='vendor.bundle.js'></script>
    <script src='bundle.js'></script>


    module.exports = {
        entry: {
            a: './a',
            b: './b'
        },
        output: {
            filename: '[name].js'
        },
        plugins: [
            new webpack.optimize.CommonsChunkPlugin('init.js')
        ]
    }
    <script src='init.js'></script>
    <script src='a.js'></script>
    <script src='b.js'></script>

==================================================================

    output: { // './bin/app.bundle.js'
        path: './bin',
        filename: 'app.bundle.js' // '[name].bundle.js'
        =============================
        path: path.join(__dirname, 'assets', '[hash]'),
        publicPath: 'assets/[hash]/',
        filename: 'output.[hash].bundle.js',
        chunkFilename: '[id].[hash].bundle.js'
    },

    output: {
        libraryTarget: 'var', // export itself to a global var
        library: 'Foo'  // name of the global var: 'Foo'
    },
    externals: {
        jquery: 'jQuery' // require('jquery') is external and available on the global var jQuery
    }

==================================================================
    resolve: {
        extensions: ['', '.js', '.coffee'],
        fallback: path.join(__dirname, 'node_modules')
    },
    resolveLoader: {
        fallback: path.join(__dirname, 'node_modules')
    },
    module: {
        loaders: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: 'babel-loader?mimetype=image/png'
            },
            {
                test: /\.css$/,
                loaders: [
                    'style-loader?mimetype=image/png',
                    'css-loader?mimetype=image/png'
                ]
            },
            {
                test: /\.png$/,
                loader: 'url-loader',
                query: {
                    mimetype: 'image/png'
                }
            },
            {
                test: /\.jsx?$/,
                exclude: /(node_modules|bower_components)/,
                loaders: [{
                loader: 'babel-loader',
                query: {
                    cacheDirectory: true
                }
            }
        ]
    },
    plugins: [
        new webpack.IgnorePlugin(/file\.js$/),
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            output: {
                comments: false
            }
        }),
        new ComponentPlugin()
    ]
};

==================================================================

var webpack = require('webpack');

webpack(
    {
        entry: './main.js',
        output: {
            filename: 'bundle.js'
        }
    }
    , function(err, stats) {
        console.log(err); // => fatal compiler error (rar)
        var json = stats.toJson() // => webpack --json
        console.log(json.errors); // => array of errors
        console.log(json.warnings); // => array of warnings
    }
);

==================================================================

var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
    entry: {
        posts: './posts',
        post: './post',
        about: './about'
    },
    output: {
        filename: '[name].js',
        chunkFilename: '[id].js'
    },
    module: {
        loaders: [
            {
                test: /\.css$/,
                loader: ExtractTextPlugin.extract('style-loader', 'css-loader')
            },
            {
                test: /\.less$/,
                loader: ExtractTextPlugin.extract('style-loader', 'css-loader!less-loader')
            }
        ]
    },
    plugins: [
        new ExtractTextPlugin('[name].css')
    ]
}

Output files:

posts.js
posts.css

post.js
post.css

about.js
about.css

Styles in Commons Chunk

// ...
module.exports = {
    // ...
    plugins: [
        new webpack.optimize.CommonsChunkPlugin('commons', 'commons.js'),
        new ExtractTextPlugin('[name].css')
    ]
}

Output files:

commons.js
commons.css

posts.js
posts.css

post.js
post.css

about.js
about.css

==================================================================

var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
module.exports = {
    entry: {
        p1: './page1',
        p2: './page2',
        p3: './page3',
        ap1: './admin/page1',
        ap2: './admin/page2'
    },
    output: {
        filename: '[name].js'
    },
    plugins: [
        new CommonsChunkPlugin('admin-commons.js', ['ap1', 'ap2']),
        new CommonsChunkPlugin('commons.js', ['p1', 'p2', 'admin-commons.js'])
    ]
};
// <script>s required:
// page1.html: commons.js, p1.js
// page2.html: commons.js, p2.js
// page3.html: p3.js
// admin-page1.html: commons.js, admin-commons.js, ap1.js
// admin-page2.html: commons.js, admin-commons.js, ap2.js