原文:https://isux.tencent.com/high-performance-wechat-app-development.html

前言

微信小程序是一个工程,就和盖房子一样,打好了地基,才能保证后续工程师建立在可靠牢固的基础上。

笔者需要经常新建项目,每次都要重复“修改项目结构 -> 从老项目中复制粘贴文件 -> 删除一些老项目中代码”这样的过程,实在是…费心费力。

另一个痛点是:每次新建小程序页面要生成三个文件名相同的文件 ( .wxml、.wxss 和 .js ),命令行太长(据微信同事:也可以在 app.json 的 pages 字段下添加新页面的路径,保存后也会生成对应的文件)。

因此,阅读本文需要对小程序开发稍有了解(简易教程指路)。

目标

我们现在有两个目标:

  1. 根据通用模板新建项目
  2. 一键新建页面目录以及在目录中的三个文件 :.wxml、 .wxss 和 .js也可以直接在 app.json 的 pages 字段创建页面,保存后生成这三个文件。笔者没有采用这个方法的缘由一个是开始时不知道有此功能,另一个是不合平时的操作习惯,再者想到 js 文件初始化后,需要引入常用库,要插入代码片段,所以保留了这个功能。

这两个需求其实很简单,不需要 GUI,所以我们可以做一个 npm 命令行工具。想象一下这个命令行用起来应该是什么样的呢:

  1. ~ npm install wxapp -g
  2. ~ wxapp -i myapp && cd myapp
  3. ~ wxapp -p list

用流程图示意就是:

实现

正式开始之前,请先确认本地的开发环境,笔者的本地环境是:

  1. ~ npm -v
  2. 3.10.10
  3. ~ node -v
  4. v6.9.4

我们把问题分解为三步:

  1. 实现命令行工具,可以在任意目录直接运行
  2. 通过输入不同的命令行参数,以执行不同的功能
  3. 考虑项目模板的存放位置,是集成到工具中,还是和工具分开呢

不用担心,都很容易解决,我们一个个看。

命令行工具

package.json 中有一个字段是 bin

  1. {
  2. ...
  3. "bin": {
  4. "mywxapp": "./index.js"
  5. }
  6. }
这个字段可以将开发者希望执行的脚本注册到环境变量 (PATH) 中,不同的 key 对应执行不同的脚本。也就是说现在,当我们直接在命令行中执行:
  1. ~ mywxapp

等价于在 terminal 中执行:

  1. ~ /path/to/index.js
第一个问题轻松解决,关于 bin 字段更多信息请参考 npm 文档中 package.json 一节

命令行参数

执行 index.js 时,可以通过 process.argv 获取执行时的参数,但是要从参数数组中拆分出参数无疑很麻烦。不过,npm 发展至今,处理命令行参数的库肯定存在,就是 commander。简单好用易上手,那么第二个问题也解决啦。

项目模板的存放位置

考虑项目模板的存放位置,是集成到工具中,还是和工具分开呢?

笔者选择分开管理。 在一个单独的模板代码仓库中管理模板内容,方便我们维护。目前的模板还比较简单(详见下文“模板详解”),只有标准目录结构,预期后面会加上自动化的部分(比如 less -> wxss),所以未来会改动比较频繁。

download-git-repo 可以把给定地址的仓库内容拷贝到执行目录中。API 简单,所以就是它了。

问题都解决了,现在就让我们看看伪代码(注意:伪码中没有考虑出错情况):

  1. const mkdirp = require('mkdirp');
  2. const download = require('download-git-repo');
  3. // 创建项目
  4. function initProj(projName){
  5. if(currentDir.exsits(projName))
  6. console.warn(projName + '项目已经存在于当前目录中,请使用别的名字');
  7. else
  8. download('path/to/tmpl', currentDir+'/'+projName);
  9. }
  10. // 注册页面
  11. function registerPage(pagesName) {
  12. // 读配置文件
  13. readFile(configFile, function(data){
  14. // 将新建的所有页面都写入配置文件中
  15. for(name in pagesName){
  16. data.pages.push('pages/' + name + '/' + name);
  17. }
  18. writeFile(configFile);
  19. });
  20. }
  21. // 创建页面
  22. function createPage(pages) {
  23. for(var index in pages) {
  24. var page = pages[index];
  25. mkdirp(pagePath, function(){
  26. createFile(page+'.wxml');
  27. createFile(page+'.wxss');
  28. createFile(page+'.js');
  29. })
  30. }
  31. // 将页面注册到 app.json 中
  32. registerPage(pages);
  33. }

使用

在编写好了这个工具之后,只需要在本地全局使用的话:

  1. npm install -g

在本地开发过程中,如果更新了开发版本的代码,需要更新同步到全局,这时候需要执行:

  1. npm link
就会看到安装到环境变量中的工具目录地址已经和开发目录关联起来了:
  1. ~/Documents/kmokidd/cli-build$ npm link
  2. /usr/local/bin/wxapp -> /usr/local/lib/node_modules/@kmokidd/wxapp-generator/index.js
  3. /usr/local/bin/node_modules/@kmokidd/wxapp-generator -> /Users/kmokidd/Documents/kmokidd/cli-build/index.js

