Webpack についてちょっと試してみる

Azure Functions の Cold start 問題に関しては、`App Service Plan` + `Always On` option を使う方法があるが、それに加えて、node の場合は、`webpack` を使うと良さげ。C# の場合はプリコンパイルオプション。今日はさらっと試しただけのなので、明日以降色々試してみたい。

* [Cold start of Azure Function with large npm module trees is slow in Consumption plan #298](https://github.com/Azure/azure-webjobs-sdk-script/issues/298)
* [Cold Start and Warm Start on Consumption Plan #131](https://github.com/Azure/Azure-Functions/issues/131)

まずは[webpack](https://webpack.js.org/concepts/)についてちょっと試してみた。

# Webpack でビルドしてみる

ここに便利なリポジトリがあった。

* [Example WebPack with Azure Functions](https://github.com/christopheranderson/azure-functions-webpack-sample)


ちょっとインストラクションが古いけど、下記のようにすればできる。clone して下記のようにする。[Azure Functions CLI](https://github.com/Azure/azure-functions-cli)はインストールずみのこと。

```
npm install
npm run build
func init
func host start
```

これで、サーバーが動く

<img width="682" alt="Screen Shot 2017-10-02 at 11.30.48 PM.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/cbbcbfde-ddb0-5b79-4e06-df4074a4856e.png">

# webpack の実態をみる。

webpack のやりたいことは、すぐにわかる。`build/index.js` というファイルができてるのでみてみよう。

```js
module.exports =
/******/ (function(modules) { // webpackBootstrap
/******/        // The module cache
/******/        var installedModules = {};
/******/
/******/        // The require function
/******/        function __webpack_require__(moduleId) {
/******/
/******/                // Check if module is in cache
/******/                if(installedModules[moduleId]) {
/******/                        return installedModules[moduleId].exports;
/******/                }
/******/                // Create a new module (and put it into the cache)
/******/                var module = installedModules[moduleId] = {
/******/                        i: moduleId,
/******/                        l: false,
/******/                        exports: {}
/******/                };
/******/
/******/                // Execute the module function
/******/                modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
 : 以下続く
```
# webpack の今回の目的での効能

つまり、一つのファイルに、node_moduleの下にあるライブラリをまとめている。もともと、`webpack` の `Azure Functions` による使用のきっかけは、`consumption plan` での起動が、`webpack` をするとかなり早くなるという話だった。

<img width="682"  src="https://camo.githubusercontent.com/ea90f0ebb3d74beec81f6ea56b84b06f48146c9e/68747470733a2f2f746f6c64617a757265626c6f62616363657373746573742e626c6f622e636f72652e77696e646f77732e6e65742f746573742f5765627061636b506572666f726d616e6365322e706e67">

つまり、ファイルを１つにまとめることで、起動時のスピードが早くなるらしい。これが、どんな感じになっているか、各ファイルをみてみよう。

# webpack のやること

`build` をみると、単純に、`webpack` を実行している。

```json
$ cat package.json 
{
  "name": "asdf",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "lodash": "^4.17.4",
    "ms-rest-azure": "^1.15.4"
  },
  "devDependencies": {
    "webpack": "^2.2.1"
  }
}

```

webpack は、`webpack.config.js` を見てライブラリをまとめる作業を実施。どこに、結果を吐き出すかも書いている。

```js
$ cat webpack.config.js 
var webpack = require('webpack');
var path = require('path');
module.exports = {
  entry: './index.js',
  target: 'node',
  output: {
    path: path.join(__dirname, "build"),
    filename: 'index.js',
    library: "index",
    libraryTarget: "commonjs2"
  },
  node: {
    __filename: false,
    __dirname: false,
  },
}
```

ちなみに、参照されている、`./index.js`は、各functions を参照。

```js
$ cat index.js 
var HttpTriggerJS = require('./HttpTriggerJS/index')
var HTTPJS2 = require('./HTTPJS2/index')

module.exports = {
    HttpTriggerJS: HttpTriggerJS,
    HTTPJS2: HTTPJS2
}
```

そして、各functions は、生成された `build/index.js` を参照している。

function.json

```json
$ cat function.json 
{
  "disabled": false,
  "scriptFile":"../build/index.js",
  "entryPoint":"HttpTriggerJS",
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}
```

functions の記述は変更がない。

```js
$ cat index.js 
let msRestAzure = require('ms-rest-azure');
let _ = require('lodash');

module.exports = function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    if (req.query.name || (req.body && req.body.name)) {
        res = {
            // status: 200, /* Defaults to 200 */
            body: "Hello " + (req.query.name || req.body.name)
        };
    }
    else {
        res = {
            status: 400,
            body: "Please pass a name on the query string or in the request body"
        };
    }
    context.done(null, res);
};
```

このように、webpack を使うと、ライブラリが１つのファイルにまとめられて、立ち上げが高速課されるようだなぁ。とわかった。