【前端】移动端工程结构最佳实践(v4/v5)

阅读之前

你应该:

  • 了解node与npm相关内容
  • 了解lerna包管理工具的相关内容
  • 了解git仓库的相关内容
  • 了解rollup的相关内容

工程结构包示例

Vue项目结构包下载-v4.7.x
Vue项目结构包下载-v5.2.x

工程结构详解

工程结构
├── packages
│   ├── kunlun-mobile-boot
│   │   ├── package.json
│   │   ├── public
│   │   │   ├── favicon.ico
│   │   │   └── index.html
│   │   ├── src
│   │   │   ├── main.ts
│   │   │   └── shim-vue.d.ts
│   │   ├── tsconfig.json
│   │   └── vue.config.js
│   ├── kunlun-module-mobile-demo
│   │   ├── scripts
│   │   │   ├── postpublish.js
│   │   │   └── prepublish-only.js
│   │   ├── src
│   │   │   ├── index.ts
│   │   │   └── shim-vue.d.ts
│   │   ├── index.ts
│   │   ├── package.json
│   │   ├── rollup.config.js
│   │   └── tsconfig.json
│   └── kunlun-modules-mobile-demo
│       ├── scripts
│       │   ├── build.config.js
│       │   ├── postpublish.js
│       │   └── prepublish-only.js
│       ├── packages
│       │   ├── module-demo1
│       │   │   ├── index.ts
│       │   │   ├── package.json
│       │   │   ├── rollup.config.js
│       │   │   └── src
│       │   │       ├── index.ts
│       │   │       └── shim-vue.d.ts
│       │   ├── module-demo2
│       │   │   ├── index.ts
│       │   │   ├── package.json
│       │   │   ├── rollup.config.js
│       │   │   └── src
│       │   │       ├── index.ts
│       │   │       └── shim-vue.d.ts
│       │   └── module-dependencies
│       │       ├── index.ts
│       │       ├── package.json
│       │       └── src
│       │           └── dependencies.ts
│       ├── lerna.json
│       ├── tsconfig.json
│       └── package.json
├── lerna.json
└── package.json

壳工程

├── packages
│   └── ......
├── lerna.json
└── package.json

壳工程仅用于将多个包进行统一安装,并通过lerna包管理工具进行相关的软链接操作。

壳工程包含了除了node和npm外其他相关的安装依赖,如lernarimraf等。这样可以避免由于开发环境差异带来的一系列问题。

我们建议所有开发人员均使用相同的壳工程进行开发,因此,我们有必要将其提交并推送到git远程仓库进行共享。

壳工程目录下执行npm install命令即可完成一系列安装操作。

需要注意的是,lerna.json中定义了所有需要统一安装的子工程路径,安装前需要确认是否满足当前需要,但这些修改都应该只在本地完成,而不应该推送到git远程仓库

安装完成后,所有公共依赖均会安装在壳工程node_modules目录下,每个子工程的node_modules中仅包含软链接目录。并且在壳工程node_modules目录下不会出现本地已经存在的工程依赖。

单工程包管理

├── packages
│   └── kunlun-module-mobile-demo
│       ├── scripts
│       │   ├── postpublish.js
│       │   └── prepublish-only.js
│       ├── src
│       │   ├── index.ts
│       │   └── shim-vue.d.ts
│       ├── index.ts
│       ├── package.json
│       ├── rollup.config.js
│       └── tsconfig.json
├── lerna.json
└── package.json

作为一个独立的工程,它可以是一个项目的总工程,也可以是多个项目共同使用的子工程。这也是最常见的工程包结构。

通常情况下,kunlun-module-mobile-demo工程会使用一个独立的git仓库进行管理。

通过kunlun-module-mobile-demo打包生成的@kunlun/module-mobile-demo包,将可以被发布到npm仓库或其他地方,供其他工程或项目使用。

