webpack5についての勉強 (react + less + eslint + babel + 静的ファイル)

31 min read読了の目安(約28700字

bundleとは?

プログラムのソースコードをコンパイル、圧縮、文法チェック、互換性処理をブラウザで実行可能の1つのファイルに最適な形でまとめること

webpackとは?

  • webpackはbundleツールの一つです。

ほかにVitegulpなどもあります。ちなみに今は Vue3が使ってる ViteWebpackより性能が良いらしいけど、まだ不安定みたいです。

  • webpackでは、フロントエンドのすべてのリソースファイル(js/json/css/img/less)がモジュールとして扱われます。
  • モジュール内の全てのファイルの依存度関係に基づいて静的分析を行い、それぞれを1つのファイルにまとめます。

webpackの五つの重要な概念

  • Entry :
    入口(entry point) webpackがどのモジュールを使用するべきかを示し、そこからその内部依存関係の構築をする。

  • Outout :
    output属性はwebpackに対して、作成したbundlesをどこで出力しますかを示す。また、これらのファイルの名前はどうなりますかを指定する。デフォルトは./dist

  • Loader :
    loaderを使うことでwebpackに非javascript/jsonファイルを処理させます(webpack自身はjavascript/jsonを解析することしかできません)

  • Pugins :
    プラグインは、より広い範囲のタスクを実行するために使用できます。(bundle性能アップ、環境変数の再定義とか)

  • Mode :
    開発モード、本番用モード

ゼロから始めるwebpack

初期化プロジェクト

mkdir webpack-handson
cd webpack-handson
npm init

package.jsonを生成する
デフォルト設定で以下のもの生成しました。

{
  "name": "webpack-handson",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

webpackをインストール

npm install webpack webpack-cli -g
npm install webpack webpack-cli -D

後でコマンドとしての実行するため、グローバルもインストールが必要

bundleするものを作成する

  1. jsファイルの作成
src/js/index.js
// js
import {sum} from './module1'
import  {sub} from './module2'
import module3 from "./module3";
// json
import json from '../json/test';

console.log(sum(1,2));
console.log(sub(4,6));
console.log(module3.mul(5,6));
console.log(module3.div(10,5));
console.log(json,typeof json);
src/js/module1.js
export function sum(a,b){
  return a+b;
}
src/js/module2.js
function sub(a,b) {
  return a-b;
}
export {sub}
src/js/module3.js
export default {
  mul(a,b) {
    return a*b;
  },
  div(a,b) {
    return a/b;
  }
}
  1. jsonファイルの作成
src/json/test.json
{
  "name": "kobe",
  "age": 18
}
  1. index.htmlの作成
src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
</head>
<body>
    <script type="text/javascript" src="../dist/js/main.js"></script>
    <h1>hello webpack</h1>
</body>
</html>

ここまでの構成

webpack
├─package.json
├─src
|  ├─index.html
|  ├─json
|  |  └test.json
|  ├─js
|  | ├─index.js
|  | ├─module1.js
|  | ├─module2.js
|  | └─module3.js

webpackコマンドでソースコード(js, json)をbundleする

webpack ./src/js -o ./dist/js --mode=development

webpackはjsとjsonのファイルをbundleして、そしてes6モジュール文法をブラウザで識別できる文法に変換することもできます。

index.htmlを開きF12で以下のもの確認できたらオッケー

less-loaderで.lessをbundleする

  • lessファイルの作成
src/css/index.less
.demo{
  width: 400px;
  height: 400px;
  background-color: red;
}
  • jsファイルの修正:lessのimport
src/js/index.less
// js
import {sum} from './module1'
import {sub} from './module2'
import module3 from "./module3";
// json
import json from '../json/test';
// less
import '../css/index.less'

console.log(sum(1,2));
console.log(sub(4,6));
console.log(module3.mul(5,6));
console.log(module3.div(10,5));
console.log(json,typeof json);
  • htmlファイルの修正:lessを適用する
src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
</head>
<body>
    <script type="text/javascript" src="../dist/js/index.js"></script>
    <h1>test</h1>
	
    <div class="demo"></div>
	
</body>
</html>

このままでwebpack ./src/js -o ./dist/js --mode=developmentを実行すると下記エラーが発生しちゃう

ERROR in ./src/css/index.less 1:0
Module parse failed: Unexpected token (1:0)
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

loaderの紹介でも話したがwebpack自体はjs/jsonしか扱えない。lessを適用するためにloaderの設定が要ります。

  1. とりあえず必要なloaderをインストール
npm i css-loader style-loader less-loader less -D
  1. webpack.config.jsを設定します。
src/webpack.config.js
let {resolve} = require('path');

// entry
module.exports = {
    entry:'./src/js/index.js',
    output:{
        path:resolve(__dirname,'dist/js'),
        filename: "index.js",
    },
    module: {
        rules: [
            // less-loader
            {
                test: /\.less$/,        // すべてのlessファイルをmatch
                use: [                  // 配列内のloaderは実行順番が後ろから前 つまりless > css > styleの順番です
                    "style-loader",     // 役割:HTMLファイルにstyleタグを作りスタイルを入れる
                    "css-loader",       // 役割:cssをCommentJsモジュールに変換
                    "less-loader"       // 役割:lessをコンパイルしcssに変換する、cssファイル生成せず、メモリ内に保存する
                ],
            },
        ]
    },
    plugins: [],
    mode:'production',
}
  1. コマンドでソースコードをbundleする
webpack

ここまでの構成

webpack-handson
├─package-lock.json
├─package.json
├─webpack.config.js
├─src
|  ├─index.html
|  ├─json
|  |  └test.json
|  ├─js
|  | ├─index.js
|  | ├─module1.js
|  | ├─module2.js
|  | └module3.js
|  ├─css
|  |  └index.less
├─dist
|  ├─js
|  | └index.js

この画面を確認できたらlessの部分は完了

eslint-loaderで静的解析の実装

  1. とりあえず必要なloaderをインストール
npm i eslint-loader eslint -D
  1. webpack.config.jsの設定を追加します。
src/webpack.config.js
let {resolve} = require('path');

// entry
module.exports = {
    entry:'./src/js/index.js',
    output:{
        path:resolve(__dirname,'dist/js'),
        filename: "index.js",
    },
    module: {
        rules: [
            // less-loader
            {
                test: /\.less$/,        // すべてのlessファイルをmatch
                use: [                  // 配列内のloaderは実行順番が後ろから前 つまりless > css > styleの順番です
                    "style-loader",     // 役割:HTMLファイルにstyleタグを作りスタイルを入れる
                    "css-loader",       // 役割:cssをCommentJsモジュールに変換
                    "less-loader"       // 役割:lessをコンパイルしcssに変換する、cssファイル生成せず、メモリ内に保存する
                ],
            },
            // eslint-loader
            {
                test:/\.js$/,           // すべてのjsファイルをmatch
                exclude:/node_modules/, // node_modulesフォルダ内のものはEslintでチェックしない
                enforce:"pre",          // webpackによるbundleする前に実施
                use:{
                    loader:"eslint-loader",
                },
            },
        ]
    },
    plugins: [],
    mode:'production',
}
  1. package.jsonの追加設定(eslint configの設定)
package.json
{
  "name": "webpack-handson",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "css-loader": "^5.2.0",
    "eslint": "^7.23.0",
    "eslint-loader": "^4.0.2",
    "less": "^4.1.1",
    "less-loader": "^8.0.0",
    "style-loader": "^2.0.0",
    "webpack": "^5.30.0",
    "webpack-cli": "^4.6.0"
  },
  "eslintConfig": {
    "parserOptions": {
      "ecmaVersion": 6,
      "sourceType": "module"
    },
    "env": {
      "browser": true,
      "node": true
    },
    "globals": {
      "$": "readonly",
      "Promise": "readonly"
    },
    "rules": {
      "no-console": 0,
      "eqeqeq": 0,
      "no-alert": 0
    },
    "extends": "eslint:recommended"
  }
}

  1. コマンドでソースコードをbundleする。
webpack

文法に問題なければbundle行けるはず。

ps. eslint通らなかったの例

src/js/index.jsに適当に定数を作る。下記のようなエラーでbundleできないはず

ERROR in ./src/js/index.js
Module Error (from ./node_modules/eslint-loader/dist/cjs.js):

/home/ec2-user/environment/webpack-handson/src/js/index.js
10:7 error 'a' is assigned a value but never used no-unused-vars

✖ 1 problem (1 error, 0 warnings)

webpack 5.30.0 compiled with 1 error in 1084 ms

babel-loaderで古いブラウザをサポートする

  1. とりあえず必要なloaderをインストール
npm i babel-loader @babel/core @babel/preset-env core-js -D
  1. webpack.config.jsの設定を追加します。
src/webpack.config.js
let {resolve} = require('path');

// entry
module.exports = {
    entry:'./src/js/index.js',
    output:{
        path:resolve(__dirname,'dist/js'),
        filename: "index.js",
    },
    module: {
        rules: [
            // less-loader
            {
                test: /\.less$/,        // すべてのlessファイルをmatch
                use: [                  // 配列内のloaderは実行順番が後ろから前 つまりless > css > styleの順番です
                    "style-loader",     // 役割:HTMLファイルにstyleタグを作りスタイルを入れる
                    "css-loader",       // 役割:cssをCommentJsモジュールに変換
                    "less-loader"       // 役割:lessをコンパイルしcssに変換する、cssファイル生成せず、メモリ内に保存する
                ],
            },
            // eslint-loader
            {
                test:/\.js$/,           // すべてのjsファイルをmatch
                exclude:/node_modules/, // node_modulesフォルダ内のものはEslintでチェックしない
                enforce:"pre",          // webpackによるbundleする前に実施
                use:{
                    loader:"eslint-loader",
                },
            },
            // es6 let/constなどを古いブラウザも処理させるように
            {
                test: /\.m?js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        // babelでどんな交換性処理を設定する
                        presets: [
                            ['@babel/preset-env', { targets: "defaults" }]
                        ]
                    }
                }
            },
            // browser core   promiseなどの対応
            {
                test: /\.js$/, 
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        // babelでどんな交換性処理を設定する
                        presets: [
                            [
                                '@babel/preset-env',
                                {
                                    useBuiltIns: 'usage',
                                    corejs: {
                                        version: 3
                                    },
                                    targets: {
                                        chrome: '60',   // chrome60バージョン以降のブラウザを対応する
                                        firefox: '60',
                                        ie: '11',
                                        safari: '10',
                                        edge: '17'
                                    }
                                }
                            ]
                        ],
                        cacheDirectory:true,
                    }
                }
            },
        ]
    },
    plugins: [],
    mode:'production',
}

