webpackで静的サイトのレイアウトをつくる

Sat Feb 1, 2020 - webpack
Tue Mar 3, 2020

フロントエンドをガッツリやるようになると避けられないのがwebpackということで、webpackでレイアウト20ページ程度の静的サイトをつくる場合の方法をメモしておきます。

環境

  • macOS Catalina 10.15.2

  • node.js v10.16.0

  • npm 6.13.4

最初に

プロジェクトルートで

1
$ npm init -y (設定ファイルを生成) 

webpackのインストール

1
$ npm install --save-dev webpack webpack-cli

--save-devオプションは、インストールするパッケージの情報をpackage.jsonに記録するという意味です。

オプション

  • --save-dev アプリ開発で利用するツールをインストールする場合に利用する

  • --save アプリそのものを実行する場合にインストールする

webpackのインストールをインストールしたらpackage.jsonにこのように記録されます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
  "name": "e-learning-general",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10"
  }
}

htmlのレイアウトをpugで作成する

webpackでもheaderfooterなどを共通化して書き出すこともできるらしいのですが、どうも上手いやり方がわからなかったので、あきらめてpugで組み立てて、公開するpublicフォルダに書き出す方法にしました。

というわけで、ここでは一旦webpackのことを忘れて、必要となるpugpug-cliをインストールします。

1
$ npm install --save-dev pug pug-cli

次にプロジェクト直下に公開するpublicフォルダとhtmlのlayoutを格納するsrcフォルダを作成します。

1
$ mkdir public src

pugファイルを格納するlayoutフォルダをsrc直下に作成します。

1
$ mkdir src/layout

ここまで、出来たらあとはpugでゴリゴリ書いていけばいいのですが、pugIncludesを使えばヘッダーやフッターなどを部品化できるので、僕の場合は、_commonフォルダの中に共通部品を入れ込んでいます。フォルダ構成はこんな感じ。

1
2
3
4
5
layout/_common
         |- _partialsフォルダ ヘッダーとかフッターなどの共通ファイル
         |- _baseof.pug 基盤となるpugファイル
      /user
      /money

次に基盤となる_baseof.pugを作成します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
block pagedata
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.0")
        link(href="https://fonts.googleapis.com/css?family=Roboto:300,400,500" rel="stylesheet")
        title #{pageTitle} | サンプル
    body
        include ./_partials/_header ← 共通部分
        block main ← ここに各ページのコンテンツが入る
        include ./_partials/_footer ← 共通部分
    block pagejs ← 各ページのjs

ここまで、できたら後は共通の部分のpugを作って、各ページを作るだけ。user画面を作成するとこんな感じ。まずbaseof.pugファイルを読み込んで、それから組み立ていく流れ、静的サイトのディレクトリのpath変数を設定してあげると便利。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
//- テンプレート読み込み
extend ../_common/_baseof
//-ページ独自の設定
append pagedata
    - var pageTitle= "このサイトについて";
    - var path = '../';
//- ページ独自のjs
append pagejs
    script(src=`${path}main.js`)
//- ページのコンテンツ
block main ここにユーザーが表示されるよ

レイアウトをpugで作成したらこれをpublicフォルダに書き出すために、スクリプトを作成します。

場所はどこでもいいですが、とりあえずプロジェクト直下にsample.shを作成します。

1
$ touch sample.sh

sample.shpugをbuildするスクリプトを書きます。

1
2
3
#sample.sh

