uniapp vuecli项目融合[小记]:将多个项目融合,打包成一个小程序/App,拆分多个H5应用

news2024/11/16 1:24:35
前言:

        目前两个uniapp vuecli开发的项目【A、B】,新规划的项目C:需要融合项目B 80%的功能模块,同时也需要涵盖项目A的所有功能模块。

应用需求:

        1、新项目C【小程序】可支持切换到应用A/C界面【内部通过初始化、路由跳转实现切换】【因此新项目C考虑基于项目A的工程上开发, git引入项目B

        2、工程A在H5中需要打包成两个应用:A应用、C应用;

实现思路:

        1、A项目工程上开发新应用C,引入B工程的模块/代码:通过git地址,安装依赖的方式引入B项目;

        2、A工程:小程序打包为一个应用[A+C]、H5拆分应用[A/C]:通过pages.json动态改写来实现,通过不同的打包命令来区分;

A工程改造:基于A开发C应用、融合B项目,步骤梳理:
1. 通过git地址,安装依赖的方式引入B项目:package.json
"mobileB": "git+https://git.xxxx/mobileB.git#xxxxxxxxxx"

注:git+<项目B仓库地址>#<git提交commit id>

2. 解决问题:项目B使用了TS,项目A未使用TS,引入后需要转换支持:vue.config.js
module.exports = {
  /**
   * 某个依赖项是TypeScript编写的,但是目标环境中并不支持TypeScript,
   * 那么我们需要在打包前先将其转换为JavaScript代码
   */
  transpileDependencies: ['mobileB'],
  // ...其他配置
}
3. webpack编译构建过程中,处理mobileB模块导入路径

        引入mobileB后,因为mobileB中的别名等,无法正确被解析,所以需要在编译阶段,进行修改。

        定义一个名为CustomAliasResolverPlugin.js的文件,实现webpack插件类,在webpack编译过程中处理mobileB模块导入路径,确保mobileB中的别名路径都能正确的指向。

class CustomAliasResolverPlugin {
  constructor() {
    this.path_mobileB = 'mobileB/src';
  }

  apply(compiler) {
    // 监听了normalModuleFactory事件,在每个普通模块被创建时执行回调函数
    compiler.hooks.normalModuleFactory.tap(
      'CustomAliasResolverPlugin',
      (factory) => {
        // 回调函数接收一个模块工厂实例factory作为参数,并在其上进一步监听 beforeResolve 事件。beforeResolve 是在模块解析之前触发的钩子,此时可以修改模块请求信息
        factory.hooks.beforeResolve.tapAsync(
          'CustomAliasResolverPlugin',
          (data, callback) => {
            // 在 beforeResolve 的回调函数内,从数据对象data中获取当前模块的请求路径request和解析上下文context。
            const { request, context } = data;
            // 解析上下文包含指定的基础路径,确保是mobileB下的模块
            if (context.includes(this.path_mobileB)) {
              if (request.startsWith('@src')) {
                data.request = request.replace('@src', `${this.path_mobileB}/src`);
              } else if (request.startsWith('@service')) {
                data.request = request.replace('@service', `${this.path_mobileB}/service`);
              }
            }
            callback(null, data);
          }
        );
      }
    );
  }
}

module.exports = CustomAliasResolverPlugin;

        CustomAliasResolverPlugin 是一个自定义的webpack插件,要求它在项目构建时会参与到webpack的模块解析阶段,因此我们需要在添加到plugins中,以及解决可能存在的路径问题;

        vue.config.js:

const CustomAliasResolverPlugin = require('./config/CustomAliasResolverPlugin');

module.exports = {
  configureWebpack: {
    plugins: [new CustomAliasResolverPlugin()]
  }
  // ...其他配置
}
4. pages.json动态改写:实现H5应用拆分、小程序整合

        uniapp页面文件的打包是基于pages.json,所以我们需要根据需求,使用nodeJs动态生成对应的pages.json文件。

示例:

common.js:编写需要打包成A、C两个项目的公共页面路由及其他配置

// 小程序的分包
const subPackages = []
const pages = [
  {
    path: 'pages/home/home',
    aliasPath: '/'
  }
]

// 其他配置相关
const otherConfig = {
  globalStyle: {
    navigationStyle: 'custom',
    allowsBounceVertical: 'NO',
    renderingMode: 'seperated',
    pageOrientation: 'portrait',
    rpxCalcMaxDeviceWidth: 540,
    rpxCalcBaseDeviceWidth: 375
  },
  // 需要自动注册的自定义组件
  easycom: {
    autoscan: true,
    custom: {
      '^ant-tree-(.*)':
        '@/components/businessComponent/ant-tree/ant-tree-$1.vue',
      '^ant-customize-(.*)':
        '@/components/businessComponent/ant-customize/ant-customize-$1.vue',
      '^u-(.*)': 'uview-ui/components/u-$1/u-$1.vue',
      '^anmc-(.*)': 'antm-ui/components/common/anmc-$1/anmc-$1.vue',
      '^anmb-(.*)': 'antm-ui/components/business/anmb-$1/anmb-$1.vue'
    }
  }
};

