はじめに
前回、elm0.19の開発環境を構築したので、
elmを試すために、Elm 0.18で作るTodoアプリ(1)を試してみる。
ElmをSPAではなく一部適用にしたいので調整する。
開発環境
- Windows 10
- Vagrant 2.1.5
- Virtualbox 5.2.18
- Ubuntu 18.04 LTS (Bionic Beaver)
- Docker version 18.06.0-ce, build 0ffa825
- docker-compose version 1.22.0, build f46880fe
ファイル構成イメージ
以下のようなファイル構成としたい。
- src
- card.js # elmを読み込むためのjsファイル
- html
- card.html # jsファイルを読み込むhtmlファイル
- Card
- Main.elm # 大元のプログラム
- Handout.elm # 見た目を設定するためのファイル
ファイル変更点
環境設定
webpack.config.js全文
webpack.config.js
const path = require("path");
const webpack = require("webpack");
const merge = require("webpack-merge");
const history = require('koa-connect-history-api-fallback');
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var MODE = process.env.npm_lifecycle_event === "prod" ? "production" : "development";
const filename = MODE == "production" ? "[name]-[hash].js" : "[name].js";
const files = {index:"./src/index.js", card:"./src/card.js"};
var common = {
mode: MODE,
entry: files,
output: {
path: path.join(__dirname, "dist"),
filename: filename
},
plugins: [
new HTMLWebpackPlugin({
template: "src/index.html",
inject: "body",
chunks:['index']
}),
new HTMLWebpackPlugin({
filename: "card.html",
template: "src/html/card.html",
chunks:['card']
})
],
resolve: {
modules: [path.join(__dirname, "src"), "node_modules"],
extensions: [".js", ".elm", ".scss", ".png"]
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.scss$/,
exclude: [/elm-stuff/, /node_modules/],
loaders: ["style-loader", "css-loader", "sass-loader"]
},
{
test: /\.css$/,
exclude: [/elm-stuff/, /node_modules/],
loaders: ["style-loader", "css-loader"]
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
exclude: [/elm-stuff/, /node_modules/],
loader: "url-loader",
options: {
limit: 10000,
mimetype: "application/font-woff"
}
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
exclude: [/elm-stuff/, /node_modules/],
loader: "file-loader"
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: "file-loader"
}
]
},
};
if (MODE === "development") {
console.log("Building for dev...");
module.exports = merge(common, {
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.NoEmitOnErrorsPlugin()
],
module: {
rules: [
{
test: /\.elm$/,
exclude: [/elm-stuff/, /node_modules/],
use: [
{ loader: 'elm-hot-webpack-loader' },
{
loader: "elm-webpack-loader",
options: {
debug: true,
forceWatch: true,
// optimize: true // debugと同時には使えない
}
}
]
}
]
},
serve: {
inline: true,
stats: "errors-only",
content: [path.join(__dirname, "src/assets")],
add: (app, middleware, options) => {
app.use(history());
},
devMiddleware: {
watch:true,
watchOptions:{
aggregateTimeout: 300,
poll:1000
}
},
hotClient:{
host: {
client: '192.168.50.10',
server: '0.0.0.0',
},
port:{
server:3002,
client: 3002
},
allEntries: true
},
},
watch:true,
watchOptions: {
ignored: /node_modules/,
aggregateTimeout: 300,
poll: 5000
},
});
}
if (MODE === "production") {
console.log("Building for Production...");
module.exports = merge(common, {
plugins: [
new CleanWebpackPlugin(["dist"], {
root: __dirname,
exclude: [],
verbose: true,
dry: false
}),
new CopyWebpackPlugin([
{
from: "src/assets"
}
]),
new MiniCssExtractPlugin({
filename: "[name]-[hash].css"
})
],
module: {
rules: [
{
test: /\.elm$/,
exclude: [/elm-stuff/, /node_modules/],
use: [
{ loader: "elm-webpack-loader", options:{optimize: true} }
]
},
{
test: /\.css$/,
exclude: [/elm-stuff/, /node_modules/],
loaders: [MiniCssExtractPlugin.loader, "css-loader"]
},
{
test: /\.scss$/,
exclude: [/elm-stuff/, /node_modules/],
loaders: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
}
]
}
});
}
card.jsのバンドルファイルを作る設定を追加する
var MODE = process.env.npm_lifecycle_event === "prod" ? "production" : "development";
const filename = MODE == "production" ? "[name]-[hash].js" : "[name].js";
const files = {index:"./src/index.js", card:"./src/card.js"};
var common = {
mode: MODE,
entry: files,
card.htmlをwebpackに読み込ませるための設定。
plugins: [
new HTMLWebpackPlugin({
template: "src/index.html",
inject: "body",
chunks:['index'] // card.jsを適用したくないのでindexのみに
}),
new HTMLWebpackPlugin({
filename: "card.html",
template: "src/html/card.html",
inject: false // htmlのほうにjsも記述
})
],
hot-loadをindex.html以外のcard.htmlにも適用する。
hotClient:{
allEntries: true
},
HTMLファイル
マテリアルデザインを適用してみる。 → 失敗。elmと相性が悪い?
card.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/css/materialize.min.css" />
<!--materialize.jsは後から読むと一瞬デザインがちらつくのでhead内で読み込む-->
<script src='https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/js/materialize.min.js'></script>
<title>ハンドアウト</title>
</head>
<h1>ハンドアウト</h1>
<body>
<div class="print">
<div id="cards"></div>
</div>
</body>
</html>
jsファイル
id="cards"の要素にelm要素をひもづける。
card.js
'use strict';
require("./styles.scss");
const {Elm} = require('./Card/Main');
const mountNode = document.getElementById('cards');
const app = Elm.Main.init({flags: 6, node: mountNode});
ライブラリ
package.json
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "elm-test",
"start": "npm run dev",
"dev": "webpack-serve --port 3000",
"build": "webpack",
"prod": "webpack -p"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.0.1",
"@babel/preset-env": "^7.0.0",
"babel-loader": "^8.0.2",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.5.2",
"css-loader": "^1.0.0",
"elm": "^0.19.0-bugfix2",
"elm-format": "^0.8.0",
"elm-hot-webpack-loader": "^1.0.1",
"elm-verify-examples": "^3.0.0",
"elm-webpack-loader": "^5.0.0",
"file-loader": "^2.0.0",
"html-webpack-plugin": "^3.2.0",
"koa-connect-history-api-fallback": "^0.3.1",
"mini-css-extract-plugin": "^0.4.2",
"node-sass": "^4.9.3",
"resolve-url-loader": "^2.3.1",
"sass-loader": "^7.1.0",
"style-loader": "^0.23.0",
"url-loader": "^1.1.1",
"webpack": "^4.18.0",
"webpack-cli": "^3.1.0",
"webpack-merge": "^4.1.4",
"webpack-serve": "^2.0.2"
},
"dependencies": {
"purecss": "^1.0.0"
}
}
実行
http://192.168.50.10:3000/card.html (仮想環境のIP:今回設定したポート)にアクセスし、hot loadができていることを確認する。