url-loader, file-loaderで画像ファイルなどの静的ファイルをbundleする

  1. とりあえず必要なloaderをインストール
npm i file-loader url-loader -D
  1. スタイルを修正する(背景を画像にする)
src/css/index.less

先ずはsrc下にassetフォルダを作り適当に画像を入れる

次からlessの修正

.demo{
  width: 400px;
  height: 400px;
  background-image: url("../asset/test_1.png");
}
  1. webpack.config.jsの設定を追加します。
src/webpack.config.js
let {resolve} = require('path');

// entry
module.exports = {
    entry:'./src/js/index.js',
    output:{
        path:resolve(__dirname,'dist/js'),
        filename: "index.js",
    },
    module: {
        rules: [
            // less-loader
            {
                test: /\.less$/,        // すべてのlessファイルをmatch
                use: [                  // 配列内のloaderは実行順番が後ろから前 つまりless > css > styleの順番です
                    "style-loader",     // 役割:HTMLファイルにstyleタグを作りスタイルを入れる
                    "css-loader",       // 役割:cssをCommentJsモジュールに変換
                    "less-loader"       // 役割:lessをコンパイルしcssに変換する、cssファイル生成せず、メモリ内に保存する
                ],
            },
            // eslint-loader
            {
                test:/\.js$/,           // すべてのjsファイルをmatch
                exclude:/node_modules/, // node_modulesフォルダ内のものはEslintでチェックしない
                enforce:"pre",          // webpackによるbundleする前に実施
                use:{
                    loader:"eslint-loader",
                },
            },
            // es6 let/constなどを古いブラウザも処理させるように
            {
                test: /\.m?js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        // babelでどんな交換性処理を設定する
                        presets: [
                            ['@babel/preset-env', { targets: "defaults" }]
                        ]
                    }
                }
            },
            // browser core   promiseなどの対応
            {
                test: /\.js$/, 
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        // babelでどんな交換性処理を設定する
                        presets: [
                            [
                                '@babel/preset-env',
                                {
                                    useBuiltIns: 'usage',
                                    corejs: {
                                        version: 3
                                    },
                                    targets: {
                                        chrome: '60',   // chrome60バージョン以降のブラウザを対応する
                                        firefox: '60',
                                        ie: '11',
                                        safari: '10',
                                        edge: '17'
                                    }
                                }
                            ]
                        ],
                        cacheDirectory:true,
                    }
                }
            },
            //url-loader 画像処理 file-loaderと比べると base64に変換するのが可能
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit:8192,
                            publicPath:'images/',
                            outputPath:'images',
                            name:'[hash:5].[ext]',
                        },
                    }
                ]
            },
            //file-loader
            {
                test:/\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
                loader:'file-loader',
                options: {
                    outputPath:'media',
                    name:'[hash:5].[ext]'
                }
            },
        ]
    },
    plugins: [],
    mode:'production',
}