module.exports = {
  subPackages,
  pages,
  otherConfig
};

ant4Pages.js/erpPages.js: A/C应用的页面路由

module.exports = {
  pages: [],
  subPackages: []
}

main.js: 根据条件重写pages.json


const common = require('./common')
const subPackages = common.subPackages || []
const otherConfig = common.otherConfig || {}
const commonPages = common.pages || []

const fs = require('fs');
const ant4pages = require('./ant4Pages');
const erppages = require('./erpPages');
const pagesPath = process.env.UNI_INPUT_DIR + '/pages.json';
let pagesJson = {};
// 判断是否H5
if (process.env.UNI_PLATFORM === 'h5') {
  let subPackagesProxy = subPackages
  // 判断是否是ERP项目:对应文中说到的C应用【H5】
  // VUE_APP_NODE_APP_TYPE是命令上自行添加的字段,用来区分
  if (process.env.VUE_APP_NODE_APP_TYPE === 'erp') {
    const erpSubPackages = erppages.subPackages
    erpSubPackages.forEach(item => {
      const root = subPackagesProxy.find(sub => sub.root === item.root)
      if (root) {
        item.pages = [
          ...root.pages,
          ...item.pages
        ]
        subPackagesProxy = subPackagesProxy.filter(sub => sub.root !== item.root)
      }
    })
    pagesJson = {
      ...erppages,
      pages: [...commonPages, ...erppages.pages],
      subPackages: [...subPackagesProxy, ...erpSubPackages],
      ...otherConfig
    }
  } else {
    const antSubPackages = ant4pages.subPackages
    antSubPackages.forEach(item => {
      const root = subPackagesProxy.find(sub => sub.root === item.root)
      if (root) {
        item.pages = [
          ...root.pages,
          ...item.pages
        ]
        subPackagesProxy = subPackagesProxy.filter(sub => sub.root !== item.root)
      }
    })
    pagesJson = {
      ...ant4pages,
      pages: [...commonPages, ...ant4pages.pages],
      subPackages: [...subPackagesProxy, ...antSubPackages],
      ...otherConfig
    }
  }
} else {
  // 小程序打包,整合所有的路由配置
  const subPackagesProxy = subPackages
  let antSubPackages = ant4pages.subPackages
  let erpSubPackages = erppages.subPackages
  subPackagesProxy.forEach(item => {
    const antRoot = antSubPackages.find(sub => sub.root === item.root)
    const erpRoot = erpSubPackages.find(sub => sub.root === item.root)
    if (antRoot) {
      item.pages = [
        ...antRoot.pages,
        ...item.pages
      ]
      antSubPackages = antSubPackages.filter(sub => sub.root !== item.root)
    }
    if (erpRoot) {
      item.pages = [
        ...erpRoot.pages,
        ...item.pages
      ]
      erpSubPackages = erpSubPackages.filter(sub => sub.root !== item.root)
    }
  })
  pagesJson = {
    pages: [...commonPages, ...ant4pages.pages, ...erppages.pages],
    subPackages: [...subPackagesProxy, ...antSubPackages, ...erpSubPackages],
    ...otherConfig
  };
}

// 将最终的结果写入pages.json,在项目运行或构建时
fs.writeFileSync(pagesPath, JSON.stringify(pagesJson), {
  flag: 'w'
});

将src/config/appPages/main.js文件引入vue.config.js中;

        注:直接在vue.congfig.js顶部导入对于pages.json的重写,vue.config.js 文件是 Vue CLI 在构建项目时默认查找并加载的第一个用户自定义配置文件,目前测试没有出现什么异常,如果存在异常,可考虑调整至预处理脚本中,具体根据实际情况而定:

{
  "scripts": {
    "prebuild": "node ./src/config/main.js",
    "build": "vue-cli-service build"
  },
}
5. router拦截处理【参考】

6. vuex整合: mobileB中vuex中的modules,添加到当前主工程的modules中:
import Vue from 'vue';
import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate';
import getters from './getters';
import user from './modules/user.js';
// 项目B的store集合,全部抛出来,添加到modules中
import Bstore from 'mobileB/src/store/main

Vue.use(Vuex);
export default new Vuex.Store({
  plugins: [
    createPersistedState({
      storage: {
        // ...
      },
      reducer(value) { // 选择性配置持久化
        return {
        }
      }
    })
  ],
  modules: {
    user,
    ...Bstore
  },
  getters
});
7. 初始化B项目依赖的一些数据缓存等;

        可以在B项目中提供一个应用初始化的方法,在引用项目中合适的时机调用;以下示例仅供参考:

