Search code examples
javascriptvue.jswebpackvue-routerhtml-webpack-plugin

The VueRouter is not willing to substitute the `router-view` tag


I am trying to integrate the VueRouter into my small application, but I end up with the router-view tag replaced with a comment.

Perhaps, it is because of HtmlWebpackPlugin.

Sorry for the huge listings, but I think every detail is important.

main.js:

import Vue from "vue";
import VueRouter from "vue-router";

import PumpView from "./PumpView.vue";

Vue.use(VueRouter);

const router = new VueRouter({
    routes: [
        { path: "/", component: PumpView },
    ],
});

new Vue({
    router,
}).$mount("#app");

index.html:

<!doctype html>
<html lang="en">

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

<body>
    <div id="app">
        <router-view></router-view>
    </div>
</body>

</html>

PumpView.vue:

<template>
    <div class="pump-view">
        <chart-mini-grid></chart-mini-grid>
    </div>
</template>

<style>
.pump-view {
    height: inherit;
}
</style>

<script>
import ChartMiniGrid from "./ChartMiniGrid.vue";

export default {
    components: {
        ChartMiniGrid,
    },
};
</script>

webpack.config.js:

const path = require("path");
const webpack = require("webpack");

const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const VueLoaderPlugin = require("vue-loader/lib/plugin");

module.exports = function () {
    return {
        target: "web",
        mode: "production",
        entry: {
            main: "./src/main.js",
        },
        module: {
            rules: [
                {
                    test: /\.js$/,
                    loader: "babel-loader"
                },
                {
                    test: /\.vue$/,
                    loader: "vue-loader"
                },
                {
                    test: /\.tsx?$/,
                    use: "ts-loader",
                    exclude: /node_modules/,
                },
                {
                    test: /\.css$/,
                    use: [
                        "vue-style-loader",
                        "css-loader"
                    ]
                },
            ]
        },
        resolve: {
            extensions: [".js", ".ts"]
        },
        optimization: {
            runtimeChunk: "single",
            splitChunks: {
                chunks: "all",
                maxInitialRequests: Infinity,
                minSize: 0,
                cacheGroups: {
                    vendor: {
                        test: /[\\/]node_modules[\\/]/,
                        name (module) {
                            const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
                            return `npm.${packageName.replace('@', '')}`;
                        },
                    },
                },
            },
        },
        plugins: [
            new CleanWebpackPlugin({
                cleanAfterEveryBuildPatterns: [
                    path.join(__dirname, "src/lightweight-charts/dist"),
                ],
            }),
            new webpack.DefinePlugin({
                PRODUCTION: true,
            }),
            new webpack.HashedModuleIdsPlugin(),
            new HtmlWebpackPlugin({
                title: "Geralt",
                filename: "index.html",
                template: "src/index.html",
                favicon: "src/assets/favicon.png",
            }),
            new VueLoaderPlugin(),
        ],
        output: {
            path: path.join(__dirname, "dist"),
            filename: "[contentHash].js",
            chunkFilename: "[name].[contentHash].js",
            publicPath: "/",
        },
    };
};

I have been trying to mess around the stuff for a few hours, including removing the HtmlWebpackPlugin and putting the HTML template into the Vue object constructor:

new Vue({
    router,
    template: `<html>...</html>`,
}).$mount("#app");

Now I don't know what else I can try.

I suspect some stuff in my Webpack config is conflicting with the idiomatic VueRouter configuration.

My PumpView component is not broken, as everything works like a charm if I add the render function beside the router field:

new Vue({
    router,
    render: h => h(PumpView),
}).$mount("#app");

P.S. I am not using webpack-dev-server, but building with the production config, so it is not the case.


Solution

  • First, you need the App.vue, the container which include the router-view

    <!-- App.vue -->
    <template>
      <div>
        <router-view/>
      </div>
    </template>
    

    then, use it when initialize the Vue

    import App from './App.vue'
    new Vue({
      router,
      render: h => h(App)
    }).$mount('#app')
    

    Because the router-view is the Vue component, you shouldn't use it in the outer html