ここまで設定できたらwebpackの実行成功するけど、入れた画像は表示できない。

なぜならwebpackはhtmlをbundleできない。ここでPluginsを加入します。

HTMLWebpackPluginでhtmlファイルをbundleする

  1. 先ずはpluginをインストールする
npm i html-webpack-plugin -D
  1. webpack.config.jsの設定を追加します。
src/webpack.config.js
const {resolve} = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry:'./src/js/index.js',
    output:{
        path:resolve(__dirname,'dist'),
        filename: "js/index.js",
    },
    module: {
        rules: [
            // less-loader
            {
                test: /\.less$/,        // すべてのlessファイルをmatch
                use: [                  // 配列内のloaderは実行順番が後ろから前 つまりless > css > styleの順番です
                    "style-loader",     // 役割:HTMLファイルにstyleタグを作りスタイルを入れる
                    "css-loader",       // 役割:cssをCommentJsモジュールに変換
                    "less-loader"       // 役割:lessをコンパイルしcssに変換する、cssファイル生成せず、メモリ内に保存する
                ],
            },
            // eslint-loader
            {
                test:/\.js$/,           // すべてのjsファイルをmatch
                exclude:/node_modules/, // node_modulesフォルダ内のものはEslintでチェックしない
                enforce:"pre",          // webpackによるbundleする前に実施
                use:{
                    loader:"eslint-loader",
                },
            },
            // es6 let/constなどを古いブラウザも処理させるように
            {
                test: /\.m?js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        // babelでどんな交換性処理を設定する
                        presets: [
                            ['@babel/preset-env', { targets: "defaults" }]
                        ]
                    }
                }
            },
            // browser core   promiseなどの対応
            {
                test: /\.js$/, 
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        // babelでどんな交換性処理を設定する
                        presets: [
                            [
                                '@babel/preset-env',
                                {
                                    useBuiltIns: 'usage',
                                    corejs: {
                                        version: 3
                                    },
                                    targets: {
                                        chrome: '60',   // chrome60バージョン以降のブラウザを対応する
                                        firefox: '60',
                                        ie: '11',
                                        safari: '10',
                                        edge: '17'
                                    }
                                }
                            ]
                        ],
                        cacheDirectory:true,
                    }
                }
            },
            //url-loader 画像処理 file-loaderと比べると base64に変換するのが可能
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit:8192,
                            publicPath:'images/',
                            outputPath:'images',
                            name:'[hash:5].[ext]',
                        },
                    }
                ]
            },
            //file-loader
            {
                test:/\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
                loader:'file-loader',
                options: {
                    outputPath:'media',
                    name:'[hash:5].[ext]'
                }
            },
        ]
    },
    plugins: [
        new HTMLWebpackPlugin({
            template: "./src/index.html",
        })
    ],
    mode:'production',
}

