LoginSignup
1
0

More than 3 years have passed since last update.

SPAじゃない開発でVue+Webpackの構成

Last updated at Posted at 2021-02-03

様々な事情で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"
  }
};
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0