前言
微信小程序是一个项目,就像盖房子一样。只有打好基础,后续的工程师才能打下可靠、坚实的基础。
笔者需要频繁创建新项目,每次都要重复“修改项目结构->从旧项目中复制粘贴文件->删除旧项目中的一些代码”的过程,真是.. . 费力。
还有一个痛点是:每次新建一个小程序页面,都要生成三个同名文件(.wxml、.wxss、.js),而且命令行太长(据微信同事介绍:也可以在app.json字段下添加新页面的路径,保存后也会生成对应的文件)。
因此,阅读本文需要对小程序开发有一点了解(简单教程引导)。
目标
我们现在有两个目标:
基于通用模板创建新项目
一键新建页面目录,目录下三个文件:.wxml、.wxss、.js。也可以直接在app.json字段创建页面,保存后生成这三个文件。笔者之所以没有采用这种方法,是因为我一开始并不知道这个功能的存在,而且与我平时的操作习惯不符。另外,我想到js文件初始化后,需要引入公共库,插入代码片段,所以保留了这个功能。
这两个需求其实很简单,不需要GUI,所以我们可以做一个npm命令行工具。想象一下这个命令行应该是什么样子:
~ npm install wxapp -g
~ wxapp -i myapp && cd myapp
~ wxapp -p list
流程图如下:
完成
正式开始之前,请先确认本地的开发环境。作者本地环境为:
~ npm -v
3.10.10
~ node -v
v6.9.4
我们将问题分为三步:
实现可以在任意目录下直接运行的命令行工具
通过输入不同的命令行参数来执行不同的功能
考虑项目模板的存储位置,是集成到工具中还是与工具分开。
别担心,这一切都很容易解决,我们来一一看看。
命令行工具
.json 中的一个字段是 bin:
{
...
"bin": {
"mywxapp": "./index.js"
}
}
该字段可以将开发者想要执行的脚本注册到环境变量(PATH)中。不同的按键对应不同的脚本。也就是说,现在,当我们直接从命令行执行时:
~ mywxapp
相当于执行在:
~ /path/to/index.js
第一个问题很容易解决。有关 bin 字段的更多信息,请参阅 npm 文档中的 .json 部分。
命令行参数
执行.js时,可以通过.argv获取执行参数,但从参数数组中拆分参数无疑是麻烦的。不过,npm 发展至今,处理命令行参数的库肯定是存在的。简单、好用、好用,所以第二个问题也解决了。