修正した箇所:

const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    ...
    output:{
        path:resolve(__dirname,'dist'),
        filename: "js/index.js",
    },
    ...
    plugins: [
        new HTMLWebpackPlugin({
            template: "./src/index.html",  //このパスを基にhtmlファイルを生成しbundleしたものを自動的に入れる
        })
    ],
    ...
}    
  • webpackはloaderが自動的にインポートされますが、pluginは自分でインポートしないと効かない。

importとrequireの違い

  • requireはcommonJSつまりNodejsの環境で動作してくれる書き方です。
  • importはes6の書き方
  • outputを修正したのでbundleで生成したdistの構成も綺麗になった

webpackを実行して結果を確認しましょう

webpack

ここまでの構成

webpack-handson
├─package-lock.json
├─package.json
├─webpack.config.js
├─src
|  ├─index.html
|  ├─json
|  |  └test.json
|  ├─js
|  | ├─index.js
|  | ├─module1.js
|  | ├─module2.js
|  | └module3.js
|  ├─css
|  |  └index.less
|  ├─asset
|  |   └test_1.png
├─dist
|  ├─index.html
|  ├─js
|  | └index.js
|  ├─images
|  |   └dd2d1.png

distフォルダ下のindex.htmlを開いて結果を確認しましょう

これ確認できたらオッケー

