本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Vue.js 2.0作为主流前端框架,通过Vue CLI和Webpack支持高效构建多页面应用。本项目“vue20模板支持多页面”提供完整的多页面解决方案,涵盖环境配置、多入口打包、公共资源管理及跨环境变量控制,适用于大型模块化项目开发。开发者可通过该模板实现开发、测试、生产环境的分离,并利用热更新与Vue DevTools提升调试效率,显著提升项目可维护性与构建灵活性。

Vue 2.0 多页面应用的工程化实践:从架构设计到自动化部署

前端工程走到今天,已经不再是简单地写几个组件、搭个路由就能应付得了的活儿了。尤其当你面对的是一个中后台系统——登录页、控制台、报表中心、用户管理……这些页面不仅功能独立,访问路径不同,权限逻辑各异,甚至背后的微服务都不一样。这时候你还用单页应用(SPA)那一套?可能刚上线一个月,打包体积就突破10MB,首屏加载慢得像老牛拉车 🐮。

于是,越来越多团队开始重新审视 多页面应用(MPA) 的价值。

没错,Vue 官方主推的是 SPA,但别忘了它底层是基于 Webpack 构建的。而 Webpack 最擅长什么?就是灵活配置入口和输出!只要我们愿意深入一点,完全可以用 Vue 2.0 搭出一套高效、可维护、性能优越的 MPA 架构。

这不是“复古”,而是 理性回归 :把复杂问题拆解成一个个小而美的模块,各自独立又协同工作。就像一座城市里不同的街区,每条街有自己的风格与节奏,但共享同一套交通网络和基础设施。


多页面架构的本质:解耦 + 自治

先来聊聊为什么我们会需要 MPA。

SPA 的瓶颈你真的避不开吗?

在 SPA 中,所有页面共用一个 HTML 文件,通过 Vue Router 实现视图切换。这种模式对用户体验确实友好——无刷新跳转、状态保留、动画流畅。但代价也很明显:

  • 首包过大 :所有路由组件被打包进一个 bundle,哪怕用户只看登录页也得下完整资源;
  • 内存累积 :页面间切换不销毁实例,长时间运行容易内存泄漏;
  • SEO 不友好 :搜索引擎爬虫难以抓取动态内容;
  • 权限控制粒度粗 :登录后才能判断能否访问某页面,无法做到服务端直出拦截;
  • 构建慢、调试难 :改一行代码热更新要等十几秒,开发体验打折。

反观 MPA 呢?

每个页面都是独立的 index.html + main.js ,天然具备:
- 更好的 性能隔离
- 更清晰的 模块边界
- 更优的 SEO 支持
- 更细的 部署粒度

比如你想只发布“报表中心”这个功能,不需要重新构建整个项目;再比如你可以为登录页单独启用 PWA,其他页面保持传统模式——灵活性直接拉满!

那 Vue CLI 能支持 MPA 吗?

当然能!虽然 Vue CLI 默认生成的是 SPA 结构,但它本质上是对 Webpack 的封装。只要你懂 entry HtmlWebpackPlugin ,就能轻松实现多入口构建。

关键就在于: 入口文件与 HTML 模板的一一映射关系


目录结构怎么组织才够“工程化”?

很多人一开始做 MPA,就是复制粘贴一堆 main.js index.html ,结果越往后越乱。所以我们必须从一开始就建立规范。

推荐如下目录结构:

src/
├── pages/
│   ├── login/
│   │   ├── main.js
│   │   ├── App.vue
│   │   └── index.html
│   ├── dashboard/
│   │   ├── main.js
│   │   ├── App.vue
│   │   └── index.html
│   └── report/
│       ├── main.js
│   │   ├── App.vue
│   │   └── index.html
├── components/
│   └── common/
├── utils/
├── assets/
└── plugins/  # 全局插件集中管理

看到没?核心是 pages 目录。每一个子目录代表一个完整的页面单元,包含自己的入口、根组件和模板。这样做的好处简直太多了👇

职责分明 :新人进来一眼就知道某个功能在哪
构建友好 :便于脚本自动扫描入口
部署灵活 :可以按需打包某个页面
SEO 友好 :每个页面可自定义 <title> <meta>

