Vite & Webpack & Rollup 入口与产出配置与示例

对Vite v5.x、Webpack v5.x、Rollup v4.x三个主流前端构建工具,分别记录入口与产出的配置,并且给出与配置文件相对应的项目结构和构建后的示例文件内容。

备注:输出产物文件夹统一采用"构建工具名称+dist"命名,静态资源路径统一采用"构建工具名称+asset"命名。

一、Vite v5.x 配置与输出示例

1.1 核心配置文件(vite.config.js)

javascript 复制代码
import { defineConfig } from 'vite'
export default defineConfig({
  // 项目根目录配置(自定义为src目录)
  root: './src', // 自定义项目根目录为src,入口路径需基于此目录编写
  // 基础路径配置(自定义为子路径部署场景)
  base: '/vite-app/', // 自定义为子路径/vite-app/,适配生产环境部署到子目录的场景
  // 静态资源公共目录配置(publicDir)
  publicDir: '../vite-public', // 配置public目录为项目根目录下的vite-public,存放无需处理的静态资源
  // 打包配置
  build: {
    // 产出配置
    outDir: '../vite-dist', // 因root为src,需向上一级输出,保持工具名+dist规则
    assetsDir: 'vite-asset', // 静态资源路径:构建工具名称+asset
    assetsInlineLimit: 4096, // 小于4kb的静态资源内联,超过则输出到assetsDir
    rollupOptions: {
      // 明确入口文件配置(基于root:./src,路径简化)
      input: {
        main: './main.js', // 主入口,基于root:./src,实际路径为src/main.js
        subPage: './subPage.js' // 子入口,实际路径为src/subPage.js
      },
      // 多入口对应输出配置(可选,默认按入口名生成对应文件)
      output: {
        entryFileNames: 'vite-asset/js/[name]-[hash].js', // 入口JS输出路径及命名
        chunkFileNames: 'vite-asset/js/[name]-[hash].js', // 代码分割chunk输出路径及命名
        assetFileNames: 'vite-asset/[ext]/[name]-[hash].[ext]' // 静态资源(css、图片等)输出路径及命名
      }
    },
    sourcemap: false, // 是否生成sourcemap,生产环境建议关闭
    minify: 'esbuild' // 压缩工具,Vite默认使用esbuild,可替换为terser
  },
  ...
})

1.2 入口与产出配置说明

配置类型 具体配置项 配置值 说明
入口配置 主入口 ./main.js 基于root:./src,实际路径为src/main.js,负责初始化应用
子入口 ./subPage.js 基于root:./src,实际路径为src/subPage.js,多入口场景可独立打包
产出及基础配置 项目根目录(root) ./src 自定义为src目录,入口路径需基于此编写,简化入口路径写法
基础路径(base) /vite-app/ 自定义为子路径,适配生产环境部署到域名下/vite-app/子目录的场景,影响资源引用路径
静态资源公共目录(publicDir) ../vite-public 基于root:./src,实际路径为项目根目录下vite-public,存放无需处理的静态资源,打包时直接复制到产物根目录
产物根目录 ../vite-dist 因root为src,需向上一级输出,保持"工具名+dist"规则,实际位于项目根目录下
静态资源目录 vite-asset 存放JS、CSS、图片等经处理的静态资源,遵循"构建工具名称+asset"规则
入口JS输出路径 vite-asset/js/[name]-[hash].js [name]为入口名,[hash]为文件哈希值,用于缓存控制
chunk输出路径 vite-asset/js/[name]-[hash].js 代码分割后生成的公共模块或异步模块文件路径
其他静态资源路径 vite-asset/[ext]/[name]-[hash].[ext] [ext]为文件扩展名,按扩展名分类存放经处理的图片、CSS等资源

1.3 打包后文件内容示例

1.3.1 文件结构

