webpack4.39.2でexternalsを使ったときに o is not a functionと言われた時のメモ

## 概要
momentをcdnから読み込んで使おうと思ったのだが、webpack-dev-serverで問題なく動いていたものが、webpackでビルドすると
以下のエラーがでてしまうこととなった。

```
o is not a function
```

minifyをしていたため、oとなっているので、モードをdevelopmentにしてビルドしなおしたところ、以下のエラーであった。

```
moment is not a function
```

## 解決

以下の書き方で解決した。ぼんやり * as library みたいなのを使っていたのが災いした感じ。

```diff:index.ts
- import * as moment from 'moment';
+ import moment from 'moment';
```

このとき、出力されるビルド結果の違いは以下。
分かりやすいように改行を入れている。

```js
var moment = _interopRequireWildcard(__webpack_require__(/*! moment */ \"moment\"));\n\n
function _interopRequireWildcard(obj) {
\n  if (obj && obj.__esModule) {\n    return obj;\n  } 
else {\n    var newObj = {};\n\n    if (obj != null) {\n      for (var key in obj) {\n        if (Object.prototype.hasOwnProperty.call(obj, key)) {\n          var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {};\n\n          if (desc.get || desc.set) {\n            Object.defineProperty(newObj, key, desc);\n          } else {\n            newObj[key] = obj[key];\n          }\n        }\n      }\n    }\n\n    newObj.default = obj;\n    return newObj;\n  }\n} 
```

```js
var _moment = _interopRequireDefault(__webpack_require__(/*! moment */ \"moment\"));\n\n
function _interopRequireDefault(obj) {
\n  return obj && obj.__esModule ? obj : {\n    default: obj\n  };\n} 
```

## オプション
参考に、webpackのオプションをのせておく。

```js:webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const MODE = 'production';
const filename = MODE === 'production' ? '[name]-[hash].js' : 'index.js';

// ソース・出力先の設定
const opts = {
  src: path.join(__dirname, 'separate/pre-dist'),
  dest: path.join(__dirname, 'separate/dist'),
};

module.exports = {
  mode: MODE,
  entry: path.join(opts.src, 'assets/js/index.js'),
  output: {
    path: opts.dest,
    // spaの場合は、絶対パスにしないと、cssの読み込みやjsの読み込みがルート以外でおかしくなる
    publicPath: '/lobby',
    filename,
  },
  plugins: [
    new HTMLWebpackPlugin({
      template: path.join(opts.src, 'index.html'),
      inject: 'body',
    }),
    new CleanWebpackPlugin({
      verbose: true,
      dry: false,
    }),
    new MiniCssExtractPlugin({
      filename: '[name]-[hash].css',
    })
    , new webpack.DefinePlugin({
      REPRACE_TEST: JSON.stringify(process.env.REPRACE_TEST)
    })
  ],
  resolve: {
    modules: [opts.src, 'node_modules'],
    extensions: ['.js', '.css', '.png'],
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
      {
        test: /\.css$/,
        exclude: [/elm-stuff/, /node_modules/],
        loaders: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: {
              sourceMap: false,
              url: false,
            },
          },
        ],
      },
      {
        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        exclude: [/elm-stuff/, /node_modules/],
        loader: 'url-loader',
        options: {
          limit: 10000,
          mimetype: 'application/font-woff',
        },
      },
      {
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        exclude: [/elm-stuff/, /node_modules/],
        loader: 'file-loader',
      },
      {
        test: /\.(jpe?g|png|gif|svg)$/i,
        exclude: [/elm-stuff/, /node_modules/],
        loader: 'file-loader',
      },
    ],
  },
  // cdnから読み込むものはここに
  externals: {
    jquery: 'jQuery'
    , 'chart.js': 'Chart'
    , firebase: 'firebase'
    , firebaseui: 'firebaseui'
    , M: 'M' // materialize
    , moment: 'moment'
  },
};
```

## 参考

[externals](https://webpack.js.org/configuration/externals/)