公共部分统一放在 components/common utils 下,供各页面按需引入。如果某些逻辑跨页面复用频繁,还可以封装成 Vue 插件或 Mixin,后面会详细讲。


入口文件是怎么跑起来的?

来看看最基础的一个页面是如何启动的。

login/main.js 为例:

// src/pages/login/main.js
import Vue from 'vue';
import App from './App.vue';

new Vue({
  render: h => h(App),
}).$mount('#app');

对应模板:

<!-- src/pages/login/index.html -->
<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8" />
  <title>用户登录</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
</head>
<body>
  <div id="app"></div>
</body>
</html>

这段代码熟悉吧?和 SPA 的 main.js 几乎一模一样。唯一的区别在于: 它是孤立存在的 ,不会和其他页面产生依赖纠缠。

Webpack 在构建时,需要确保这个 main.js 编译后的 JS 被正确注入到对应的 HTML 中。这事谁干? HTMLWebpackPlugin

而且必须是一对一的关系:

入口文件 对应模板
src/pages/dashboard/main.js src/pages/dashboard/index.html
src/pages/report/main.js src/pages/report/index.html

这就要求我们在 Webpack 配置中,为每个页面创建独立的 entry HtmlWebpackPlugin 实例。手动写?那肯定不行,页面一多就炸了 💣。

所以我们要搞自动化!


如何让 Webpack 自动发现所有页面入口?

目标很明确: 新增一个页面,只需加个目录,无需改任何构建配置

怎么做?Node.js + glob 来帮忙!

先装个依赖:

npm install glob --save-dev

然后写个工具函数:

// build/utils.js
const path = require('path');
const glob = require('glob');

exports.getEntries = (pattern) => {
  const entries = {};
  const files = glob.sync(pattern);

  files.forEach(file => {
    const dirName = path.basename(path.dirname(file)); // 提取目录名作为key
    entries[dirName] = path.resolve(__dirname, '../', file);
  });

  return entries;
};

调用一下试试:

const { getEntries } = require('./build/utils');
const pages = getEntries('src/pages/*/main.js');

console.log(pages);
// 输出示例:
// {
//   login: '/project/src/pages/login/main.js',
//   dashboard: '/project/src/pages/dashboard/main.js'
// }

完美!现在不管你在 pages/ 下建多少个子目录,只要符合 */main.js 规则,都会被自动识别出来。

接下来,把这个结果塞进 Webpack 配置里:

// webpack.config.js
const { getEntries } = require('./build/utils');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

const entries = getEntries('src/pages/*/main.js');

module.exports = {
  entry: entries,
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].[contenthash:8].js',
    chunkFilename: 'js/[name].[contenthash:8].chunk.js'
  },
  plugins: Object.keys(entries).map(pageName => {
    return new HtmlWebpackPlugin({
      filename: `${pageName}.html`,
      template: `src/pages/${pageName}/index.html`,
      chunks: [pageName] // 仅注入当前页面的chunk
    });
  })
};

就这么几行代码,实现了:
- 自动注册多个入口 ✅
- 自动生成 HTML 文件 ✅
- 精准资源注入 ✅
- 构建产物带哈希防缓存 ✅

是不是比一个个手写爽多了?😎


页面内部还要不要用 Vue Router?

有人问:“我都 MPA 了,还用路由干嘛?”

其实不然。MPA 解决的是 页面级跳转 的问题,但一个页面内部也可能有局部导航需求,比如:

  • 控制台里的 Tab 切换(列表 / 图表 / 设置)
  • 表单分步引导(第一步填信息 → 第二步确认)
  • 弹窗式流程(点击按钮打开新“页面”)

这时候就需要用到 Vue Router 了。那么问题来了:选 hash 还是 history 模式?

模式 特点 推荐场景
hash 模式 URL 带 # ,如 /dashboard.html#/list ,不向服务器请求 静态托管、CDN 部署、免配置
history 模式 URL 更干净,如 /dashboard/list ,但需服务器支持回退 有 Nginx/Apache 配置权,追求极致体验

