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 代码集(学习js的朋友可以看下)
Jul 22 Javascript
分享20款好玩的jQuery游戏
Apr 17 Javascript
ajax上传时参数提交不更新等相关问题
Dec 11 Javascript
js与jQuery 获取父窗、子窗的iframe
Dec 20 Javascript
Javscript删除数组中指定元素并返回新数组
Mar 06 Javascript
js实现漂浮回顶部按钮实例
May 06 Javascript
基于javascript实现单选及多选的向右和向左移动实例
Jul 25 Javascript
轻量级网页遮罩层jQuery插件用法实例
Jul 31 Javascript
谈谈基于iframe、FormData、FileReader三种无刷新上传文件的方法
Dec 03 Javascript
JS中Object对象的原型概念基础
Jan 29 Javascript
vue之a-table中实现清空选中的数据
Nov 07 Javascript
vue项目配置同一局域网可使用ip访问的操作
Oct 23 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
神族 Protoss 剧情介绍
2020/03/14 星际争霸
php各种编码集详解和以及在什么情况下进行使用
2011/09/11 PHP
Laravel5.4简单实现app接口Api Token认证方法
2019/08/29 PHP
laravel框架数据库操作、查询构建器、Eloquent ORM操作实例分析
2019/12/20 PHP
js 模式窗口(模式对话框和非模式对话框)的使用介绍
2014/07/17 Javascript
javascript函数特点实例分析
2015/05/14 Javascript
实例详解Nodejs 保存 payload 发送过来的文件
2016/01/14 NodeJs
jQuery简单实现页面元素置顶时悬浮效果示例
2016/08/01 Javascript
JS实现侧边栏鼠标经过弹出框+缓冲效果
2017/03/29 Javascript
jQuery:unbind方法的使用详解
2017/08/14 jQuery
Vue2实时监听表单变化的示例讲解
2018/08/30 Javascript
详解element-ui中form验证杂记
2019/03/04 Javascript
Koa从零搭建到Api实现项目的搭建方法
2019/07/30 Javascript
vuejs+element UI table表格中实现禁用部分复选框的方法
2019/09/20 Javascript
实例讲解Python中SocketServer模块处理网络请求的用法
2016/06/28 Python
python 动态加载的实现方法
2017/12/22 Python
python虚拟环境迁移方法
2019/01/03 Python
解决Python 命令行执行脚本时,提示导入的包找不到的问题
2019/01/19 Python
python实现Dijkstra算法的最短路径问题
2019/06/21 Python
python3.5 cv2 获取视频特定帧生成jpg图片
2019/08/28 Python
详解Python多线程下的list
2020/07/03 Python
运行Python编写的程序方法实例
2020/10/21 Python
HTML5通用接口详解
2016/06/12 HTML / CSS
Ever New加拿大官网:彰显女性美
2018/10/05 全球购物
Java中实现多态的机制是什么?
2014/12/07 面试题
简述网络文件系统NFS,并说明其作用
2016/10/19 面试题
开办饭店创业计划书
2013/12/28 职场文书
会计专业大学生职业生涯规划书
2014/02/11 职场文书
软件部经理岗位职责范本
2014/02/25 职场文书
飞机制造技术专业求职信
2014/07/27 职场文书
网球场地租赁协议范本
2014/10/07 职场文书
个人查摆问题自查报告
2014/10/16 职场文书
幼儿园教师节感谢信
2015/01/23 职场文书
2015年保险业务员工作总结
2015/05/27 职场文书
大学生安全教育心得体会
2016/01/15 职场文书
Python如何解决secure_filename对中文不支持问题
2021/07/16 Python