multiple pages in Vue.js CLI

非 Y 不嫁゛ 提交于 2019-12-02 15:18:15

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 to take a look at the answer provided by PJ.Wanderson bellow which should be the accepted answer

Inital 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: it contains all the html your page should display (this is where you put the html of your pages)
  • Script: it contains all JavaScript code that will be executed on the page/component
  • Style: it contains the CSS that will style that specific component/page

You can check this tutorial out for a quick-start Vue.js 2 Quickstart Tutorial 2017

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

First: always read the official documentation. With Vue , you can build a SPA, as well: a MPA it no problem. Just follow the guide:

Using Vue CLI 3, you can create a new project with vue create youProject, and set to manually configure it. Then, don't choose the SPA option. Vue will 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 a SPA one. But, make this 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, at your like
  • Create a vue.config.js and set like this: https://cli.vuejs.org/config/#pages

Below, I have three image 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

You don't need to create the pages folder, just 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>

One easy solution

  1. Update your backend sever to either GET and/or POST
  2. axios.get/post(to_the_url)
  3. Serve back the html (like render_template in flask)
  4. You can extract the url from response.request.responseURL
  5. Now set window.location.href = response.request.responseURL
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!