GitHub Pagesはとても手軽に公開ができ、
自分のようなフロントエンドエンジニアにはとても重宝しています。
ですが、Webpackを用いたページ作成の際、躓き、
これといった解決方法がWeb上に見つからず、自己解決したので、解決方法を残しておきます
どんな問題か?
GitHub Pagesは通常、
https://userName.github.io/repository/
というURLがルートとなる構成となっています。(userNameとrepositoryは任意)
その際、ルートディレクトリが1階層ずれてしまい、その影響で
fetch('../data/hoge.json')
といったファイルを読み込もうとしたときパスがずれてしまい404エラーとなってしまいました。
問題発生時の環境
WebpackにはJSとSASS(Scss)だけを通して、JSとCSSで出力していました。
長くなってしまったので各詳細はまとめてあります。
ディレクトリ構成
├ src/ <- 開発用ディレクトリ
│ ├ script/
│ │ ├ entry.js
│ │ ├ fetchJson.js
│ │ ├ ...
│ │
│ ├ data/
│ │ └ hoge.json
│ │
│ ├ style/
│ │ └ fuga.scss
│ │
│ └ index.html
│
├ dist/ <- コンパイル先ディレクトリ
│ ├ script/
│ │ └ main.js
│ │
│ ├ data/
│ │ └ hoge.json
│ │
│ ├ style/
│ │ └ style.css
│ │
│ └ index.html
│
├ docs/ <- 掲載時ディレクトリ(公開用ディレクトリ)
│ ├ script/
│ │ └ main.js
│ │
│ ├ data/
│ │ └ hoge.json
│ │
│ ├ style/
│ │ └ style.css
│ │
│ └ index.html
│
├ package.json
├ webpack.common.js
├ webpack.dev.js
├ webpack.prod.js
...
無駄なファイル、要素などは省いて書いたつもりですが、それでも長くなっちゃいますね。
Webpackの設定
common, dev, prodで3つに分けています。
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
var webpack = require('webpack');
module.exports = {
entry: path.resolve('src', 'script', 'entry.ts'),
output: {
filename: 'main.js',
},
plugins: [
new MiniCssExtractPlugin({
filename: '../style/style.css',
}),
]
};
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const sourceMap = true;
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge(common, {
mode: 'development',
watch: true,
devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'dist', 'script'),
},
module: {
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
{ loader: MiniCssExtractPlugin.loader, },
{
loader: 'css-loader',
options: { url: false, sourceMap, importLoaders: 2, },
},
{
loader: 'sass-loader',
options: { sourceMap, },
},
],
},
],
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
port: 3000,
watchContentBase: true,
hot: true,
open: true,
},
});
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge(common, {
mode: 'production',
output: {
path: path.resolve(__dirname, 'docs', 'script'),
},
module: {
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
{ loader: MiniCssExtractPlugin.loader, },
{
loader: 'css-loader',
options: { url: false, importLoaders: 2, },
},
{
loader: 'sass-loader',
},
],
},
],
},
});
これで、jsonファイルを読みにいこうすると
async () => {
await ('../data/hoge.json')
};
開発環境ではOKですが、
GitHub上ではエラーになります
GET https://userName.github.io/data/hoge.json 404 (Not Found)
読みに行こうとしているパスが1つがずれています。
正しくは
https://userName.github.io/repository/data/hoge.json
にファイルを取りに行きたいのです。
ですが、webpackの設定をいろいろ調整してみましたが、上手くいきません...。
(1日以上無駄にした)
解決策
「webpackの設定が悪いんだ!」と自分に暗示をかけていたのが悪かったです。
1歩後ろに下がって観察してみると簡単に解決策が見つかりました。
(簡単に解決策が見つかりました...。)
srcディレクトリ構成を変える
これが僕の答えです。
srcのすぐ下で開発しないといけないという
謎の固定概念にとらわれていました。
├ src
│ └ repository
│ └ index.html
という形でsrcと開発ファイルの間に1つディレクトリをはさみ、
コンパイル時に
├ dist
│ └ repository
│ └ index.html
└ docs
└ index.html
というようにディレクトリの階層を変えてあげることで
開発サーバー上でもGitHub Pagesでもエラーが起きず表示することができました!
解決時のディレクトリ構成・webpack設定
【解決】ディレクトリ構成
├ src/ <- 開発用ディレクトリ
│ └ repository/ <- 1個ディレクトリを追加することで解決!
│ ├ script/
│ │ ├ entry.js
│ │ ├ fetchJson.js
│ │ ├ ...
│ │
│ ├ data/
│ │ └ hoge.json
│ │
│ ├ style/
│ │ └ fuga.scss
│ │
│ └ index.html
│
├ dist/ <- コンパイル先ディレクトリ
│ └ repository/ <- 1個ディレクトリをはさみで解決!
│ ├ script/
│ │ └ main.js
│ │
│ ├ data/
│ │ └ hoge.json
│ │
│ ├ style/
│ │ └ style.css
│ │
│ └ index.html
│
├ docs/ <- 掲載時ディレクトリ(公開用ディレクトリ)
│ │ <- ここはディレクトリをはさめない!
│ ├ script/
│ │ └ main.js
│ │
│ ├ data/
│ │ └ hoge.json
│ │
│ ├ style/
│ │ └ style.css
│ │
│ └ index.html
│
├ package.json
├ webpack.common.js
├ webpack.dev.js
├ webpack.prod.js
...
【解決】Webpackの設定
common, dev, prodで3つに分けています。
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
var webpack = require('webpack');
module.exports = {
// repositoryフォルダを追加
entry: path.resolve('src', 'repository', 'script', 'entry.ts'),
output: {
filename: 'main.js',
},
plugins: [
new MiniCssExtractPlugin({
filename: '../style/style.css',
}),
]
};
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const sourceMap = true;
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge(common, {
mode: 'development',
watch: true,
devtool: 'source-map',
output: {
// repositoryフォルダを追加
path: path.resolve(__dirname, 'dist', 'repository', 'script'),
},
module: {
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
{ loader: MiniCssExtractPlugin.loader, },
{
loader: 'css-loader',
options: { url: false, sourceMap, importLoaders: 2, },
},
{
loader: 'sass-loader',
options: { sourceMap, },
},
],
},
],
},
devServer: {
contentBase: path.join(__dirname, 'dist', 'repository'),
port: 3000,
watchContentBase: true,
hot: true,
open: true,
},
});
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge(common, {
mode: 'production',
output: {
// ここはそのまま!
path: path.resolve(__dirname, 'docs', 'script'),
},
module: {
rules: [
{
test: /\.(sc|c|sa)ss$/,
use: [
{ loader: MiniCssExtractPlugin.loader, },
{
loader: 'css-loader',
options: { url: false, importLoaders: 2, },
},
{
loader: 'sass-loader',
},
],
},
],
},
});
所感
- Webpackというものはとても便利という反面、
どうゆう動きをしているのか把握するのは難しい。 - ここが悪いという決めつけが問題解決を遅らせてしまうというのは
コーディング時によくあるはなし。細かいところを見る視点を持ちながら俯瞰な視点も忘れずに開発したい。
本音はこれがベストプラクティスとは思えないというところです。
Webpackの知見がある方、是非、もっとよい解決策を教えてください!