import { libraryId } from "@service/user";
import { setLocal } from "src/utils/utils";
import { YB_MOBILE_LIBRARY_INFO } from "src/configs/constants";

/**
 * 对外git引用,初始化方法
 */
async function appInit(appType: string) {
  // 存储用户信息、token等
  // 初始化一些业务数据等等
  const res: any = await libraryId({});
  getApp().globalData.appType = appType || 'anterp'
  setLocal(YB_MOBILE_LIBRARY_INFO, res.res.data.libraryId);
}

export default appInit;
8. 项目A/C工程中,使用项目B的组件或页面;

        在路由中对应配置项目B中的路由,对应创建页面文件,将项目B中的文件当作组件引入:【注:目前项目统一使用uni-simple-router路由管理插件,项目B中的路由跳转,只要在项目A/C工程中同样存在该路由,及可跳转】

<script>
import templateDetail from 'mobileB/src/pages/common/templateDetailInfo/index.vue';
export default {
  components: {
    templateDetail
  }
};
</script>
备注

        在实际的项目开发场景中,对需要融合项目架构的技术、实现方案统一性、代码规范等等有较高的要求,同时会遇到很多问题需要处理,如主题样式、不同平台的语法支持等等,本文仅对实现方案进行一个大致梳理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1411502.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

对于小微企业而言,数字化转型的重要性是什么?

数字化转型对于小微企业至关重要&#xff0c;原因如下&#xff1a; 1.效率和生产力&#xff1a;采用数字工具和技术可以简化业务流程、自动化重复性任务并提高整体效率。这使得小型企业能够用更少的资源完成更多的工作&#xff0c;最终提高生产力。 2.节省成本&#xff1a;数…

Gradle学习笔记:Gradle的简介、下载与安装

文章目录 一、什么是Gradle二、为什么选择Gradle三、下载并安装Gradle四、Gradle的bin目录添加到环境变量五、测试Gradle是否安装正常 一、什么是Gradle Gradle是一个开源构建自动化工具&#xff0c;专为大型项目设计。它基于DSL&#xff08;领域特定语言&#xff09;编写&…

江科大STM32 中

目录 6、TIM&#xff08;Timer&#xff09;定时器基本定时器通用定时器高级定时器示例程序&#xff08;定时器定时中断&定时器外部时钟&#xff09;TIM输出比较示例程序&#xff08;PWM驱动LED呼吸灯&PWM驱动舵机&PWM驱动直流电机&#xff09;TIM输入捕获示例程序&…

Qt 基于海康相机 的视频标绘

需求&#xff1a; 基于 视频 进行 标注&#xff0c;从而进行测量。 曾经搞在线教育时&#xff0c;尝试在视频上进行文字或者图形的绘制&#xff0c;但是发现利用Qt widget 传sdk 句柄的方式&#xff0c;只能使用窗口叠加的方式&#xff08;Qt 基于海康相机的视频绘图_海康相…

在 Linux 上搭建 Java 环境

目录 一、安装jdk 1. 挑选 jdk 版本 2. 安装 3. 验证 jdk 二、安装tomcat 1. 下载压缩包 2. 上传压缩包给 Linux &#xff08;需要用到 rz 命令&#xff09; 3. 解压压缩包&#xff08;需要用到 unzip&#xff09; 4. 进入 bin 目录 5. 给启动脚本增加可执行权限 6. 启…

CAN基础知识介绍

1.CAN的基本介绍 CAN&#xff08;Controller Area Network&#xff09;&#xff0c;是ISO国际标准化的串行通信协议。为了满足汽车产业的“减少线束的数量”、“通过多个LAN&#xff0c;进行大量数据的高速通信”的需求。 发展历史&#xff1a; 1986年&#xff0c;博世公司开…

JVM篇----第七篇

系列文章目录 文章目录 系列文章目录前言一、老年代二、永久代三、JAVA8 与元数据四、引用计数法五、可达性分析前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 一…

postman自动化测试如何设置环境变量教程

在接口测试中&#xff0c;我们经常会用到一些通用请求参数&#xff0c;或者需要使用某个接口的返回参数作为另一个接口的请求参数&#xff0c;静态的参数还好&#xff0c;如果是经常变动的参数&#xff0c;那么操作起来&#xff0c;就特别的麻烦&#xff0c;这时候&#xff0c;…

pytorch代码实现注意力机制之SK Attention

SK注意力机制 简介&#xff1a;在标准卷积神经网络 &#xff08;CNN&#xff09; 中&#xff0c;每一层人工神经元的感受野被设计为共享相同的大小。在神经科学界众所周知&#xff0c;视觉皮层神经元的感受野大小受到刺激的调节&#xff0c;这在构建 CNN 时很少被考虑。我们在…

