様々な事情でSPAじゃない開発やらないといけないorそうじゃないほうが都合が良いこともあるよね。
個人的にハマったので備忘録として投稿。
やりたいこと
index.html
index2.html
・・・
があってそれぞれに
app.js→コンポーネントApp
app2.js→コンポーネントApp,App2
・・・
を紐づけたい。
index.htmlに集約させたくない。
構成
|- dist
|- |- js
|- |- |- app.js //ビルド後のJS
|- |- |- app2.js //ビルド後のJS
|- src
|- |- js
|- |- |- app.js
|- |- |- app2.js
|- |- |- components
|- |- |- |- App.vue
|- |- |- |- App2.vue
|- index.html
|- index2.html
|- package.json
|- webpack.config.js
Vue
App.vue
<template>
<div>
<span class="text">app</span>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style lang="scss" scoped>
.text {
color: red;
}
</style>
App2.vue
<template>
<div>
<span class="text">app2</span>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style lang="scss" scoped>
.text {
color: blue;
}
</style>
app.js
import Vue from 'vue';
import App from './components/App.vue';
new Vue({
el: "#app",
render: h => h(App)
})
app2.js
import Vue from 'vue';
import App from './components/App.vue';
import App2 from './components/App2.vue';
new Vue({
el: "#app",
render: h => h(App)
})
new Vue({
el: "#app2",
render: h => h(App2)
})
html
index.html
<!DOCTYPE html>
<html lang="ja" dir="ltr">
<head>
<meta charset="utf-8">
<title>sample</title>
</head>
<body>
<div id="app"></div>
<script src="./dist/js/app.js"></script>
</body>
</html>
index2.html
<!DOCTYPE html>
<html lang="ja" dir="ltr">
<head>
<meta charset="utf-8">
<title>sample</title>
</head>
<body>
<div id="app"></div>
<div id="app2"></div>
<script src="./dist/js/app2.js"></script>
</body>
</html>
パッケージとか
package.json
{
"name": "gin_test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "npx webpack --mode development",
"watch": "npx webpack -w --mode development"
},
"author": "",
"license": "ISC",
"dependencies": {
"@vue/cli-init": "^4.5.11"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"axios": "^0.21.1",
"babel-loader": "^8.2.2",
"css-loader": "^5.0.1",
"html-webpack-plugin": "^4.5.1",
"node-sass": "^5.0.0",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"sass-loader": "^10.1.1",
"style-loader": "^2.0.0",
"terser-webpack-plugin": "^5.1.1",
"vue": "^2.6.12",
"vue-loader": "^15.9.6",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.12",
"webpack": "^5.19.0",
"webpack-cli": "^4.4.0",
"webpack-dev-server": "^3.11.2"
}
}
webpack.config.js
// 開発or本番モードの選択(development、production、noneのいずれか設定必須)
// development: 開発時のファイル出力のモード(最適化より時間短縮,エラー表示などを優先)
// production: 本番時のファイル出力のモード(最適化されて出力される)
const MODE = "development";
// ソースマップの利用有無(productionのときはソースマップを利用しない)
const enabledSourceMap = MODE === "development";
// ファイル出力時の絶対パス指定に使用
const path = require('path'),
glob = require('glob'),
_ = require('lodash');
// プラグイン
// js最適化
const TerserPlugin = require('terser-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const webpack = require('webpack');
const jsBasePath = path.resolve(__dirname, 'src/js'),
jsDistPath = path.resolve(__dirname, 'dist/js')
String.prototype.filename = function () {
return this.match(".+/(.+?)([\?#;].*)?$")[1];
}
var targets = _.filter(glob.sync(`${jsBasePath}/**/*.js`), (item) => {
return !item.filename().match(/^_/) && !item.match(/node_modules/) && !item.match(/lib/)
});
// entryに入れるhash
var entries = {};
// pathも含めたfilenameからpathとfilenameでhashを作る
targets.forEach(value => {
var path = jsBasePath.replace(/\\/g, '\/')
var re = new RegExp(`${path}/`);
var key = value.replace(re, '');
key = key.replace(".js", '');
// 確認用に取得したファイル名を出す
//console.log('--------------------------')
//console.log(path)
//console.log(key)
//console.log(value.filename())
entries[key] = value;
});
module.exports = {
// エントリーポイント(メインのjsファイル)
entry: entries,
// ファイルの出力設定
output: {
path: jsDistPath,
filename: '[name].js'
},
mode: MODE,
// ソースマップ有効
devtool: 'source-map',
// ローダーの設定
module: {
rules: [
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"]
},
{
test: /\.vue$/,
loader: "vue-loader"
},
{
// ローダーの対象 // 拡張子 .js の場合
test: /\.js$/,
// ローダーの処理対象から外すディレクトリ
exclude: /node_modules/,
// Babel を利用する
loader: "babel-loader",
// Babel のオプションを指定する
options: {
presets: [
// プリセットを指定することで、ES2019 を ES5 に変換
"@babel/preset-env"
]
}
}
]
},
// import 文で .ts ファイルを解決するため
resolve: {
// Webpackで利用するときの設定
alias: {
vue$: "vue/dist/vue.esm.js"
},
extensions: ["*", ".js", ".vue", ".json"]
},
plugins: [
// Vueを読み込めるようにするため
new VueLoaderPlugin()
],
// mode:puroductionでビルドした場合のファイル圧縮
optimization: {
minimizer: MODE
? []
: [
// jsファイルの最適化
new TerserPlugin({
// すべてのコメント削除
extractComments: 'all',
// console.logの出力除去
terserOptions: {
compress: { drop_console: true }
},
}),
]
},
// js, css, html更新時自動的にブラウザをリロード
devServer: {
// サーバーの起点ディレクトリ
// contentBase: "dist",
// バンドルされるファイルの監視 // パスがサーバー起点と異なる場合に設定
publicPath: jsDistPath,
//コンテンツの変更監視をする
watchContentBase: true,
// 実行時(サーバー起動時)ブラウザ自動起動
open: true,
// 自動で指定したページを開く
openPage: "index.html",
// 同一network内からのアクセス可能に
host: "0.0.0.0"
}
};