npmとwebpackを利用してフロントエンド開発環境を構築するのサムネイルイメージ

はじめに

JavaScriptという言語は、それ自体はシンプルに書き始めることができます。HTMLとCSS、そしてJavaScriptの、クライアントサイドの基本的なセットであれば、複雑で高度な開発環境は必要がないかもしれません。

しかし、外部ライブラリを柔軟に導入したい場合、どうしてもパッケージ管理システムなどが必要になってきます。さらに、仮にパッケージ管理システムを導入したとしても、現行の仕様ではそのままライブラリを読み込むだけでは外部ライブラリを利用できません。それらのライブラリを実行可能な状態にするツールが必要になります。
また、JavaScriptはブラウザごとに実装されている技術に差があり、これが処理や表示の違いなど、バグの原因になりやすいため、どのブラウザでも互換性のあるコードにする必要があります。

このように、JavaScriptは書き進めるとだんだんシンプルではなくなってきます。また今日では、JavaScriptはWebページにちょっとした動きを追加する言語というだけではなく、大規模な開発にも使われることが当たり前となっています。そこで、上記のような開発環境にまつわる問題点を、なるべく解決してくれる便利なツールがたくさん作られました。その最も基本と言えるものがnpmwebpackです。

上で述べた問題点は、npmとwebpackを利用することで解決できます。さらに、上記の問題だけはなく、開発を効率的にしてくれる様々な機能があります。
本記事では、現代のJavaScript開発環境において必要不可欠なツール、npmとwebpackの基本的な使い方を解説します。

npmとは

npmとは、Node Package Managerの略で、フロントエンド開発で利用されているパッケージ管理システムです。

npmは本来、JavaScriptをサーバサイドで実行できる環境であるNode.jsのパッケージ管理システムですが、サーバ環境のみならずローカル環境においても様々なパッケージの利用が行えるため、フロントエンド開発における重要なエコシステムとなっています。

npmを利用すると、外部ライブラリのインストールやアップデート、あるいは自作したパッケージの共有などを簡単に行えます。

npmと同じくらい人気があり、互換性のあるパッケージ管理システムとしてYarnがあります。

webpackとは

webpackとは、JavaScriptをはじめとしたフロントエンドのファイルの依存関係を解決し、1つのファイルにまとめてくれるモジュールバンドラーと呼ばれるツールです。非常に様々な機能があり、主に以下の点においてフロントエンド開発では欠かせないツールとなっています。

  • ECMAScript6以降の新しい仕様で記述したJavaScriptや、TypescriptなどのJavaScript拡張言語(スーパーセット)を、現在普及しているブラウザに互換性のある形式に変換(トランスパイル)できる。
  • JavaScriptのモジュールを利用した際、依存関係を解決し1つのファイルにまとめることができる。
  • npmなどのパッケージ管理システムからインストールした外部パッケージを利用可能な状態にできる。
  • SassをCSSのコードにトランスパイルでき、かつCSSをJavaScriptとともにバンドルできる。
  • コードを圧縮して軽量化できる。
  • 1つのファイルにまとめるため、HTTPリクエストの数を減らすことができる。
  • 1つのファイルにまとめずに好きなように分割できるなど、柔軟な設定ができる。
  • 非常の多くのオプションやプラグインがあり、多種多様な利用ができる。
  • 多くのWebアプリケーションフレームワークに取り入れられている。

webpackはnpmパッケージとして利用するため、以降の手順としてまずはnpmのインストールを行い、その後webpackを導入します。

npmのインストール

npmはNode.jsをインストールすると一緒にインストールされます。
Node.jsはNode.jsのダウンロードページからインストーラーをダウンロードしてインストールすることもできるほか、HomebrewやWSL2などのCLIツールを使ってインストールすることもできます。
ほかにもNodebrewやnvmなど、様々なツールがありますので、好みの方法でインストールします。

Windows

WindowsではWSL2を利用してNode.jsをインストールすることもできます。
WSL2からインストールする場合は以下のMicrosoftのページを参考にしてください。(少し分かりづらい気もしますが…)

Windows 10 用 Windows Subsystem for Linux のインストール ガイド

WSL 2 を使用して Node.js 開発環境を設定する

Mac

MacではHomebrewを利用してNode.jsをインストールすることもできます。
Homebrew自体のインストールは以下のページを参考にしてください。

MacにHomebrewを導入する

Homebrewをインストールしたら、下記のコマンドをターミナルに入力してください。

$ brew install node

インストールの確認

