LoginSignup
4
0

More than 3 years have passed since last update.

node-fetchをwebpackすると実行できない・・・

Last updated at Posted at 2020-05-20

やりたかったこと

シンプルにとあるWebサイトをスクレイピングして、情報を取得したかった。
過去にもスクレイパーを作成したことはあるのだが、その時リクエストを送信するのにrequestモジュールを使用していたが、どうやらパッケージが2020年2月に廃止されたらしい…
そこで見つけたのが「node-fetch」。
試しにこれを使って指定したページのHTML要素を取得したい。

使ってみる

TypeScriptをインストール

yarn add typescript

詳しい環境構築はこの記事の本筋からズレるため省略させていただきます。

node-fetchをインストール

yarn add node-fetch

ここでは詳しい使い方などは省略させていただきます。
詳しくはこちらを

サンプルコードを作成

index.ts
import fetch from 'node-fetch';

const url: string = "https://qiita.com/";

fetch(url)
  .then(res => res.text())
  .then(body => console.log(body));

これでHTMLが取得できるはず。

補足

JavaScriptで動的に生成されている要素を取得したい場合、ヘッドレスブラウザが必要になるようです。
この記事の本筋と異なるため、こちらも省略させていただきます。
(今回スクレイピングするサイトには必要なかったので詳しく調べてないです…ごめんなさい)

実行してみる

ts-nodeを使用して実行してみる。

package.json
"scripts": {
  "start": "ts-node ./index.ts",
  "build": "webpack"
}

実行

$ npm run start

<!DOCTYPE html><html><head><meta charset="utf-8" />
<title>Qiita</title><meta content="Qiitaは、プログラマのための技術情報共有サービスです。 プログラミングに関するTips、ノウハウ、メモを簡単に記録 &amp;amp; 公開することができます。" name="description" />
<meta content="width=device-width,initial-scale=1,shrink-to-fit=no" name="viewport" />
<meta content="#55c500" name="theme-color" />
<meta content="XWpkTG32-_C4joZoJ_UsmDUi-zaH-hcrjF6ZC_FoFbk" name="google-site-verification" />
<link href="/manifest.json" rel="manifest" />
<link href="/opensearch.xml" rel="search" title="Qiita" type="application/opensearchdescription+xml" />
<meta name="csrf-param" content="authenticity_token" />

....省略

うん。取れた。

webpack

たったこれだけなのでJavaScriptで書いても良かったのですが、今回作るプロダクトではTypeScriptを使いたかった。
というわけでwebpackでトランスパイルします。

まずはwebpackのツールをインストール

yarn add -D webpack webpack-cli ts-loader

webpack.config.jsを作成します。

webpack.config.js
const path = require('path');

module.exports = {
  mode: 'development',
  entry: './index.ts',
  output: {
      path: path.join(__dirname, "dist"),
      filename: "index.js"
  },
  module: {
    rules: [{
      test: /\.ts$/,
      use: [
        {loader: 'ts-loader'}
      ]
    }]
  },
  resolve: {
      modules: [
      "node_modules",
      ],
      extensions: [ '.ts', '.js', 'json' ]
  }
};

webpackして実行

$ node ./dist/index.js

webpack:///./node_modules/node-fetch/browser.js?:11
        throw new Error('unable to locate global object');
        ^

Error: unable to locate global object
    at getGlobal (webpack:///./node_modules/node-fetch/browser.js?:11:8)
    at eval (webpack:///./node_modules/node-fetch/browser.js?:14:14)
    at Object../node_modules/node-fetch/browser.js (/Users/taisei/Documents/project/MagicReview/scraping/dist/index.js:97:1)
    at __webpack_require__ (/Users/taisei/Documents/project/MagicReview/scraping/dist/index.js:20:30)
    at eval (webpack:///./src/index.ts?:26:36)
    at Object../src/index.ts (/Users/taisei/Documents/project/MagicReview/scraping/dist/index.js:109:1)
    at __webpack_require__ (/Users/taisei/Documents/project/MagicReview/scraping/dist/index.js:20:30)
    at /Users/taisei/Documents/project/MagicReview/scraping/dist/index.js:84:18
    at Object.<anonymous> (/Users/taisei/Documents/project/MagicReview/scraping/dist/index.js:87:10)
    at Module._compile (internal/modules/cjs/loader.js:1158:30)

あれ?トランスパイルしたらエラーでた…

解決方法

調査した結果、以下の方法で解決しました。

webpack.config.js
// 省略

target: "node",   //この行を追加
module: {
    rules: [{
      test: /\.ts$/,
      use: [
        {loader: 'ts-loader'}
      ]
    }]
  },

....

どうやら、webpackでバンドルするときにtargetをnodeに指定しないとbrowserオブジェクトが取得できないようです。
省略しますが、webpack.config.jsを上記のように修正後、webpack→実行すると意図した結果が得られました。

targetをnodeに指定することで、Node.js環境で実行できるようにコンパイルしてくれるようです。
参考→webpackドキュメント

追記

ちなみに、axiosでやってみても同じことが起こりました。
フロントでaxiosを使用していたときには、targetを指定しなくても意図した挙動をしてくれていたのですが、サーバーサイド(Node.js環境)で使用するには必要なようです。
いい勉強になりました。

4
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
0