使用阿里云的oss对象存储服务实现图片上传(前端vue后端java详解)

一&#xff1a;前期准备&#xff1a; 1.1&#xff1a;注册阿里云账号&#xff0c;开启对象存储oss功能&#xff0c;创建一个bucket&#xff08;百度教程多的是&#xff0c;跟着创建一个就行&#xff0c;创建时注意存储类型是标准存储&#xff0c;读写权限是公共读&#xff09;…

深度学习(6)---Transformer

文章目录 一、介绍二、架构2.1 Multi-head Attention2.2 Encoder(编码器)2.3 Decoder(解码器) 三、Encoder和Decoder之间的传递四、Training五、其他介绍5.1 Copy Mechanism5.2 Beam Search 一、介绍 1. Transformer是一个Seq2Seq&#xff08;Sequence-to-Sequence&#xff09;…

redis + 拦截器 :防止数据重复提交

1.项目用到,不是核心 我们干系统开发,不免要考虑一个点&#xff0c;数据的重复提交。 我想我们之前如果要校验数据重复提交要求&#xff0c;会怎么干?会在业务层&#xff0c;对数据库操作&#xff0c;查询数据是否存在,存在就禁止插入数据; 但是吧,我们每次crud操作都会连接…

【史上最全之 ChatGPT 和文心一言对比】

ChatGPT 和文心一言哪个更好用&#xff1f; 在当今的AI助手领域中&#xff0c;ChatGPT与文心一言无疑是备受瞩目的两位选手。两者分别由美国OpenAI公司和中国百度研发&#xff0c;均致力于提供卓越的人工智能对话体验。接下来&#xff0c;我们将从智能回复、语言准确性以及知识…

SQL - 事务控制

SQL - 事务控制 文章目录 SQL - 事务控制TCL - 事务事务的边界事务的特性事务的应用 事务隔离等级MySQL支持四种隔离级别 TCL - 事务 **模拟场景&#xff1a;**生活当中转账是转账方账户扣钱&#xff0c;收账方账户加钱。用数据库操作来模拟现实转账。 数据库模拟&#xff1a…

HH44X-16微阻缓闭式止回阀常见的问题

HH44X-16微阻缓闭式止回阀常见的问题 HH44X-16微阻缓闭式止回阀常遇问题包括以下几点&#xff1a; 一、泄漏&#xff1a; HH44X-16微阻缓闭式止回阀在关闭时可能会发生泄漏&#xff0c;导致介质倒流。泄漏可能由于密封失效、阀门磨损或堵塞等原因造成。 二、堵塞&#xff1a;…

复盘_用工具提升效率

流量池 从 2017 年 10 月&#xff0c;我开始写公众号&#xff0c;一直以来都是零零散散地写&#xff0c;读者也只是随随便便地看。而今年在连续日更了 10 天后&#xff0c;我获得了今年的第一次流量池推荐。 尽管和别人动辄十万百万的阅读量没法比。但是&#xff0c;考虑到我的…

echarts 绘制垂直滚动热力图

问题1&#xff1a;提示功能无效 问题2&#xff1a;值筛选无效 效果 在线浏览 下载echarts官网例子(heatmap Examples - Apache ECharts) 稍作改动&#xff1a; generateData 入参改为长度和宽度noise.perlin2(i / 40, j / 20) Math.random() * 5y轴倒置指定zlevel为2 通过定…

如何使用Jellyfin+cpolar搭建私人影音平台实现无公网ip远程访问

文章目录 1. 前言2. Jellyfin服务网站搭建2.1. Jellyfin下载和安装2.2. Jellyfin网页测试 3.本地网页发布3.1 cpolar的安装和注册3.2 Cpolar云端设置3.3 Cpolar本地设置 4.公网访问测试5. 结语 1. 前言 随着移动智能设备的普及&#xff0c;各种各样的使用需求也被开发出来&…

2024年广东省安全员A证第四批(主要负责人)证模拟考试题库及广东省安全员A证第四批(主要负责人)理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年广东省安全员A证第四批&#xff08;主要负责人&#xff09;证模拟考试题库及广东省安全员A证第四批&#xff08;主要负责人&#xff09;理论考试试题是由安全生产模拟考试一点通提供&#xff0c;广东省安全员A证…

HCIE之BGP路由策略(三)

BGP 一、路由控制工具ACLIP-PREFIXRoute-Policy 二、BGP路由控制通过更改MED属性调节选路通过更改Local_Pref属性调节选路理解ACL、IP-PREFIX和Route-Policy中permit、deny的含义 三、BGP属性特点-团体属性练习no-advertise属性ORF 一、路由控制工具 在对BGP进行路由控制之前&…