注意 本文章对应版本已经过时,请查阅最新版文档 https://github.com/maichong/l...


QQ交流群 282140496


在微信公布小程序的文档和开发工具后,脉冲软件在第一时间进行了学习和体验,我们发现微信小程序的技术架构和开发体验让我们非常失望。

由于微信小程序的运行环境并不是一个标准的浏览器环境,而且微信的封装工作并不完善,所以我们以往开发中的很多经验并不适用。

这并非简单的开发习惯不适应,更重要的是我们的开发流程、规范将不适用。

微信小程序开发第一宗罪: 无法调用NPM包

虽然微信小程序开发工具打包时实现了require函数加载依赖,但并不是完整的CommonJS依赖管理。因为require函数仅仅能够加载项目中的JS文件,而且必须严格定义JS文件路径,路径不支持CommonJS的路径风格。例如如下加载方式都将出错:

require('lodash');

require('lodash/map');

require('./foo');

在微信小程序开发工具中,我们必须对应写为如下格式:

require('node_modules/lodash/lodash.js');

require('node_modules/lodash/map.js');

require('./foo.js');

虽然我们可以像上面代码一样加载node_modules目录中的库,但是实际运行时却发生了:

在调试工具的Network选项卡中,我们看到运行时加载了1000多个文件,总数据量1.8MB,而我们仅仅是在代码中加载了一个lodash库而已!这是因为微信小程序开发工具会将所有项目下的js文件视为项目文件,并进行打包。而实际开发中,我们需要安装很多的NPM扩展库,而这些扩展库中有大量的不需要打包的文件,例如lodash中有上千文件,而我们只需要用到其中的非常少的一部分。

另外,在开发中,我们往往需要安装babal、eslient、webpack、grunt等待开发工具,微信小程序开发工具会一视同仁将这些工具的源码也进行打包......实测开发者工具将崩溃!开发者将崩溃!我崩溃!

所以不支持NPM包的原因,是微信开发者工具不支持CommonJS标准,不支持CommonJS标准的原因,是微信开发者工具想当然地认为项目目录下的js文件一定是项目文件,所以只实现了简单的require函数,想当然的原因是。。。

微信小程序开发第二宗罪: 无法使用Babel转码

无法使用Babel转码的原因其实仍然归结于无法加载NPM库。但是后果将十分严重。因为你将不能再安全使用ES6/7特性,你将无法使用async/await函数,你将和无尽的callback做斗争,你该怎样描述自己?回调地狱中的苦逼程序员?

如果你看到这里不明白Babel为何物,那么祝贺你,因为不曾见过天堂就不知何为地狱,你无须为不支持ES6/7而烦恼。但一旦你的大脑支持了ES6/7,用过了Babel,你就回不去了,像我一样,无Babel不编码。

微信小程序开发第三宗罪: 无法重用组件

其实微信小程序开发是并非完全不能重用组件,比如WXML语法中支持import和 include。但是那仅仅是视图模板可重用,并非组件可重用,因为我们认为组件在应当包含视图和逻辑。

WXML其实是基于可重用的组件,但是不允许我们自定义组件。如果你有React经验,你就会明白我的意思。

例如,你的小程序是个电商APP,项目中有两个页面中同时包含了商品列表组件,比如某分类下商品列表和搜索结果列表,我们知道这两个列表其实仅仅是参数不同而已。但是在小程序开发中,你只能将列表的模板抽象出来,不能将逻辑抽象出来,所以你就需要在两个页面上都实现一遍列表组件的控制逻辑,比如刷新、加载更多。。。

我们的实践

只吐槽、管杀不管埋是不道德的,既然发现了微信小程序开发中的各种弊端,我们脉冲软件在开发之中总结出了一套流程和工具,专为解决上述三个问题,并免费发布到了开源社区,这就是Labrador。接下来我们一起来尝试一下我们脉冲软件的开发体验。

安装Labrador

通过命令 npm install -g labrador-cli 全局安装Labrador控制行工具。

