[ 雑に対策 ] Webpackプラグインでエラーが出たので、作り方を調べて直してみた。

# DeprecationWarning: Tapable.plugin is deprecated. Use new API on .hooks instead

↑
こんなエラーが出て困ってる人のヒントになれば幸い。

## 結果

↓こうしたら動きました。

```javascript:index.js
const fs = require('fs');
const RawSource = require('webpack-sources').RawSource;
const SourceMapSource = require('webpack-sources').SourceMapSource;
const iconv = require('iconv-lite');
let ModuleFilenameHelpers = require('webpack').ModuleFilenameHelpers;
if (!ModuleFilenameHelpers) {
  ModuleFilenameHelpers = require('webpack/lib/ModuleFilenameHelpers')
}

class EncodingPlugin {
  constructor(options) {
    if (typeof options === 'string') {
      this.options = {
        encoding: options
      }
    } else {
      this.options = options || {}
    }
  }

  apply(compiler) {
    let options = this.options;
    options.test = options.test || /(\.js|\.css)($|\?)/i;

    let matchFileName = ModuleFilenameHelpers.matchObject.bind(undefined, options);

    compiler.hooks.emit.tapPromise('EncodingPlugin', compilation => {
      return new Promise((resolve, reject) => {
        let files = Object.keys(compilation.assets).filter(matchFileName);
        files.forEach(function (file) {
          let asset = compilation.assets[file];
          try {
            let source, map;
            if (asset.sourceAndMap) {
              let sourceAndMap = asset.sourceAndMap();
              source = sourceAndMap.source;
              map = sourceAndMap.map
            } else {
              source = asset.source();
              map = typeof asset.map === 'function'
                ? asset.map()
                : null
            }

            let encodedSource = iconv.encode(source, options.encoding, options.config);
            if (asset.existsAt && fs.existsSync(asset.existsAt)) {
              fs.writeFileSync(asset.existsAt, encodedSource)
            }

            compilation.assets[file] = map
              ? new SourceMapSource(encodedSource, file, map)
              : new RawSource(encodedSource)

          } catch (e) {
            compilation.errors.push(new Error(file + ' from EncodingPlugin: ' + e.message))
          }
        });

        console.log('Assets converted to ' + options.encoding);
        resolve();
      });
    });
  }
}

module.exports = EncodingPlugin;

```

## 経緯

今開発しているサイトの文字コードが `EUC-JP` 限定だったので、
JavaScriptの文字コードを `EUC-JP` にしたく、
`webpack-encode-plugin` というプラグインを実装してみたところ、
↓こんなエラーが出て怒られた。

```
DeprecationWarning: Tapable.plugin is deprecated. Use new API on .hooks instead
```

**webpack-encode-plugin**
https://www.npmjs.com/package/webpack-encode-plugin

## ググってみたけどこのプラグインのissuが見つからず。。

`DeprecationWarning: Tapable.plugin is deprecated. Use new API on .hooks instead`

でググってみたけど解決策が見つからなかった。

## よし、とりあえず直訳だ！

英語も得意じゃないので、とりあえず Google翻訳 にかけてみた。
結果が↓こちら

```
DeprecationWarning：Tapable.pluginは非推奨です。代わりに.hooksに新しいAPIを使用してください
```

ふむ。
まあ要は Plugin 内の記述方法を新しいAPIに変えろと言っているっぽい。

## `Tapable.plugin` とはなんぞや？

「非推奨です。」って言われている `Tapable.plugin` がなんのか分からなかったので、
「site:webpack.js.org Tapable.plugin」でググってみたら、
**Plugin API** のページがヒットした。

**Plugin API**
https://webpack.js.org/api/plugins/

そこに `Tapable` class という記述を発見。
**Tapable | Plugin API**
https://webpack.js.org/api/plugins/#tapable

ドキュメントへのリンクも発見。
**webpack/tapable | GitHub**
https://github.com/webpack/tapable

「この辺を読み解いて、ソースコードいじればなんとかなるかも？」 と思った。

## ひとまずプラグインの中身を見てみた

GitHub に上がっていたソースコードが↓こちら
https://github.com/ricosmall/webpack-encode-plugin/blob/master/index.js

う〜ん、どの辺が `Tapable` クラスか分からず。。。

## `Tapable.plugin webpack` でもググってみた

↓こんなページを発見
**Extending with Plugins**
https://survivejs.com/webpack/extending/plugins/

webpackプラグインの書き方ページっぽいけど、
今回エラーの出た `webpack-encode-plugin` の記述方法がこれによく似てた。
この書き方がもう古いってことなんだろうな。。。と推測。



## Plugin API のページを再度確認

Plugin Types の箇所に

```javascript
compiler.hooks...
```

という記述を発見。

以前は、 `compiler.plugin` としていた書き方が、
`compiler.hooks` というメソッドに変わったんだなと推測。

**Plugin Types**
https://webpack.js.org/api/plugins/#plugin-types

さて、

## `compiler.hooks.` のあとはどうする？

**Compiler Hooks** というページがあったので、
見てみたがいっぱいあった。。。

でもなんとなく、 `emit` を選択。

文字コード変換は output ディレクトリへの出力直前がよい気がしたので。


## `compiler.hooks.emit.` のあとはどうする？

**Hook types** に色々あった。
https://github.com/webpack/tapable#hook-types

非同期の `Promise` ベースで `resolve()` 返せれば無難かなと思い、
`.tapPromise()` を選択

## 組み直した結果うまく機能して文字コード変換されました。

だいぶ大雑把な修正のしかたをしたけど、
まあ動いたのでよし。

時間に余裕ができたらもっとちゃんと調べて理解してみよう。

## なんとかなったけども

記述に問題があったりする可能性大だと思っているので、
大元の `webpack-encode-plugin` へはこの内容は送ってません。

おかしな点などありましたらご指摘いただけると嬉しいです（＞人＜）