vue大型项目之分模块运行/打包的实现


Posted in Javascript onSeptember 21, 2020

本文以vue-cli3+为例,实现多系统集成下的分模块打包。分模块打包方式多种多样,下文可适用于多系统之间互不干扰,主系统可集成各子系统,各子系统又可单独运行的业务场景。

一、目标

我们要实现什么?所谓分模块打包,那么各个模块内就必须得有自己独立的入口文件,路由文件。按照这种构想,我在一个新的脚手架src目录下新建了一个projects目录:

vue大型项目之分模块运行/打包的实现

如上图,可以看到Aproject、B、C、D四个项目。我在A项目中建了assets,common和views文件夹,其中assets可以再建img和css的文件夹,common内可以放公共组件或者方法,views页面可以放页面,甚至你还可以建一个components文件夹专门用来放组件。

好了,我们的视图目录结构大概就是上面的样子。我们期待的是,我们可以打包这个A模块这个‘小vue',就像打包一个完整vue的项目一样。那么如何实现这部分呢?

二、打包单个模块

我们知道,在package.json中,有项目启动,打包的命令。

vue大型项目之分模块运行/打包的实现

我们可以从这里入手。

这里就不得不提到cross-env这个模块了。
我们之前在设置生产环境,测试环境,开发环境时也会用到这个模块。在这里不详细表述了。

cross-env:npm install --save-dev cross-env

现在我们的思路大概是这样的,当我们执行打包命令的时候,通过cross-env去找到我们的入口文件,然后再打包。

所以我们可以模仿环境变量的写法,在package中写入如下图代码。

vue大型项目之分模块运行/打包的实现

代码:

"dev:projectA": "cross-env PROJECT_NAME=projectA vue-cli-service serve",
  "dev:projectB": "cross-env PROJECT_NAME=projectB vue-cli-service serve",
  "dev:projectC": "cross-env PROJECT_NAME=projectC vue-cli-service serve",
  "dev:projectD": "cross-env PROJECT_NAME=projectD vue-cli-service serve",
  "build:projectA": "cross-env PROJECT_NAME=projectA vue-cli-service build",
  "build:projectB": "cross-env PROJECT_NAME=projectB vue-cli-service build",
  "build:projectC": "cross-env PROJECT_NAME=projectC vue-cli-service build",
  "build:projectD": "cross-env PROJECT_NAME=projectD vue-cli-service build",

写完了这些,我们就可以着手模仿vue配置小vue的文件了。

在main.js中配置如下代码:

import Vue from "vue";
		import App from "./App.vue";
		import router from "./router";
		import store from "./store";
		
		Vue.config.productionTip = false;
		
		new Vue({
		  router,
		  store,
		  render: h => h(App)
		}).$mount("#app");

在App.vue中配置如下代码:

<template>
		 <div id="app">
		  <router-view />
		 </div>
		</template>
		
		<style lang="less">
		
		</style>

在router.js中配置如下代码

import Vue from "vue";
		import Router from "vue-router";
		import Home from "./views/Home.vue";
		
		Vue.use(Router);
		
		export default new Router({
		 routes: [
		  {
		   path: "/",
		   name: "home",
		   component: Home
		  }
		 ]
		});

在page文件夹中建立Home.vue,写入如下代码:

<template>
		 <div>
		  我是a项目
		 </div>
		</template>
		
		<script>
		export default {};
		</script>
		
		<style></style>

在项目最外层建立config文件夹,在其中新建projectsConfig.js写入:

const config = {
 projectA: {
  pages: {
   index: {
    entry: "src/projects/projectA/main.js",
    template: "public/index.html",
    filename: "index.html"
   }
  },
  devServer: {
   port: 8080, // 端口地址
   open: false, // 是否自动打开浏览器页面
   host: "0.0.0.0", // 指定使用一个 host,默认是 localhost
   https: false, // 使用https提供服务
   disableHostCheck: true,
   // 设置代理
   proxy: {
    "/eopenhapi": {
     target: "http://open.jdpay.com",
     changeOrigin: true
    },
    "/hapi": {
     target: "http://open.jdpay.com",
     changeOrigin: true
    }
   }
  }
 },
 projectB: {},
 projectC: {}
};
module.exports = config;

把projectsConfig.js并入vue.config.js,vue.config.js中代码如下

const config = require("./config/projectsConfig.js");
let projectName = process.env.PROJECT_NAME;

module.exports = {
 ...config[projectName],
 // pages: conf.pages,

 // 基本路径
 // baseUrl: './',//vue-cli3.3以下版本使用
 publicPath: "./", // vue-cli3.3+新版本使用

 // 输出文件目录
 outputDir: "dist/" + projectName + "/"
};

写到这里我们就建立一个完整的小vue了。

运行命令 cnpm run dev:projectA

vue大型项目之分模块运行/打包的实现

运行命令 cnpm run build:projectA