下記のコマンドを入力して、バージョン情報が表示されたらインストールは正しく行われています。

$ node -v
v14.4.0
$ npm -v
6.14.4

npmの使い方

プロジェクト用のディレクトリを作る

まずはターミナルを開き、任意の場所にディレクトリを作成し、そのディレクトリへ移動します。

$ mkdir project-name
$ cd project-name

package.jsonの作成

ディレクトリ内に移動したら、npm init -yコマンドを実行します。

$ npm init -y

このnpm initというコマンドを実行すると、現在のディレクトリにpackage.jsonというファイルが新たに作成されます。
今回は-yオプションを利用しましたが、このオプションを付けずにコマンドを実行すると、ターミナル内で対話的にプロジェクト名やユーザ名を設定することもできます。

package.jsonの中身を見てみます。作成された直後の内容は、概ね以下のようになっていると思います。もしかするとnpmのバージョンによっては微妙に異なることがあるかもしれません。

project-name/package.json

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

package.jsonは、拡張子にあるようにJSON(JavaScript Object Notation)と呼ばれる形式で表記されています。名前の通りJavaScriptのオブジェクト構文とよく似た書き方になっています。馴染みのない方でもなんとなく読めるかと思います。

package.jsonは、このプロジェクトの名前や作者といった基本情報に加え、どの外部パッケージをどのバージョンで用いるのか(依存するのか)などを表記します。いわばプロジェクトを管理するための設定ファイルです。
package.jsonを直下に置いたこのディレクトリが、ひとつのプロジェクトとして認識され、また共有する際にはこのプロジェクト自体がパッケージとなります。

npmパッケージのインストール

パッケージのインストールは、package.jsonのあるディレクトリ内で、npm install パッケージ名あるいは省略形のnpm i パッケージ名コマンドで行います。

例として、試しにSimpleMDEというMarkdownエディタをインストールしてみます。

$ npm install simplemde

npm install パッケージ名1 パッケージ名2のように、パッケージ名の間を半角スペースで区切ることで、複数のパッケージを一度にインストールできます。

npmインストールを行うと、ディレクトリ内に主に3つの変更が加わります。

  1. package.jsonファイルにdependenciesという項目が追記される。
  2. プロジェクト直下にnode_modulesというディレクトリが作成される。
  3. プロジェクト直下にpackage-lock.jsonというファイルが作成される。

順を追って見ていきましょう。

dependencies

まず一つ目の変更点として、package.jsonファイルにdependenciesという項目が追記されています。
先ほどの例のnpm install simplemdeを実行した後のpackage.jsonは以下のようになっています。

project-name/package.json

{
  "name": "project-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "simplemde": "^1.11.2"
  }
}

ファイルの下の方にdependenciesという項目が追加されているのが確認できます。
dependenciesの項目内には、このプロジェクトで使用するパッケージが記述されます。

"dependencies": {
  "simplemde": "^1.11.2"
}

今回の例では、先ほどインストールしたSimpleMDEのパッケージ名とバージョン指定に関する値が書いてあります。
バージョンの数値はnpm installした時期など状況によって異なります。バージョンの指定方法については「パッケージのバージョンの指定方法」の項で後述します。

node_modules

続いて二つ目の変更点を確認します。npm installの後、プロジェクトディレクトリ直下にnode_modulesディレクトリが作成されます。
このnode_modulesディレクトリ内に、インストールしたnpmパッケージ(モジュール)が格納されます。

project-name/
├-- package.json
├-- package-lock.json
└-- node_modules/   
    └-- 以下略

インストールするパッケージによっては、他のパッケージと依存関係を持っているものもあるため、その場合は依存関係にあるパッケージもまとめてnode_modulesに格納されます。
今回の例ではsimplemdeだけでなく他にもcodemirrormarkedなどのパッケージがインストールされていることがわかります。

package-lock.json

三つ目の変更点を確認します。npm installの後、プロジェクト直下にpackage-lock.jsonというファイルが作成されます。

package-lock.jsonとは、package.jsonに書かれた情報をもとに、実際にnode_modulesディレクトリにインストールされたパッケージ名と、その明確なバージョン情報などが記載されたファイルです。

なぜpackage.jsonpackage-lock.jsonという、似た二つのファイルがあるのかというと、package.jsonの方はプロジェクトの設定ファイルであり、パッケージのバージョン情報についてはあくまで指定をするためのファイルだからです。

