Buen texto con diez mil palabras, te enseña cómo hacer un proyecto de plantilla full-stack "vue3+express+typescript"

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 typescriptse debe principalmente a que javascriptproporciona typescriptfunciones 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 vuexy vue-router) con él, y reacteste tipo de elección debe investigarse entre routervarios routerPor supuesto, al ajustar la configuración del paquete, podemos vuereemplazarlo 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 viteson principalmente para consideraciones de escalabilidad. Si desea vuecambiar sin problemas a otros marcos front-end, especialmente algunos marcos de nicho, entonces vitees 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 pnpmtiene una velocidad de instalación más rápida y node_modulesun 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 nodejsproceso daemon muy conveniente y también admite funciones como el reinicio automático, que es expressimprescindible para ejecutar servicios en el servidor.


3. Inicializar el proyecto

3-1, monorepo

En este proyecto de plantilla, administraremos monorepoel 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 packageeste. directorio , colóquelos respectivamente Código para frontend y backend.clientserver

3-2 Inicializar npm

Luego, ejecute npm initel 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 initel comando nuevamente para inicializar el repositorio de git.

3-4 Inicializar mecanografiado

Luego, ejecute pnpm add typescript -Del comando para instalar typescriptlas dependencias. tsconfig.jsonDespués de instalar las dependencias, creamos un nuevo archivo en el directorio raíz del proyecto , que se utiliza para la configuración.El typescriptcontenido 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 expressel comando para instalar expressy luego ejecuta pnpm add @types/expressel comando para instalar el archivo de declaración de tipo correspondiente.

Después de instalar las dependencias, necesitamos hacer ajustes tsconfig.json. Podemos package/servercrear un nivel de directorio en el directorio tsconfig.jsonpara controlar los archivos serveren 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.staticpara la carga de recursos estáticos, combinado con compressionla función gzip provista, para comprimir aún más el volumen del producto.
  • Úselo express.Routerpara enrutar la solicitud al correspondiente controllery manejarla.

4-2-1 Carga de recursos estáticos

Primero, package/servercreamos un nuevo app.tsarchivo en el directorio, que es expressel punto de entrada del proyecto, luego usamos compressionmiddleware y staticmiddleware, 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/serverun nuevo db.tsarchivo 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/servercreamos un nuevo directorio en el directorio , creamos un nuevo archivo serviceen el directorio y escribimos una clase para controlar la lógica relacionada con el usuario. El contenido específico es el siguiente:userService.tsUserService

// 路径: 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/servercreamos un nuevo directorio bajo el directorio , creamos un nuevo archivo controllerbajo el directorio , y escribimos una clase para controlar la lógica relacionada con la interfaz.El contenido específico es el siguiente:userController.tsUserController

// 路径: 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/serverun nuevo router.tsarchivo 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.tsregistramos 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-nodepara ejecutar directamente typescriptel archivo y luego usar nodemonpara detectar servercambios en el directorio y actualizarlo en caliente.

Luego primero ejecutamos pnpm add -g ts-node nodemonpara instalarlos globalmente, y luego package.jsonescribimos 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 nodemontodos 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/**/*.tsts-node ./package/server/app.tsapp.ts

De esta manera, pnpm run dev:serverpodemos localhost:8081iniciar 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 typescriptproporcionado tscpara typescriptcompilar el archivo en javascriptun archivo, es decir, el siguiente comando:

// 路径: package.json

"scripts": {
    
    
  // ... 其他命令
  "build:server": "NODE_ENV=prod tsc --p ./package/server",
},

Una de ellas --p ./package/serveres seleccionar ./package/serverel directorio para tsconfig.jsonla compilación, de modo que el archivo compilado se coloque en el directorio tsconfig.jsonespecificado enoutput

De esta forma, ejecutamos pnpm run build:serverpara 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 staticFilePathla variable que estaba vacía hace un momento? En nuestra secuencia de comandos de empaquetado frontal, los archivos empaquetados se colocarán output/clienten 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 devlas variables de entorno en el entorno de desarrollo y prodlas 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/serveruno nuevo en el configdirectorio 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 getConfigla 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 vue3y webpackdesarrollar 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 -Del comando para instalar dependencias y las instala devDependenciesporque 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/clientcrear un nivel de directorio en el directorio tsconfig.jsonpara controlar los archivos clienten 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/clientcreamos un nuevo archivo en el directorio index.html, que es nuestro htmlarchivo de plantilla. Insertaremos el archivo de recursos empaquetado de acuerdo con la estructura de este archivo htmly generaremos el archivo final . El código específico es el siguiente:jscsshtml

<!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 typescriptpara el desarrollo, debemos declarar manualmente vueel tipo de archivo. Por lo tanto, debemos crear un nuevo package/client/typedirectorio y crear un nuevo vue.d.tsarchivo 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/clienten 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.tsapp.vuewebpackDOM

5-2 Configurar paquete web

Elegimos webpackempaquetar los archivos de recursos en el proyecto front-end y también usarlo webpack-dev-servercomo un servidor de actualización en caliente durante el desarrollo. Por lo tanto, también debemos configurarlo webpackpara cumplir con estos requisitos.

Primero usamos pnpm add webpack webpack-cli webpack-dev-server webpack-merge -Del comando para instalar webpacklas dependencias relevantes.

Luego tenemos que seguir agregando algunas webpacksumas para que podamos empaquetar el proyecto normalmente.El comando loaderespecífico pluginpara 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/clientcree 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) builden este directorio . El contenido específico es el siguiente (el análisis de configuración puede ser se encuentra en las notas):webpack.base.jswebpack.dev.jswebpack.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.vueescribir 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 axiospara iniciar httpuna solicitud, por lo que debe ejecutarse primero pnpm add axios -Dpara 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-serveractualización activa, por lo que usamos webpack serveel comando para iniciar dev-servery 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:servery dev:clientejecutarlos juntos

// 路径: package.json

"scripts": {
    
    
  // ... 其他命令
  "dev:all": "npm run dev:client & npm run dev:server",
},

5-4-1 Comando compilar:cliente

Al empaquetar, usamos webpackcomandos 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:servery build:clientejecú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 vuexuna lógica de vue-routercarga de imágenes, puede mirar directamente el código.svg

6. Parte de despliegue

nodejsCuando queremos ejecutar el archivo compilado en el servidor javascrpit, debemos usarlo pm2para proteger el nodeproceso, pm2lo 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 pm2para 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:allpara generar los productos de compilación front-end y back-end en outputel directorio y luego ejecutamos pnpm run startpara iniciar nodeel servicio que escribimos en el servidor.

¡Finalmente, ingrese en el navegador localhost:8081/static/index.htmlpara acceder a nuestros servicios y páginas!
Por favor agregue una descripción de la imagen

Supongo que te gusta

Origin blog.csdn.net/u011748319/article/details/122058571
Recomendado
Clasificación