1. Escribe al frente
Hace mucho tiempo, el "desarrollo de front-end" y la "gente de herramientas de corte" se equiparaban básicamente. Pero con el desarrollo de Node.js, el front-end puede hacer un trabajo completo, lo que mejora en gran medida la eficiencia del desarrollo (no hay necesidad de interactuar con el campo de interfaz de batalla del back-end, ¡es genial!).
Este artículo registra todo el proceso de creación del proyecto de plantilla de pila completa "vue3+express+typescript". Siga este artículo paso a paso y podrá crear su propio proyecto de plantilla de pila completa, que es muy adecuado para estudiantes de front-end.
Este proyecto ha sido de código abierto en GitHub, asígnele una estrella y vaya: https://github.com/shadowings-zy/vue-express-ts-template-project
2. Selección de tecnología
2-1 Las principales dependencias utilizadas
- Lenguaje de programación: mecanografiado
- Herramienta de gestión de paquetes: pnpm
- Framework front-end: vue3 (compatible con el uso de vuex y vue-router)
- Herramienta de empaquetado: webpack
- Marco de back-end: expreso
- Herramienta de implementación: pm2
2-2 Razones para elegir estas dependencias
La elección del lenguaje de programación typescript
se debe principalmente a que javascript
proporciona typescript
funciones avanzadas como tipos, enumeraciones, interfaces, clases, herencia, etc., que son muy útiles para construir y mantener proyectos a gran escala.
El marco de front-end elige el cubo de la familia vue3, porque prefiero el marco de front-end como vue, que oficialmente proporciona la infraestructura de soporte (como vuex
y vue-router
) con él, y react
este tipo de elección debe investigarse entre router
varios router
Por supuesto, al ajustar la configuración del paquete, podemos vue
reemplazarlo por completo con react
.
Se selecciona la herramienta de empaquetado webpack
, una herramienta de empaquetado anticuada y potente. Las herramientas de empaquetado como No Choice vite
son principalmente para consideraciones de escalabilidad. Si desea vue
cambiar sin problemas a otros marcos front-end, especialmente algunos marcos de nicho, entonces vite
es probable que su uso los haga pasar por alto, y es posible que ni siquiera pueda encontrar ellos a cómo migrar.
Se eligió la herramienta de administración de paquetes pnpm
, principalmente porque pnpm
tiene una velocidad de instalación más rápida y node_modules
un tamaño más pequeño que otras herramientas de administración de paquetes, que aún es muy fragante.
El marco de back-end está seleccionado express
, no hace falta decir que el poderoso marco de back-end principal está bien si lo elige sin pensar.
La herramienta de implementación está seleccionada pm2
, puede ser un nodejs
proceso daemon muy conveniente y también admite funciones como el reinicio automático, que es express
imprescindible para ejecutar servicios en el servidor.
3. Inicializar el proyecto
3-1, monorepo
En este proyecto de plantilla, administraremos monorepo
el proyecto front-end y el proyecto en segundo plano de la misma manera, es decir, se colocarán en el mismo almacén de código, por lo que creamos un nuevo directorio y agregamos un directorio debajo de package
este. directorio , colóquelos respectivamente Código para frontend y backend.client
server
3-2 Inicializar npm
Luego, ejecute npm init
el comando para generar el proyecto package.json
, y el contenido generado es el siguiente:
// 路径: package.json
{
"name": "vue-express-ts-template-project",
"description": "vue express ts template project",
"author": "shadowings-zy",
"license": "ISC"
}
3-3 Inicializar git
Ejecute git init
el comando nuevamente para inicializar el repositorio de git.
3-4 Inicializar mecanografiado
Luego, ejecute pnpm add typescript -D
el comando para instalar typescript
las dependencias. tsconfig.json
Después de instalar las dependencias, creamos un nuevo archivo en el directorio raíz del proyecto , que se utiliza para la configuración.El typescript
contenido específico es el siguiente:
// 路径: tsconfig.json
{
"compilerOptions": {
"lib": ["ES2019", "dom"], // 编译引入的库
"target": "ES2019", // 编译目标
"module": "commonjs" // 模块类型
},
"exclude": ["./node_modules"] // 不包含的文件
}
3-5 Estructura del directorio actual
Nuestra estructura de directorio actual es la siguiente:
.
├── package
│ ├── client # 前端代码
│ └── server # 后端代码
├── package.json # npm配置
└── tsconfig.json # typescript配置
Después de completar estas operaciones de inicialización, la estructura básica de nuestro proyecto está lista y luego es un tiempo de desarrollo agradable.
Cuarto, la parte trasera
Esta sección presentará cómo construir un servicio backend paso a paso express
.
4-1 Preparación para el desarrollo
El backend primero ejecuta pnpm add express
el comando para instalar express
y luego ejecuta pnpm add @types/express
el comando para instalar el archivo de declaración de tipo correspondiente.
Después de instalar las dependencias, necesitamos hacer ajustes tsconfig.json
. Podemos package/server
crear un nivel de directorio en el directorio tsconfig.json
para controlar los archivos server
en el directorio typescript
. El contenido específico es el siguiente:
// 路径: package/server/tsconfig.json
{
"extends": "../../tsconfig.json", // 继承根目录的tsconfig
"compilerOptions": {
"outDir": "../../output", // 编译后的js文件地址
"moduleResolution": "node", // 模块解析策略
"esModuleInterop": true // 支持按照es6模块规范导入commonjs模块
},
"include": ["./**/*.ts"], // 包含的文件
"exclude": ["../../node_modules"] // 不包含的文件
}
4-2 Desarrollar servicios back-end
La siguiente es la parte más importante de este artículo: desarrollar servicios de back-end.
Analicemos brevemente las funciones que proporcionará el servicio backend:
- 1. Procesar páginas html y proporcionar recursos estáticos front-end empaquetados (js, css, etc.).
- 2. Proporcione una interfaz API para el acceso frontal.
Luego, para estas dos funciones, podemos elegir el middleware correspondiente para tratar:
- Úselo
express.static
para la carga de recursos estáticos, combinado concompression
la función gzip provista, para comprimir aún más el volumen del producto. - Úselo
express.Router
para enrutar la solicitud al correspondientecontroller
y manejarla.
4-2-1 Carga de recursos estáticos
Primero, package/server
creamos un nuevo app.ts
archivo en el directorio, que es express
el punto de entrada del proyecto, luego usamos compression
middleware y static
middleware, y escuchamos el puerto.El código específico es el siguiente:
// 路径: package/server/app.ts
import express from "express";
import compression from "compression";
const staticFilePath = ""; // 静态资源路径,先空着,一会在“其他工作”中再填充
const main = async () => {
const app = express();
const port = 8081;
app.use(compression()); // 使用compression中间件gzip静态资源文件
app.use("/static", express.static(config.staticFilePath)); // 静态资源文件在服务器中的位置
// 监听端口,起服务
app.listen(port, () => {
console.log(`server started at http://localhost:${
port}`);
});
};
main();
4-2-2 Desarrollo de la interfaz
Tomemos como ejemplo el desarrollo de la interfaz "obtener lista de usuarios".
Primero, creemos package/server
un nuevo db.ts
archivo en el directorio y almacenemos los datos directamente en una matriz. Esto es un poco más simple. De hecho, reemplazaremos esto con la lógica de leer la base de datos.
// 路径: package/server/db.ts
export enum IUserStatus {
INUSE,
UNUSE,
}
const user = [
{
username: "user1", email: "[email protected]", status: IUserStatus.INUSE },
{
username: "user2", email: "[email protected]", status: IUserStatus.INUSE },
{
username: "user3", email: "[email protected]", status: IUserStatus.INUSE },
{
username: "user4", email: "[email protected]", status: IUserStatus.INUSE },
{
username: "user5", email: "[email protected]", status: IUserStatus.INUSE },
{
username: "user6", email: "[email protected]", status: IUserStatus.UNUSE },
];
export const getUser = () => {
return user;
};
Luego, package/server
creamos un nuevo directorio en el directorio , creamos un nuevo archivo service
en el directorio y escribimos una clase para controlar la lógica relacionada con el usuario. El contenido específico es el siguiente:userService.ts
UserService
// 路径: package/server/service/userService.ts
import {
getUser, IUserStatus } from "../db";
// user相关的service
export class UserService {
private userData = getUser();
// 获取用户列表信息
getUserData = () => {
const output = this.userData.filter(
(item) => item.status === IUserStatus.INUSE
);
return output ? output : [];
};
}
Luego, package/server
creamos un nuevo directorio bajo el directorio , creamos un nuevo archivo controller
bajo el directorio , y escribimos una clase para controlar la lógica relacionada con la interfaz.El contenido específico es el siguiente:userController.ts
UserController
// 路径: package/server/controller/userController.ts
import {
Request, Response } from "express";
import {
UserService } from "../service/userService";
export class UserController {
private userService = new UserService(); // 实例化service
// 获取用户列表的接口处理逻辑
getUser = (req: Request, res: Response) => {
try {
const data = this.userService.getUserData();
return res.status(200).json({
data, message: "get user successful" });
} catch (e) {
return res.status(500).json({
data: {
}, message: e.message });
}
};
}
Después de completar la lógica de procesamiento de la interfaz, podemos configurar el archivo de enrutamiento. Creamos package/server
un nuevo router.ts
archivo en el directorio y configuramos el enrutamiento y el método ejecutado cuando se alcanza el enrutamiento. El código específico es el siguiente:
// 路径: package/server/router.ts
import express from "express";
import {
UserController } from "./controller/userController";
export const getRouter = () => {
const userController = new UserController(); // 实例化controller
const router = express.Router();
router.get("/user", userController.getUser); // 配置路由执行的方法,当访问/user路径时,执行getUser方法
return router;
};
Finalmente, package/server/app.ts
registramos la ruta en , y completamos el desarrollo de la interfaz para la obtención de la lista de usuarios, el código específico es el siguiente:
// 路径: package/server/app.ts
import express from "express";
import compression from "compression";
import {
getRouter } from "./router";
const staticFilePath = ""; // 静态资源路径,先空着,一会在“其他工作”中再填充
const main = async () => {
const app = express();
const port = 8081;
app.use(compression()); // 使用compression中间件gzip静态资源文件
app.use("/static", express.static(config.staticFilePath)); // 静态资源文件在服务器中的位置
app.use("/api", getRouter()); // 挂载路由
// 监听端口,起服务
app.listen(port, () => {
console.log(`server started at http://localhost:${
port}`);
});
};
main();
¡De esta manera, hemos completado el desarrollo del servicio back-end!
4-3 Escribir secuencia de comandos npm
Después de escribir el código de back-end, todavía tenemos que hacer algo de trabajo para que la aplicación de back-end se ejecute realmente.
Por ejemplo, necesitamos actualizaciones urgentes durante el desarrollo, y el entorno en línea también necesita protección de procesos, que deben escribirse por separado npm script
.
4-3-1.dev:comando servidor
Al desarrollar, necesitamos usar ts-node
para ejecutar directamente typescript
el archivo y luego usar nodemon
para detectar server
cambios en el directorio y actualizarlo en caliente.
Luego primero ejecutamos pnpm add -g ts-node nodemon
para instalarlos globalmente, y luego package.json
escribimos el siguiente comando en:
// 路径: package.json
"scripts": {
// ... 其他命令
"dev:server": "NODE_ENV=dev nodemon --watch './package/server/**/*.ts' --exec 'ts-node' ./package/server/app.ts",
},
Este comando detectará los cambios de nodemon
todos los archivos que acierten en la regla , y si hay alguna modificación, se ejecutará el comando, es decir, la lógica en ejecución../package/server/**/*.ts
ts-node ./package/server/app.ts
app.ts
De esta manera, pnpm run dev:server
podemos localhost:8081
iniciar el servicio en la implementación y comenzar un desarrollo feliz.
4-3-2 Comando build:servidor
Y cuando nuestro desarrollo esté completo, necesitamos usar el comando typescript
proporcionado tsc
para typescript
compilar el archivo en javascript
un archivo, es decir, el siguiente comando:
// 路径: package.json
"scripts": {
// ... 其他命令
"build:server": "NODE_ENV=prod tsc --p ./package/server",
},
Una de ellas --p ./package/server
es seleccionar ./package/server
el directorio para tsconfig.json
la compilación, de modo que el archivo compilado se coloque en el directorio tsconfig.json
especificado enoutput
De esta forma, ejecutamos pnpm run build:server
para compilar el código del backend.
4-4 Establecer archivo de configuración
Además, el entorno de desarrollo y el entorno en línea de nuestro servicio tienen algunas configuraciones diferentes, y tenemos que escribir una lógica de "configuración de lectura según el entorno".
¿Recuerdas staticFilePath
la variable que estaba vacía hace un momento? En nuestra secuencia de comandos de empaquetado frontal, los archivos empaquetados se colocarán output/client
en el directorio, lo que genera incoherencias entre los directorios señalados en el entorno de desarrollo y el entorno de producción staticFilePath
, por lo que debemos configurarlos por separado en el archivo de configuración.
En la escritura anterior npm script
, configuramos dev
las variables de entorno en el entorno de desarrollo y prod
las variables de entorno en el entorno en línea. Podemos distinguir diferentes entornos en función de estas dos variables y leer diferentes configuraciones. Creamos package/server
uno nuevo en el config
directorio del directorio y escribimos los siguientes tres archivos de código:
// 路径: package/server/config/dev.ts
import path from "path";
export const developmentConfig = {
staticFilePath: path.join(__dirname, "../../../output/client"),
};
// 路径: package/server/config/prod.ts
import path from "path";
export const productionConfig = {
staticFilePath: path.join(__dirname, "../client"),
};
// 路径: package/server/config/index.ts
import {
developmentConfig } from "./dev";
import {
productionConfig } from "./prod";
const env = process.env.NODE_ENV;
const getConfig = () => {
if (env === "dev") {
return developmentConfig;
}
return productionConfig;
};
export const config = getConfig();
Luego, usamos getConfig
la función para obtener la configuración correspondiente y asignarla staticFilePath
, tal como el comentario en el siguiente código:
// 路径: package/server/app.ts
import express from "express";
import {
getRouter } from "./router";
import {
config } from "./config";
import compression from "compression";
const main = async () => {
const app = express();
const port = 8081;
app.use(compression());
app.use("/static", express.static(config.staticFilePath)); // 这里直接使用了配置文件中对应的配置
app.use("/api", getRouter());
app.listen(port, () => {
console.log(`server started at http://localhost:${
port}`);
});
};
main();
4-5 Estructura de back-end
¡De esa manera el backend está hecho! La estructura general del directorio ahora es la siguiente:
.
├── output # 编译产物
├── package
│ ├── client # 前端代码
│ └── server # 后端代码
│ ├── app.ts
│ ├── config
│ │ ├── dev.ts
│ │ ├── index.ts
│ │ └── prod.ts
│ ├── controller
│ │ └── userController.ts
│ ├── db.ts
│ ├── router.ts
│ ├── service
│ │ └── userService.ts
│ └── tsconfig.json
├── package.json
└── tsconfig.json
Cinco, la parte delantera
Esta sección presentará paso a paso cómo usar vue3
y webpack
desarrollar una página de front-end que pueda extraer datos de la interfaz de back-end y mostrarlos.
5-1 Preparación para el desarrollo
El front-end primero ejecuta pnpm add vue@next @vue/compiler-sfc @vue/runtime-dom -D
el comando para instalar dependencias y las instala devDependencies
porque en realidad usamos archivos de recursos empaquetados al implementar, en lugar de depender directamente de ellos.
Después de instalar las dependencias, necesitamos hacer ajustes tsconfig.json
. Podemos package/client
crear un nivel de directorio en el directorio tsconfig.json
para controlar los archivos client
en el directorio typescript
. El contenido específico es el siguiente:
// 路径: package/client/tsconfig.json
{
"extends": "../../tsconfig.json", // 继承根目录的tsconfig
"compilerOptions": {
"outDir": "../../output/client", // 编译后的js文件地址
"moduleResolution": "node", // 模块解析策略
"esModuleInterop": true, // 支持按照es6模块规范导入commonjs模块
"target": "esnext", // 编译生成esnext规范的js代码
"module": "esnext" // 编译生成的代码使用什么模块化规范
},
"include": ["./**/*.ts", "./**/*.d.ts"],
"exclude": ["../../node_modules"]
}
Luego, package/client
creamos un nuevo archivo en el directorio index.html
, que es nuestro html
archivo de plantilla. Insertaremos el archivo de recursos empaquetado de acuerdo con la estructura de este archivo html
y generaremos el archivo final . El código específico es el siguiente:js
css
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title><%=htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="root"></div>
</body>
</html>
Al mismo tiempo, debido a que lo usamos typescript
para el desarrollo, debemos declarar manualmente vue
el tipo de archivo. Por lo tanto, debemos crear un nuevo package/client/type
directorio y crear un nuevo vue.d.ts
archivo de declaración en él. El contenido es el siguiente:
declare module "*.vue" {
import type {
DefineComponent } from "vue";
const component: DefineComponent<{
}, {
}, any>;
export default component;
}
Además, necesitamos crear un nuevo archivo y un nuevo archivo package/client
en el directorio . El primero es el punto de entrada de nuestro paquete, y el segundo es el componente raíz que queremos montar en él. El contenido específico se puede completar más adelante. .main.ts
app.vue
webpack
DOM
5-2 Configurar paquete web
Elegimos webpack
empaquetar los archivos de recursos en el proyecto front-end y también usarlo webpack-dev-server
como un servidor de actualización en caliente durante el desarrollo. Por lo tanto, también debemos configurarlo webpack
para cumplir con estos requisitos.
Primero usamos pnpm add webpack webpack-cli webpack-dev-server webpack-merge -D
el comando para instalar webpack
las dependencias relevantes.
Luego tenemos que seguir agregando algunas webpack
sumas para que podamos empaquetar el proyecto normalmente.El comando loader
específico plugin
para agregar dependencias es:pnpm add vue-loader@next css-loader html-webpack-plugin mini-css-extract-plugin postcss-loader ts-loader -D
Después de instalar las dependencias, package/client
cree un nuevo directorio en el directorio y cree tres nuevos archivos llamados (configuración básica), (configuración de desarrollo) y (configuración en línea) build
en este directorio . El contenido específico es el siguiente (el análisis de configuración puede ser se encuentra en las notas):webpack.base.js
webpack.dev.js
webpack.prod.js
// 路径: package/client/webpack.base.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const {
VueLoaderPlugin } = require("vue-loader");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: path.resolve(__dirname, "../main.ts"), // 打包文件入口
module: {
rules: [
// 解析css文件
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
"css-loader",
"postcss-loader",
],
},
// 解析ts文件
{
test: /\.ts$/,
loader: "ts-loader",
options: {
appendTsSuffixTo: [/\.vue$/],
configFile: "./tsconfig.json",
},
exclude: /node_modules/,
},
// 解析vue文件
{
test: /\.vue$/,
use: "vue-loader",
},
],
},
resolve: {
extensions: [".ts", ".js", ".vue", ".json"], // 要打包的文件后缀
alias: {
vue: "@vue/runtime-dom", // 模块名简称
},
},
plugins: [
// 将打包好的js文件插入html中
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../index.html"),
filename: "index.html",
title: "template-project",
}),
// 打包vue模板文件需要实例化一个VueLoaderPlugin
new VueLoaderPlugin(),
],
};
// 路径: package/client/webpack.dev.js
const {
merge } = require("webpack-merge");
const base = require("./webpack.base.js");
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// merge函数会将webpack基础配置和dev配置合到一起
module.exports = merge(base, {
mode: "development", // 开发模式
devtool: "inline-source-map",
output: {
filename: "js/[name].[fullhash].js", // 输出js文件名称
path: path.resolve(__dirname, "../../../output/client"), // 输出js文件路径
},
devServer: {
port: 8080, // devServer的端口
compress: true, // 是否压缩
proxy: {
context: ["/api", "/api"], target: "http://localhost:8081" }, // devServer的代理,会将请求代理到localhost:8081,也就是后端服务器上
},
plugins: [
// 单独打包css文件
new MiniCssExtractPlugin({
filename: "css/[name].css",
chunkFilename: "css/[id].css",
}),
],
});
// 路径: package/client/webpack.prod.js
const {
merge } = require("webpack-merge");
const base = require("./webpack.base.js");
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
// merge函数会将webpack基础配置和prod配置合到一起
module.exports = merge(base, {
mode: "production", // 开发模式
output: {
filename: "js/[name].[contenthash].js", // 输出js文件名称
path: path.resolve(__dirname, "../../../output/client"), // 输出js文件路径
},
plugins: [
// 单独打包css文件
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash].css",
chunkFilename: "css/[id].[contenthash].css",
}),
],
});
5-3 Desarrollar servicios front-end
El siguiente paso es desarrollar el servicio front-end.¿Recuerdas el archivo que acabamos de crear main.ts
? Escribimos la siguiente lógica en este archivo para montar el componente raíz en DOM
:
// 路径: package/client/main.ts
import {
createApp } from "vue";
import App from "./page/app.vue";
const app = createApp(App);
app.mount("#root");
Luego, podemos app.vue
escribir la lógica del componente en , la función de este componente es extraer la lista de usuarios del fondo y mostrarla.
En el componente, lo usamos axios
para iniciar http
una solicitud, por lo que debe ejecutarse primero pnpm add axios -D
para instalar las dependencias relevantes.
// 路径: package/client/app.vue
<template>
<div class="user">
<div v-for="(item, index) in userList" :key="`user-${index}`">
用户名: {
{
item.username }} 邮箱: {
{
item.email }}
</div>
</div>
</template>
<script lang="ts">
import {
onMounted, reactive, toRefs } from 'vue';
import axios from 'axios';
// 开发环境和线上环境的url不一样,通过环境变量进行区分
const DEV_BASE_URL = 'http://localhost:8081';
const PROD_BASE_URL = '';
const AXIOS_BASE_URL = process.env.NODE_ENV === 'dev' ? DEV_BASE_URL : PROD_BASE_URL;
export default {
setup() {
const data = reactive({
userList: []
});
onMounted(async () => {
const res = await http.get(`${
AXIOS_BASE_URL}/api/user`); // 使用axios发起请求
data.userList = res.data.data; // 把数据赋值给userList
});
return {
...toRefs(data) // 将userList变成reactive的,这样在模板中也可以访问了
};
}
};
</script>
<style scoped>
.user {
margin-top: 50px;
text-align: center;
}
</style>
5-4 Escribir secuencia de comandos npm
Después de escribir el código de front-end, también necesitamos hacer algo de trabajo para que la aplicación de front-end realmente se ejecute.
5-4-1.dev:comando cliente
Al desarrollar la página de inicio, necesitamos crear una webpack-dev-server
actualización activa, por lo que usamos webpack serve
el comando para iniciar dev-server
y establecer la ruta del archivo de configuración en ./package/client/build/webpack.dev.js
.
// 路径: package.json
"scripts": {
// ... 其他命令
"dev:client": "NODE_ENV=dev webpack serve --progress --hot --config ./package/client/build/webpack.dev.js",
},
5-4-2.dev:comando todo
Entonces, si queremos desarrollar el front-end y el back-end juntos, podemos ponerlos dev:server
y dev:client
ejecutarlos juntos
// 路径: package.json
"scripts": {
// ... 其他命令
"dev:all": "npm run dev:client & npm run dev:server",
},
5-4-1 Comando compilar:cliente
Al empaquetar, usamos webpack
comandos para empaquetar archivos y establecer la ruta del archivo de configuración en ./package/client/build/webpack.prod.js
.
// 路径: package.json
"scripts": {
// ... 其他命令
"build:client": "NODE_ENV=prod webpack --config ./package/client/build/webpack.prod.js"
},
5-4-2 Comando build:all
Del mismo modo, si queremos que el front-end y el back-end se empaqueten juntos, simplemente póngalos build:server
y build:client
ejecútelos juntos
// 路径: package.json
"scripts": {
// ... 其他命令
"build:all": "npm run clean && npm run build:client && npm run build:server",
},
5-5 Estructura frontal
¡De esta manera, nuestros códigos front-end y back-end están todos escritos! La estructura general del directorio ahora es la siguiente:
.
├── README.md
├── output # 打包产物
├── package
│ ├── client # 前端代码
│ │ ├── build # 打包配置
│ │ │ ├── webpack.base.js
│ │ │ ├── webpack.dev.js
│ │ │ └── webpack.prod.js
│ │ ├── index.html # html模板
│ │ ├── main.ts # 入口文件
│ │ ├── app.vue # 根组件
│ │ ├── tsconfig.json
│ │ └── type
│ │ ├── asset.d.ts
│ │ └── vue.d.ts
│ └── server # 后端代码
│ ├── app.ts
│ ├── config
│ │ ├── dev.ts
│ │ ├── index.ts
│ │ └── prod.ts
│ ├── controller
│ │ └── userController.ts
│ ├── db.ts
│ ├── router.ts
│ ├── service
│ │ └── userService.ts
│ └── tsconfig.json
├── package.json
└── tsconfig.json
5-6 Otros
Además, en el proyecto de plantilla real ( https://github.com/shadowings-zy/vue-express-ts-template-project ), hay vuex
una lógica de vue-router
carga de imágenes, puede mirar directamente el código.svg
6. Parte de despliegue
nodejs
Cuando queremos ejecutar el archivo compilado en el servidor javascrpit
, debemos usarlo pm2
para proteger el node
proceso, pm2
lo que proporciona muchas funciones, como ejecutar el proceso en segundo plano, reiniciarlo a tiempo cuando el proceso se cuelga, etc.
Luego primero ejecutamos pnpm add -g pm2
para instalarlo globalmente y luego escribimos el siguiente comando en package.json:
// 路径: package.json
"scripts": {
// ... 其他命令
"start": "NODE_ENV=prod pm2 start output/app.js"
},
De esta manera, primero ejecutamos pnpm run build:all
para generar los productos de compilación front-end y back-end en output
el directorio y luego ejecutamos pnpm run start
para iniciar node
el servicio que escribimos en el servidor.
¡Finalmente, ingrese en el navegador localhost:8081/static/index.html
para acceder a nuestros servicios y páginas!