# Vue app hosting

Host a Vue app built with Vite: deploy dist/ with one command, and Vue Router's history mode works with spa = true or one switch. Free to try, no account.

On the web at https://lobsite.com/hosting/vue

```sh
npm run build && npx lobsite
```

Vite builds into dist/, and npx lobsite finds it and deploys it.

A Vue app made with `npm create vue@latest` is built by Vite into `dist/`: one `index.html` and the JavaScript that draws every page. Lobsite hosts that folder. Run `npm run build`, then `npx lobsite`, and the app is live at a `*.lobsite.app` address with HTTPS. Vue Router's history mode works once single-page mode is on.

## How it works

1. **Build the app** with `npm run build`. Vite writes it to `dist/`.
2. **Run `npx lobsite`** in the project. It deploys `dist/`, not `public/`, which Vite copies into the build. The first deploy needs no account and lasts 6 hours.
3. **Turn on single-page mode** for Vue Router: `spa = true` in `lobsite.toml`, or **Single-page app** in the site's settings. Keep the site with the claim link, in a free account.

## Vue Router history mode

```js
import { createRouter, createWebHistory } from "vue-router";

const router = createRouter({
  history: createWebHistory(),
  routes,
});
```

- **`createWebHistory()`** gives clean addresses like `/projects/7`. Opening one directly asks the server for a file that doesn't exist; single-page mode answers with your `index.html`, and Vue Router shows the right view.
- **`createWebHashHistory()`** (addresses like `/#/projects/7`) works without single-page mode, since the server only sees `/`. Clean addresses are better for sharing and for search engines.
- **A catch-all route** (`path: "/:pathMatch(.*)*"`) is where your app's own "page not found" view goes, since with single-page mode every unknown page path reaches the app.

## Nuxt and the Vue CLI

- **Nuxt** builds a static site with `npx nuxi generate`, into `.output/public/`. That folder isn't found by itself, so pass it once, `npx lobsite .output/public`, and it's remembered in `lobsite.toml`. Every page is generated as its own file, so single-page mode is only needed for routes Nuxt didn't generate. Nuxt's server routes and server rendering need a host that runs Node.
- **The Vue CLI** (`@vue/cli-service`) is in maintenance mode, and new projects use Vite. An existing Vue CLI project builds into `dist/`, which deploys the same way.

## Vue hosts compared

| | Lobsite | Netlify | Vercel | GitHub Pages |
|---|---|---|---|---|
| Vue Router history mode | `spa = true`, or a switch in the dashboard | A `_redirects` rule | A rewrite in `vercel.json` | No: hash mode, or `404.html` served with status 404 |
| Missing script files after a deploy | 404, a clear error | The app's `index.html` | The app's `index.html` | 404 |
| Nuxt server rendering | No | Yes | Yes | No |
| Account before the first deploy | No: live 6 hours, then keep it free | Yes | Yes | Yes, and a repository |
| Forms without a backend | Yes, once the site is in an account | Yes | No | No |
| Custom domain | Yes, free | Yes | Yes | Yes |

For a Vue app that runs in the browser, Lobsite is one command from `dist/` to a live address, with history mode a single setting away and a preview URL for every deploy.

## Frequently asked questions

### Why do Vue Router pages show "Not found" when reloaded?

History mode addresses only exist inside the app. Turn on single-page mode, `spa = true` in `lobsite.toml` or **Single-page app** in the site's settings, so those paths open your `index.html`.

### Should a Vue app on Lobsite use hash mode or history mode?

History mode, with single-page mode on. The addresses are cleaner and search engines treat them as separate pages. Hash mode is only worth it where you can't change the server's settings.

### Can I deploy a Nuxt site to Lobsite?

Yes, a generated one: run `npx nuxi generate`, then `npx lobsite .output/public`. Pages that need Nuxt's server, such as server routes, won't run.

### How do I show a "page not found" view in a Vue app?

Add a catch-all route at the end of your routes, `{ path: "/:pathMatch(.*)*", component: NotFound }`. With single-page mode on, every unknown page path reaches the app, so the router decides what to show.

