This article is studying Vue but wants to build an app based on TypeScript! It is a content to actually build an environment from scratch for those who say! By the way, I will build it with Docker and create an application that runs in a container environment!
As for the configuration, I will aim for an environment that has module extensibility while building Docker + Vue.js + Express (Node.js) + MySQL based on TypeScript!
"Vue-> Vuex-> HTTP communication (Axios)-> API (Express)-> MySQL data acquisition (Sequelize)-> Store response (Express)-> Vue" It will be the flow.
--Docker, Docker-Compose is already installed (available) --Understanding the basics of JavaScript / Vue.js
The purpose is to quickly build an environment on Docker, and it does not cover Docker in detail. What is Docker in the first place? We recommend that you refer to the following article. [Illustration] Understanding the whole picture of Docker -Part 1-
How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ MySQL edition ~
How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Express edition ~
How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Sequelize ~
First, create a file to create a container with docker-compose. Create the required files with the following configuration.
root
├─ docker
│ └─ app
│ └─ Dockerfile
└─ docker-compose.yml
docker-compose.yml
version: "3"
services:
app:
container_name: app_container
build: ./docker/app
ports:
- 8080:8080
volumes:
- ./app:/app
stdin_open: true
tty: true
environment:
TZ: Asia/Tokyo
This is the basic docker-compose configuration file. We will add API server container and DB container later, but we will create only APP container once.
Dockerfile
FROM node:12.13-alpine
RUN yarn global add @vue/cli
WORKDIR /app
This time, we will use lightweight alpine as the base image. Since vue-cli is used in the container, perform global installation.
$ docker-compose build
Build the image below the design document created earlier
$ docker-compose up -d
Actually start the built container. Start in detached mode (background) by adding -d.
$ docker ps
The following is the output result, so let's check if it is actually started.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
//OK if the created container is displayed here
Now that you have a base container, you can actually go inside the container and build your app.
$ docker exec -it app_container sh
/app # //If this happens, you can access the container
$ vue create app
Manual selection With TypeScript With Router With Vuex Babel ** None **
The version is 2.x. Use class-style component syntax? Yes ** * This is important ** yarn ** * I'm going to use Yarn for the package. ** ** The rest is your choice.
$ cd app
$ yarn serve
At this point, you have created the app inside the container and executed the app from inside the container. Since this work is troublesome every time, we will set the application inside to be automatically executed when the container is started.
$ controll + c
$ exit
$ docker-compose stop
The app directory directly under root is a hindrance, so please go somewhere.
Before
root
├─ app //Ported here(This guy is deleted)
│ └─ app //Every directory
│ ├─ node_modules
│ ├─ public
│ ├─ src
│ Others
│
├─ docker
│ └─ app
│ └─ Dockerfile
└─ docker-compose.yml
After
root
├─ app
│ ├─ node_modules
│ ├─ public
│ ├─ src
│ Others
│
├─ docker
│ └─ app
│ └─ Dockerfile
└─ docker-compose.yml
docker-compose.yml
version: "3"
services:
app:
container_name: app_container
build: ./docker/app
ports:
- 8080:8080
volumes:
- ./app:/app
stdin_open: true
tty: true
environment:
TZ: Asia/Tokyo
command: yarn serve //Add this guy
$ docker-compose up -d
If you access localhost: 8080 in this state and the application is launched, it is successful! The app will be launched when the docker container is launched without yarn serve!
I hate JavaScript semicolons, so I will introduce Prettier that will automatically format it. Please feel free to use this area.
$ docker exec -it app_container sh
$ yarn add prettier --dev
Create app / **. prettierrc **
{
"singleQuote": true,
"semi": false
}
Actually, this is my favorite this time. While writing Vue in TypeScript, we will introduce a library that can be written neatly and intuitively by using a decorator (@). In the future, Vue files will come up with some unfamiliar writing styles, but these libraries are nice and tidy.
$ yarn add vue-class-component vue-property-decorator vuex-class vuex-module-decorators
The following article is very easy to understand, so please read it if you are interested.
-Vue component starting with TypeScript (vue-class-component) -First vue-property-decorator (also supports nuxt)
src/App.vue
<template>
<div id="app">
<router-view />
</div>
</template>
<style>
#app {
width: 95%;
margin: 0 auto;
}
</style>
I want to leave the component to be displayed to the Router side, so delete router-link and replace it with router-view.
├─ assets
│ └─ logo.ping //Delete
├─ components
│ └─ HelloWorld.vue //Delete
├─ views //Delete the entire directory
│ ├─ Home
│ └─ About
Please leave the files that you will not use in the future.
/pages/Test.vue
<template>
<div class="test">
<h1>Test Page</h1>
</div>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class Test extends Vue {}
</script>
Create a test component to check the following:
/router/index.ts
import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router'
import Test from '../pages/Test.vue'
Vue.use(VueRouter)
const routes: Array<RouteConfig> = [
{
path: '/',
name: 'Test',
component: Test,
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
})
export default router
Set the routing so that the created Test component is called by the route.
If you reload and "Test Page" is displayed, it's OK! You can freely increase the number of pages by connecting URLs and components in this way!
yarn add vuetify
yarn add --dev sass sass-loader fibers deepmerge
If you use only vuetify, an error will occur, so install the necessary libraries as well.
src/plugins/vuetify.ts
import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'
Vue.use(Vuetify)
const opts = {}
export default new Vuetify(opts)
This is a configuration file for applying Vuetify to the entire app.
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import vuetify from './plugins/vuetify' //add to
import 'vuetify/dist/vuetify.min.css' //add to
Vue.config.productionTip = false
new Vue({
vuetify, //add to
router,
store,
render: (h) => h(App),
}).$mount('#app')
By loading the plugin created above, you can use Vuetify in your application.
<template>
<v-app> <!--add to-->
<div id="app">
<router-view />
</div>
</v-app> <!--add to-->
</template>
Finally, it is OK if you enclose the View of the application body.
<v-btn large color="primary">test</v-btn>
If the button is displayed, the installation of Vuetify is complete! Thank you for your hard work! After that, you can freely increase the number of pages in this way!
Now that the application template is complete, we will create a counter function after checking whether Vuex / Store can be used correctly.
pages/Counter.vue
<template>
<div class="counter">
<h1>Counter</h1>
</div>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class Counter extends Vue {}
</script>
Creating a Counter page
import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router'
import Test from '../pages/Test.vue'
import Counter from '../pages/Counter.vue' //add to
Vue.use(VueRouter)
const routes: Array<RouteConfig> = [
{
path: '/',
name: 'Test',
component: Test,
},
{
path: '/counter', //add to
name: 'Counter', //add to
component: Counter, //add to
},
]
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes,
})
export default router
Set the routing so that the above components are rendered at "localhost: 8080 / counter".
store/modules/**counter.ts**
import {
getModule,
Module,
VuexModule,
Mutation,
Action,
} from 'vuex-module-decorators'
import store from '../index'
type CounterState = {
count: number
}
@Module({ store, dynamic: true, namespaced: true, name: 'Test' })
class CounterModule extends VuexModule implements CounterState {
count = 0
@Mutation
SET_COUNT(payload: number) {
this.count = payload
}
@Action
async increment() {
this.SET_COUNT(this.count + 1)
}
@Action
async decrement() {
this.SET_COUNT(this.count - 1)
}
@Action
async reset() {
this.SET_COUNT(0)
}
}
export const counterModule = getModule(CounterModule)
You can intuitively describe the Store module with "vuex-module-decorators" introduced at the beginning. This time, we will use the data "count" to check whether count changes dynamically when Action is fired.
tsconfig.json
"experimentalDecorators": true, //add to
If you get angry with Linter, please set this.
pages/Counter.vue
<template>
<v-card>
<v-container>
<v-card-title>Counter</v-card-title>
<v-divider />
<v-container>
<v-avatar v-for="item in count" :key="item" color="primary">
<span class="white--text headline">{{ item }}</span>
</v-avatar>
</v-container>
<v-divider />
<v-card-actions>
<v-btn @click="increment">+</v-btn> <!--Execute increment method when clicked-->
<v-btn @click="decrement">-</v-btn> <!--Execute decrement method when clicked-->
<v-btn text @click="reset">Reset</v-btn> <!--Execute reset method when clicked-->
</v-card-actions>
</v-container>
</v-card>
</template>
<script lang="ts">
import { Vue, Component } from 'vue-property-decorator'
import { counterModule } from '../store/modules/counter'
@Component
export default class Counter extends Vue {
get count() {
return counterModule.count //Returns the Store count as is
}
/**
*Add count
*/
increment() {
counterModule.increment() //Fire the Store increment method
}
/**
*Minus the count
*/
decrement() {
counterModule.decrement() //Fire the store's decrement method
}
/**
*Reset the count
*/
reset() {
counterModule.reset() //Fire the Store reset method
}
}
</script>
<style lang="scss" scoped></style>
Let's take full advantage of Vuetify here. Edit it so that v-avatars are generated for the number of counts, and then just move it!
If you press [+] [-] to increase or decrease the counter, it's OK! Thank you for your hard work!
I created a simple counter and checked the behavior of Vuex (Store), but by inserting API communication in the Action of the Store, it is possible to link with the actual DB. Next time, I will create a container for the API server and the DB that actually operates it!
How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ MySQL edition ~
How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Express edition ~ How to build [TypeScript + Vue + Express + MySQL] environment with Docker ~ Sequelize ~
Recommended Posts