大家好,我是Echa。
好消息,饿了么官网MorJS 前端研发团队宣布 MorJS v1.0.0 正式发布。经过 MorJS 前端研发团队2个多月的没日没夜的赶工研发,终于面世大众了。
说到MorJS 前端研发团队,让小编第一时间联想到饿了么线上外卖和即时配送服务以及开源项目,饿了么开源项目大家庭分别有:Element UI、mint-ui、v-charts、vue-amap、vue-infinite-scroll、crayfish、vue-infinite-scroll、UETool等等,现在又新增一名新成员:MorJS。
饿了么是2008年创立的本地生活平台,主营在线外卖、新零售、即时配送和餐饮供应链等业务。创业15年,饿了么以“Everything 30min”为使命,致力于用科技打造本地生活服务平台,推动了中国餐饮行业的数字化进程,将外卖培养成中国人继做饭、堂食后的第三种常规就餐方式。创始人为张旭豪。
饿了么在线外卖平台覆盖全国670个城市和逾千个县,在线餐厅340万家,用户量达2.6亿, 旗下“蜂鸟”即时配送平台的注册配送员达300万。 业绩持续高速增长的同时,公司员工也超过15000人。
2018年4月,阿里巴巴联合蚂蚁金服对饿了么完成全资收购, 饿了么全面汇入阿里巴巴推进的新零售战略, 拓展本地生活服务新零售的全新升级。 2018年8月8日,饿了么获金云奖年度 最佳效果运营奖。
今天小编给大家先细聊这个MorJS 到底是个什么,能做什么事情呢?请继续下面阅读。
全文大纲继 2017 年非常流行小程序诞生以来,由于其独特的商业模式和轻应用的用户体验,在移动社交电商等领域不断取得亮眼成绩。目前各大平台都相继推出了自己的小程序,饿了么 C 端业务需要在不同平台小程序进行投放,这些项目大多是以支付宝或微信原生 DSL 编写,面对业务渠道的不断增加,饿了么官方尝试了多种方法来兼容多端适配,但由于不同平台间小程序代码写法、能力支持的差异性逐步变大,过去的方案无法满足新业务的需求,饿了么官方需要一套跨端研发框架能解决以下诉求:
在明确这几点后,饿了么前端研发团队调研了业界所有主流技术框架,发现并没有能完全满足饿了么官方需求的方案,所以饿了么研发团队决定自研 MorJS。
MorJS 介绍官网:https://mor.eleme.io/
Github:https://github.com/eleme/morjs
Mor (发音为 /mɔːr/,类似 more) 是饿了么开发的一款基于小程序 DSL 的,可扩展的多端研发框架。使用小程序原生 DSL 构建,使用者只需书写一套(微信或支付宝)小程序,就可以通过 MorJS 的转端编译能力,将源码分别编译出可以在不同端(微信/支付宝/百度/字节/钉钉/快手/QQ/淘宝/H5…)运行的产物。
MorJS 以多端编译为基础,配以面向全生命周期的插件体系,覆盖从源码到构建产物的每个阶段,支持各类功能扩展和业务需求,无论是基础的页面和组件还是复杂的分包和插件,MorJS 都可以胜任,帮助你高效地开发多端小程序。
如下图:
MorJS 官网
MorJS 优势与核心能力Mor 是一套基于小程序 DSL (支付宝或微信) 的框架。他的易用性、标准化和灵活性,使得开发者能更好地专注于业务,让开发成本,招聘、管理、测试各方面成本都大幅下降,提高开发者的工作效率。
MorJS 内置了一套完整的插件体系,覆盖从源码构建到生成产物的各个阶段,主要分为以下三方面:
架构概览
直接上图,清晰明了:
MorJS整体架构图
静态编译原理
静态编译转换主要用于处理 JS、WXS/SJS、WXML/AXML、WXSS/ACSS、JSON 等源码中约束强且不能动态修改的部分,如:
如下图:
运行时补偿原理
运行时补偿主要用于处理静态编译无法处理的一些运行时动态内容,如:
如下图:
功能定制
业务可基于自身业务诉求来定制 工程插件 或 运行时插件/解决方案。
工程能力定制
运行时能力定制
MorJS 如何快速上手环境准备
MorJS 项目基于 node,请确保已具备较新的 node 环境(>=14),推荐使用 node 版本管理工具 nvm 来管理 node(Windows 下使用 nvm-windows),这样可以很方便地切换 node 版本,全局安装时候也不必再使用 sudo。
# mac 或 linux 下安装 nvm
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
$ nvm -v
0.39.1
# 安装 node
$ nvm install 14
$ nvm use 14
$ node -v
v14.21.3
创建项目
Mor 提供了 create-mor 和 mor cli 工具两种方式来创建新项目,选择其中任一一种即可。
确保你安装了符合版本的 Node.js,选定项目目录,在目录终端执行以下任一命令:
$ npm init mor # npm 创建项目
$ yarn create mor # yarn 创建项目
$ pnpm create mor # pnpm 创建项目
这一指令将会安装并执行 create-mor,它是 Mor 官方的项目脚手架工具。
确保你安装了符合版本的 Node.js,创建项目目录,全局安装 mor cli 工具
$ mkdir myapp && cd myapp # 创建项目目录
$ tnpm i @ali/mor-cli -g # 全局安装 mor cli
$ mor -v # 查看全局 mor 版本
此时你已安装了 mor cli 工具,然后通过 mor init 命令即可创建项目:
$ mor init
初始化项目
创建项目后你会看到如下命令号交互界面,选择对应的工程类型,按照提示完成初始化操作:
在项目初始化之后,Mor 会默认开始安装项目所需要的依赖,一般来说,依赖安装会自动完成,但某些情况下可能会安装失败,这时候你可以在项目目录下自己使用安装命令进行安装:
$ npm i
编译运行
使用 MorJS 的 compile 命令可以把 MorJS 代码编译成不同端的代码,然后在对应的开发工具中查看效果。MorJS 初始的编译命令配置了 dev 和 build 两种模式:
执行 npm run dev 命令,进行浏览调试:
多端产物已构建在 dist 目录下,分别用对应平台的 IDE 打开即可开发预览:
在 微信开发者工具 中打开 dist/wechat 目录即可开始微信小程序开发预览 在 支付宝小程序开发者工具 中打开 dist/alipay 目录即可开始微信小程序开发预览
MorJS 整体架构关于小程序转 Web,MorJS 的思路是将已有的小程序工程直接转成 React 代码。
借助 Webpack ,MorJS 提供了一整套的 loader,包含 axml-loader(负责编译 axml 文件)、acss-loader (负责编译 acss 文件)、js-loader (负责编译小程序中的 js 文件)。
如下图:
MorJS 整体架构
上图是小程序转 Web 的整体架构。最上面的四个部分属于内核部分,分别由 编译器、dsl runtime、api(my)、全局公共组件 四个模块组成,每一个模块都是独立可替换的。
Compiler(编译器)
编译器模块比较特殊,主要负责将 axml 、acss 、js 、json 等文件编译成模块化的 js 文件,完全是静态编译。至于详细的编译流程下面会细说。
Runtime(运行时)
runtime 提供了小程序在 h5 中的运行时功能,比如:Page 、Component 、App 等全局函数,并且提供完整的生命周期实现,事件的注册、分发(非 react 事件),slot、block 等全局 DSL 层面组件实现,等等。
API (my.*)
api 模块提供了类似支付宝小程序中 my 一系列 api 的实现,事实上,目前 api 的实现其实相对来说比较分散,在 api 模块并没有提供全部的支付宝小程序 api 的实现,有些 api 在全局公共组件来实现(比如:UI 相关的 api,下拉刷新等),甚至有些 api 需要开发者自己来实现(比如:登录态的获取等等)。
Components(全局公共组件)
全局公共组件指的是 view、button、scroll-view 等支付宝小程序原生提供的组件,在 MorJS 中,这些组件是基于 web-components 来实现的,之所以使用web-components 来实现而不是 react ,是基于以下几个原因:
以上几个优势,如果用 react 来实现,虽然在技术上是可以有类似的实现,但是成本就比较高了,远不如 web-components 来的简单直接。
其它
除了以上四个核心模块以外,由于公共组件、api 的实现都是模块化的,尤其是 api 部分,可以轻易的扩展自己的 api 设置重写部分 api ,因此对于接入方来说,可以扩展自己的公共组件、api。
以上四个模块,除了编译器模块,剩余的三个模块整体才算一个完整的小程序运行时。
运行流程
运行流程
上图中的运行流程其实跟普通的 react 工程运行流程差不多,仅仅是多了一个针对 axml 文件、acss 文件、js 文件进行额外编译转码的流程,最终还是通过 webpack 进行打包运行。
进一步可以分析出,这样的流程,不管是整个工程级别的转码,还是组件库级别转码,甚至是已有 react 项目直接引入小程序代码,都可以通过上图中的方式直接(loader 方式)或者间接(命令行)运行。
编译流程
不同的文件,编译的方式是不一样的,编译处理的内容也是不一样的。
AXML
整个小程序编译器,就数 axml 文件编译最复杂。整个编译流程如上图所示。
axml 编译复杂的部分,不在 ast,而是在 generate 中,各种小程序 dsl 的特性都需要在这里进行转换。
ACSS
acss 编译,其实很简单,目前只是做了三件事:
JS
最新版本的编译器,极大简化了 JS 文件的编译。目前 JS 编译器仅仅如如下几个事情。
总结
但从编译器来说,最核心的就是 AXML 的编译,而 acss 和 js 文件 的编译相对来说很简单。
MorJS 运行时原理不管是 Page 还是 Component,在 MorJS 中,都会被视作组件处理。
上图是一个小程序组件不同代码文件最终被合并成一个组件的大概流程。从上图中可以看到,acss 文件、axml 文件在编译的时候就会被编译成 react render function ,而且是最终的渲染函数。这个函数只接受一个参数(render-data),根据 data 渲染出 html,没有任何其他的功能。
而 Component(options) -(其实就是 js 文件)会被编译器以模块的形式导出,在 runtime 中会根据 options 动态生成一个 Component 的实例(非 react 组件),这个实例就是小程序中可以通过 this 访问的实例。
而上图中提到的 React 基础组件 可以这么理解,每个小程序组件的实例(Component)都会对应一个 React 基础组件,这个 React 组件负责管理生命周期函数的调用,并且负责渲染,同时也负责事件的交互回调。
每当 setData 被触发的时候其实是在 Component 中触发的,然后 Component 会调用 react 组件的 render 函数,进一步调用到上面提到的 react render function。
Component 和 React 组件 之间是一个循环交互的过程,Component 跟 React 组件 是通过 setData 进行交互进而触发 render,而 React 组件 和 Component 之间是通过直接方法调用的形式来交互。这个双向交互的流程就组成了 MorJS Web runtime 的内核部分。
从上图也可以看出,acss 、axml 两个文件其实跟 Component 并没有强关系,仅仅是一个渲染函数,根据给定的 render-data 而渲染出结果而已,如果把 Componet(options) 去掉,也就是把小程序中的 js 文件去掉,那么就是一个模板文件,而事实上 MorJS 中也是这么实现 template 功能的。
MorJS 主包体积优化背景
互联网时代中人们对信息的需求逐渐趋向快捷化、方便化、效率化,为了适应快节奏的社会发展,小程序应运而生,作为快时代的产物,各平台小程序逐渐进入大众用户的视野,成为人们生活中不可或缺的一部分,不用安装 APP,不用记住网址,随用随取简单方便。
小程序作为轻量级应用,为了保障顺畅运行,各平台对于小程序体积大小有着严格的规定,而随着业务需求的不断累积,通常小程序的体积也在不断增大,官方也推出了支持小程序分包加载功能,将小程序划分成不同的子包,在构建时打包成不同的分包,用户在使用时按需进行加载,但是每个使用分包小程序必定含有一个主包。(关于主包分包的概念可参考文档:复杂小程序集成-概念-模块类型)
以目前几个主流平台为例,支付宝、微信小程序都要求单个分包/主包大小不能超过 2M,所以对于优化小程序主包,降低小程序主包大小,成为大多数开发者都将面临的问题。
动机
主包中并非所有组件、文件都会被主包及多个分包使用,部分公共 js 代码、node_modules 代码和 npm 组件文件可能仅在某一个分包中使用,只要通过解析各文件依赖,建立分组关系,在编译时动态的将文件调配到不同分包中去,让分包自己的模块仅编译到自身路径内,仅分包间共享的模块才会进入主包,对于从未使用(引用)的代码或模块在编译时并不会一同打到产物中,以此用于优化主包体积。
相比与主包需要尽可能压缩自身体积,分包显然自身容量有较大的余留,那么把各个分包依赖的内容直接编译到对应分包中去,可以最大化利用分包自身的容量大小,在主包中由于该依赖内容不再有相关使用(引用),根据文件依赖的分析,在编译时这些已被冗余到各个分包的依赖就不会被一同打到主包产物中,减小主包体积的同时提升分包利用率。
目标
方案
模块依赖图
一个完整的项目,经过模块依赖图的分析,会给每个文件 Module 进行相关的依赖分析和分组,以文件的全路径作为唯一标识,分析构建其依赖图,对于各分包的文件分组到各自对应分包,对于主包文件若是被多个分包共享依赖则分组到主包,若是仅被某一个分包使用则会动态分组到该分包,而通过这些文件 Module 、分组 Group 等结构组成一张完整的模块依赖图,编译时通过各个文件的文件依赖树和分组关系,对应 entries 的文件信息进行编译产出产物。
分包动态编译优化
分包在执行编译的过程中,编译每个文件时会通过文件依赖树找到对应依赖及其文件信息,根据两者的分组关系,动态将公共 js 代码、node_modules 代码和 npm 组件文件调配到不同分包中去,生成该分包内的公共模块文件,而拆分出来的文件则因为在主包中不被任何其他模块依赖,将从主包编译中删除
独立分包冗余编译
将分包依赖的内容直接编译到对应分包中去,不论这些依赖是否和已有的分包有重叠,也不管是不是主包的组件,都会以冗余的方式编译到每个分包中去,最大化利用分包自身容量大小。
最后一台电脑,一个键盘,尽情挥洒智慧的人生;几行数字,几个字母,认真编写生活的美好;
一 个灵感,一段程序,推动科技进步,促进社会发展。
创作不易,喜欢的老铁们加个关注,点个赞,打个赏,后面会不定期更新干货和技术相关的资讯,速速收藏,谢谢!你们的一个小小举动就是对小编的认可,更是创作的动力。
,Copyright © 2008-2022 秒下下载站
m.down10s.com .All Rights Reserved