モダンフロントエンド開発入門 - Node.jsの学習5

導入

  • ブラウザとNode.jsでのモジュールの取り扱いの違いについて学ぶ。
  • 現在のフロントエンド開発はビルドツールが乱立しているため、それらについて学ぶ。
  • 各ツールの役割と特徴を捉えることで今後の指針とする

ブラウザ環境とNode.js環境におけるモジュールシステムの違い

// Common JSの書き方なので、ブラウザでは実行できない
const myModule = require("./sub")

// ES Modulesの書き方
import { helloFromSub } from "./sub.js"

helloFromSub()
function helloFromSub() {
  console.log("hello, sub")
}

// Common JSの書き方なので、ブラウザでは実行できない
exports.helloFromSub = helloFromSub
// or
module.exports = {
  helloFromSub,
}

// ES Modulesの書き方
export { helloFromSub }

なぜ、npmパッケージはブラウザから読み込めないのか

Node.jsはもともと、Common JSのシステムで動いていたので、Common JSで書かれたパッケージも多い。
インストールしたパッケージはアップデートされるのが一般的。なので、ファイル内を書き換えて使うことはNG行為。

ES Modulesでrequireを使う方法

import { helloFromSub } from "./sub.js"

// ブラウザーでの読み込み
import isOdd from "./node_modules/is-odd/index.js"
// or
import { createRequire } from "module"
const require = createRequire(import.meta.url)
const isOdd = require("is-odd")

helloFromSub()
const oddy = isOdd(3)
console.log(oddy)
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hello</h1>
    <script type="module" src="./dist/main.js"></script>
  </body>
</html>

webpackでnpmパッケージをブラウザ環境で使う

# インストール
npm i -D webpack-cli

# 実行
npx webpack --entry "./main.js"

# 初期化
npm init -y

モジュールバンドラーを使えば、exportimport、Common JSの規格に沿ったrequiremodule.exportsなどが排除された状態のコードが生成される。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>Hello</h1>
    <!-- <script type="module" src="./dist/main.js"></script> -->
    <!-- ES Modules形式のexportもimportもないので、`type="module"も必要ない` -->
    <script src="./dist/main.js"></script>
  </body>
</html>

webpack.config.jsの設定

webpackはCommon JSで実行されるので、package.jsontype: modules を設定しているとエラーが発生する。なので、削除する。

const path = require("path")

// ES Modulesで書きたい場合
import * as url from "url"
// import.meta.url -> 現在のファイルがURL形式で取得できる
// url.fileURLToPath -> URL形式をパス形式に変換する
const __dirname = url.fileURLToPath(new URL(".", import.meta.url))

console.log(__dirname)

module.exports = {
  mode: "development", // production
  entry: "./main.js",
  output: {
    path: path.resolve(__dirname, "public"), // dist
    filename: "bundle.js",
  },
}

webpackで開発用サーバー立ち上げ

npm i -D webpack-dev-server
const path = require("path")

console.log(__dirname)

module.exports = {
  mode: "development", // production
  entry: "./main.js",
  output: {
    path: path.resolve(__dirname, "dist"), // dist
    filename: "bundle.js",
  },
  devServer: {
    port: 9000,
    // ブラウザで開くか
    open: true,
    // サーバーの対象フォルダ
    static: {
      directory: path.resolve(__dirname, "dist"),
    },
  },
}
{
  "name": "end",
  "version": "1.0.0",
  "main": "main.js",
  "scripts": {
    "build": "webpack",
    "start": "webpack serve"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "is-odd": "^3.0.1"
  },
  "devDependencies": {
    "webpack": "^5.89.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.15.1"
  },
  "description": ""
}

フロントのビルドツール界隈の現状把握

様々なビルドツール

フロントエンド開発で用いるツール群

  • スクランナー
  • Linter/Formatter
  • モジュールバンドラー
  • Native ESMビルダー
  • トランスパイラー

スクランナー

リリースに必要なコマンドを実行するツール

  • 学習コスト低
  • 簡易なビルドに使用
    • SassからCSSへの変換
    • ファイルの圧縮・フォルダのコピー
  • ⭕️Web制作 ✖️複雑な開発

ツール

  • Gulp

Linter / Formatter

プログラムがルールに沿って記述されているかどうかを確認&整形するツール

  • Linter: 記述ルールチェックツール
    • ESLint / TSLint / stylelint
  • Formatter: コード整形ツール
    • Prettier

Minifier

CSS、JSのコードを圧縮するツール

  • JSの圧縮
    • Terser
  • CSSの圧縮
    • CSSNANO

トランスパイラー(JS/TS)

ソースコードJavaScriptの特定のバージョンのコードに変換する機能

ツール

  • SWC
  • Babel
  • tsc

トランスパイラー(Sass/CSS

ソースコードを特定のCSSに変換する機能

ツール

  • Sass
  • postcss

バンドラー

モジュールファイルを一つのファイルに統合(バンドル)するためのツール

  • webpack
  • Parcel
  • rollup
  • esbuild

なぜバンドルする必要があるのか?

JSに求められる機能の増加。(SPAなど)

AMD、CJS、ESMなどのモジュール管理の仕組みが登場。

ブラウザではモジュールシステム(ESM)がなかったため、バンドルが必要になった。
HTTP/1ではリクエスト数がサイトのパフォーマンスによって大きく影響したため。(HTTP/2では改善)

次世代ビルドツール Vite

開発サーバーとHMR

  • 開発サーバー:PC上に立てる開発用のサーバー
  • HMR:画面のリロード無しに変更点を画面に反映する機能

Native ESMを使った開発環境

開発時はバンドルせず、NativeのESM機能で動作

Viteの特徴

  • 試験用:Native ESMを使用
    • ブラウザが読み込めるように依存関係の記述を変換(esbuild)で実行
  • 本番用:バンドルされたファイルを使用
    • Rollupでモジュールをバンドル
      ※何千ものモジュールをインターネット越しに読み込むのは時間がかかるため
      ※esbuildよりも動作が安定している

Vite プロジェクトの作成とビルド

npm initnpm createは同じ意味。
npm init vite でViteを使用しプロジェクトを作成できる

{
  "name": "040_vite_sample",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    // 開発用サーバーの立ち上げ、依存関係の解決
    "dev": "vite",
    // rollupによってバンドルファイルを生成
    "build": "vite build",
    // 生成ファイルを確認するためのサーバーの立ち上げ
    "preview": "vite preview"
  },
  "devDependencies": {
    "vite": "^5.0.0"
  }
}

HMR (Hot Module Replacement) → コードの修正がリアルタイムで反映される

Viteの基本はSPAを作成するものだが、 PHPRailsと連携して開発したい場合、下記に設定方法が記載されている。

github.com

まとめ

  • リンター/フォーマッター
    • Linter → ESLint
    • Formatter → Prettier
  • トランスパイラー
    • TypeScript → tsc
    • JS → Babel, SWC
    • Sass → sass
  • ミニファイアー
    • JS → Terser
    • CSS → CSSNANO
  • バンドラー
    • 信頼と実績 → webpack
    • おすすめ → Vite