multiple pages in Vue.js CLI
Asked Answered
L

4

71

I'm having trouble figuring out how to have multiple pages in a Vue CLI project. Right now I have my home page with a few components and I want to create another page but I do not know how to do that. Am I supposed to create multiple html files where the index.html by default is? In a simple file structure with css js img folder and html files as pages I know that creating another html file means making another page. But I don't understand how this works with Vue CLI project.

I saw stuff like vue-router and "pages" in Vue documentation but I do not understand them very well. What are my alternatives? Is there a guide that explains that in detail, because I wasn't able to find any, let alone detailed. Would be very happy if you could help! Thank you!

Loudermilk answered 5/8, 2018 at 6:42 Comment(0)
W
-9

Note pointing users to what should be the accepted answer
At the moment of posting my initial answer, I wasn't aware of the possibility of actually building MPAs in VueJS. My answer doesn't address the question asked therefore I will recommend taking a look at the answer provided by PJ. Wanderson which should be the accepted answer

Initial Answer
Vue.js projects are SPAs(single-page applications). You only have one .html file in the entire project which is the index.html file you mentioned. The "pages" you want to create, in vue.js are referred to as components. They will be plugged into the index.html file and rendered in the browser. A vue.js component comprises 3 parts:

<template>
    
</template>

<script>
export default {

}
</script>

<style>

</style>
  • Template: contains all the HTML your page should display (this is where you put the HTML of your component).
  • Script: contains all JavaScript code that will be executed on the component.
  • Style: contains the CSS that will style that specific component.

You can check this tutorial out for a quick start: Getting started with Vue.

It explains the Vue.js project structure and how the various files relate to each other

Washerman answered 5/8, 2018 at 8:56 Comment(4)
This is not entirely correct. You can create MPA with Vue Cli. That's what you have pages for.Similarity
Just adding more to what @Similarity has said, this is actually isn't even a valid answer. It's not entirely correct isn't the right word. It's should be a false answer. This answer shouldn't even deserve as a solution. For you who interested in creating Multiple Pages Application (MPA) with Vue you can start one with Vue CLI 3, built in in Vue itself.. For more info please check the official docs at cli.vuejs.org/config/#pagesKordofanian
I agree with irfandy and avizzzy though they aren't enough documentation on how to do this except for the Vue 3 documentation as of now.Ridley
Sorry just updating, at the time @hippolyte edited this (Aug 8, 18), Vue CLI 3 has just released on Aug 10, 18, so this answer is not entirely wrong I guess. But since I'm new and barely touch that version before 3.x I can't say much for the version before it. Just noting others that this answer has been outdated.. @Silverster there are correct answer by @Kary which I just tested on Vue CLI 3.4.0.Kordofanian
K
135

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 app this same app, with the changes I made above the 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

Kary answered 27/9, 2018 at 11:56 Comment(20)
Best solution yet, altough i couldn't find a more detailed tutorial of multi pagesMirilla
set to manually configure it. Then, don't choose the SPA option. Vue will create a nice "start" project using a MPA approach. This is not correct, I tried using Vue CLI 3.4.0, I chose manual, there is no option to choose/not choose SPA. Vue CLI will generate a standard boilerplate project using SPA approach.Francesfrancesca
It seems they have changed it. Anyway, you need to follow the example on here: cli.vuejs.org/config/#pages. Also: don't select "Route" option when opt for manually configure itKary
This should be the accepted answer.. so far it's working fine on Vue CLI 3.4.0, should be noted Vue CLI doesn't watch changes in your vue.config.js so if you want to see the new settings that you have changed you have to npm run serve again.Kordofanian
You also, can make use of nodenomKary
does that mean that the "two apps" can build separately? can have different node modules? and share the same common components without uploading them to npm or something like that?Hale
They are still a same app. The node_modules and any component you build, can be shared between them, just by import - at same way you do with a SPA. I doesn't get what you mean by "without uploading to npm".Kary
how do you debug/serve a specific page in this case? Something like 'vue-cli-service serve about' doesn't seem to workSkeen
You could install http-server + nodemon and create a custom script in package.json. Keeping this page open in the browser, the changes will be handled by the nodemon and published by the http-server.Kary
if i refresh page then it again loads index page, which i dont wantShaina
@FarooqBellard, it seems something went wrong with your config. Check your main.js file or the individuals page/main.js.Kary
//below is my vue.config file, even if i type URL like "localhost:5000/userdash" in browser i am redirecting to index page. module.exports = { pages: { 'index': { entry: './src/home/main.js', template: 'public/index.html', filename:'index.html', }, 'userdash':{ entry: './src/pages/main.js', template: 'public/userdash.html', filename:'userdash.html', } }, }, };Shaina
@Kary hey but that thing works perfectly on my local machine, the problem only arises when I push my code on the server or when I ran dist folder like serve -s dist on my local machinShaina
@Kary this is awesome as works for me for any page in /pages. But how to make further nested subpages work?. i.e. reading from a folder /pages/org/ for instance. as I want to further nest a group of pages in domain/org/profile1 and domain/org/profile2 etc.Lecce
@Kary closing this as my issue has now been sorted --> #62935157Lecce
@Kary I am wondering pros/cons of keeping template: 'public/index.html' for both pages. In our case we using 1 for the frontend of the app and 1 for the admin screens of the app. Does this even matter what template you point this at?Quadriplegia
Really nice explanation, the images really helped me as I am new to Vue structuring and get all my apps under 1 roof with shared components and such. Though I have 20+ years of dev experience, this still really helped me big time.Brick
I have a problem, I use different template: "public/index.html", and I have template: "public/index.html", and template: "public/pdf.html",. when I go to /pdf - it also includes chunks and common from /index - I do not want it, I want only includes from ./src/pages/pdf/main.js. how to fix it?Alderman
Doesn't work for me at all, can't navigate to any subpage specified in vue.config.jsScarlatti
/modules/router.jsCottle
U
20

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