使用起来是这样的:

模板和插件地址将附在参考资料一节中

发布 npm 插件

如果和笔者一样,希望在多个机器上使用这个工具,可以选择发布到 npm 官网上。发布步骤非常简单,基本上就是:

  1. npm login
  2. npm publish

不过笔者考虑到,项目模板毕竟是因人而异的东西,所以选择了发布 scope package,也就是在插件的 package.json 中的 name 字段使用 @scopeName/wxapp-generator 这样的值。

如果你也有类似的想法,并且也是个 npm 免费用户,那么发布的时候要执行:

  1. npm publish --access public

scope 对使用没有任何影响,但是安装的时候要记得带上 scope name 执行:

  1. npm install @scopeName/wxapp-generator -g

模板详解

一千个人中有一千种项目模板。根据业务/个人爱好不同,大家的项目模板可能也相去甚远。笔者自觉目前的模板用起来还不错,将在这一节介绍一下。以下是项目的文件结构:

  1. wxapp
  2. ├── app.js
  3. ├── app.json
  4. ├── app.wxss
  5. ├── base-styles/
  6. ├── images/
  7. ├── pages/
  8. │ ├── tmpl/
  9. ├── utils /
  10. │ ├── view.js
  11. │ ├── util.js
  12. │ ├── polyfiil.js
  13. └── └── Deferred.js

之所以采用这样的结构,是希望尽可能解耦 UI 逻辑与业务逻辑。但是由于完全解耦是不可能的,基本思路是单纯的“变量分离”。通常 UI 的改变是通过 class 的切换或者内联样式的调整,所以笔者的思路,是将“要切换的 class”或者“要调整的内联样式”作为变量,由于大部分情况下业务逻辑和 UI 变化是联动的,通过抽离出来的变量,实现在业务逻辑中简单直白地改变 UI。

可能看到这里,读者会有些困惑,那让我们直接以「企鹅听书」为例,具象地看看笔者是怎么做的吧。听书的界面会出现变化的时以下两种场景:

  1. 一共有两种播放器:minibar 和 全屏的播放器,播放器的播放按钮有“播放”和“暂停”两种状态(图片)切换,这个可以通过 class 来控制
  2. 当播放器进入全屏模式后,节目列表将被隐藏;点击箭头以后,节目列表将重新显示出来

上文的文件结构中的 view.js 就是 UI 逻辑的代码。pages/ 目录中的 js 文件将通过 import 引用 view.js,view.js 中的接口分为“通用”和“页面使用”这两个类型:

  1. module.exports = {
  2. // 通用
  3. general: {
  4. hide: 'hide', // 变量分离在此
  5. show: 'show'
  6. },
  7. // 播放器页面
  8. playerView : {
  9. class: {
  10. listItemPlaying: 'playing'
  11. }
  12. }
  13. // 其他页面如果也有需要,以页面为单位添加...
  14. }

如果未来出现更多 UI 变化的场景,可以再通过变量添加上去,比如 pageView.id

举个超级简单的例子(如下),模拟工作流程:

  1. 在 wxss 中定义好控制不同样式的 class
  2. 将需要变化的 class 写到 view.js 中,并暴露接口
  3. 在 wxml 中的对应结构中绑定 event handler
  4. 在对应的 page.js 里实现 event handler 的具体内容,也就是切换 class 的触发条件

老司机一看就知道是 MVVC 模式,这样分离也就是为了 UI 有独立的控制器,不至于和业务逻辑耦合严重,在页面开发的阶段就可以完成 UI 上的变化。从这个角度上看,小程序反而能给 UI 工程师更多控制 UI 逻辑的能力,确定好代码规范和接口。

总结

初始化一个项目是开始编码的第一步,值得多花一些时间找到合适团队合适自己的项目模板。

结束之前,先允许笔者打一个广告,企鹅 FM 有两个小程序:致敬传统电台,听广播节目的「小电台」;听有声小说专用的「企鹅听书」。以及轻量版的「微云」。大家可以扫码体验。性能的优化和功能的完善也在一步步迭代中,希望大家多多使用多多反馈意见~ 比心

参考资料

npm 参考

  1. 笔者写的小程序项目模板以及小程序生成器
  2. 其他开发者写的工具:MeCKodo/wxapp-cli
  3. ES2015 & babel 实战:开发 NPM 模块
  4. Creating Your First Node.js Command-line Application
  5. Writing Command-Line Applications in NodeJS
  6. Building command line tools with Node.js
  7. npm-developers Developer Guide
  8. 如何使用NPM来管理你的Node.js依赖

小程序参考

  1. 推荐 · 还不错用的小程序 ST snippet
  2. 更新及时的小程序开发汇总
  3. 小程序框架 wepy
  4. 另一个小程序框架 labrador