在 MPA 环境下,我强烈建议优先使用 hash 模式,理由很简单:

  1. 部署简单 :不用配 try_files 或重定向规则;
  2. 容错性强 :用户刷新页面不会 404;
  3. 职责清晰 :外部跳转靠 HTML,内部跳转靠 hash,互不干扰。

当然,如果你公司 CI/CD 很成熟,服务器也能配合,那对特定页面开启 history 也不是不行。例如:

// src/pages/dashboard/router/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import ListView from '../views/List.vue';

Vue.use(VueRouter);

const router = new VueRouter({
  mode: 'history',
  base: '/dashboard/', // 匹配输出路径
  routes: [
    { path: '/list', component: ListView }
  ]
});

export default router;

同时配 Nginx:

location /dashboard/ {
  try_files $uri $uri/ /dashboard/index.html;
}

这样一来,访问 /dashboard/list 就能正确加载资源。不过记住:这是“加分项”,不是“必选项”。大多数情况下, hash 就够用了。


输出结构怎么安排才利于维护?

构建产物不能乱七八糟扔一起,否则后期查问题都找不到源头。

建议采用分类输出策略:

output: {
  path: path.resolve(__dirname, 'dist'),
  filename: 'assets/js/[name].[contenthash:8].js',
  chunkFilename: 'assets/js/[name].[contenthash:8].chunk.js',
  assetModuleFilename: 'assets/media/[name].[hash:6][ext]',
  clean: true // 构建前清空 dist
}

解释一下:
- filename : 主入口文件输出格式
- chunkFilename : 动态导入的 chunk(懒加载组件)
- assetModuleFilename : 图片、字体等静态资源
- 加上 clean: true ,避免旧文件残留

另外,通过 publicPath 控制资源引用前缀也很重要:

output: {
  publicPath: process.env.NODE_ENV === 'production' ? '//cdn.example.com/' : '/'
}

上线时一键切换 CDN 地址,提升加载速度,还能实现灰度发布。👏


如何用 HtmlWebpackPlugin 实现高级定制?

HtmlWebpackPlugin 不只是生成 HTML,它还能玩出很多花样。

给每个页面设置不同的标题和图标

想让登录页显示“请登录”,控制台显示“数据总览”?没问题!

先改模板,支持变量传参:

<!-- src/pages/login/index.html -->
<title><%= htmlWebpackPlugin.options.title %></title>
<link rel="icon" href="<%= htmlWebpackPlugin.options.favicon %>"/>

然后在插件配置中传值:

new HtmlWebpackPlugin({
  filename: 'login.html',
  template: 'src/pages/login/index.html',
  chunks: ['login'],
  title: '用户登录 - 后台系统',
  favicon: 'favicon-login.ico'
})

更进一步,你可以把这些元信息抽成一个 JSON 配置文件,动态读取:

// config/pages.json
{
  "login": {
    "title": "用户登录",
    "favicon": "login.ico"
  },
  "dashboard": {
    "title": "控制台",
    "favicon": "dashboard.ico"
  }
}

再写个函数合并进去,彻底解放双手~

公共资源如何提取并去重?

多个页面都用了 Vue、Axios、Lodash 怎么办?难道每个都打包一遍?

当然不行!我们可以用 SplitChunksPlugin 抽出公共库:

optimization: {
  splitChunks: {
    cacheGroups: {
      vendor: {
        test: /[\\/]node_modules[\\/]/,
        name: 'vendors',
        chunks: 'all',
        enforce: true
      }
    }
  }
}

然后在 HtmlWebpackPlugin 中显式注入:

chunks: [pageName, 'vendors']

注意加上 excludeChunks: ['vendors'] 到其他非必要页面,防止误注入。

最终效果:所有页面共享一份 vendors.js ,浏览器缓存一次,处处受益。🚀

下面这张流程图展示了整个构建过程的全貌:

graph TD
    A[扫描 src/pages/*] --> B[发现 main.js 入口]
    B --> C[生成 entry 对象]
    C --> D[Webpack 多入口编译]
    D --> E[输出 js/[name].js]
    D --> F[输出 css/[name].css]
    E --> G[HtmlWebpackPlugin 生成 HTML]
    F --> G
    G --> H[注入对应资源]
    H --> I[输出 dist/login.html]
    H --> J[输出 dist/dashboard.html]
    H --> K[输出 dist/report.html]

是不是感觉整个体系瞬间清晰起来了?

为了方便查阅,这里整理了一个常用配置对照表:

配置项 作用 示例值
filename 输出的 HTML 文件名 'login.html'
template 模板文件路径 'src/pages/login/index.html'
chunks 指定注入的 chunk ['login']
minify 是否压缩 HTML true in production
inject 脚本注入位置 'body'

公共逻辑怎么复用才不重复造轮子?

随着页面增多,你会发现很多代码都在重复出现:权限校验、日期格式化、通用弹窗……怎么办?

别急,我们有一整套“三层治理体系”:

  1. 代码级复用 :组件、mixin、plugin
  2. 构建级优化 :externals、DLL、SplitChunks
  3. 配置级管理 :.env + config 文件夹 + 自定义插件

层层递进,稳得很!

工具函数 & 通用组件:统一 import 即可

最简单的复用方式,就是把通用逻辑提成模块:

// src/utils/auth.js
export const hasPermission = (role, requiredRole) => role === requiredRole;

export const getToken = () => localStorage.getItem('token');

任一页都能引入:

import { getToken } from '@/utils/auth';
axios.defaults.headers.common['Authorization'] = `Bearer ${getToken()}`;

记得配好 @ 别名,否则 ESLint 会报错哦~

不同类型复用方式对比:

方案 优点 缺点 适用场景
单独 import 易调试,按需加载 初次打包无法自动去重 工具函数、小型组件
全局注册 一次注册处处可用 增加内存占用 通用 UI 组件(Button、Modal)
动态导入 支持懒加载 增加网络请求 非核心功能模块

流程图帮你理清思路:

graph TD
    A[入口文件 main.js] --> B{是否使用全局组件?}
    B -->|是| C[Vue.component 注册]
    B -->|否| D[局部 import 使用]
    C --> E[所有页面均可调用]
    D --> F[仅当前页面可用]
    E --> G[构建时合并到 bundle]
    F --> G

跨页面行为复用:Mixin 还是 Plugin?

当多个页面都有 loading 状态、埋点逻辑、权限指令时,就得考虑更高阶的抽象了。

Mixin 示例:统一 loading 控制
// src/mixins/loading.js
export default {
  data() {
    return {
      loading: false,
    };
  },
  methods: {
    startLoading() { this.loading = true; },
    stopLoading() { this.loading = false; }
  },
  created() {
    this.$emit('page-created', this.$options.name);
  }
};

混入页面即可获得能力:

import loadingMixin from '@/mixins/loading';

new Vue({
  mixins: [loadingMixin],
  name: 'DashboardPage'
}).$mount('#app');

但 Mixin 有个致命缺点: 命名冲突风险高 ,且逻辑隐式传递,后期难维护。

所以更推荐使用 Vue 插件模式

Plugin 示例:注册全局指令 v-permission
// src/plugins/directive.js
const permissionDirective = {
  inserted(el, binding) {
    const userRole = localStorage.getItem('role');
    if (userRole !== binding.value) {
      el.parentNode && el.parentNode.removeChild(el);
    }
  }
};

export default {
  install(Vue) {
    Vue.directive('permission', permissionDirective);
  }
};

全局安装:

// main.js
import DirectivePlugin from '@/plugins/directive';
Vue.use(DirectivePlugin);

模板中直接用:

<button v-permission="'admin'">删除用户</button>

逻辑清晰、职责明确,还不污染全局作用域。👍


第三方库要不要打包进每个页面?

答案是: 绝对不要!

想象一下,十个页面每个都打包一份 Vue 和 Lodash,那得多浪费?

解决方案:用 externals 把它们剥离出去,改由 CDN 引入。

// vue.config.js
module.exports = {
  configureWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      config.externals = {
        vue: 'Vue',
        vuex: 'Vuex',
        axios: 'axios',
        lodash: '_'
      };
    }
  }
};

然后在 HTML 中手动引入:

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>

这样做的好处太明显了:
- 包体积大幅缩小 💥
- 构建速度加快 ⚡
- 浏览器缓存利用率高 🔁

还能结合 AddAssetHtmlPlugin 自动注入 CDN 脚本,实现全自动管理。

看看这个饼图就知道节省了多少:

pie
    title 构建前后体积对比(单页面)
    “原始打包体积” : 45
    “使用 externals 后” : 15
    “节省比例” : 30

接近 70% 的压缩率 ,香不香?😍


环境变量怎么管才安全又好用?

不同环境 API 地址不一样,调试开关也不一样,硬编码肯定不行。

Vue CLI 提供了 .env 文件机制,非常强大。

.env 文件加载规则

文件名 触发条件 是否提交 Git
.env 所有环境
.env.local 所有环境(本地覆盖) ❌ 不提交
.env.development serve
.env.production build
.env.staging --mode staging

示例:

# .env.development
VUE_APP_API_BASE_URL=http://localhost:3000/api
VUE_APP_DEBUG=true

# .env.production
VUE_APP_API_BASE_URL=https://api.example.com
VUE_APP_DEBUG=false

启动命令决定加载哪个:

npm run serve                    # 开发环境
npm run build --mode production  # 生产环境
npm run build --mode staging     # 预发环境

process.env 到底是怎么注入的?

你以为 process.env.VUE_APP_XXX 是 Node.js 的环境变量?错啦!

它是 构建时静态替换 的结果。Vue CLI 内部用了 Webpack 的 DefinePlugin ,把所有 VUE_APP_* 替换成字符串字面量。

源码:

axios.get(`${process.env.VUE_APP_API_BASE_URL}/users`);

构建后变成:

axios.get("https://api.example.com/users"); // production

这意味着:
- 不能动态修改 :一旦打包完成,配置就固定了
- 安全性高 :只有 VUE_APP_* 开头的才会暴露给前端,私密信息不会泄露

序列图说明全过程:

sequenceDiagram
    participant Dev as 开发者
    participant CLI as Vue CLI
    participant WP as Webpack
    Dev->>CLI: npm run build --mode staging
    CLI->>CLI: 加载 .env 和 .env.staging
    CLI->>WP: 注入 DefinePlugin({ 'process.env.*': value })
    WP->>Bundle: 替换所有 process.env 引用为字面量
    Bundle-->>Dev: 输出最终 JS 文件

自定义构建流程:config 目录怎么建?

对于大型项目, vue.config.js 可能不够用。这时可以借鉴传统 Webpack 项目结构,建立 config/ 目录。

// config/webpack.base.conf.js
const path = require('path');
module.exports = {
  resolve: {
    alias: {
      '@': path.resolve('src')
    }
  }
};
// config/webpack.dev.conf.js
const merge = require('webpack-merge');
const base = require('./webpack.base.conf');
module.exports = merge(base, {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map'
});
// config/webpack.prod.conf.js
const merge = require('webpack-merge');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = merge(base, {
  mode: 'production',
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()]
  }
});

通过 webpack-merge 合并配置,避免重复。

还能写自定义插件监听构建生命周期:

class BuildTimePlugin {
  apply(compiler) {
    let startTime;
    compiler.hooks.compile.tap('BuildTimePlugin', () => {
      startTime = Date.now();
    });
    compiler.hooks.done.tap('BuildTimePlugin', () => {
      console.log(`✨ 构建耗时: ${(Date.now() - startTime)/1000}s`);
    });
  }
}

// vue.config.js
configureWebpack: {
  plugins: [new BuildTimePlugin()]
}

这种插件可用于统计、报警、集成 Sentry 等高级场景。


开发体验怎么提升?

HMR 热更新怎么让它更灵敏?

默认情况下,Vue CLI 已经支持 HMR。但在 MPA 中要注意: 每个入口都要独立监听

配置建议:

// vue.config.js
module.exports = {
  configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'development') {
      config.devServer = {
        hot: true,
        liveReload: false, // 关闭整页刷新,强制 HMR
        client: {
          overlay: {
            errors: true,
            warnings: false,
          },
        },
      };
    }
  },
};

这样改一个组件,只会局部更新,不会整个页面闪一下。

Vue DevTools 能不能识别多个实例?

当然可以!Vue DevTools 会自动检测页面中所有 new Vue() 实例,并允许你在不同上下文之间切换。

只要你不关生产提示,它就能正常工作。

source map 怎么配才方便定位错误?

开发环境用 eval-source-map ,速度快还精确到行:

configureWebpack: {
  devtool: process.env.NODE_ENV === 'development' ? 'eval-source-map' : 'source-map'
}

生产环境用 source-map ,配合 Sentry 上传,线上报错直接定位到 .vue 文件。

上传命令示例:

sentry-cli releases files v1.0.0 upload-sourcemaps ./dist --url-prefix ~/js/

自动化发布怎么做?

npm scripts 怎么设计才清晰?

{
  "scripts": {
    "serve": "vue-cli-service serve",
    "build:dev": "vue-cli-service build --mode development",
    "build:prod": "vue-cli-service build --mode production",
    "build:staging": "vue-cli-service build --mode staging",
    "lint": "vue-cli-service lint",
    "preview": "http-server dist -p 8080",
    "postbuild:prod": "node check-build.js"
  }
}

每个命令对应一个环境,CI/CD 中直接调用即可。

构建完成后怎么验证?

写个脚本检查输出完整性:

// check-build.js
const fs = require('fs');
const path = require('path');

const pages = ['login', 'dashboard', 'report'];
const distDir = path.resolve(__dirname, 'dist');

pages.forEach(page => {
  const htmlPath = path.join(distDir, `${page}.html`);
  if (!fs.existsSync(htmlPath)) {
    console.error(`❌ Missing HTML for page: ${page}`);
    process.exit(1);
  } else {
    console.log(`✅ Built: /${page}.html`);
  }
});

全局配置怎么动态切换?

推荐模式:构建时注入 + 运行时拉取

// src/config/index.js
const CONFIG = {
  API_BASE: process.env.VUE_APP_API_BASE,
  VERSION: process.env.VUE_APP_VERSION || '1.0.0',
  ENABLE_ANALYTICS: process.env.VUE_APP_ENABLE_ANALYTICS === 'true',
  ENV: process.env.NODE_ENV
};

export default CONFIG;

混合方案支持远程更新:

async function loadRemoteConfig() {
  try {
    const res = await fetch('/config/runtime.json');
    const remote = await res.json();
    return { ...CONFIG, ...remote };
  } catch {
    return CONFIG;
  }
}

未来还可接入 Apollo、Nacos 等配置中心,实现热更新。

流程图展示决策逻辑:

graph TD
    A[本地.env配置] --> B{是否启用远程配置?}
    B -->|否| C[使用本地默认值]
    B -->|是| D[HTTP请求获取runtime.json]
    D --> E[合并配置对象]
    E --> F[初始化Vue应用]

最后总结:这套体系的核心价值是什么?

不是炫技,而是 解决真实痛点

  • 页面太多?→ 用 MPA 拆分隔离 ✅
  • 构建太慢?→ 自动扫描入口 + externals 剥离 ✅
  • 配置混乱?→ .env + config 分层管理 ✅
  • 发布低效?→ CI/CD 自动化流水线 ✅

整套方案基于 Vue 2.0 + Webpack + Vue CLI,技术栈稳定、文档丰富、社区活跃,适合中大型团队长期演进。

更重要的是,它教会我们一种思维方式: 把复杂系统拆成小模块,每个模块自治,再通过标准化接口协作

这不仅是前端工程化的精髓,也是现代软件开发的通用法则。💡

所以别再迷信 SPA 万能了。有时候,回到“多页”的原点,反而能走得更远。🌍

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Vue.js 2.0作为主流前端框架,通过Vue CLI和Webpack支持高效构建多页面应用。本项目“vue20模板支持多页面”提供完整的多页面解决方案,涵盖环境配置、多入口打包、公共资源管理及跨环境变量控制,适用于大型模块化项目开发。开发者可通过该模板实现开发、测试、生产环境的分离,并利用热更新与Vue DevTools提升调试效率,显著提升项目可维护性与构建灵活性。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