Plain 复制代码
// 项目整体目录结构(体现root、publicDir与outDir关系)
project-root/          // 实际项目根目录
├── src/               // root配置指定的项目根目录
│   ├── main.js        // 主入口文件
│   ├── subPage.js     // 子入口文件
│   └── vite.config.js // Vite配置文件(因root为src,配置文件可放src内)
├── vite-public/       // publicDir配置指定的静态资源公共目录
│   ├── favicon.ico    // 网站图标(无需处理,打包直接复制)
│   └── static/        // 公共静态资源子目录
│       └── global.css // 全局静态CSS(无需构建工具处理)
└── vite-dist/         // 产物根目录,由outDir:../vite-dist生成
    ├── index.html     // 主入口对应的HTML文件
    ├── subPage.html   // 子入口对应的HTML文件
    ├── favicon.ico    // 从vite-public复制过来的网站图标
    ├── static/        // 从vite-public复制过来的静态资源子目录
    │   └── global.css // 从vite-public复制过来的全局CSS
    └── vite-asset/    // 经构建工具处理后的静态资源目录
        ├── js/        // JS文件目录
        │   ├── main-8f7d2b.js      // 主入口JS文件(哈希值示例)
        │   ├── subPage-3e5a1c.js   // 子入口JS文件(哈希值示例)
        │   └── vendor-7b9c4d.js    // 公共依赖chunk(如Vue框架)
        ├── css/       // CSS文件目录
        │   ├── main-5d8f3e.css     // 主入口对应的CSS文件
        │   └── subPage-2a4c6b.css  // 子入口对应的CSS文件
        └── img/       // 图片资源目录
            └── logo-9a3b5d.png     // 图片资源文件(哈希值示例,经处理后输出)

1.3.2 关键文件内容示例

1. vite-dist/index.html

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vite 主入口页面</title>
  <link rel="icon" href="/vite-app/favicon.ico"> 
  <link rel="stylesheet" href="/vite-app/static/global.css"> 
  <!-- 资源引用路径前缀为base配置的/vite-app/,经处理的CSS在vite-asset下 -->
  <link rel="stylesheet" href="/vite-app/vite-asset/css/main-5d8f3e.css">
</head>
<body>
  <div id="app"></div>
  <!-- 脚本引用路径同样添加base前缀,经处理的JS在vite-asset下 -->
  <script type="module" src="/vite-app/vite-asset/js/vendor-7b9c4d.js"></script>
  <script type="module" src="/vite-app/vite-asset/js/main-8f7d2b.js"></script>
</body>
</html>

2. vite-dist/vite-asset/js/main-8f7d2b.js(简化版)

javascript 复制代码
import { createApp } from './vendor-7b9c4d.js';
import App from './App.vue';
createApp(App).mount('#app');
// 业务逻辑代码(已压缩,此处为简化展示)
console.log('Vite 主入口应用启动');

二、Webpack v5.x 配置与输出示例

2.1 核心配置文件(webpack.config.js)

javascript 复制代码
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 生成HTML文件的插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 提取CSS为单独文件的插件