项目模板的存储位置
考虑项目模板的存储位置。它应该集成到工具中还是与工具分开?
作者选择将它们分开管理。模板内容放在单独的模板代码仓库中管理,方便我们维护。目前的模板比较简单(参见下面的“模板详细说明”),只有标准的目录结构。预计后面会增加自动化部分(比如less -> wxss),所以以后改的会比较频繁。
-git-repo 可以将给定地址的仓库内容复制到执行目录。 API 很简单,仅此而已。
问题已经解决了,现在我们看一下伪代码(注:伪代码中没有考虑错误情况):
const mkdirp = require('mkdirp');
const download = require('download-git-repo');
// 创建项目
function initProj(projName){
if(currentDir.exsits(projName))
console.warn(projName + '项目已经存在于当前目录中,请使用别的名字');
else
download('path/to/tmpl', currentDir+'/'+projName);
}
// 注册页面
function registerPage(pagesName) {
// 读配置文件
readFile(configFile, function(data){
// 将新建的所有页面都写入配置文件中
for(name in pagesName){
data.pages.push('pages/' + name + '/' + name);
}
writeFile(configFile);
});
}
// 创建页面
function createPage(pages) {
for(var index in pages) {
var page = pages[index];
mkdirp(pagePath, function(){
createFile(page+'.wxml');
createFile(page+'.wxss');
createFile(page+'.js');
})
}
// 将页面注册到 app.json 中
registerPage(pages);
}
使用
编写完这个工具后,只需要在本地和全局使用即可:
npm install -g
在本地开发过程中,如果开发版本的代码有更新,则需要将更新同步到全局。这时候需要执行:
npm link
会看到环境变量中安装的工具目录地址已经和开发目录关联起来:
~/Documents/kmokidd/cli-build$ npm link
/usr/local/bin/wxapp -> /usr/local/lib/node_modules/@kmokidd/wxapp-generator/index.js
/usr/local/bin/node_modules/@kmokidd/wxapp-generator -> /Users/kmokidd/Documents/kmokidd/cli-build/index.js
模板和插件地址将附在资源部分
发布 npm 插件
如果你和笔者一样,想在多台机器上使用这个工具,可以选择发布到npm官网。发布步骤非常简单,基本上:
npm login
npm publish
不过笔者考虑到项目模板毕竟是因人而异的东西,所以我选择了发布,即在插件的.json中的name字段中使用@/-这样的值。
如果你有类似的想法,并且也是免费的npm用户,那么发布时执行以下命令:
npm publish --access public
对使用没有影响,但是安装时记得带上名称:
npm install @scopeName/wxapp-generator -g
模板详细说明
一千个人就有一千个项目模板。根据业务/个人爱好的不同,每个人的项目模板可能会有很大不同。笔者觉得目前的模板很好用,所以本节就介绍一下。以下是项目的文件结构:
wxapp
├── app.js
├── app.json
├── app.wxss
├── base-styles/
├── images/
├── pages/
│ ├── tmpl/
├── utils /
│ ├── view.js
│ ├── util.js
│ ├── polyfiil.js
└── └── Deferred.js
之所以采用这样的结构,是为了尽可能地解耦UI逻辑和业务逻辑。但由于完全解耦是不可能的,所以基本思想就是简单的“变量分离”。通常是通过切换或者内联样式调整来改变UI,所以笔者的想法是用“要切换的”或者“要调整的内联样式”作为变量,因为大多数情况下业务逻辑和UI的改变都是链接起来,通过提取的变量,可以在业务逻辑中简单直接地更改UI。
读者看到这里可能会有些困惑,那么我们就直接以《企鹅有声读物》为例来具体看看作者是如何做到的。以下两种场景听书界面会发生变化:
有两种类型的播放器:和全屏播放器。播放器的播放按钮有“播放”和“暂停”两种状态(如图)切换。这可以通过 来控制。
当播放器进入全屏模式时,节目列表将被隐藏;单击箭头后,将重新显示程序列表。
上述文件结构中的view.js就是UI逻辑的代码。 /目录下的js文件会引用view.js。 view.js中的接口分为“通用”和“页面使用”两种:

module.exports = {
// 通用
general: {
hide: 'hide', // 变量分离在此
show: 'show'
},
// 播放器页面
playerView : {
class: {
listItemPlaying: 'playing'
}
}
// 其他页面如果也有需要,以页面为单位添加...
}
如果将来发生更多 UI 更改,您可以通过变量添加它们,例如 .id。
举一个超级简单的例子(如下)来模拟工作流程:
在wxss中定义不同样式的控件
将需要进行的更改写入view.js并暴露接口
在wxml中对应的结构体中绑定
对应的page.js中实现的具体内容就是切换的触发条件。
老司机一看就知道是MVVC模式。这种分离是为了UI有一个独立的控制器,以免与业务逻辑严重耦合。 UI的改变可以在页面开发阶段完成。从这个角度来看,小程序可以让UI工程师更好地控制UI逻辑并确定代码规范和接口。
总结
初始化项目是开始编码的第一步,值得花费一些额外的时间为合适的团队和您自己找到合适的项目模板。
在结束之前,我想允许作者打个广告。企鹅FM有两个小程序:一个是向传统广播电台致敬、收听广播节目的“小电台”;一个是向传统广播电台致敬的“小电台”。还有一本专门听有声小说的“企鹅听书”。还有轻量版的“微云”。大家可以扫码体验。性能优化和功能完善也在逐步迭代。希望大家多多使用并给我们反馈~
参考
npm 参考
作者编写的小程序项目模板和小程序生成器
其他开发者编写的工具:/-cli
& 实战:开发NPM模块
你的 Node.js 行
- 线路输入
与 Node.js 一致
npm-
如何使用 NPM 管理 Node.js 依赖项
小程序参考
推荐·非常好用的小程序ST
更新及时的小程序开发总结
小程序框架wepy
另一个小程序框架