vue大型项目之分模块运行/打包的实现

效果完美。

三、打包总项目及子系统

一个大型项目必然会有公共模块,这里会写一个导航栏作为公共组件。

在projects下建立公共模块的文件夹common,写入前面A项目的目录结构,如图:

vue大型项目之分模块运行/打包的实现

在package.json中写入运行命令和打包命令。

"dev:common": "cross-env PROJECT_NAME=common vue-cli-service serve",
 "build:common": "cross-env PROJECT_NAME=common vue-cli-service build",

在Home.vue中写公共导航

这里会使用iview作为ui组件,但也因此有一个问题,我的A,B,C,D四个项目每个项目引入一遍UI框架,那打包出来整个项目将会非常的大,所以我们在项目必须采用按需引入的方式。(项目中还是下载整个ivew)

写入如下代码:

<template>
 <div class="main-content">
  <Layout>
   <header class="head-box">
    <Menu
     mode="horizontal"
     theme="primary"
     active-name="1"
     @on-select="menuClick"
    >
     <div class="layout-logo">Oralinge</div>
     <div class="layout-nav">
      <div class="layout-nav-content">
       <!-- 系统列表 -->
       <span v-for="(item, index) in systemList" :key="index">
        <MenuItem
         :name="item.basepath + '?systemId=' + item.systemId"
         @click="go(item)"
        >
         <Icon type="ios-navigate"></Icon>
         {{ item.title }}
        </MenuItem>
       </span>
      </div>
     </div>
     <div class="layout-right">
      <Dropdown>
       <!-- 登录姓名 -->
       <a href="javascript:void(0)" rel="external nofollow" >
        {{ user.userName }}
        <Icon type="ios-arrow-down"></Icon>
       </a>
       <!-- 退出登录 -->
       <DropdownMenu slot="list">
        <DropdownItem name="logout">退出登录</DropdownItem>
       </DropdownMenu>
      </Dropdown>
     </div>
    </Menu>
   </header>
  </Layout>
  <iframe
   :src="systemUrl"
   width="100%"
   height="100%"
   frameborder="0"
   class="iframe"
   id="bossIframe"
  ></iframe>
 </div>
</template>
<script>
import {
 Layout,
 Menu,
 MenuItem,
 Dropdown,
 DropdownItem,
 DropdownMenu
} from "view-design";

export default {
 components: {
  Layout,
  Menu,
  MenuItem,
  Dropdown,
  DropdownItem,
  DropdownMenu
 },
 data() {
  return {
   systemUrl: "",
   isFullscreen: false,
   loading: false,
   systemList: [
    {
     title: "A项目",
     basepath: "http://localhost:8080/#/",
     systemId: "A"
    },
    {
     title: "B项目",
     basepath: "http://localhost:8082/#/",
     systemId: "B"
    },
    {
     title: "C项目",
     basepath: "http://localhost:8083/#/",
     systemId: "c"
    },
    {
     title: "D项目",
     basepath: "http://localhost:8084/#/",
     systemId: "D"
    }
   ],
   user: {}
  };
 },
 mounted() {
  this.systemUrl =
   this.systemList[0].basepath + "?systemId=" + this.systemList[0].systemId;
 },
 methods: {
  menuClick(name) {
   this.systemUrl = name;
  }
 }
};
</script>

<style lang="less" scoped>
@head-height: 50px;
.main-content {
 height: 100%;
 padding-top: @head-height;
 box-sizing: border-box;
 overflow: hidden;
}
.head-box {
 width: 100%;
 height: @head-height;
 line-height: @head-height;
 position: fixed;
 top: 0;
 left: 0;
 min-width: 1200px;

 .ivu-menu-horizontal {
  height: 100%;
  line-height: @head-height;
 }
 .layout-logo {
  display: inline-block;
  width: 200px;
  color: #fff;
  font-size: 28px;
  text-align: center;
  vertical-align: top;
  position: absolute;
  left: 0;
  top: 0;
  background-color: #2d8cf0;
  z-index: 5;
 }
 .layout-nav {
  display: inline-block;
  width: 100%;
  height: 100%;
  padding-left: 200px;
  padding-right: 100px;
  box-sizing: border-box;
  overflow-x: auto;
  z-index: 4;
  &-content {
   //  width: 100%;
   overflow: hidden;
   height: 100%;
  }
 }
 .layout-right {
  padding-right: 20px;
  padding-left: 20px;
  position: absolute;
  right: 0;
  top: 0;
  background-color: #2d8cf0;
  z-index: 5;
  a {
   color: #fff;
  }
 }

 .ivu-menu-item-active {
  font-size: 20px;
 }
}
</style>

效果:

vue大型项目之分模块运行/打包的实现

B项目使用同样的方法配置文件。
配置后效果如下:

vue大型项目之分模块运行/打包的实现

到这里,我们就基本实现了分模块运行以及集体运行了。

下面看一下打包。