module.exports = {
  // 项目根目录配置
  context: path.resolve(__dirname, 'src'), // 自定义根目录为src,入口路径基于此编写
  // 入口配置(基于context:src,路径简化)
  entry: {
    main: './main.js', // 主入口,基于context:src,实际路径为src/main.js
    subPage: './subPage.js' // 子入口,实际路径为src/subPage.js
  },
  // 产出配置
  output: {
    path: path.resolve(__dirname, 'webpack-dist'), // 输出产物文件夹:构建工具名称+dist
    filename: 'webpack-asset/js/[name]-[contenthash].js', // 入口JS输出路径及命名
    chunkFilename: 'webpack-asset/js/[name]-[contenthash].chunk.js', // 代码分割chunk输出路径
    assetModuleFilename: 'webpack-asset/[ext]/[name]-[contenthash].[ext]', // 静态资源输出路径
    publicPath: '/webpack-app/', // 基础路径,适配子路径部署
    clean: true // 打包前清理输出目录
  },
  // 模块解析规则
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'], // 提取CSS为单独文件
      },
      {
        test: /\.(png|svg|jpg|jpeg|gif)$/i,
        type: 'asset', // 自动判断是否内联或输出为文件
        parser: {
          dataUrlCondition: {
            maxSize: 4 * 1024 // 4kb以下内联,超过输出到静态资源目录
          }
        }
      },
      {
        test: /\.m?js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader', // 转译ES6+语法
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  },
  // 插件配置
  plugins: [
    // 为每个入口生成对应的HTML文件
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: path.resolve(__dirname, 'public/index.html'), // 模板路径需补全根目录
      chunks: ['main', 'vendor'] // 引入主入口JS和公共依赖chunk
    }),
    new HtmlWebpackPlugin({
      filename: 'subPage.html',
      template: path.resolve(__dirname, 'public/subPage.html'), // 模板路径需补全根目录
      chunks: ['subPage', 'vendor'] // 引入子入口JS和公共依赖chunk
    }),
    // 配置CSS输出路径
    new MiniCssExtractPlugin({
      filename: 'webpack-asset/css/[name]-[contenthash].css',
      chunkFilename: 'webpack-asset/css/[name]-[contenthash].chunk.css'
    })
  ],
  // 代码分割配置
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendor', // 公共依赖chunk名称
          priority: -10 // 优先级,多个缓存组规则冲突时,按优先级决定模块归属
        }
      }
    },
    runtimeChunk: 'single' // 提取运行时代码,优化缓存
  },
  mode: 'production' // 生产环境模式(自动开启压缩等优化)
};

2.2 入口与产出配置说明

配置类型 具体配置项 配置值 说明
入口配置 主入口 ./main.js 基于context:src,实际路径为src/main.js,负责初始化应用
子入口 ./subPage.js 基于context:src,实际路径为src/subPage.js,多入口场景可独立打包
产出及基础配置 项目根目录(context) path.resolve(__dirname, 'src') 类似Vite的root,自定义根目录为src,入口路径基于此编写
基础路径(publicPath) /webpack-app/ 类似Vite的base,适配子路径部署,自动为资源添加路径前缀
产物根目录 webpack-dist 打包后所有文件的根文件夹,遵循"构建工具名称+dist"规则
静态资源根目录 webpack-asset 存放JS、CSS、图片等静态资源,遵循"构建工具名称+asset"规则
入口JS输出路径 webpack-asset/js/[name]-[contenthash].js [name]为入口名,[contenthash]为内容哈希值,用于长效缓存
chunk输出路径 webpack-asset/js/[name]-[contenthash].chunk.js 代码分割后生成的公共模块(如vendor)或异步模块文件路径
图片等资源输出路径 webpack-asset/[ext]/[name]-[contenthash].[ext] [ext]为文件扩展名,按扩展名分类存放静态资源

2.3 打包后文件内容示例

2.3.1 文件结构

Plain 复制代码
// 项目整体目录结构(体现context与output.path关系)
project-root/          // 实际项目根目录
├── src/               // context配置指定的项目根目录
│   ├── main.js        // 主入口文件(基于context简化路径)
│   ├── subPage.js     // 子入口文件
│   └── webpack.config.js // Webpack配置文件(可放项目根目录,需补全路径)
├── public/            // 静态模板目录
│   ├── index.html     // 主入口HTML模板
│   └── subPage.html   // 子入口HTML模板
└── webpack-dist/      // 产物根目录,由output.path生成
    ├── index.html     // 主入口对应的HTML文件
    ├── subPage.html   // 子入口对应的HTML文件
    ├── webpack-asset/ // 静态资源目录
    │   ├── js/        // JS文件目录
    │   │   ├── main-9f2d7b.contenthash.js       // 主入口JS文件
    │   │   ├── subPage-4e6a3c.contenthash.js    // 子入口JS文件
    │   │   ├── vendor-8b7c5d.contenthash.js     // 公共依赖chunk(如第三方库)
    │   │   └── runtime-main.contenthash.js      // 运行时代码chunk
    │   ├── css/       // CSS文件目录
    │   │   ├── main-6d9f4e.contenthash.css      // 主入口对应的CSS文件
    │   │   └── subPage-3a5c7b.contenthash.css   // 子入口对应的CSS文件
    │   └── png/       // 图片资源目录(按扩展名分类)
    │       └── logo-7a4b6d.contenthash.png      // 图片资源文件
    └── favicon.ico    // 从public目录复制的静态文件(若有)

