Closed12

webpackの設定で困ったこと集

Hiroki MatsumotoHiroki Matsumoto

webpack-dev-serverが立ち上がらない!!

Udemyの『最短で学ぶReactとReduxの基礎から実践まで』を学習していてwebpackのサーバーが立ち上がらなかったので備忘録。
そもそも講義で使っているwebpackのバージョンは3で、私が導入したバージョンは5だった。
講義と同様のバージョンにすれば解決すると思うが、どうしてもwebpack 5を使いたかったため色々ググった。

webpackのバージョンは以下の通り。

"dependencies": {
  "webpack": "^5.65.0",
  "webpack-cli": "^4.9.1",
  "webpack-dev-server": "^4.7.2"
}
Hiroki MatsumotoHiroki Matsumoto

余計なオプションが入っていたことが原因

講義のdevServerhistoryApiFallbackcontentBaseが設定されていた。
webpack 5ではこれだけでは足らずstaticの設定も必要になる。

devServer: {
  historyApiFallback: true,
  contentBase: path.resolve(__dirname, 'public'),
},

staticを追加して実行!

devServer: {
  historyApiFallback: true,
  contentBase: path.resolve(__dirname, 'public'),
+ static: './public',
},

動かない…

devServer: {
- historyApiFallback: true,
- contentBase: path.resolve(__dirname, 'public'),
  static: './public',
},

試しにhistoryApiFallbackcontentBaseを消してみると…
動きました!

https://www.webdesignleaves.com/pr/jquery/webpack_basic_01.html

Hiroki MatsumotoHiroki Matsumoto

create-react-appせずにwebpack × React × TypeScriptの開発環境を構築する

まずは初期化

npm init
devDependencies
npm install --save-dev webpack webpack-cli babel-loader @babel/core @babel/preset-env typescript ts-loader
dependencies
npm install react react-dom @types/react @types/react-dom

その他のライブラリをインストールする

dependencies
npm install react-redux react-router-dom@5.3.0 @types/react-redux @types/react-router-dom

https://ics.media/entry/16028/#webpack-babel-react

https://ics.media/entry/16329/

Hiroki MatsumotoHiroki Matsumoto

webpack.config.jsを書く

下記リンクの設定をそのまま写経
https://github.com/ics-creative/170330_webpack/blob/master/tutorial-babel-react/webpack.config.js

webpack.config.js
module.exports = {
  mode: 'production',
  entry: './src/index.jsx',
  output: {
    path: `${__dirname}/public`,
    filename: 'main.js',
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            loader: 'babel-loader',
            options: { presets: ['@babel/preset-env', '@babel/react'] },
          },
        ],
      },
    ],
  },
  target: ['web', 'es5'],
  devServer: {
    port: 3000,
  },
};

そして、package.jsonscripsを登録

package.json
"build": "webpack"

そしてコマンド実行

npm run build

するとエラーが…

Invalid configuration object. Webpack has been initialized using a configuration object that does not match the API schema.
 - configuration.module.rules[0].use[0] has an unknown property 'option'. These properties are valid:
   object { ident?, loader?, options? }

単にタイポミスでした。
options(複数形)のところがoption(単数形)になっていました。

そして再度ビルド

assets by status 1.27 KiB [cached] 1 asset
./src/main.js 39 bytes [built] [code generated] [1 error]

ERROR in ./src/main.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@babel/preset-react' imported from /Users/hrkmtsmt/Projects/redux-todo/babel-virtual-resolve-base.js
    at new NodeError (/Users/hrkmtsmt/Projects/redux-todo/node_modules/@babel/core/lib/vendor/import-meta-resolve.js:2552:5)
    at packageResolve (/Users/hrkmtsmt/Projects/redux-todo/node_modules/@babel/core/lib/vendor/import-meta-resolve.js:3208:9)
    at moduleResolve (/Users/hrkmtsmt/Projects/redux-todo/node_modules/@babel/core/lib/vendor/import-meta-resolve.js:3242:18)
    at defaultResolve (/Users/hrkmtsmt/Projects/redux-todo/node_modules/@babel/core/lib/vendor/import-meta-resolve.js:3281:13)
    at /Users/hrkmtsmt/Projects/redux-todo/node_modules/@babel/core/lib/vendor/import-meta-resolve.js:3304:14
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (/Users/hrkmtsmt/Projects/redux-todo/node_modules/@babel/core/lib/vendor/import-meta-resolve.js:63:103)
    at _next (/Users/hrkmtsmt/Projects/redux-todo/node_modules/@babel/core/lib/vendor/import-meta-resolve.js:65:194)
    at /Users/hrkmtsmt/Projects/redux-todo/node_modules/@babel/core/lib/vendor/import-meta-resolve.js:65:364
    at new Promise (<anonymous>)

webpack 5.69.1 compiled with 1 error in 850 ms

またエラーが…
何やねんこれ。

よくよく読むと「@babel/preset-reactが見つかりません!」ってなってる。
ので、インストール。

npm install --save-dev @babel/preset-react

ビルドコマンドを実行。
ちゃんとコンパイルされてビルドできました。

Hiroki MatsumotoHiroki Matsumoto

webpack-dev-serverを立ち上げるコマンドを登録する

なにはともあれ、webpack-dev-serverをインストール。

npm install --save-dev webpack-dev-server

package.jsonscriptsに以下のコマンドを登録。

"start": "run webpack-dev-server"

https://original-game.com/how-to-use-webpack-dev-server/

webpack.config.jsの設定

サーバーをpublicを起点にして、ポートを3000番に指定。