後述の「パッケージのバージョンの指定方法」と「package.jsonをもとにパッケージをインストールする」の項で詳しく説明しますが、package.jsonは手動で編集することができますが、package-lock.jsonは原則的に直接編集することはありません。package.jsonをもとに、実際にインストールされたパッケージのバージョン情報を反映したファイルがpackage-lock.jsonとなっているからです。

-Dオプションでのインストール

npm installコマンドに--save-devもしくは省略形の-Dオプションを付けると、開発の時だけに利用し、実際のアプリケーションには組み込まれないパッケージとしてインストールすることができます。

$ npm install -D パッケージ名

--save-dev-Dオプションでインストールされたパッケージは、package.jsonにはdevDependenciesという項目内に記述されます。
微妙にdependenciesと名前が似ていますがdevDependenciesです。

今回の記事で利用するwebpackは、開発時のみ必要なパッケージであり、完成したアプリケーションでは使わないのでdevDependenciesを使って管理します。

グローバルインストール

npm installの際に-gオプションを付けるとグローバルインストールとなります。

$ npm install -g パッケージ名

-gオプションをつけてインストールされたパッケージは、プロジェクト内のnode_modules配下にはインストールされません。
代わりにコンピュータ内のnpmルートパスにあるnode_modulesにインストールされます。
グローバルインストールされたnpmパッケージは、プロジェクトに限らず利用できるようになります。
そのためグローバルインストールコマンドは、特定のプロジェクト外でも実行できます。

パッケージのアンインストール

npm uninstallあるいはnpm unコマンドを使います。

$ npm un パッケージ名

グローバルインストールされたパッケージは-gオプションをつけます。

$ npm uninstall -g パッケージ名

パッケージのバージョンの指定方法

package.jsondependenciesdevDependenciesには、インストールするパッケージのバージョンを様々な書き方で指定できます。
以下によく使われる指定方法を記します。

npmのバージョンはsemver(Semantic Versioning)に沿ってバージョニングする規約となっています。
バージョンの各数値はmajor.minor.patch形式で表現されます。

  1. APIの変更に互換性のない場合はメジャーバージョンを、
  2. 後方互換性があり機能性を追加した場合はマイナーバージョンを、
  3. 後方互換性を伴うバグ修正をした場合はパッチバージョンを上げます。

semver(Semantic Versioning)

完全一致

指定したバージョンに完全に一致したバージョンがインストールされます。

"dependencies": {
  "foo": "1.1.2"
}

比較演算子を使った指定

比較演算子を使ってバージョンを指定できます。

"dependencies": {
  "foo": ">1.1.2", // 1.1.2より大きいバージョン
  "hoge": "<=1.1.2" // 1.1.2以下のバージョン
}

ワイルドカードを使った指定

x*はワイルドカードとして利用できます。

"dependencies": {
  "foo": "*", // バージョンを指定しない
  "hoge": "1.2.x", // >= 1.2.0 < 1.3.0
  "bar": "1.x", // >= 1.0.0 < 2.0.0
  "bar": "" // バージョンを指定しない
}

チルダ記号(~)を使った指定

チルダ記号(~)を使用すると、明記したバージョン値の位置以下は更新を許可します。
例えば下記のように、~major.minorまでバージョンが記述されている場合はpatchレベルの値は更新されることを許可します。
そうでない場合は、minorレベルの値を上げることを許可します。

"dependencies": {
  "foo": "~1.2", // 1.2.x
}
"dependencies": {
  "foo": "~1", // 1.x
  "hoge": "~1.1.2" // >= 1.1.2 < 1.2.0
}

キャレット記号(^)を使った指定

キャレット記号(^)を使うと、majorレベルは更新されず、それ以外が更新されます。

"dependencies": {
  "foo": "^1.2.3", // >= 1.2.3 < 2.0.0
  "hoge": "^0.2.3", // >= 0.2.3 < 0.3.0
  "hoge": "^0.0.3" // >= 0.0.3 < 0.0.4
}

コマンドラインでのバージョン指定方法

npm installコマンドを実行の際にもパッケージのバージョンを指定できます。
パッケージ名の後ろに@をつけ、その後ろにバージョン値を入力します。

$ npm install foo@1.1.2

package.jsonをもとにパッケージをインストールする

これまでは空のディレクトリにpackage.jsonを新たに作成し、パッケージを管理する方法を説明しましたが、すでにpackage.jsonがあるプロジェクトの場合は、package.jsonのあるディレクトリに移動し、npm installコマンドを実行すると、package.jsonに基づいてパッケージをインストールできます。

$ npm i