2.3.2 关键文件内容示例

1. webpack-dist/index.html

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Webpack 主入口页面</title>
  <!-- 资源路径自动添加publicPath前缀/webpack-app/ -->
  <link href="/webpack-app/webpack-asset/css/main-6d9f4e.contenthash.css" rel="stylesheet">
</head>
<body>
  <div id="app"></div>
  <script src="/webpack-app/webpack-asset/js/runtime-main.contenthash.js"></script>
  <script src="/webpack-app/webpack-asset/js/vendor-8b7c5d.contenthash.js"></script>
  <script src="/webpack-app/webpack-asset/js/main-9f2d7b.contenthash.js"></script>
</body>
</html>

2. webpack-dist/webpack-asset/js/main-9f2d7b.contenthash.js(简化版)

javascript 复制代码
"use strict";
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
// 引入依赖和业务代码
const App = require('./App.js');
App.init('#app');
console.log('Webpack 主入口应用启动');
},{'./App.js':2}]},{},[1]);

三、Rollup v4.x 配置与输出示例

3.1 核心配置文件(rollup.config.js)

javascript 复制代码
import { defineConfig } from 'rollup';
import babel from '@rollup/plugin-babel'; // 转译ES6+语法
import resolve from '@rollup/plugin-node-resolve'; // 解析第三方模块
import commonjs from '@rollup/plugin-commonjs'; // 转换CommonJS模块为ES模块
import css from 'rollup-plugin-css-only'; // 处理CSS文件
import html from '@rollup/plugin-html'; // 生成HTML文件
import image from '@rollup/plugin-image'; // 处理图片资源
import { terser } from 'rollup-plugin-terser'; // 压缩JS代码
import hash from 'rollup-plugin-hash'; // 生成文件哈希值
import path from 'path';

export default defineConfig({
  // 项目根目录配置,rollup需要通过插件配置
  plugins: [
    // 配置根目录为src,解析模块时优先从src查找
    resolve({
      rootDir: path.resolve(__dirname, 'src'),
      moduleDirectories: [path.resolve(__dirname, 'src')]
    }),
    // 转换CommonJS模块为ES模块
    commonjs(),
    // 转译ES6+语法
    babel({
      exclude: 'node_modules/**',
      presets: ['@babel/preset-env']
    }),
    // 处理CSS文件,提取为单独文件
    css({
      output: 'rollup-asset/css/[name]-[hash].css'
    }),
    // 处理图片资源,小图片内联为base64,大图片输出为文件
    image({
      limit: 4 * 1024 // 4kb以下内联
    }),
    // 生成HTML文件,自动引入打包后的资源(配置base路径)
    html({
      fileName: ({ name }) => `${name}.html`, // 为每个入口生成对应HTML
      publicPath: '/rollup-app/', // 基础路径(类似Vite的base),适配子路径部署
      template: ({ attributes, bundle, files, publicPath, title }) => {
        const jsFiles = files.js.filter(file => file.name === title.toLowerCase());
        const cssFiles = files.css.filter(file => file.name === title.toLowerCase());
        return `
          <!DOCTYPE html>
          <html>
          <head>
            <meta charset="utf-8">
            <title>${title}</title>
            ${cssFiles.map(file => `<link rel="stylesheet" href="${publicPath}${file.fileName}">`).join('')}
          </head>
          <body>
            <div id="app"></div>
            ${jsFiles.map(file => `<script type="module" src="${publicPath}${file.fileName}"></script>`).join('')}
          </body>
          </html>
        `;
      },
      title: ({ name }) => `Rollup ${name.charAt(0).toUpperCase() + name.slice(1)} Page`
    }),
    // 生成文件哈希值,用于缓存控制
    hash({
      dest: 'rollup-dist',
      hashLength: 8 // 哈希值长度
    }),
    // 生产环境压缩JS代码
    terser()
  ],
  // 入口配置(基于rootDir:src,路径简化)
  input: {
    main: './main.js', // 主入口,基于rootDir:src,实际路径为src/main.js
    subPage: './subPage.js' // 子入口,实际路径为src/subPage.js
  },
  // 产出配置(多入口时可配置多个输出)
  output: [
    {
      dir: '../rollup-dist', // 因rootDir为src,需向上一级输出,保持工具名+dist规则
      format: 'esm', // 输出为ES模块格式
      entryFileNames: 'rollup-asset/js/[name]-[hash].js', // 入口JS输出路径
      chunkFileNames: 'rollup-asset/js/[name]-[hash].chunk.js', // 代码分割chunk路径
      assetFileNames: 'rollup-asset/[extname]/[name]-[hash][extname]', // 静态资源路径
      sourcemap: false
    }
  ],
  // 代码分割配置
  preserveModules: false, // 关闭保留模块结构,合并相关模块
});