初始化项目

通过如下命令新建一个Labrador项目:

mkdir demo

cd demo

npm init

labrador init

项目初始化完成后,该目录是这个样子的:

图中的src是我们的源码目录,node_modules是NPM包目录,dist是目标输出目录。请在开发者工具中新建一个项目,并设置路径到dist目录,请勿设置为demo目录!使用WebStorm或Sublime打开demo目录,开发过程中,我们使用WebStorm或Sublime修改src目录下的源码,请勿直接修改dist目录中的文件,因为dist目录是通过labrador命令生成的。

在demo目录中运行 labrador build 命令编译项目,该命令会将src目录下的文件一一处理并生成dist目录下对应的文件。我们也可以运行 labrador watch 命令监控src目录下的文件变化,这样就不用每次修改后手动运行编译命令。

加载NPM包

我们以lodash包为例,在src/app.js中键入代码 const _ = require('lodash'); 编译后,我们看到dist目录下的文件是这样的:

我们看到dist目录下有一个npm/lodash目录,该目录下只有一个lodash.js文件,那么在微信web开发者工具中打包预览,lodash的库将只有这个文件被加载。

这一切是怎么发生的?

我们看一下dist/app.js的源码,发现源码中const _ = require('lodash'); 被编译为 var _ = require('./npm/lodash/lodash.js'); 然后labrador命令将node_modules/lodash/lodash.js 文件复制到了 dist/npm/lodash/lodash.js 。这就是通过labrador可以调用NPM包的原理。

重要的是,只有真正用到的js文件才被labrador命令加入到项目目录中。这样一个小小的改进象征着我们的小程序可以便捷调用NPM仓库中海量的扩展库!

Babel转码

在初始化的示例代码src/app.js中的内容是这样的:

图中timer和getUserInfo属性都为async函数,函数体内使用await调用异步操作。labrador 库对微信API进行了封装,使用 const wx = require('labrador'); 覆盖默认的全局变量wx; 封装后的wx对象提供的异步方法返回的都是Promise异步对象,结合async/await函数彻底终结callback,将异步代码同步写,轻松逃离回调地狱!

但目前async/await函数是不被浏览器支持的,我们需要使用babel对其转码,labrador编译命令已经内置了babel转码,转码后的代码可以查看dist/app.js,内容过长,不再张贴。

重用组件

重用组件最需要解决的问题是组件的逻辑代码怎样重用。在实例代码中有一个src/components目录,用来存放项目内的可重用组件,其结构是这样的:

子目录src/components/list中存放着一个可重用的组件。list.js / list.less / list.xml 分别对应微信小程序的 js / wxss / wxml 文件。JS为控件的逻辑层,其代码如下:

文件导出一个List类,这个组件类拥有像Page一样的生命周期函数onLoad, onReady, onShow, onHide, onUnload 以及setData函数。

LESS文件对应微信的WXSS文件,因为微信小程序实现的限制,LESS中无法使用连级选择语法,但是可以定义变量,方便开发。

XML文件对应微信的WXML文件,是组件视图描述文件,list.xml内容为:

文件中导出一个名为list的template。
组件不但可以存放在src/components目录内,还可以单独做成NPM包,这样就可以轻松做到跨项目间的组件共享。

组件定义完成后,接下来是在页面中调用,在 src/pages/index/index.js 中有如下代码:

代码中首先引入了labrador库替换全局的默认wx对象,并使用labrador.createPage方法代替全局的Page函数声明页面。然后加载List组件类,在页面声明配置中,增加了components属性,并将List组件类实例化传入。labrador.createPage方法是对Page方法的一层封装,目的是在页面初始化时和组件对象进行关联。

在 src/pages/index/index.less 中加入代码 @import 'list' 即可调用list组件的样式,如果在src/components/list中找不到list.less,那么编译命令将在NPM包中寻找 node_modules/list/index.less 。