启动工程中的package.json中添加"@kunlun/module-mobile-demo": "~1.0.0"相关依赖进行引入。并在入口文件main.ts中导入相关的js和css相关内容。

如示例中所示:

// 按需引入
import '@kunlun/module-mobile-demo/dist/kunlun-module-mobile-demo.css';

import '@kunlun/module-mobile-demo';

需要注意的是,在本地开发中,css文件相关内容应该是被临时注释的,因为通过import '@kunlun/module-mobile-demo';已经将相关内容引入,无需使用打包好的css文件。

多工程包管理

├── packages
│   └── kunlun-modules-mobile-demo
│       ├── scripts
│       │   ├── build.config.js
│       │   ├── postpublish.js
│       │   └── prepublish-only.js
│       ├── packages
│       │   ├── module-mobile-demo1
│       │   │   ├── index.ts
│       │   │   ├── package.json
│       │   │   ├── rollup.config.js
│       │   │   └── src
│       │   │       ├── index.ts
│       │   │       └── shim-vue.d.ts
│       │   ├── module-mobile-demo2
│       │   │   ├── index.ts
│       │   │   ├── package.json
│       │   │   ├── rollup.config.js
│       │   │   └── src
│       │   │       ├── index.ts
│       │   │       └── shim-vue.d.ts
│       │   └── module-mobile-dependencies
│       │       ├── index.ts
│       │       ├── package.json
│       │       └── src
│       │           └── dependencies.ts
│       ├── lerna.json
│       ├── tsconfig.json
│       └── package.json
├── lerna.json
└── package.json

单工程包管理类似,多工程包管理方案为了解决整体结构复杂,并且功能需要做最小化拆分的场景。在多工程包中提供的module-dependencies作为整个工程包的总入口向外提供功能。

如示例中所示:

// 视情况按需引入
// import '@kunlun/module-mobile-demo/dist/kunlun-module-mobile-demo1.css';
// import '@kunlun/module-mobile-demo/dist/kunlun-module-mobile-demo2.css';

import '@kunlun/modules-mobile-dependencies';

与单工程包唯一的区别在于启动工程的导入方式有所不同,仅需通过import '@kunlun/modules-mobile-dependencies';导入所有功能即可。在总入口处将对所有子工程包进行统一的导出并且包含了对应的css相关内容。

特别的是,如果多个工程间的css样式出现冲突,但又需要依赖js文件时,css相关内容将不能在总入口处进行导入,需要放在对应的启动工程中进行导入处理。原则上,我们应该避免这种情况的发生。

启动工程

├── packages
│   └── kunlun-mobile-boot
│       ├── package.json
│       ├── public
│       │   ├── favicon.ico
│       │   └── index.html
│       ├── src
│       │   ├── main.ts
│       │   └── shim-vue.d.ts
│       ├── tsconfig.json
│       └── vue.config.js
├── lerna.json
└── package.json

作为vue项目的启动工程,它应该仅用于工程组合,即选择性的使用某几个工程进行启动。

rollup脚本简述

通过package.json构建所需工程名称

const buildName = (name) => {
  const libraryName = name.replace('@', '').replace('/', '-');
  const pathName = libraryName.substring(packagePrefix.length);
  const camelCaseName = libraryName.replace(/-(\w)/g, (all, letter) => letter.toUpperCase());
  return { libraryName, pathName, camelCaseName };
};

使用方法:

import pkg from './package.json';

const res = buildName(pkg.name);
const libraryName = res.libraryName;

转换结果:@kunlun/module-mobile-demo -> kunlun-module-mobile-demo.esm.js

多工程包构建脚本的使用

方法签名
function rollupConfig(name = '', external = [], hasSCSS = true, extendPlugins)
示例脚本
import pkg from './package.json';
import rollupConfig from '../../scripts/build.config.js';