3.2 入口与产出配置说明

配置类型 具体配置项 配置值 说明
入口配置 主入口 ./main.js 基于rootDir:src,实际路径为src/main.js,负责初始化应用
子入口 ./subPage.js 基于rootDir:src,实际路径为src/subPage.js,独立生成对应文件
产出及基础配置 项目根目录(rootDir) path.resolve(__dirname, 'src') 类似Vite的root,通过resolve插件配置,入口路径基于此简化
基础路径(publicPath) /rollup-app/ 类似Vite的base,在html插件中配置,为资源引用添加路径前缀
产物根目录 ../rollup-dist 因rootDir为src,向上一级输出,实际位于项目根目录,遵循工具名+dist规则
静态资源根目录 rollup-asset 存放JS、CSS、图片等静态资源,遵循"构建工具名称+asset"规则
入口JS输出路径 rollup-asset/js/[name]-[hash].js [name]为入口名,[hash]为文件哈希值,输出为ES模块格式
CSS输出路径 rollup-asset/css/[name]-[hash].css 通过rollup-plugin-css-only提取的单独CSS文件路径

3.3 打包后文件内容示例

3.3.1 文件结构

Plain 复制代码
// 项目整体目录结构(体现rootDir与output.dir关系)
project-root/          // 实际项目根目录
├── src/               // rootDir配置指定的项目根目录
│   ├── main.js        // 主入口文件(基于rootDir简化路径)
│   ├── subPage.js     // 子入口文件
│   └── rollup.config.js // Rollup配置文件(放src内,需适配根目录)
└── rollup-dist/       // 产物根目录,由output.dir:../rollup-dist生成
    ├── main.html      // 主入口对应的HTML文件
    ├── subPage.html   // 子入口对应的HTML文件
    ├── manifest.json  // 哈希值映射表(记录原文件名与哈希文件名的对应关系)
    └── rollup-asset/  // 静态资源目录
        ├── js/        // JS文件目录
        │   ├── main-7d2f9b.js      // 主入口JS文件(哈希值示例)
        │   ├── subPage-3c5a1e.js   // 子入口JS文件(哈希值示例)
        │   └── common-5b7c4d.js    // 公共模块chunk(代码分割生成)
        ├── css/       // CSS文件目录
        │   ├── main-4f8d3e.css     // 主入口对应的CSS文件
        │   └── subPage-2b6c5a.css  // 子入口对应的CSS文件
        └── png/       // 图片资源目录(按扩展名分类)
            └── logo-6d3b5a.png     // 图片资源文件(哈希值示例,超过4kb时输出)

3.3.2 关键文件内容示例

1. rollup-dist/main.html

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Rollup Main Page</title>
  <!-- 资源引用路径添加publicPath前缀/rollup-app/ -->
  <link rel="stylesheet" href="/rollup-app/rollup-asset/css/main-4f8d3e.css">