devServerで開発効率アップ

webpackコマンドで毎回毎回打ち込むのが面倒ので、コマンドを実行しなくてもブラウザで結果を確認したいなぁ。

  1. インストールから
npm i webpack-dev-server -D
  1. webpack.config.jsの設定を追加します。
src/webpack.config.js
const {resolve} = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry:'./src/js/index.js',
    output:{
        path:resolve(__dirname,'dist'),
        filename: "js/index.js",
    },
    module: {
        rules: [
            // less-loader
            {
                test: /\.less$/,        // すべてのlessファイルをmatch
                use: [                  // 配列内のloaderは実行順番が後ろから前 つまりless > css > styleの順番です
                    "style-loader",     // 役割:HTMLファイルにstyleタグを作りスタイルを入れる
                    "css-loader",       // 役割:cssをCommentJsモジュールに変換
                    "less-loader"       // 役割:lessをコンパイルしcssに変換する、cssファイル生成せず、メモリ内に保存する
                ],
            },
            // eslint-loader
            {
                test:/\.js$/,           // すべてのjsファイルをmatch
                exclude:/node_modules/, // node_modulesフォルダ内のものはEslintでチェックしない
                enforce:"pre",          // webpackによるbundleする前に実施
                use:{
                    loader:"eslint-loader",
                },
            },
            // es6 let/constなどを古いブラウザも処理させるように
            {
                test: /\.m?js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        // babelでどんな交換性処理を設定する
                        presets: [
                            ['@babel/preset-env', { targets: "defaults" }]
                        ]
                    }
                }
            },
            // browser core   promiseなどの対応
            {
                test: /\.js$/, 
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        // babelでどんな交換性処理を設定する
                        presets: [
                            [
                                '@babel/preset-env',
                                {
                                    useBuiltIns: 'usage',
                                    corejs: {
                                        version: 3
                                    },
                                    targets: {
                                        chrome: '60',   // chrome60バージョン以降のブラウザを対応する
                                        firefox: '60',
                                        ie: '11',
                                        safari: '10',
                                        edge: '17'
                                    }
                                }
                            ]
                        ],
                        cacheDirectory:true,
                    }
                }
            },
            //url-loader 画像処理 file-loaderと比べると base64に変換するのが可能
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit:8192,
                            publicPath:'images/',
                            outputPath:'images',
                            name:'[hash:5].[ext]',
                        },
                    }
                ]
            },
            //file-loader
            {
                test:/\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/,
                loader:'file-loader',
                options: {
                    outputPath:'media',
                    name:'[hash:5].[ext]'
                }
            },
        ]
    },
    plugins: [
        new HTMLWebpackPlugin({
            template: "./src/index.html",
        })
    ],
    devServer: {
        open:true,
        contentBase: './dist',
        compress: true,
        port:8080,
        hot: true,
        allowedHosts: [
            '.amazonaws.com'    //cloud9で開発する人
        ],
    },
    mode:'development',
    devtool:'eval-cheap-source-map',
}
  1. package.jsonの設定を追加します。(スクリプトを追加する)