在分别运行了B项目和common的打包命令以后,效果正常。

vue大型项目之分模块运行/打包的实现

另外,我在这里采用了iframe的方式嵌入了其他项目,是因为引入的方式打包的时候会打包太多。

这样做的好处就是公共项目仅仅作为一个外壳使用,其他项目与其并没有太多的关联,保证了每个项目模块的独立性。

四、demo地址

https://github.com/Oralinge/pointsmodule

到此这篇关于vue大型项目之分模块运行/打包的实现的文章就介绍到这了,更多相关vue分模块打包内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
用js实现上传图片前的预览(TX的面试题)
Aug 14 Javascript
JavaScript中的比较操作符&gt;、=、
Dec 31 Javascript
jQuery插件jFade实现鼠标经过的图片高亮其它变暗
Mar 14 Javascript
JavaScript控制图片加载完成后调用回调函数的方法
Mar 20 Javascript
jquery实现的代替传统checkbox样式插件
Jun 19 Javascript
jQuery zTree加载树形菜单功能
Feb 25 Javascript
JQuery实现简单的服务器轮询效果实例
Mar 31 Javascript
JavaScript实现图片懒加载(Lazyload)
Nov 28 Javascript
JS敏感词过滤代码
Dec 23 Javascript
使用原生js+canvas实现模拟心电图的实例
Sep 20 Javascript
仿淘宝JSsearch搜索下拉深度用法
Jan 15 Javascript
Node.js API详解之 Error模块用法实例分析
May 14 Javascript
Vue+Element ui 根据后台返回数据设置动态表头操作
Sep 21 #Javascript
JS实现小米轮播图
Sep 21 #Javascript
vue 里面的 $forceUpdate() 强制实例重新渲染操作
Sep 21 #Javascript
vue组件入门知识全梳理
Sep 21 #Javascript
Ajax获取node服务器数据的完整步骤
Sep 20 #Javascript
微信小程序获取当前时间及星期几的实例代码
Sep 20 #Javascript
vue操作dom元素的3种方法示例
Sep 20 #Javascript
You might like
「OVERLORD」动画重要删减!雅儿贝德的背叛?至尊猎杀队结成
2020/04/09 日漫
PHP 长文章分页函数 带使用方法,不会分割段落,翻页在底部
2009/10/22 PHP
ThinkPHP php 框架学习笔记
2009/10/30 PHP
Windows下PHP开发环境搭建教程(Apache+PHP+MySQL)
2016/06/13 PHP
PHP PDOStatement::errorInfo讲解
2019/01/31 PHP
jquery 插件 web2.0分格的分页脚本,可用于ajax无刷新分页
2008/12/25 Javascript
jquery 定位input元素的几种方法小结
2013/07/28 Javascript
Servlet实现文件上传,可多文件上传示例
2016/12/05 Javascript
js实现刷新页面后回到记录时滚动条的位置【两种方案可选】
2016/12/12 Javascript
微信小程序 增、删、改、查操作实例详解
2017/01/13 Javascript
weebox弹出窗口不居中显示的解决方法
2017/11/27 Javascript
js原生实现移动端手指滑动轮播图效果的示例
2018/01/02 Javascript
微信小程序自定义可滑动日历界面
2018/12/28 Javascript
ES6中Symbol、Set和Map用法详解
2019/08/20 Javascript
p5.js绘制旋转的正方形
2019/10/23 Javascript
js实现固定区域内的不重叠随机圆
2019/10/24 Javascript
js实现页面图片消除效果
2020/03/24 Javascript
[44:47]Ti4 循环赛第三日 iG vs NaVi
2014/07/12 DOTA
[06:45]DOTA2-DPC中国联赛 正赛 Magma vs LBZS 选手采访
2021/03/11 DOTA
Python模拟登录12306的方法
2014/12/30 Python
python对象及面向对象技术详解
2016/07/19 Python
pandas 空的dataframe 插入列名的示例
2018/10/30 Python
python 中如何获取列表的索引
2019/07/02 Python
python3.7环境下安装Anaconda的教程图解
2019/09/10 Python
Mysql数据库反向生成Django里面的models指令方式
2020/05/18 Python
在pycharm中关掉ipython console/PyDev操作
2020/06/09 Python
凯蒂·佩里个人女鞋品牌:Katy Perry Collections
2019/04/04 全球购物
六个一活动实施方案
2014/03/21 职场文书
县委务虚会发言材料
2014/10/20 职场文书
新员工试用期自我评价
2015/03/10 职场文书
公司晚宴祝酒词
2015/08/11 职场文书
会计继续教育培训心得体会
2016/01/19 职场文书
2016年大学光棍节活动总结
2016/04/05 职场文书
JavaScript 防篡改对象的用法示例
2021/04/24 Javascript
Redis 彻底禁用RDB持久化操作
2021/07/09 Redis
Java 写一个简单的图书管理系统
2022/04/26 Java/Android