export default rollupConfig(pkg.name, [
  'vue',
  'lodash-es',
  'vant',
  '@ant-design/icons-vue',
  '@kunlun/mobile-dependencies',
  '@kunlun/vue-ui-mobile-vant'
], false);
  • pkg.name:通过当前路径的package.json获取name属性。
  • external:打包时排除当前工程中导入的第三方包,原则上需要全部排除,否则会出现内存变量不一致的问题。
  • hasSCSS:是否进行scss编译。当使用scss时,必须开启。
  • extendPlugins:扩展插件。

Oinone社区 作者:nation原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/49.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
nation的头像nation数式员工
上一篇 2023年6月20日 pm4:07
下一篇 2023年11月2日 pm1:58

相关推荐

  • 【界面设计器】自定义字段组件实战——轮播图

    阅读之前 此文章为实战教程,已假定你熟悉了【界面设计器】较为完整的【自定义组件】相关内容。 如果在阅读过程中出现的部分概念无法理解,请自行学习相关内容。【前端】文章目录 业务背景 用户需要从【创建/编辑】页面中上传多张图片,并且在【详情】页面将这多张图片进行【轮播】展示。 业务分析 从需求来看,我们需要实现一个【轮播图】组件,并且该组件允许在【详情】视图中使用。在其他视图中,我们可以直接使用平台内置的【图片】组件,实现基础的编辑和展示功能。 名词解释 业务模型:需要进行可视化管理的存储模型或代理模型。 准备工作 你需要在某个业务模型下创建一个【表格视图】用于查看全部数据,创建【表单视图】用于创建/编辑数据,并创建【详情视图】展示必要的信息。(为了方便起见,你可以在所有视图中仅使用编码和名称两个字段) 你需要将【表格视图】绑定到某个菜单上,并通过【跳转动作】将三个视图进行关联,可以完整执行当前模型的全部【增删改查】操作。 业务模型定义 (以下仅展示本文章用到的模型字段,忽略其他无关字段。) DemoModel 名称 API名称 业务类型 是否多值 长度(单值长度) 编码 code 文本 否 128 名称 name 文本 否 128 轮播图 carouselImages 文本 是 512 实现页面效果展示 表格视图 表单视图-创建 表单视图-编辑 详情视图 根据业务背景添加轮播图字段到所有视图 轮播图字段信息: 字段业务类型:文本 多值:是 使用组件:图片 无代码模型 在模型设计器创建轮播图字段,并从【组件库】-【模型】拖放至视图中即可。 PS:这里需要注意的是,在模型设计器中需要切换至专家模式,并确认字段长度为512,否则当URL超长时将无法保存。 低代码模型 与服务端同学确认字段,并从【组件库】-【模型】中拖放至视图中即可。 将上图中的【演示】数据进行【编辑】,并上传三张图片,在【详情视图】查看默认展示效果。 演示图片下载 创建组件、元件 准备工作完成后,我们需要根据【业务背景】确定【组件】以及【元件】相关信息,并在【界面设计器】中进行创建。 以下操作过程将省略详细步骤,仅展示可能需要确认的关键页面。 创建轮播图组件 创建轮播图元件 根据业务背景,我们需要根据模型中的字段确定业务类型,在这个场景中,可以使用如下配置。(暂时可以不进行属性面板的设计) 在【详情视图】中将【轮播图字段】的组件切换为我们新创建的【轮播图组件】 PS:这里会发现组件变成了【输入框】的样式,这是由于我们没有提供对应元件的代码实现,使得SPI找到了默认组件。 启动SDK工程进行组件基本功能开发 (npm相关操作请自行查看SDK工程中内置的README.MD) Carousel.vue <template> <a-carousel class="carousel" effect="fade" autoplay> <div class="carousel-item" v-for="image in images" :key="image"> <img :src="image" :alt="image" /> </div> </a-carousel> </template> <script lang="ts"> import { Carousel as ACarousel } from 'ant-design-vue'; import { computed, defineComponent, PropType } from 'vue'; export default defineComponent({ name: 'Carousel', components: { ACarousel }, props: { value: { type: Array as PropType<string[]> } }, setup(props) { const images = computed(() => props.value || []); return { images }; } }); </script> <style lang="scss"> .carousel { .slick-slide { height: 160px; & > div, .carousel-item { width: 100%; height: 100%; } img { max-width: 100%; max-height: 100%; margin: auto; } } } </style> 效果展示 开发完成后,我们将重新打包生成的JS文件和CSS文件在【界面设计器】的【低无一体】进行上传,就可以在【设计器环境】中正常使用了。 设计轮播图的属性面板 通过我们使用的a-carousel组件,我们发现组件中提供了很多【属性】或【功能】可以进行配置,比如是否自动切换(autoplay)、面板指示点位置(dotPosition)、是否显示面板指示点(dots)等。在这里我们将对这三个属性的配置方式进行演示,其他更多属性可以自行设计并开发。 我们可以在【界面设计器】的【属性面板设计】中根据这三个属性的字段类型确定以下信息: 功能 API名称 业务类型 选用组件 可选项 是否自动切换 autoplay 布尔 开关 -…

    2023年11月1日
    3.9K00
  • 前端视图的元数据与数据的传递、交互

    在阅读本篇文章之前,您需要学习以下知识点: 1: 元数据 视图的元数据 在日常开发中,我们会经常遇到自定义的字段、动作、视图需要界面设计器配置的数据,这些数据可能是当前页面的字段,也有可能动作,那么如何获取呢? 视图元数据分为两种:1: 当前视图(metadataRuntimeContext)2: 根视图(rootRuntimeContext) 那么这两种类型怎么区分呢? 举个例子:1: 如果当前字段是在表单中,那么当前视图就是表单,根视图就表单的父级视图,如果只有一个表单视图,那么当前视图就是根视图。2: 如果当前视图是表单,但是表单里面有个表格,对于表格字段而言,当前视图就是表格,根视图就是表单。 当前视图的元数据(metadataRuntimeContext) 在前端,我们通过 metadataRuntimeContext 来获取视图的元数据,例如: export class CustomFormStringFieldSingleWidget extends FormStringFieldSingleWidget { protected mounted(): void { console.log(this.metadataRuntimeContext); } /** * 界面设计器配置的动作 */ @Widget.Reactive() protected get modelActions() { return this.metadataRuntimeContext.model.modelActions } /** * 界面设计器配置的字段 */ @Widget.Reactive() protected get modelFields() { return this.metadataRuntimeContext.model.modelFields } } 属性名 类型 可选性 描述 viewAction RuntimeViewAction 是 运行时跳转动作(通过跳转动作创建的运行时上下文具备该属性) module RuntimeModule 否 运行时模块 model RuntimeModel 否 运行时模型 view RuntimeView 否 运行时视图 viewLayout DslDefinition \| undefined 否 视图布局 DSL,从运行时视图解析获得 viewDsl DslDefinition \| undefined 否 视图模板 DSL,从运行时视图解析获得 viewTemplate DslDefinition 否 视图最终执行 DSL,从运行时视图解析获得或根据布局 DSL 和模板 DSL 合并生成 getModel (model: string, isBelong?: boolean) => GetModelResult \| undefined 否 获取模型,返回获取的模型和所在的运行时上下文 getModelField (data: string, isBelong?: boolean) => GetModelFieldResult \| undefined 否 获取模型字段,返回获取的模型字段和所在的运行时上下文 getRequestModelFields (options?: GetRequestModelFieldsOptions) => RequestModelField[] 否 获取请求字段 getDefaultValue () => Promise<Record<string, unknown>> 否 获取默认值 getInitialValue () => Promise<Record<string, unknown>> 否 获取初始值 运行时模型(model) 属性名 类型 可选性 描述 id string 是 模型 id model string 否 模型编码 name string 否 技术名称 modelFields RuntimeModelField[] 否 模型字段 modelActions RuntimeAction[] 否 模型动作 type ModelType 是 模型类型 module string 是 模块编码 moduleName string 否 模块名称 moduleDefinition RuntimeModule 是…

    2024年10月8日
    2.7K00
  • 界面设计器 扩展字段的查询上下文

    默认情况下oinone平台对于查询条件,只提供的当前登录用户这一个配置,但是允许开发者扩展 开发者可以在前端代码的main.ts进行扩展 import { SessionContextOptions, ModelFieldType } from '@kunlun/dependencies'; const currentDeptOption = { ttype: ModelFieldType.String, value: '$#{currentDept}', displayName: '当前登录部门', label: '当前登录部门' }; SessionContextOptions.push(currentDeptOption as any); 加上上面的代码,然后再去界面设计器,我们就会发现,多了一个配置

    2023年11月8日
    1.5K00
  • 如何自定义 GraphQL 请求

    在开发过程中,有时需要自定义 GraphQL 请求来实现更灵活的数据查询和操作。本文将介绍两种主要的自定义 GraphQL 请求方式:手写 GraphQL 请求和调用平台 API。 方式一:手写 GraphQL 请求 手写 GraphQL 请求是一种直接编写查询或变更语句的方式,适用于更复杂或特定的业务需求。以下分别是 query 和 mutation 请求的示例。 1. 手写 Query 请求 以下是一个自定义 query 请求的示例,用于查询某个资源的语言信息列表。 const customQuery = async () => { const query = `{ resourceLangQuery { queryListByEntity(query: {active: ACTIVE, installState: true}) { id name active installState code isoCode } } }`; const result = await http.query('resource', query); this.list = result.data['resourceLangQuery']['queryListByEntity']; }; 说明: query 语句定义了一个请求,查询 resourceLangQuery 下的语言信息。 查询的条件是 active 和 installState,只返回符合条件的结果。 查询结果包括 id、name、active、installState 等字段。 2. 手写 Mutation 请求 以下是一个 mutation 请求的示例,用于创建新的资源分类信息。 const customMutation = async () => { const code = Date.now() const name = `测试${code}` const mutation = `mutation { resourceTaxKindMutation { create(data: {code: "${code}", name: "${name}"}) { id code name createDate writeDate createUid writeUid } } }`; const res = await http.mutate('resource', mutation); console.log(res); }; 说明: mutation 语句用于创建一个新的资源分类。 create 操作的参数是一个对象,包含 code 和 name 字段。 返回值包括 id、createDate 等字段。 方式二:调用平台的 API 平台 API 提供了简化的 GraphQL 调用方法,可以通过封装的函数来发送 query 和 mutation 请求。这种方式减少了手写 GraphQL 语句的复杂性,更加简洁和易于维护。 1. 调用平台的 Mutation API 使用平台的 customMutation 方法可以简化 Mutation 请求。 /** * 自定义请求方法 * @param modelModel 模型编码 * @param method 方法名或方法对象 * @param records 请求参数,可以是单体对象或者对象的列表 * @param requestFields…

    2024年9月21日
    1.6K00
  • 组件生命周期(v4)

    阅读之前: 你应该: 了解DSL相关内容。母版-布局-DSL 渲染基础(v4) 对第三方框架的组件生命周期有所了解。如Vue组件生命周期 了解平台实现的Class Component(ts)相关内容。Class Component(ts)(v4) 组件生命周期 任何一个Widget其标准生命周期应当包括beforeCreated、created、beforeMount、mounted、beforeUnmount、unmounted这六个基本的生命周期函数、以及beforeUpdate和updated在响应式更新时会进行调用的生命周期函数。特别的,还有activated和deactivated在组件搭配keep-alive特性时使用的生命周期函数。 具体的生命周期执行过程在这里不再进行赘述,这里的基本逻辑与Vue组件生命周期基本完全一致,感兴趣的读者可以阅读Vue相关文档进行学习。

    2023年11月1日
    1.1K10

Leave a Reply

登录后才能评论