multiple pages in Vue.js CLI multiple pages in Vue.js CLI vue.js vue.js

multiple pages in Vue.js CLI


First: always read the official documentation. With Vue you can build a SPA, and a MPA is also no problem. Just follow the guides:

You should create a new project with Vue CLI 3. Once you've created your project set it to be manually configured. Make sure you don't choose the SPA option. Vue will then create a nice "start" project using a MPA approach. After that, just repeat the config on vue.config.js.


Updated #1

It seems that some updates on Vue Cli, have changed the way to build a MPA app, so:

  • Create a new application vue create test
  • Choose Manual configuration

The boilerplate created will be for a SPA. So make the following changes:

  • Create a folder under src named pages (optional)

  • Into this folder create your own pages: Home, About, etc.

  • Copy and paste the App.vue and main.js from src, into your new folders - Home, etc.

  • Format the App.vue into this folders, to your liking.

  • Create a vue.config.js and set it like this: https://cli.vuejs.org/config/#pages

Below, I have three images demonstrating this:

  • First: a fresh new app
  • Second: this same app, with the changes I made above
  • Third: the vue.config.js from this app

fresh new appthis same app, with the changes I made abovethe vue.config.js from this app

You don't need to create the pages folder, this is just to get the idea.

Link to GitHub: Building a MPA App


EDIT: Vue has this built-in. Skip to the bottom for more.

Original answer:

There are two ways to interpret your question, and therefore to answer it.

The first interpretation is: "how can I support routing to different pages within the same single-page app, e.g. localhost:8080/about and localhost:8080/report etc?". The answer to this is to use the router. It's reasonably straightforward and works well.

The second interpretation is: "my app is complex, and I have multiple single-page applications, e.g. one app for the 'website' part, one app for consumers to log in and do work, one app for admins, etc - how can vue do this, without making three entirely separate repositories?"

The answer to the latter is a single repository with multiple single-page apps. This demo looks like exactly what you're after:

https://github.com/Plortinus/vue-multiple-pages/

Look in particular at: https://github.com/Plortinus/vue-multiple-pages/blob/master/vue.config.js

Updated answer:

It turns out that vuejs has the idea of multiple top-level pages built-in. I mean, it makes sense - it's going to be really common, despite what many incorrect answers are saying about "no, it's for single page apps"!

You want the pages option in the vue.config.js file:

https://cli.vuejs.org/config/#pages

If your project doesn't have that file in the root directory, create it and vuejs will discover it.

There is a long and a short way to define each page. I used the short form here:

module.exports = {  pages: {    index: 'src/pages/index/main.ts',    experiment: 'src/pages/experiment/main.ts'  }}

You don't have to put your work under "pages". It could be "/src/apps/index/index.ts" or whatever.

After moving code around and changing some imports from:

import HelloWorld from './components/HelloWorld'

to

import HelloWorld from '@/components/HelloWorld'

The app works - but the "experiment" app in my repo had to be loaded like this:

http://localhost:8080/experiment.html

Pretty ugly, and even worse because it uses the router which resulted in URLs like:

http://localhost:8080/experiment.html/about

Ugh.

Fortunately, this stackoverflow answer solved it. Update the vue.config.js file to include devServer options (make sure this is at the top level of the exported object:

devServer: {  historyApiFallback: {    rewrites: [      { from: /\/index/, to: '/index.html' },      { from: /\/experiment/, to: '/experiment.html' }    ]  }}

Then also modify the router.ts file to append the extra path (in my case "experiment/":

export default new Router({  mode: 'history',  base: process.env.BASE_URL + 'experiment/',  ...

Then URLs resolve nicely, e.g.: http://localhost:8080/experiment/about


This may not be relevant to the question, but bear with me, maybe my answer can help someone.I use webpack+vue, and I have figured out how to build multiple pages applications. Here my webpack.config.js:

const path = require('path');const fs = require('fs')const HtmlWebpackPlugin = require('html-webpack-plugin');const CleanWebpackPlugin = require('clean-webpack-plugin');const VueLoaderPlugin = require('vue-loader/lib/plugin');const TerserPlugin = require('terser-webpack-plugin');const MiniCssExtractPlugin = require("mini-css-extract-plugin");const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");module.exports = {    entry: {        app: './src/app.js',        mgmt: ['./src/modules/mgmt/mgmt.js'],        login: './src/modules/login/login.js'    },    output: {        path: path.resolve(__dirname, 'dist'),        // publicPath: '/ahezime/',        filename: (chunkData) => {            console.log('chuckData.chunk.name => ', chunkData.chunk.name)            return chunkData.chunk.name === 'app' ? './[name].bundle.js' : './[name]/[name].bundle.js';        }    },    optimization: {        minimizer: [            new TerserPlugin(),            new OptimizeCSSAssetsPlugin({})        ]    },    plugins: [        new MiniCssExtractPlugin({            filename: "[name].css",            chunkFilename: "[id].css"        }),        new CleanWebpackPlugin(['dist']),        new VueLoaderPlugin(),        new HtmlWebpackPlugin({            title: 'app',            template: './src/app.html',            // inject: false,            chunks: ['app'],            filename: './index.html'        }),        new HtmlWebpackPlugin({            title: 'mgmt',            template: './src/modules/mgmt/mgmt.html',            // inject: false,            chunks: ['mgmt'],            filename: './mgmt/index.html'        }),        new HtmlWebpackPlugin({            title: 'login',            template: './src/modules/login/login.html',            // inject: false,            chunks: ['login'],            filename: './login/index.html'        })    ],    module: {        rules: [            {                test: /\.m?js$/,                exclude: /(node_modules|bower_components)/,                use: {                    loader: 'babel-loader',                    options: {                        presets: ['@babel/preset-env'],                        plugins: ['@babel/plugin-proposal-object-rest-spread']                    }                }            }        ],        rules: [            {                test: /\.vue$/,                exclude: /node_modules/,                loader: 'vue-loader'            },            {                test: /\.css$/,                use: [                    'vue-style-loader',                    'style-loader',                    'css-loader',                    'sass-loader'                ]            },            {                test: /\.scss?$/,                use: ['style-loader', 'css-loader', 'sass-loader']            },            {                test: /\.(png|svg|jpg|gif)$/,                use: [                    'file-loader'                ]            },            {                test: /\.(woff|woff2|eot|ttf|otf)$/,                use: [                    'file-loader'                ]            }        ]    }};

And here's my directory structure:

https://i.stack.imgur.com/uFvKx.png

And you can jump pages:

<template>    <div>        <h1>App</h1>        <div>            <a href="./login">Please click me, and let take you into the login page!!!</a>        </div>        <span>Before computed: {{ message }} </span>        <br>        <span>Afer computed: {{ computedMessage() }} </span>    </div></template><script>    export default {        data() {            return {                message: 'Hello World!'            }        },        computed: {            reversedMessage: function() {                return this.message.split('').reverse().join('')            }        },        methods: {            computedMessage: function() {                return this.message.split('').reverse().join('')            }        }    }</script>