これにより、開発者同士で同じパッケージのバージョン環境で開発できるようになります。

同じように、package.jsonファイルのdependenciesdevDependenciesを直接編集した場合も、npm installコマンドを実行することでパッケージのインストールや管理が行えます。
つまり、npm install simplemdeとコマンドラインで実行するのと、下記のようにpackage.jsondependenciesの項目に、simplemdeパッケージとバージョン指定を記入した後にnpm installコマンドを実行するのは、(バージョンの指定によりますが)同じ結果となります。

project-name/package.json

"dependencies": {
  "simplemde": "^1.11.2"
}

package.jsonを編集した後npm install

$ npm i

パッケージのアップデート

パッケージのバージョンアップにはnpm update パッケージ名または省略形としてnpm up パッケージ名コマンドを使用します。
パッケージのアップデートの範囲は、package.jsonに記載したバージョン指定に基づきアップデートされます。

$ npm up simplemde

その他の使い方

npmのその他の使い方については公式ドキュメントをご覧ください。

npm Docs


webpackを利用する

ここまでずいぶん説明が長くなりましたが、これからwebpackの使い方について記述します。
まずはwebpackを動作させるための準備を行います。

作業用のディレクトリとファイルの作成

作業用のディレクトリとファイルを、現在のプロジェクトディレクトリ直下に作成します。

$ mkdir src dist
$ touch src/index.js src/style.scss dist/index.html webpack.config.js

srcディレクトリには開発用のファイルを入れるようにします。ここではindex.jsとSassファイルのstyle.scssを作成します。

distディレクトリには、webpackによってバンドルされたファイルが出力されるように、後に設定します。
バンドルされたjsファイルを読み込んで実行するために、同階層にindex.htmlを作成します。

そして、webpackの設定用ファイルであるwebpack.config.jsをプロジェクト直下に作成します。

ディレクトリ構成図は以下のようになります。

project-name/
├-- webpack.config.js
├-- src
|   ├-- index.js
|   └-- style.scss
├-- dist
|   └-- index.html
├-- package.json
├-- package-lock.json
└-- node_modules/ 
    └-- 以下略

index.htmlへ内容を記述

dist/index.htmlのコンテンツを記入します。
15行目で、webpackによって出力されたファイルを<script src="main.js" defer></script>で読み込むように設定しています。
また本記事では、webpackで処理した後に、JavaScriptとCSSを分岐して出力するオプションをつけるため、12行目の<link rel="stylesheet" href="style.css">でCSSファイルを読み込むようにしています。

body要素内には、見出しとSimpleMDE用のコードを記述しています。バンドルが正しく行われれば、Markdownエディタが表示されるようにしています。

project-name/dist/index.html

<!DOCTYPE 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">
  <meta name="format-detection" content="telephone=no">

  <title>テストページ - npmとwebpackを利用してフロントエンド開発環境を構築する</title>

  <!-- webpack処理後のCSSファイルを読み込む -->
  <link rel="stylesheet" href="style.css">

  <!-- webpack処理後のJavaScriptファイルを読み込む -->
  <script src="main.js" defer></script>

</head>
<body>

  <h1>npmとwebpackを利用してフロントエンド開発環境を構築する</h1>

  <!-- SimpleMDEを使う -->
  <textarea id="mde"></textarea>

</body>
</html>

SCSSファイル

src/style.scssのコンテンツを記述します。
ここでは例として、見出しのスタイルを、Sassの変数機能を使って定義しています。

無事webpackが実行されるとスタイルが変更されます。

project-name/src/style.scss

$variable-color: #e06c75;
h1 {
  color: $variable-color;
  font-size: 42px;
}

JSファイル

src/index.jsには以下の内容を記述します。
2行目では、import文を使って、SimpleMDEモジュールをnode_modulesから読み込むように指定しています。
また5行目では、SimpleMDEパッケージ内にあるCSSファイルをインポートしています。

7行目から9行目までのコードでSimpleMDEをロードしています。
最後に、12行目では、Sassファイルを相対パスでimportしています。

JavaScriptファイルの中にCSSやSassも読み込むようにしています。

project-name/src/index.js

// import文でSimpleMDEを読み込む
import SimpleMDE from 'simplemde'

// SimpleMDEのCSSをimport文で読み込む
import 'simplemde/dist/simplemde.min.css'

const simplemde = new SimpleMDE({
  element: document.getElementById('mde')
});

// Sassを相対パスでimport文で読み込む
import "./style.scss"

JavaScriptのimport文の詳しい使い方については下記リンクが参考になるかと思います。