高效编写微信小程序的更多相关文章

  1. 快速高效实现微信小程序图片上传与腾讯免费5G存储空间的使用

    本文介绍了如何在微信小程序开发中使用腾讯官方提供的云开发功能快速实现图片的上传与存储,以及介绍云开发的 5G 存储空间的基本使用方法,这将大大提高微信小程序的开发效率 对于一般的图片上传功能开发,我们 ...

  2. 【微信小程序】使用vscode编写微信小程序项目

    1. 在微信开发者工具(以下简称:开发者)中新建一个模板微信小程序 2. 在开发者中将模拟器分隔开 3. 设置在保存时编译 4. 在vscode中打开项目目录 5. 下载代码提示插件 这样就可以在vs ...

  3. 微信小程序踩坑集合

    1:官方工具:https://mp.weixin.qq.com/debug/w ... tml?t=1476434678461 2:简易教程:https://mp.weixin.qq.com/debu ...

  4. 微信小程序开发笔记

    前言: 因为前段时间一直在做关于微信小程序方面的项目,作为一名后端的攻城狮而言做一些简单的前端页面数据操作和管理还是比较容易快上手的,当然前提是要理解微信小程序的基本语法和请求原理.该篇博客主要记录的 ...

  5. 微信小程序官方DEMO解读

    我们在开始微信小程序开发的时候,对JS,HTML等前端知识一无所知,完完全全就是门外汉在尝试一个新的方向. 在下载好开发工具,微信就已经提供了一个DEMO例子: 从程序开发的角度来看这个陌生的目录结构 ...

  6. 微信小程序图片上传并展示

    1.首先编写微信小程序的页面和样式: index.js var total = []; Page({ data: { perImgSrc: [] }, onLoad: function (option ...

  7. 微信小程序子组件样式不起作用的解决办法

    今天我在编写微信小程序项目时,发现父组件引用子组件过后,子组件的样式不起作用,在上网查了很多解决办法后,成功解决了这一问题. 解决办法: 1.在全局样式文件app.wxss中引入子组件的样式,如 @i ...

  8. 通俗易懂,C#如何安全、高效地玩转任何种类的内存之Span的脾气秉性(二)。 异步委托 微信小程序支付证书及SSL证书使用 SqlServer无备份下误删数据恢复 把list集合的内容写入到Xml中,通过XmlDocument方式写入Xml文件中 通过XDocument方式把List写入Xml文件

    通俗易懂,C#如何安全.高效地玩转任何种类的内存之Span的脾气秉性(二).   前言 读完上篇<通俗易懂,C#如何安全.高效地玩转任何种类的内存之Span的本质(一).>,相信大家对sp ...

  9. 《微信小程序项目开发实战:用WePY、mpvue、Taro打造高效的小程序》(笔记1)WePY开发环境的安装

    WePY的安装或更新都通过npm进行,全局安装或更新WePY命令行工具,使用以下命令: npm install wepy-cli -g 稍等片刻,成功安装后,即可创建WePY项目. 注意:如果npm安 ...

随机推荐

  1. Javassist 字节码 简介 案例 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  2. DIV+CSS规范命名集合

    我们开发CSS+DIV网页(Xhtml)时候,比较困惑和纠结的事就是CSS命名,特别是新手不知道什么地方该如何命名,怎样命名才是好的方法. 命名规则说明: 1).所有的命名最好都小写 2).属性的值一 ...

  3. 在Asp.Net中使用SmtpMail发送邮件的方法

    在ASP中,就可以通过调用CDONTS组件发送简单邮件,在ASP.Net中,自然也可以.不同的是,.Net Framework中,将这一组件封装到了System.Web.Mail命名空间中. 一个典型 ...

  4. ubuntu完全卸载apache2

    最近刚接触ubuntu和apache,第一次配置就被apahce搞到完全崩溃,跟着网上的配置修改apache的charset和apache2.conf以后,开始出现访问http://localhost ...

  5. 转:Eclipse配色方案

    http://www.cnblogs.com/arci/archive/2011/01/23/1942646.html 参考配色方案: http://www.cs.cmu.edu/~maverick/ ...

  6. ASP入门(一)环境的搭建

    突然转战ASP是因为,手头要实现一个类似管理系统的东东,正好把ASP再从头学习一下下. ASP可以做什么? ASP,它的原文是 Active Server Pages . ASP最核心的扩展内容:Ac ...

  7. python之simplejson,Python版的简单、 快速、 可扩展 JSON 编码器/解码器

    python之simplejson,Python版的简单. 快速. 可扩展 JSON 编码器/解码器 simplejson Python版的简单. 快速. 可扩展 JSON 编码器/解码器 编码基本的 ...

  8. javascript的冒泡排序, 快速排序, 选择排序, 插入排序

    冒泡排序, 最经典的排序, 把比较大的数字往后放, 和选择排序恰恰相反: <!DOCTYPE html> <html lang="en"> <head ...

  9. Provide your license server administrator with the following information.error code =-42,147

    ArcEngine应用程序开发中,许可不必不可少的.一般采取两种方式来获取许可——License控件和AoInitialize类,但今天在VS2010打开程序时,隔一会弹出错误窗口:Provide y ...

  10. MySql 分区 分库 分表

    ubuntu下MySQL配置和管理:http://www.2cto.com/database/201306/222510.html mysql分表,分区的区别和联系:http://my.oschina ...