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:
- https://cli.vuejs.org/
- https://cli.vuejs.org/guide/html-and-static-assets.html#building-a-multi-page-app
- https://cli.vuejs.org/config/#pages
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
namedpages
(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
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>