Undertow answered 19/12, 2018 at 11:2 Comment(6)
Is this devServer option to rewrite the URLs to look nicer meant to be used in production?Sommers
Not in my opinion, no It's a development server, designed to make development easy, and not intended for production use. Webpack produces nice lean output that can be served in production as a set of static files, eg cloud front, nginx, etc. That doesn't answer how to serve an api, but that's another question entirely.Undertow
What you're saying is that when you build it for prod, the cli will create dist/index.html, dist/experiment/index.html, etc. and each index.html is it's own SPA? But it doesn't work that way in DEV.Sommers
Yes, that's correct, and IMO how it should be. It sounds like you have a concern about something there. If so, I suggest ask a new full question about it, and that concern could be addressed properly.Undertow
Is it possible to utilize the pages of vue.config.js to also produce different versions of css/, img/, and js/ directories for each page?Uncourtly
@orestes kappa I don't think so, unless you're using we pack to produce those directories, and I'm not sure that'd be the right tool for the job. Perhaps add more context... Or better, ask a new stackoverflow question for this and add more detail.Undertow
V
3

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.sstatic.net/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>
Ventilation answered 29/1, 2019 at 16:6 Comment(1)
Audience please be noted, I haven't tried your solution yet, but please be noted. This is for Vue CLI before 3.x, Vue CLI 3 provides configuration for your Vue Projects, more info can be checked from the official docs on cli.vuejs.org/config/#pagesKordofanian
W
-9

Note pointing users to what should be the accepted answer
At the moment of posting my initial answer, I wasn't aware of the possibility of actually building MPAs in VueJS. My answer doesn't address the question asked therefore I will recommend taking a look at the answer provided by PJ. Wanderson which should be the accepted answer

Initial Answer
Vue.js projects are SPAs(single-page applications). You only have one .html file in the entire project which is the index.html file you mentioned. The "pages" you want to create, in vue.js are referred to as components. They will be plugged into the index.html file and rendered in the browser. A vue.js component comprises 3 parts:

<template>
    
</template>

<script>
export default {

}
</script>

<style>

</style>
  • Template: contains all the HTML your page should display (this is where you put the HTML of your component).
  • Script: contains all JavaScript code that will be executed on the component.
  • Style: contains the CSS that will style that specific component.

You can check this tutorial out for a quick start: Getting started with Vue.

It explains the Vue.js project structure and how the various files relate to each other

Washerman answered 5/8, 2018 at 8:56 Comment(4)
This is not entirely correct. You can create MPA with Vue Cli. That's what you have pages for.Similarity
Just adding more to what @Similarity has said, this is actually isn't even a valid answer. It's not entirely correct isn't the right word. It's should be a false answer. This answer shouldn't even deserve as a solution. For you who interested in creating Multiple Pages Application (MPA) with Vue you can start one with Vue CLI 3, built in in Vue itself.. For more info please check the official docs at cli.vuejs.org/config/#pagesKordofanian
I agree with irfandy and avizzzy though they aren't enough documentation on how to do this except for the Vue 3 documentation as of now.Ridley
Sorry just updating, at the time @hippolyte edited this (Aug 8, 18), Vue CLI 3 has just released on Aug 10, 18, so this answer is not entirely wrong I guess. But since I'm new and barely touch that version before 3.x I can't say much for the version before it. Just noting others that this answer has been outdated.. @Silverster there are correct answer by @Kary which I just tested on Vue CLI 3.4.0.Kordofanian

© 2022 - 2024 — McMap. All rights reserved.