npx pug src/layout/user/*.pug --pretty --out public/terms

さて、ここまできたら試しにスクリプトを実行してみましょう。

1
% sh sample.sh

きちんとbuildされればpublicフォルダにhtmlが書き出されていると思います。ここまでで、htmlは終わりです。

webpack-dev-server

webpack-dev-serverを使えばファイルを更新すると即座に反映してくれるので、インストールしておきましょう。

1
$ npm install --save-dev webpack-dev-server

webpack-dev-serverを有効にするためにwebpack.config.jsを作成します。

1
$ touch webpack.config.js

webpack-dev-serverとエントリーポイントなどを含めてた基本の形はこんな感じ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
module.exports = {
    entry: './src/index.js',
    output: {
        path: `${__dirname}/public`,
        filename: 'main.js'
    },
     devServer: {
        contentBase: `${__dirname}/public`,
    },
};

webpack-dev-serverを簡単に起動できるようにpackage.jsonnpm scripts編集します。

ついでにbuildコマンドも追加しておきます。

1
2
3
4
  "scripts": {
    "start": "webpack-dev-server --open",
    "build": "webpack --config webpack.config.js"
  },

webpck エントリーポイントを作成する

エントリーポイントとなるindex.jssrcフォルダ直下に作成する。

1
$ touch src/index.js

エントリーポイントとはバンドルをするときの開始するファイルのことです。

1
2
// index.js
console.log('ここはエントリーポイント')

ここまで、終わればwebpack-dev-serverを起動してみましょう。

まずは、buildして、main.js を出力します。

1
$ npm run build

webpack-dev-serverを起動させる。

1
$ npm start

問題なく画面が表示されたらdeveloperツールでconsoleを確認してみましょう。

ここはエントリーポイントと表示されているはずです。

scssをバンドルする

スタイルシートをバンドルするための、css-loader,style-loader,sass-loader,とscssをコンパイルするのに必要になるnode-sassをインストールします。

1
$ npm install --save-dev webpack webpack-cli css-loader style-loader sass-loader node-sass

インストールが終わったら、webpack.config.jsmodule-rulesパラメーターにローダーを適用するtestファイルと適用するuseローダーを指定します。

ローダーは右から適用されます。ちょっと改行してるので、この場合は下から適用されます。まず、sass-loadernode-sassを使ってsassをcssにコンパイルして、css-loaderがそれをバンドルし、最後にjsファイルにcssを入れるのにstyle-loaderが適用されるとう流れです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    module: {
        rules: [
            {
                test: /\.css|scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ],
            },
        ],
    }

試しに、style.scssを以下のようにして。

1
2
3
body {
    background-color: red;
}

このstyle.scssをエントリーポイントのindex.jsにモジュールとしてimportします。

1
import './assets/scss/style.scss';
1
$ npm start

bodyが赤になっていれば成功です。scssを更新したらすぐさまに色が変わると思います。

Normalize.cssをインストール

1
$ npm install --save normalize.css

normalize.cssをインポート

1
import 'normalize.css'

normalize.cssはnpmが公式から公開されていますので、そのままインスールします。

buildするとmain.jsの中にnormalize.cssが追加されているのが確認できると思います。

1
$ npm run buiild

開発時と本番時を分ける

本番時はソースコードを圧縮したり、余計なconsole.logを削除してbuildしたいかと思います。その時に利用するのがwebpack-mergeです。

プロジェクト直下に以下のファイルを作成しましょう。

1
$ touch webpack.base.js webpack.development.js webpack.production.js
  • 共通設定: webpack.base.js

  • 開発用設定: webpack.development.js

  • 本番用設定: webpack.production.js

webpack-mergeをインストールする。

1
$ npm install --save-dev webpack webpack-cli webpack-merge

まず、最初に共通の設定から行います。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 共通設定: webpack.base.js

module.exports = {
    entry: './src/index.js',
    output: {
        path: `${__dirname}/public`,
        filename: 'main.js'
    },
    devServer: {
        contentBase: `${__dirname}/public`,
    },
    module: {
        rules: [
            {
                test: /\.css|scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ],
            },
        ],
    }
};

次にwebpack.development.jsの設定です。開発中ですのでsourcemapなどを確認できたほうがいいので、基本はこんな感じ。

1
2
3
4
5
6
const merge = require('webpack-merge');
const base = require('./webpack.base.js');
module.exports = merge(base, {
    mode: 'development',
    devtool: 'eval-source-map',
})

本番は圧縮の設定はwebpackmodeproductionにするだけ勝手によしなしにやってくれます。細かい設定が必要ならその都度、プラグインなどで設定します。以下は、console.logを出力しないようにterser-webpack-pluginを使っています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
const merge = require('webpack-merge');
const base = require('./webpack.base.js');
const TerserPlugin = require('terser-webpack-plugin');

module.exports = merge(base, {
    mode: 'production',
    optimization: {
        minimize: true,
        minimizer: [new TerserPlugin({
            terserOptions: {
                compress: {drop_console: true}
            }
        })],
    }
})

package.jsonの開発用と本番用設定

webpack-mergeを使って開発用と本番用設定を分割したので、今度はこの設定をpackage.jsonに指定します。

1
2
3
4
5
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --open-page -config webpack.development.js",
    "build": "webpack --config webpack.production.js && sh sample.sh"
  },

これでnpm startの時は開発用の設定で起動し、npm run buildの時は本番設定でbuildします。

終わり。