import - JavaScript MDN

webpackのインストール

下準備は終わりましたので、これからnpmを使って必要なパッケージをインストールします。
下記のコマンドを実行します。

$ npm install -D webpack webpack-cli @babel/core @babel/preset-env babel-loader css-loader style-loader sass sass-loader mini-css-extract-plugin

このインストールには-Dオプションを付けています。webpackをはじめ今回使用するパッケージは、実際のアプリケーションには使わず、開発環境のみで使用するため-Dオプションをつけてインストールします。

今のコマンドで以下のパッケージをインストールしました。かなりたくさんあります。node_modules内にもとんでもない数のパッケージが入っています…。
では、どんなパッケージをインストールしたのか見ていきます。

  • webpack
  • webpack-cli
  • @babel/core
  • @babel/preset-env
  • babel-loader
  • css-loader
  • style-loader
  • sass
  • sass-loader
  • mini-css-extract-plugin

上記のパッケージのうち、webpack本体はwebpackwebpack-cliです。webpackに取り込まれたJavaScriptやCSSなどのファイルは、一つのJavaScriptファイルにバンドルされます。

babelと書かれたパッケージは、Babelというトランスパイラのパッケージです。Babelは、ECMAScript6以降の新しい仕様で記述したJavaScriptや、TypescriptなどのJavaScript拡張言語(スーパーセット)を、現在普及しているブラウザに互換性のある形式に変換(トランスパイル)してくれるツールです。

css-loaderstyle-loaderは、CSSをバンドルするためのパッケージで、sasssass-loaderはSassをCSSにトランスパイルするためのパッケージです。

mini-css-extract-pluginは、webpackに取り込んだCSSを、再度CSSファイルとして出力するためのパッケージです。JavaScriptと一つにまとめたくない場合などに利用します。

パッケージのインストールを終えた後のpackage.jsonの内容は以下のようになったかと思います。
(プロジェクト名やバージョン値は異なっている場合があります。)

project-name/package.json

{
  "name": "project-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "simplemde": "^1.11.2"
  },
  "devDependencies": {
    "@babel/core": "^7.13.10",
    "@babel/preset-env": "^7.13.10",
    "babel-loader": "^8.2.2",
    "css-loader": "^5.1.3",
    "mini-css-extract-plugin": "^1.3.9",
    "sass": "^1.32.8",
    "sass-loader": "^11.0.1",
    "style-loader": "^2.0.0",
    "webpack": "^5.26.0",
    "webpack-cli": "^4.5.0"
  }
}

webpackのコア機能

webpackの設定は、先ほど空のファイルとして作成したwebpack.config.jsに記述していきます。ただその前に、webpackのコア機能となっている「Entry」「Output」「Loader」「Plugins」の4つの仕組みを理解することが重要です。

Entry

Entryは、エントリポイントを指定する機能です。エントリポイントとは、webpackがバンドルを行う開始点となるJavaScriptファイルのことです。

Output

Outputは、バンドルされたファイルの出力先を指定する機能です。エントリポイントを起点としてバンドルされたファイルが、Outputで指定されたパスとファイル名に出力されます。

Loader

Loaderは、パッケージ(モジュール)をはじめとしたフロントエンドのファイルの依存関係を解決し、アプリケーションで利用可能な状態にまとめてくれる、webpackの処理の中核となる機能です。
またLoaderには、先ほどインストールしたbabel-loadersass-loaderstyle-loadercss-loaderのように、様々な種類があります。

Plugins

Loaderは上述のように、モジュールの変換のための機能ですが、PluginsはLoaderの機能以外の幅広いタスクを実行できる機能です。
これもまた膨大な種類があります。

今回のサンプルではmini-css-extract-pluginがこれにあたります。

webpack.config.js

ではwebpackの設定ファイルであるwebpack.config.jsに内容を記述します。
非常にたくさんのプロパティがあるため、ここでは一つ一つの細かな解説を割愛しますが、コメントに各機能の簡単な解説を載せています。
重要なこととして、webpackはローダー機能を、ファイルに書かれた処理を下から上に問い合わせて処理します。

project-name/webpack.config.js

// mini-css-extract-pluginの読み込み
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

// 定数MODEに'production'か'development'どちらかを代入します
// 'production'モードではファイルは圧縮して最適化され、'development'の場合は圧縮されず、デバッグに便利なソースマップが出力されます
const MODE = "production";

// ソースマップの利用有無(productionのときはソースマップを利用しない)
const enabledSourceMap = MODE === "development";

