Compare commits
10 Commits
61617a19db
...
1757e67770
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1757e67770 | ||
|
|
02d3fceafb | ||
|
|
bf22fbec45 | ||
|
|
6dc2d1d5a2 | ||
|
|
3584f28aad | ||
|
|
5b9698e31d | ||
|
|
7c7f0f9c8e | ||
|
|
522d0712fd | ||
|
|
32a4fd15e2 | ||
|
|
55903c0623 |
78
README.md
78
README.md
@@ -1,17 +1,87 @@
|
|||||||
# Vue3, Vite, Pinia (Vuex 5), Vue Router 4, Quasar, TypeScript Starter Template
|
# Vue3, Vite, Pinia, Vue Router, Quasar, TypeScript Starter Template
|
||||||
|
|
||||||
This repo contains a starter template that connects the following pieces:
|
This repo contains a starter template that connects the following pieces:
|
||||||
|
|
||||||
- [Vue3](https://v3.vuejs.org/)
|
- [Vue3](https://v3.vuejs.org/)
|
||||||
- [Vite](https://vitejs.dev/)
|
- [Vite](https://vitejs.dev/)
|
||||||
- [Pinia (de facto Vuex 5)](https://pinia.vuejs.org/)
|
- [Pinia](https://pinia.vuejs.org/)
|
||||||
- [Vue Router 4](https://next.router.vuejs.org/guide/)
|
- [Vue Router](https://next.router.vuejs.org/guide/)
|
||||||
- [Quasar](https://quasar.dev/)
|
- [Quasar](https://quasar.dev/)
|
||||||
|
|
||||||
|
Quasar is a powerful set of components which uses the Material UI design system. While the styles are quite plain on their own (and perhaps even off-putting), it is easy to customize it. I have used it extensively for my own projects like [Turas.app](https://turas.app), [Turas.app Chrome Extension](https://chromewebstore.google.com/detail/turasapp/lpfijfdbgohlblnadiokliolkkeeblpo), [Zeeq.ai](https://zeeq.ai), and [CodeRev.app](https://coderev.app). It is easy and fast; great for internal tooling and more than usable for public facing apps.
|
||||||
|
|
||||||
|
This project has been configured with Material Design Icons for Quasar. If you'd like to use a different configuration, [see the Quasar docs](https://quasar.dev/start/vite-plugin#using-quasar).
|
||||||
|
|
||||||
## Rationale
|
## Rationale
|
||||||
|
|
||||||
This is inspired by [Evan You's presentation at VueConf Toronto](https://www.youtube.com/watch?v=2KBHvaAWJOA) on the future state of Vue development.
|
This is inspired by [Evan You's presentation at VueConf Toronto](https://www.youtube.com/watch?v=2KBHvaAWJOA) on the future state of Vue development.
|
||||||
|
|
||||||
Having worked in Vue and React, one thing that is clear is that the Vue community reflects the fact there is a bit more of what Fred Brookes terms "conceptual integrity" because of the nature of how the ecosystem is being designed and architected as a community with a clear direction and leadership.
|
Having worked in Vue and React, one thing that is clear is that the Vue community reflects the fact there is a bit more of what Fred Brookes terms *"conceptual integrity"* because of the nature of how the ecosystem is being designed and architected as a community with a clear direction and leadership.
|
||||||
|
|
||||||
In the Vue ecosystem, there are a clear set of "best practices" which are coalescing around key building blocks which simplifies the overall architecture and, in my opinion, enhances productivity.
|
In the Vue ecosystem, there are a clear set of "best practices" which are coalescing around key building blocks which simplifies the overall architecture and, in my opinion, enhances productivity.
|
||||||
|
|
||||||
|
Whereas in the React world, one might have to choose between Redux or Mobx (or Jotai or Zustand or [Valtio](https://betterprogramming.pub/magical-experiments-in-react-state-with-valtio-2b40cf159120)) and live with the compromises of one or the other, I kind of appreciate the fact that Pinia simply got lifted up to Vuex 5 instead of forking and creating two different, fragmented practices for state management. These core functions of building front-end applications should "just work".
|
||||||
|
|
||||||
|
Many of the improvements in Evan's talk have made working with Vue much, *much* more streamlined in my opinion and this starter template pulls them all together!
|
||||||
|
|
||||||
|
## What Can You Build With This?
|
||||||
|
|
||||||
|
Quasar's default styles can be a bit...bland. But it's easy enough to overcome this with a bit of CSS, adjusting fonts, and other basic visual adjustments.
|
||||||
|
|
||||||
|
Here are some apps I've built on top of this basic scaffold:
|
||||||
|
|
||||||
|
- [Turas.app](https://turas.app): a web app for well-organized travelers to plan their itinerary; web, responsive, and PWA!
|
||||||
|
- [Turas.app Chrome Extension](https://chromewebstore.google.com/detail/turasapp/lpfijfdbgohlblnadiokliolkkeeblpo): a Chrome extension built using this same stack! Check it out for planning your next trip!
|
||||||
|
- [Zeeq.ai](https://zeeq.ai): a personal AI agent that watches the FDA ClinicalTrials.gov feed for changes and notifies you.
|
||||||
|
- [CodeRev.app](https://coderev.app): a lightweight tool to help teams use code reviews as interview but built with Nuxt; [check out the GitHub repo as well](https://github.com/CharlieDigital/coderev)!
|
||||||
|
|
||||||
|
Quasar is extremely flexible and a very productive set of components to build on as long as you are willing to take the time to get it to look the way you want.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
cd web
|
||||||
|
yarn
|
||||||
|
yarn run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
See the [Vite template README](web/README.md) for more details and notes.
|
||||||
|
|
||||||
|
## Organization
|
||||||
|
|
||||||
|
The code has been organized under the `/web` directory (planning on adding example backends).
|
||||||
|
|
||||||
|
Highlights are below:
|
||||||
|
|
||||||
|
```
|
||||||
|
/src/App.vue # Entry point
|
||||||
|
/src/layouts/MainLayout.vue # The outer chrome (left nav, top bar)
|
||||||
|
/src/views/SampleView.vue # Example of a view or page displayed in the layout
|
||||||
|
/src/components/HelloWorld.vue # Default component example with the Vite template
|
||||||
|
/src/router/routes.ts # Defines the routes
|
||||||
|
/src/stores/appState.ts # Sample application state store
|
||||||
|
```
|
||||||
|
|
||||||
|
The `HelloWorld.vue` shows an example of how to use the global application state store provided by Pinia.
|
||||||
|
|
||||||
|
Of note with Pinia is that we get full intellisense 🎉 compared to Vuex. If you need to, you can create multiple stores (see the Pinia docs for examples).
|
||||||
|
|
||||||
|
Additionally, with [Vue Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar) instead of Volar and Veture, we finally get full intellisense in the templates as well!
|
||||||
|
|
||||||
|
## Notes:
|
||||||
|
|
||||||
|
If you're not familiar with Quasar, it is one of ***the best*** and most complete front-end *frameworks* out there. Compared to the more popular Vuetify, it is:
|
||||||
|
|
||||||
|
- more "complete"
|
||||||
|
- has better controls
|
||||||
|
- has fantastic, rich documentation and code examples
|
||||||
|
- comes with pretty much everything one needs; I've rarely found myself having to pull in additional libraries when working with Quasar
|
||||||
|
|
||||||
|
All of this means that you can build apps faster and with less friction.
|
||||||
|
|
||||||
|
## More Reading
|
||||||
|
|
||||||
|
If you are just getting started with Vue, then check out:
|
||||||
|
|
||||||
|
- [A Conceptual Model of State in Vue 3.4](https://chrlschn.dev/blog/2024/01/a-conceptual-model-of-state-in-vue-34-using-definemodel/). A discussion on how Vue 3.4's release of `defineModel` changes the game for state management.
|
||||||
|
- [Vue 3x3 - A Mental Model for Building Fast](https://chrlschn.dev/blog/2023/01/vue-3x3/). How to simplify your understanding of Vue to 9 core concepts.
|
||||||
|
|||||||
@@ -2,10 +2,18 @@
|
|||||||
|
|
||||||
This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
|
||||||
|
|
||||||
|
## Included Libraries
|
||||||
|
|
||||||
|
- [Quasar](https://quasar.dev/). Quasar is a powerful set of components which uses the Material UI design system. While the styles are quite plain on their own (and perhaps even off-putting), it is easy to customize it. I have used it extensively for my own projects like [Turas.app](https://turas.app), [Turas.app Chrome Extension](https://chromewebstore.google.com/detail/turasapp/lpfijfdbgohlblnadiokliolkkeeblpo), [Zeeq.ai](https://zeeq.ai), and [CodeRev.app](https://coderev.app). It is easy and fast; great for internal tooling and more than usable for public facing apps.
|
||||||
|
- [Pinia]([https://](https://pinia.vuejs.org/introduction.html)). Pinia is state management for Vue. While it's not strictly necessary to use Pinia, it provides good integration with the devtools and hot module replacement for global state. It makes it easy to manage state that is truly global!
|
||||||
|
|
||||||
|
## More Reading
|
||||||
|
|
||||||
|
If you are just getting started with Vue, then check out:
|
||||||
|
|
||||||
|
- [A Conceptual Model of State in Vue 3.4](https://chrlschn.dev/blog/2024/01/a-conceptual-model-of-state-in-vue-34-using-definemodel/). A discussion on how Vue 3.4's release of `defineModel` changes the game for state management.
|
||||||
|
- [Vue 3x3 - A Mental Model for Building Fast](https://chrlschn.dev/blog/2023/01/vue-3x3/). How to simplify your understanding of Vue to 9 core concepts.
|
||||||
|
|
||||||
## Recommended IDE Setup
|
## Recommended IDE Setup
|
||||||
|
|
||||||
- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)
|
- [VSCode](https://code.visualstudio.com/) + [Vue Official](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
|
||||||
|
|
||||||
## Type Support For `.vue` Imports in TS
|
|
||||||
|
|
||||||
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's `.vue` type support plugin by running `Volar: Switch TS Plugin on/off` from VSCode command palette.
|
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
<head>
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<title>Vite App</title>
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
</head>
|
<title>Vite App</title>
|
||||||
<body>
|
</head>
|
||||||
<div id="app"></div>
|
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<body>
|
||||||
</body>
|
<div id="app"></div>
|
||||||
</html>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -7,18 +7,18 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "^1.12.3",
|
"@quasar/extras": "^1.16.12",
|
||||||
"pinia": "^2.0.9",
|
"pinia": "^2.2.4",
|
||||||
"quasar": "^2.4.10",
|
"quasar": "^2.17.0",
|
||||||
"vue": "^3.2.25",
|
"vue": "^3.5.12",
|
||||||
"vue-router": "4"
|
"vue-router": "4.4.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@quasar/vite-plugin": "^1.0.4",
|
"@quasar/vite-plugin": "^1.7.0",
|
||||||
"@vitejs/plugin-vue": "^2.0.0",
|
"@vitejs/plugin-vue": "^5.1.4",
|
||||||
"sass": "1.32.0",
|
"sass": "1.33.0",
|
||||||
"typescript": "^4.4.4",
|
"typescript": "^5.6.3",
|
||||||
"vite": "^2.7.2",
|
"vite": "^5.4.9",
|
||||||
"vue-tsc": "^0.29.8"
|
"vue-tsc": "^2.1.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { useAppState } from '../stores/appState'
|
||||||
|
|
||||||
defineProps<{ msg: string }>()
|
defineProps<{ msg: string }>()
|
||||||
|
|
||||||
const count = ref(0)
|
const appState = useAppState();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -27,7 +27,7 @@ const count = ref(0)
|
|||||||
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Docs</a>
|
<a href="https://v3.vuejs.org/" target="_blank">Vue 3 Docs</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<button type="button" @click="count++">count is: {{ count }}</button>
|
<button type="button" @click="appState.counter++">count is: {{ appState.counter }}</button>
|
||||||
<p>
|
<p>
|
||||||
Edit
|
Edit
|
||||||
<code>components/HelloWorld.vue</code> to test hot module replacement.
|
<code>components/HelloWorld.vue</code> to test hot module replacement.
|
||||||
|
|||||||
8
web/src/env.d.ts
vendored
8
web/src/env.d.ts
vendored
@@ -1,8 +1,8 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
declare module '*.vue' {
|
declare module '*.vue' {
|
||||||
import { DefineComponent } from 'vue'
|
import { DefineComponent } from 'vue'
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types
|
||||||
const component: DefineComponent<{}, {}, any>
|
const component: DefineComponent<{}, {}, any>
|
||||||
export default component
|
export default component
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import { createPinia } from 'pinia'
|
|||||||
import { Quasar } from 'quasar'
|
import { Quasar } from 'quasar'
|
||||||
import quasarIconSet from 'quasar/icon-set/mdi-v6'
|
import quasarIconSet from 'quasar/icon-set/mdi-v6'
|
||||||
|
|
||||||
// Import icon libraries
|
// Import icon libraries; you can choose different ones!
|
||||||
|
// See: https://quasar.dev/start/vite-plugin#using-quasar
|
||||||
import '@quasar/extras/roboto-font-latin-ext/roboto-font-latin-ext.css'
|
import '@quasar/extras/roboto-font-latin-ext/roboto-font-latin-ext.css'
|
||||||
import '@quasar/extras/mdi-v6/mdi-v6.css'
|
import '@quasar/extras/mdi-v6/mdi-v6.css'
|
||||||
|
|
||||||
@@ -40,7 +41,10 @@ myApp.use(Quasar, {
|
|||||||
*/
|
*/
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Connect Pinia
|
||||||
myApp.use(createPinia());
|
myApp.use(createPinia());
|
||||||
|
|
||||||
|
// Connect Vue Router
|
||||||
myApp.use(router);
|
myApp.use(router);
|
||||||
|
|
||||||
// Assumes you have a <div id="app"></div> in your index.html
|
// Assumes you have a <div id="app"></div> in your index.html
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ const routes: RouteRecordRaw[] =
|
|||||||
]
|
]
|
||||||
}];
|
}];
|
||||||
|
|
||||||
export default routes;
|
export default routes;
|
||||||
|
|||||||
9
web/src/stores/appState.ts
Normal file
9
web/src/stores/appState.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineStore } from 'pinia';
|
||||||
|
|
||||||
|
export const useAppState = defineStore('appState', {
|
||||||
|
state: () => {
|
||||||
|
return {
|
||||||
|
counter: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,15 +1,23 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "esnext",
|
"target": "esnext",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"jsx": "preserve",
|
"jsx": "preserve",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"lib": ["esnext", "dom"]
|
"lib": [
|
||||||
},
|
"esnext",
|
||||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
|
"dom"
|
||||||
}
|
]
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -6,14 +6,14 @@ import { quasar, transformAssetUrls } from '@quasar/vite-plugin'
|
|||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [
|
plugins: [
|
||||||
vue({
|
vue({
|
||||||
template: { transformAssetUrls }
|
template: { transformAssetUrls }
|
||||||
}),
|
}),
|
||||||
|
|
||||||
quasar({
|
quasar({
|
||||||
autoImportComponentCase: 'pascal',
|
autoImportComponentCase: 'pascal',
|
||||||
sassVariables: 'src/quasar-variables.sass'
|
sassVariables: 'src/quasar-variables.sass'
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
1444
web/yarn.lock
1444
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user