webpack.config.js
devServer: {
  contentBase: path.join(__dirname, 'public'),
  port: 3000,
},
Hiroki MatsumotoHiroki Matsumoto

publicディレクトリにindex.htmlを用意する

index.html
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Redux ToDo</title>
  </head>
  <body>
    <div id="root" class="div"></div>
    <script defer src="main.js"></script>
  </body>
</html>

Hiroki MatsumotoHiroki Matsumoto

srcディレクトリにindex.jsxを用意して、適当なコンポーネントをインポートします。

index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

そしてビルド。
するとエラーが…

ERROR in ./src/index.jsx 5:16
Module parse failed: Unexpected token (5:16)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| import App from './App';
| 
> ReactDOM.render(<App />, document.getElementById('root'));
| 

webpack 5.69.1 compiled with 1 error in 2273 ms

原因はmodule.rulesのtestの記述が問題だったようです。
そこにjsxも含めます。

module: {
  rules: [
    {
-       test: /\.(js)$/,
+       test: /\.(js|jsx)$/,
    },
  ],
}
Hiroki MatsumotoHiroki Matsumoto

WARNINGエラーを解決する

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets: 
  main.js (245 KiB)

WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
  main (245 KiB)
      main.js


WARNING in webpack performance recommendations: 
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
For more info visit https://webpack.js.org/guides/code-splitting/

https://zenn.dev/arisa_dev/articles/webpack-warning-code-splitting

Hiroki MatsumotoHiroki Matsumoto

webpack-dev-serverを立ち上げてコンパイルは成功しているが404が返ってくる

結論、output.pathとdevServer.static.directoryのパスの指定がミスっていた。
単純ミス…

> redux-todo@1.0.0 start
> webpack serve --open

<i> [webpack-dev-server] Project is running at:
<i> [webpack-dev-server] Loopback: http://localhost:3000/
<i> [webpack-dev-server] On Your Network (IPv4): http://192.168.89.5:3000/
<i> [webpack-dev-server] On Your Network (IPv6): http://[fe80::1]:3000/
<i> [webpack-dev-server] Content not from webpack is served from '/Users/{ user }/Projects/redux-tododist' directory
<i> [webpack-dev-middleware] wait until bundle finished: /
asset main.js 245 KiB [emitted] [minimized] [big] (name: main) 1 related asset
runtime modules 27.2 KiB 12 modules
orphan modules 17.3 KiB [orphan] 8 modules
modules by path ./node_modules/ 397 KiB
  modules by path ./node_modules/webpack-dev-server/client/ 63.1 KiB 5 modules
  modules by path ./node_modules/webpack/hot/*.js 4.4 KiB 4 modules
  modules by path ./node_modules/html-entities/lib/*.js 115 KiB 4 modules
  modules by path ./node_modules/react/ 9.02 KiB 2 modules
  modules by path ./node_modules/react-dom/ 177 KiB 2 modules
  modules by path ./node_modules/scheduler/ 7.24 KiB 2 modules
  + 3 modules
./src/index.tsx + 1 modules 322 bytes [built] [code generated]
webpack 5.69.1 compiled successfully in 6715 ms
^C<i> [webpack-dev-server] Gracefully shutting down. To force exit, press ^C again. Please wait...

一見成功しているように見えるが、8行目にヒントが…

<i> [webpack-dev-server] Content not from webpack is served from '/Users/{ user }/Projects/redux-tododist' directory

本来redux-todo/distであるべきところがredux-tododistに…

原因は、パスの連結を+でやっていたことだった。

webpack.config.jsに以下の内容を追加

+ const path = require('path')
// ...(省略)
- path: __dirname + 'dist'
+ path: path.join(__dirname, 'dist')

dist/distにしても良いですが、記述漏れがあるとまたエラーになるので、pathライブラリを使ったほうが堅実。

最初はpathライブラリを使っていたが、なんか同じようなエラーが出たので+を使ったのだが、もう一度pathライブラリを使ったらエラーが消えた。
なんかの勘違いか幻想か…

教訓

  • ログが成功っぽくても実はヒントが隠されている
  • pathライブラリを使え
Hiroki MatsumotoHiroki Matsumoto

TypeScriptがコンパイルされない

ts-loaderが設定されていなかったのが原因だった…

その前にloaderを設定するuseの実行順を理解する

webpackのローダーを設定するuseになっています。
この配列は後ろから順に実行されるようになっています。
下記の様な配列の場合、配列最後尾の5から順に実行され、左に5→4→3→2→1の順番で実行されます。

webpack.config.js
use: [1, 2, 3, 4, 5]

さて本題、ts-loaderをwebpackに設定する

エラーが出たときのwebpackの設定は下記の通り。
babel-loaderのみが設定されています。

webpack.config.js
use: [
  {
    loader: 'babel-loader',
    options: { presets: ['@babel/preset-env', '@babel/react'] },
  },
],

これに、ts-loaderを追加していきます。
今の所、特にオプションは必要ないので、ts-loaderとだけ記述します。

webpack.config.js
use: [
  {
    loader: 'babel-loader',
    options: { presets: ['@babel/preset-env', '@babel/react'] },
  },
+ 'ts-loader'
],

なぜts-loaderから先に実行しなければ行けないのか

それは、TypeScriptをJavaScriptにコンパイルしたあとに、BabelでES5のJacaScriptにトランスパイルする必要があるから。
Babelに素のJavaScriptを渡す必要があるから、ts-loaderを先に通す必要がるわけです。

このスクラップは2022/03/13にクローズされました