src/package.json
{
  "name": "webpack-handson",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "npx webpack serve"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.13.14",
    "@babel/preset-env": "^7.13.12",
    "babel-loader": "^8.2.2",
    "core-js": "^3.10.0",
    "css-loader": "^5.2.0",
    "eslint": "^7.23.0",
    "eslint-loader": "^4.0.2",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^5.3.1",
    "less": "^4.1.1",
    "less-loader": "^8.0.0",
    "style-loader": "^2.0.0",
    "url-loader": "^4.1.1",
    "webpack": "^5.30.0",
    "webpack-cli": "^4.6.0",
    "webpack-dev-server": "^3.11.2"
  },
  "eslintConfig": {
    "parserOptions": {
      "ecmaVersion": 6,
      "sourceType": "module"
    },
    "env": {
      "browser": true,
      "node": true
    },
    "globals": {
      "$": "readonly",
      "Promise": "readonly"
    },
    "rules": {
      "no-console": 0,
      "eqeqeq": 0,
      "no-alert": 0
    },
    "extends": "eslint:recommended"
  }
}

追加したスクリプトは

  ...
  "scripts": {
    ...
    "start": "npx webpack serve"
  },
  ...

npm run startで試しましょう。

ちなみに、startのスクリプトはrun付けなくても大丈夫

npm start

webpack 5.30.0 compiled successfully in 2527 ms
ℹ 「wdm」: Compiled successfully.

設定したポートで見られば大丈夫(自分は8080を設定しました)

React

  1. 先ずはインストール
npm i react react-dom
npm i @babel/preset-react -D
npm i babel-eslint eslint-plugin-react -D
npm i @material-ui/core
  1. babelの設定
src/babel.config.json
{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
}
  1. eslint configの設定変更
src/packge.json
{
  "name": "webpack-handson",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "npx webpack serve"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.13.14",
    "@babel/preset-env": "^7.13.12",
    "@babel/preset-react": "^7.13.13",
    "babel-eslint": "^10.1.0",
    "babel-loader": "^8.2.2",
    "core-js": "^3.10.0",
    "css-loader": "^5.2.0",
    "eslint": "^7.23.0",
    "eslint-loader": "^4.0.2",
    "eslint-plugin-react": "^7.23.1",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^5.3.1",
    "less": "^4.1.1",
    "less-loader": "^8.0.0",
    "style-loader": "^2.0.0",
    "url-loader": "^4.1.1",
    "webpack": "^5.30.0",
    "webpack-cli": "^4.6.0",
    "webpack-dev-server": "^3.11.2"
  },
  "eslintConfig": {
    "parserOptions": {
      "ecmaVersion": 6,
      "sourceType": "module"
    },
    "ecmaFeatures": {
      "experimentalObjectRestSpread": true
    },
    "plugins": [
      "react"
    ],
    "extends": "eslint:recommended",
    "parser": "babel-eslint",
    "env": {
      "browser": true,
      "node": true
    },
    "globals": {
      "$": "readonly",
      "Promise": "readonly"
    },
    "rules": {
      "no-console": 0,
      "eqeqeq": 0,
      "no-alert": 0,
      "no-unused-vars": 0
    }
  },
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  }
}
  1. index.jsを編集 (react)
src/js/index.js
// js
import {sum} from './module1'
import {sub} from './module2'
import module3 from "./module3";
// json
import json from '../json/test';
// less
import '../css/index.less'
// react
import React, { useState } from "react";
import { render } from "react-dom";

function App() {
  const [state, setState] = useState("CLICK ME");
  
  return(
    <div> 
      <Button variant="contained">Default</Button>
    </div>
    )
}

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

console.log(sum(1,2));
console.log(sub(4,6));
console.log(module3.mul(5,6));
console.log(module3.div(10,5));
console.log(json,typeof json);
  1. index.htmlを編集
src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>demo</title>
</head>
<body>
    <script type="text/javascript" src="../dist/js/index.js"></script>
    <h1>test</h1>
    
    <!--react-->
    <div id="root"></div>
    
    <div class="demo"></div>
    
</body>
</html>

npm startで起動この画面見れば大丈夫

おまけ

npx create-react-appのwebpack設定はこちらgithub facebook/create-react-app