在 src/pages/index/index.xml 中加入代码 <component key="list"/> 即可调用list组件的模板文件,component 是Labrador自定义的组件,编译后对应生成 import 和 template。如果在src/components/list中找不到list.xml,那么编译命令将在NPM包中寻找 node_modules/list/index.xml

具体的体验还需要你亲自动手才行,文章到此结束,谢谢!


注意 Labrador 已经发布0.3版本,最新接口和此文内容会有出处,如果你不曾了解Labrador,那么你可以阅读此文初步了解Labrador,如果你已经开始基于Labrador构建项目,请参阅 使用Labrador 0.3构建ES6/ES7标准模块化微信小程序 一文查看最新的接口。

26 条评论

frostbelt 2016年09月30日

build时报错怎么解决?
项目构建失败!
ReferenceError: Unknown plugin "transform-export-extensions" specified in

+1 回复

npm install transform-export-extensions

nill 4 天前 回复

lcfevr 2016年10月08日

ReferenceError: Unknown plugin "transform-export-extensions" build的时候报这个错应该怎么解决呢 楼主

+1 回复

Winglau14 2016年09月28日

楼主,照着你的教程,把你的栗子在微信开发者工具上跑了下,报加载 app-service.js 错误,不知道你那边会不会?

回复

乐悠族 2016年09月28日

app.json的pages里面去掉logs就可以了

回复

Winglau14 2016年09月28日

thx

回复

乐悠族 2016年09月28日

这样引用包之后打包大小不会大于1M?lodash一个文件就500K了,额,还需要压缩?

回复

脉冲软件_梁兴臣 作者 2016年09月29日

我觉得微信最终打包成小程序的时候会压缩的,如果等微信真正发布小程序的时候没压缩,我会把压缩加进去labrador

回复

frostbelt 2016年09月30日

组件list的css还是单独import的,能像 html-webpack-plugin 一样把css也打包到组件中吗?

回复

shenzm 2016年10月06日

关于第三点重用组件的问题,看了下CreatePage的源码,有点疑问

CreatePage的做法是 将调用方的page的onload,onReady, onShow, onHide, onUnload的生命周期中先执行 重用组件 的生命周期,然后再执行本身的。那是不是漏掉了 重用组件 中的事件响应呢?

回复

shenzm 2016年10月06日

回复

脉冲软件_梁兴臣 作者 2016年10月06日

对,目前版本存在这个问题

回复

lcfevr 2016年10月08日

项目构建失败的问题解决了吗?

回复

frostbelt 2016年10月08日

解决了,谢谢。npm install 了缺失的插件,是否 package.json 里的 dependencies 不全?

回复

lcfevr 2016年10月08日

package.json里面并没有依赖生成啊 使用的labrador init命令生成的项目文件

回复

frostbelt 2016年10月08日

labrador init 时就已经报错了,我猜可能是开发者本地有全局的插件,而我这边没有安装。npm install babel-plugin-transform-export-extensions --save-dev 安装 “transform-export-extensions”,还有其它一些依赖,就是报什么错就装什么,得有4,5个吧。然后就能跑起来了。试用了一下感觉也不是很灵活

回复

lcfevr 2016年10月08日

已经安装了 先跑起来看看效果

回复

lcfevr 2016年10月08日

感谢

回复

脉冲软件_梁兴臣 作者 2016年10月09日

最新版本已经支持组件嵌套及事件绑定 https://segmentfault.com/a/11...

回复

雨泽 1月6日

npm install -g labrador-cli这个命令安装之后并没有错误,但是我Labrador init之后什么都没有

回复

你直接敲Labrador 查看相关命令 Labrador init只是初始化 Labrador create demo是创建项目

nill 4 天前 回复

Juvenile 1月10日

npm install -g labrador-cli这个命令安装之后并没有错误,但是我Labrador init之后什么都没有

回复

载入中...
脉冲软件_梁兴臣 脉冲软件_梁兴臣

224 声望

发布于专栏

脉冲软件-梁兴臣

专注JS全栈开发

11 人关注

SegmentFault

一起探索更多未知

下载 App