</head>
<body>
  <div id="app"></div>
  <script type="module" src="/rollup-app/rollup-asset/js/common-5b7c4d.js"></script>
  <script type="module" src="/rollup-app/rollup-asset/js/main-7d2f9b.js"></script>
</body>
</html>

2. rollup-dist/rollup-asset/js/main-7d2f9b.js(简化版)

javascript 复制代码
import { commonFunc } from './common-5b7c4d.js';

class App {
  init(el) {
    this.el = document.querySelector(el);
    commonFunc();
    this.render();
  }
  render() {
    this.el.innerHTML = '<h1>Rollup 应用</h1>';
  }
}

new App().init('#app');
console.log('Rollup 主入口应用启动');

四、构建工具共性配置

4.1 共性配置(功能对标)

三大工具虽配置名称或实现方式不同,但核心功能存在明确对标关系,均围绕"入口管理、资源处理、产出控制、环境适配"四大核心场景设计,具体对标如下:

功能场景 Vite v5.x Webpack v5.x Rollup v4.x 功能共性说明
项目根目录 root context resolve.rootDir(插件配置) 定义项目基准目录,简化入口及模块引用路径,统一资源查找根节点
部署基础路径 base output.publicPath html.publicPath(插件配置) 适配子路径部署场景,为所有资源引用添加统一路径前缀,避免404错误
静态资源公共目录 publicDir(原生) copy-webpack-plugin(插件) rollup-plugin-copy(插件) 存放无需构建处理的静态资源(如favicon、全局静态CSS),打包时直接复制到产物根目录
入口配置 build.rollupOptions.input entry input 支持单入口/多入口配置,指定应用启动的核心文件路径,多入口时可独立生成产物
产物输出目录 build.outDir output.path output.dir 指定打包后产物的存放目录,均支持自定义路径
静态资源输出路径 build.assetsDir + 输出规则 output.assetModuleFilename output.assetFileNames 指定JS、CSS、图片等经处理资源的输出路径及命名规则,支持哈希值优化缓存
代码分割 build.rollupOptions.output.chunkFileNames optimization.splitChunks output.chunkFileNames 拆分公共依赖(如第三方库)或异步模块,减少重复代码,提升首屏加载速度
压缩优化 build.minify(esbuild/terser) mode: production(自动压缩) rollup-plugin-terser(插件) 生产环境压缩JS/CSS代码,移除空格、注释,降低产物体积

总结

  1. Vite:顶层配置简洁直观,原生集成开发/预览服务器,开发启动速度快,适合前端应用快速开发;
  2. Webpack:配置灵活全面,loader+插件生态丰富,支持复杂模块解析和场景适配,适合大型复杂项目;
  3. Rollup:专注ES模块打包,支持多格式输出,产物轻量无冗余,适合类库或轻量应用开发。

实际项目中可根据项目类型(应用/类库)、复杂度及团队熟悉度选择:前端应用优先选Vite,大型复杂项目选Webpack,类库开发选Rollup。

相关推荐
用户90443816324603 小时前
React 5 个 “隐形坑”:上线前没注意,debug 到凌晨 3 点
前端·javascript·react.js
StarkCoder3 小时前
打造炫酷浮动式 TabBar:让 iOS 应用导航更有格调!
前端·ios
AAA阿giao3 小时前
Promise:让 JavaScript 异步任务“同步化”的利器
前端·javascript·promise
光影少年3 小时前
vite7更新了哪些内容
前端
六月的可乐3 小时前
前端自定义右键菜单与图片复制(兼容H5)
前端
浮游本尊4 小时前
React 18.x 学习计划 - 第八天:React测试
前端·学习·react.js
麦麦在写代码4 小时前
前端学习1
前端·学习
sg_knight4 小时前
微信小程序中 WebView 组件的使用与应用场景
前端·javascript·微信·微信小程序·小程序·web·weapp
凯子坚持 c5 小时前
生产级 Rust Web 应用架构:使用 Axum 实现模块化设计与健壮的错误处理
前端·架构·rust