module.exports = {
  // modeの値は上記の定数で管理
  mode: MODE,

  // 処理の起点となるエントリポイントの指定
  entry: "./src/index.js",

  // 出力先(アウトプット)の指定
  output: {
    // ディレクトリの指定をします。dist内に出力します
    // __dirname変数は、このファイルが格納されているディレクトリのパスを取得できます
    path: `${__dirname}/dist`,
    // 出力するファイル名を指定します
    filename: 'main.js'
  },

  // ローダー機能。rules内に各ローダーの処理を明記して使用します。ローダーは下から上に処理が走ります。
  module: {
    rules: [
      {
        // 拡張子が.jsの場合
        test: /\.js$/,
        use: [
          {
            // BabelによるJsのトランスパイル機能を利用
            loader: "babel-loader",
            // オプションの設定
            options: {
              presets: [
                // プリセットを指定することで、ECMAScript5に変換
                "@babel/preset-env",
              ],
            },
          },
        ],
      },

      {
        // 拡張子がscssまたはcssの場合の処理
        test: /\.(scss|css)$/,
        use: [
          // Jsファイルに取り込まれたCSSをDOM要素へ注入するローダー
          "style-loader",

          // mini-css-extract-pluginプラグインを使用してCSSを別ファイルに書き出します。
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              esModule: false,
            },
          },
  
          {
            // Jsファイル内に書かれたCSSを取り込む機能
            loader: "css-loader",
            // オプションの指定
            options: {
              // CSSのurl()値のメディアを取り込むのを禁止
              url: false,
              // ソースマップの利用有無
              sourceMap: enabledSourceMap,

              // 0 => no loaders (default);
              // 1 => postcss-loader;
              // 2 => postcss-loader, sass-loader
              importLoaders: 2,
            },
          },
          
          {
            // SassをCSSへトランスパイルする機能
            loader: "sass-loader",
            // オプションの指定
            options: {
              // ソースマップの利用有無
              sourceMap: enabledSourceMap,
            },
          },
        ],
      },
    ],
  },

  // プラグイン
  plugins: [
    // CSSファイルを外出しにするプラグイン
    new MiniCssExtractPlugin({
      // 出力するファイル名の指定
      filename: "style.css",
    }),
  ],

  // どの環境に最適化するかを指定。webはブラウザ環境、es5はECMAScript5です。指定した環境に合わせたトランスパイルを行います。
  target: ["web", "es5"],

};

実行

これで環境構築は完了しました。実際にwebpackを動作させてみます。
webpackの実行には、npmのパッケージ実行コマンドであるnpxコマンドを使ってみます。

$ npx webpack

実行したらディレクトリ構成を確認してみてください。distディレクトリ内に、main.jsstyle.cssが生成されているかと思います。

project-name/
├-- webpack.config.js
├-- src
|   ├-- index.js
|   └-- style.scss
├-- dist
|   └-- index.html
|   └-- main.js
|   └-- style.css
├-- package.json
├-- package-lock.json
└-- node_modules/ 
    └-- 以下略

ファイルの生成が確認できたら、distディレクトリにあるindex.htmlを開いてください。下の画像のようなページが表示されたら、webpackが無事動作したことを確認できます。

完成形、npmとwebpackを使用してMarkdownエディタのSimpleMDEの画面が表示されました。

webpackの公式リファレンス

webpackをさらに詳しく知りたい場合については、公式ドキュメントを参考にしてください。

webpack

Watchオプション

開発用のファイルに変更が生じた場合、それを反映させるために手動でnpx webpackコマンドを実行する必要がありますが、--watchオプションをつけるとファイルに変更があった場合すぐに反映させることができます。 監視状態を終了させる場合はcontrol(Windowsの場合Ctrl) + Cで停止します。

npx webpack --watch

npm script

ちなみにpackage.jsonには任意のコマンドを登録できるscriptsというオプションがあります。
予約語は設定できないなどのルールはありますが、下記のように記述することができます。

project-name/package.json

{
  "name": "project-name",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  // scriptプロパティ内に任意のコマンドを指定できます。
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack", // このコマンドはnpm run buildで動作します。
    "watch": "webpack --watch" // 上記のコマンドにwatchオプションを追加したものです。
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "simplemde": "^1.11.2"
  },
  // 以下略

}

npm run スクリプト名で実行できます。
上記のbuildスクリプトの場合は、下記のコマンドで実行できます。実行するとWebpackが動作します。

npm run build