摘要

一直以来,微信小程序都自带babel编译,帮我们解决微信小程序中的api和语法差异,其实吧,微信小程序的es6支持已经是比较完善的了,我们翻看官网的es6语法支持可以发现,小程序(下文小程序都指代微信小程序)本身除了proxy以及Array.values等方法之外,其他的es6的api大多数都已经原生支持了,但我们为什么还需要babel进行js的代码编译呢?

一个是官方文档所说的平台差异,iso和安卓之间的api支持不同,使用babel可以弥补这一点。第二个就是我们想要追求编码体验,想要使用一些新的js语法来提高自己的编程体验,但是微信小程序中无法自定义babel编译,来添加一些新的语法插件以及presets来支持新的语法,那该怎么办呢?其实我本身是没考虑过那么多的,因为我一般用微信自带的es6转es5就够了,最多加个regenerator-runtime以支持async/await,不过之前我看了一下flow,想着类型检查还是很有用的,而typeScript不是一朝一夕就可以直接上手的(小程序已经支持typeScript了),我苦思冥想,想着怎么在微信小程序中使用flow(我怎么老有这些奇怪的想法?苦笑···)研究了一段时间,想了一个办法,不过其实也不是什么办法咯:

利用babel-cli将你需要编译的js先通过自己配置的babel编译一遍,然后再交由微信小程序的es6转es5编译一遍即可。或者你可以直接完全抛弃微信自带的babel编译,完全使用自己配置的babel去编译你的代码。

其实就是很简单,使用自己的配置的babel来编译你的代码,而不是通过微信小程序自带的babel编译,说起来很简单,但是在我研究过程中,还是遇到了一些坑,不过我还是总结了一些东西出来的,这些总结可以帮你解决小程序没有自定义babel编译的困扰,不过有些东西还是需要注意的。我就先通过怎么在微信小程序中使用flow来作为切入点(希望不要翻车)来展示一下我的总结吧。

ps:flow是一个js的静态类型检查工具,这里不做详细的赘述,也不会讲flow,而是以使用babel编译flow为例子,想要了解flow的,可以看其官网:https://flow.org/

使用babel

babel其实大家都比较熟悉了啊,这里就不再介绍babel的什么了,这里使用的是babel7作为参考的,这里就简单过一下。

首先你最少需要在你小程序的根目录中,使用npm安装两个babel库,@babel/core和@babel/cli,这两个一个用来提供核心的babel编译,一个用来提供命令行操作。@babel/core就是babel编译的核心,如果你在babel的配置中(.babelrc)什么也没有配置,然后使用@babel/cli编译这个js文件,那其实他差不多就是原样输出罢了(注意这里是差不多,如果有语法错误,那肯定是通不过babel的编译,他是一个code => ast => code的过程),所以,你需要配置一些语法编译的预设和插件,来告诉babel遇到某些语法时帮我编译这些语法,我这里以编译flow为例,所以安装了一个@babel/flow,然后配置的.bablerc文件如下:

{"presets": ["@babel/flow"]
}

好了,差不多babel的安装和配置就这些了,至少对于flow的编译来说,至于babel-cli的命令我们会在讲编译js时再列出来。

ps:babel的插件就是告诉babel遇到某些语法时,怎样编译这些语法,而babel的preset预设其实可以看作就是一些babel插件的集合。

微信小程序项目结构

既然我们需要自己使用babel进行js的编译,那么项目结构也需要变一变,一般,我的小程序的pages文件夹放在根目录,但是啊,既然自己配置编译,那么编译后的页面文件肯定就不是pages了,而且,你不可能只在pages里面写js吧,还有其他的地方也需要写啊,比如一些工具,api,组件这些,所以,目录结构需要改改,我决定沿用vue中的src目录作为我的源代码目录,里面存放一些pages页面,api,wxss,components这些文件,除了app.js,app.json这些放在根目录下,其他的源文件都放在src文件夹下。这个文件夹就是我们后续使用babel进行编译的源文件夹了。这里需要说明一下,微信小程序中的pages页面的路径不一定只能放在根目录中,你只要在app.json中正确配置你的pages字段中的页面路径即可。然后,我们在使用babel编译src文件夹后,会输出到一个dist文件夹中,dist文件夹中存放的就是我们编译后的文件。

好,我们现在在源文件中编写自己的小程序代码,并且可以使用flow的语法,比如在小程序中我们可以写下面这种类似的代码:

function test(x: number, y: number): string {return `result: ${x * y}`;
}console.log(test(10, 20));

熟悉flow的应该可以理解,不熟悉也没有关系,你只需要知道小程序中,这样运行肯定是会报错的(浏览器也一样),所以,你需要使用bable将其编译成普通的js代码,将和静态类型有关的代码给去掉,那么我们就来配置babel-cli来编译我们的js,我们的预期是将我们项目中的src中的js文件用babel进行编译一遍,并输出到dist目录中去(这个dist不需要自己创建,他是通过编译生成的),一般使用这个命令:

npx babel src --out-dir dist

你可以在你的项目的根目录中打开命令行去执行这个命令,至于这个npx是什么呢,这里就不详细的说明了,具体可以看这篇文章进行介绍:http://www.ruanyifeng.com/blog/2019/02/npx.html

但是,如果只使用这个命令,我们其实只编译了js文件,那么其他文件怎么办呢?尤其是像图片啊,page页面的wxss和wxml这些文件不需要编译的文件也需要在dist目录中,也就是说,src目录的中的所有源文件和dist中的文件之间的路径需要一致,这样微信小程序才可以正常工作。所幸,babel-cli有一个简单的参数可以做到:

npx babel src --out-dir dist --copy-files

添加--copy-files参数,他会把src中的js文件进行编译,然后不是js的文件原样复制到dist目录中去,这样,我们可以保证dist和src中的目录结构和文件是完全一致的。大致的话,长这样:

这样,一个简单的babel编译过程就搭建完成了,但是需要注意以下几点:

  1. 因为我们自己的src中的js源码是使用了flow进行静态类型检查的,那么小程序是肯定识别不了的,所以,你在配置app.js中的pages字段时,页面的路径是dist目录,而不是src目录,也就是指向的是编译后的目录,这里需要注意。
  2. 如果你配置app.js中的pages字段,那么对于一些小程序的默认页面路径,你需要主动指定,比如,微信小程序的生成小程序码,默认的跳转页面的路径是:pages/index/index,但是你的小程序页面可不是在根目录的pages文件夹中了,而是在dist目录中了,所以,有些拥有默认页面的配置,你需要手动指定页面路径才行,不过也不是什么大事。
  3. 即使你配置了app.js中的pages字段,让小程序的页面是指向dist中的pages页面,但是小程序还是会检测src中的js文件使用了他不识别的语法,因为默认小程序会检测整个根目录中的js文件,所以,你还需要在project.config.json中配置packOptions.ignore字段,即忽略src目录的所有文件,并且,这个忽略的文件夹不会参与小程序的打包和上传。如果不配配置这个忽略文件,那么开发者工具会报错,因为他遇到了不认识的语法。project.config.json的配置如下(可自行根据需要配置,小程序配置官网:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html):
 {"packOptions": {"ignore": [{"type": "folder","value": "src/"}]}
}

以上大致就是使用自定义的babel来编译flow,然后你在开发小程序时,就可以开心的使用flow来帮你进行静态类型检查了。并且,你还可以同时开启微信小程序自带的es6转es5,因为我们在使用自己配置的babel进行编译时,只是编译了flow的代码,而其他的es6代码并没有编译,而这一部分的编译完全可以交由微信小程序自带的babel去编译,你可能会问,同时存在两次编译,会不会冲突,或者同一个地方编译两次?其实并不会:

因为首先,我们只编译了flow的语法,其他的es6我们并没有配置babel去编译,而这一部分的编译工作是交由小程序自带的babel去实现的,其次,即使我们配置的编译功能和小程序自带编译功能重复了(比如同时配置了class的编译),那么class语法在第一次babel编译时就已经转为es5代码了,那么第二次的编译,根本就找不到有class语法的代码了,根本不会再编译class,所以,自己配置的babel和微信小程序自带的babel完全可以同时使用,你完全可以在你自定义的babel配置中只配置微信小程序不支持的语法插件,其他小程序支持的,你完全不用理睬,交由小程序自己去编译即可。

所以,如果你只想在微信小程序中使用flow,那么你只需要配置一个编译flow语法的babel就行了,其他的什么preset-env预设啊,不用配置,由小程序自己的babel编译即可。

比如我们想要在小程序中使用类的装饰器decorators语法,小程序内置的babel是不支持此语法的,虽然他支持class的语法,那么我们就可以配置一个@babel/plugin-proposal-decorators插件来编译装饰器语法:

下载@babel/plugin-proposal-decorators插件:

npm install --save-d @babel/plugin-proposal-decorators

然后在上面的.babelrc配置的基础上增加一个插件:

{"presets": ["@babel/flow"],"plugins": [["@babel/plugin-proposal-decorators", {{"legacy": true}}]]
}

然后,你就可以在项目中使用类的装饰器语法了,是不是很简单?确实很简单,不过,凡事都有两面性,尤其是这种不遵循标准, 而另辟蹊径的做法,同样,伴随着一些问题。

问题

我们的编译只能覆盖到src目录

我们配置的babel,不够强大,babel-cli命令只能编译src目录中的js,虽然一般我们也只需要将js编写在src中即可,但是,app.js就不行了,所以,这个编译不了,当然,解决方法肯定是有的。那就是单独编译一下app.js,虽然麻烦了一点,不过吧,其实app.js中也不会写很多代码,所以不是太大问题,而且后面有更好的办法。对了,你在app.js中引入js代码要引dist目录中的,不要引src中的。

编译速度变慢了,而且编译可能还麻烦了

新增加了一层编译,编译速度肯定慢了,因为要编译两次,而且,每次修改文件后,都需要手动执行一下babel-cli的命令,肯定很麻烦对不对,所以,你需要配置自定义预处理命令,这个自定义预处理命令的使用和我之前发布的"在微信小程序中使用sass编写wxss"这篇文章中的使用方法类型,这里就不再介绍,就当你了解这个功能了。不清楚的可以看我这一篇文章以及官网:

如何在微信小程序中使用sass来编写wxss代码:https://blog.csdn.net/qq_33024515/article/details/85100597

官网:https://developers.weixin.qq.com/miniprogram/dev/devtools/debug.html#%E8%87%AA%E5%AE%9A%E4%B9%89%E9%A2%84%E5%A4%84%E7%90%86

怎么使用呢,简单一点就是这样:

babel编译的自定义预处理命令

其实就是把babel-cli的命令复制到这个自定义预处理命令的编译前预处理中即可,这样,你每次编译小程序时,他都会先执行这个预处理命令,这样就不用你每次手动的在命令行来编译了(上图中的es6转es5是可以开启的,这里截图时因为我在测试功能,所以关闭了,你完全可以打开)。不过这里可以有两个可以修改的地方,

一个就是你可以关闭开发者工具的自动监听文件变化了,因为需要手动点击编译,才可以执行这些自定义预处理命令,监听文件变换的编译是不行的,不过你可以用快捷键来进行编译,这样好一些。

第二个就是你其实在src中可以把所有的不相干的其他文件给删除掉的(不删也可以,也没什么问题),只保留js文件即可。为什么要这样呢,我个人感觉可能文件夹干净一点把,或者心理上觉得babel能编译的快一点,虽然是没有依据的,看你的喜好来决定。

对了,关于app.js文件的编译,既然使用了自定义预处理命令,那么你可以直接写个bat文件来执行多个命令行的命令(window中,mac我不清楚是什么脚本命令),这样不仅可以编译src的文件,也可以编译app.js了,并且,你还可以执行其他命令,这样要灵活许多(如果你会写bat的话)

当自身配置中有babel不支持的语法,但小程序内置的babel支持时的解决方案

我在探索的过程中,发现了一个问题,我如果使用了处在实验阶段的语法时,且我自定义的babel中没有为这个实验语法配置编译插件时,那么我这个自定义babel的编译就会报错,不会给我通过,但是,小程序中却配置了相应的插件,这可能会有一个奇怪的现象,那就是你在小程序中可以使用的语法,也支持编译的语法,却通不过你自己配置的babel编译,比如,小程序支持类的属性初始化器语法,也就是小程序中你可以这么写:

class Test {constructor(name) {this.name = name;}logger() {console.log("Hello", this.name);}testVal = "like";getName = () => {console.log(1)}
}

看见类中属性的那个等号的写法了吗,那就是处于实验阶段的属性初始化器语法,可是如果你在代码中写了这种语法时,预处理中的babel编译会报错:

:Support for the experimental syntax 'classProperties' isn't currently enabled

大概就是说这个类的属性初始化器语法不被支持,然后还提示我安装@babel/plugin-proposal-class-properties这个插件来支持此语法,可是微信小程序内置的babel却支持,这可能会比较麻烦,因为如果你不用自定义的babel配置,那么你完全可以使用class语法和这个属性初始化器语法的,可是你自己增加了一层babel编译,而你这个自定义的babel编译却没有增加对一些实验阶段语法的支持,所以,你这一层自定义babel编译肯定就通不过了。

那么解决办法也很简单,在你自定义babel配置中增加一个@babel/plugin-proposal-class-properties插件,让他来编译实验阶段的语法即可(上文已说明了自定义babel和小程序内置babel可以同时存在,并且具有重复的babel编译功能时也不会有影响)。

ps:增加这些插件时你一定要注意插件的顺序,不然还是会出错的,不过这已经是属于babel配置方面的知识了,这里只是因为我被坑到了,所以提一嘴。

最好不要使用Polyfill来编译

其实我之前尝试使用Polyfill来编译的,可是怎么搞都感觉不太行,因为我不确定小程序中使用Polyfill进行扩展时会不会出问题,并且最好不要以来和babel编译有关的npm包,作为微信小程序的npm构建功能,因为微信小程序的npm构建把整个npm包打包为一个index.js文件了,而babel的polyfill编译是按照路径进行引用的,所以,会提示路径错误,找不到这个包,不过你可以使用直接引入polyfill.js这种打包方式来进行打包,有兴趣的各位可以尝试一下,我这里只是给一个建议,其实最好你是和内置的微信小程序babel同时使用,你的自定义babel配置中只编译一些微信小程序不支持的编译功能,比如flow,比如装饰器decorators这些,当然,如果你真的想要全部脱离小程序内置的babel进行编译去完全自定义babel编译,那也可以尝试,因为怎么说呢,像mpvue和wepy这些小程序框架其实也是可以自定义babel配置进行编译的,虽然不确定他们有没有为小程序做专门的处理。不过,值得研究吧,不过目前我个人暂时用不到。

总结

其实研究这个,不是说他真的是必须的,而是在研究过程中,我学到的东西,比如为了可以在小程序中自己配置babel编译,我仔细的翻看了babel的一个中文官网,让我对babel有了更深的理解,了解babel是怎么配置的,为什么需要这么配置,了解preset和插件到底是什么,对于babel的使用有了更深的了解(原理就算了,要词法分析,ast这种知识,目前不具备),而且碰到了坑并解决对我来说也是宝贵的经验,比如babel插件排放的顺序需要注意,否则会有坑等等。而且在对于小程序的理解上也有所提升。况且,我觉得这个自定义babel还是有点用处的,比如flow,而且自定义预处理命令其实真的挺好用的(比如小程序支持的typescript,其实也是通过自定义预处理命令进行编译成js的),我其实都想在微信小程序中再加个webpack的打包了,不说小程序开发工具内置的代码压缩,css自动补全,babel什么了都有了,用webpack来进行图片压缩总可以(请原谅我这么没志向),不过后续可以试试的。

ps:如果嫌麻烦,可以当看个热闹,或者是提供个思路,或者你可以直接使用微信小程序框架,比如mpvue或者wepy来进行小程序的开发。

为微信小程序扩展自定义babel编译功能相关推荐

  1. 【愚公系列】2022年09月 微信小程序-自定义导航栏功能的实现

    文章目录 前言 一.自定义导航栏功能的实现 1.组件的封装 2.使用 前言 导航栏是指位于页面顶部或者侧边区域的,在页眉横幅图片上边或下边的一排水平导航按钮,它起着链接站点或者软件内的各个页面的作用. ...

  2. 小程序组件onload_微信小程序自定义组件(一)

    好吧,突然发现学不完了,一下子,那就分开吧,由于时间太久,直接重新大致复习了一下 微信小程序自定义组件 微信小程序支持自定义组件 下方的目录 其中,components为组件目录,nodemodule ...

  3. 微信小程序自定义组件方案

    前言:小程序已于11月初开放了小程序组件功能,但事件方面还不是很完善,有的组件暂时可能还是要用其他方式来实现,这里简单记录下开发小程序自定义组件的要点. 在小程序官方开发组件开发功能之前,自定义组件的 ...

  4. php 微信小程序 循环 多选,微信小程序实现多选功能

    本文为大家分享了微信小程序实现多选功能的具体代码,供大家参考,具体内容如下 代码: {{num + 1}}/{{quesyion.length}}{{question[num][0]}} A {{qu ...

  5. 微信小程序 拍照打卡功能实现

    微信小程序 拍照打卡功能实现 附Java代码 小程序端 签到页面wxml 签到页面js 拍照页面wxml 拍照页面js Java后台 保存照片 保存打卡数据 由于拍照组件是相当于一个块,用隐藏显示的方 ...

  6. 微信小程序--自定义组件(超详细 从新建到使用)

    微信小程序–自定义组件 微信小程序官网介绍! 本文提供给急需使用自定义组件人群,以下是博主个人理解和案例!可以辅助官网来看 介绍: 从小程序基础库版本 1.6.3 开始,小程序支持简洁的组件化编程.所 ...

  7. 微信自定义tabbar有小红点_微信小程序自定义 tabbar

    一定的需求情况下,无法使用小程序原生的 tabbar 的时候,需要自行实现一个和 tabbar 功能一模一样的自制组件. 查阅了海量的博客和文档之后,亲自踩坑.总结了三种在不使用微信小程序原生 tab ...

  8. uniapp微信小程序自定义相机 ,给相机添加辅助框,解决拒绝相机默认授权后无法再次拉起相机授权问题

    微信小程序自定义相机 效果 文章目录 微信小程序自定义相机 效果 需求 一.小程序自定义相机 1.使用uniapp的camera组件 二.使用cover-view,cover-image加辅助边框 三 ...

  9. 微信小程序自定义组件的基本使用

    微信小程序自定义组件的基本使用 组件与模块类似,实现了功能的复用,提高开发速率,减少代码量 在开发过程中 , 总会遇到一些功能板块是相同或很类似的 .如两个不同页面都有搜索框 , 或者 导航栏等 . ...

  10. 一键获取微信小程序,反编译

    一键获取微信小程序,反编译 相关地址 操作方法 在这里我总结一下获取 wxapkg文件的一些注意事项. 相关地址 本文中软件为搬运,如有违规请告知.感谢作者:Cherrison 下载地址:https: ...

最新文章

  1. 使用抽象等设计工具创建一个稳固的核心机制
  2. 第三次学JAVA再学不好就吃翔(part60)--Arrays类
  3. [pytorch、学习] - 3.12 权重衰减
  4. mysql可能锁的表命令_mysql 默许是表级锁一些不太常用命令
  5. GVim中以十六进制方式打开文件
  6. Windows下安装配置ant
  7. ospf多区域路由实验
  8. Hyperledger Fabric 实战(八):couchdb 丰富查询 selector 语法
  9. 手用计算机怎么弄声音,计算器怎么调声音
  10. DLNA实现本地媒体服务器
  11. MyBatis的高频面试题
  12. 功能测试VS性能测试
  13. 航测无人机las点云数据生成DEM
  14. c语言strtok用法详细解释
  15. 俞敏洪:这是一个创业的大时代
  16. forEach、for…in、 for…of 的区别
  17. linux 查看CPU核数
  18. 泰拉瑞亚Terraria+蒲公英联机平台联机教程
  19. Linux 安装AndroidSdk 并使用zipalign对齐工具完成apk的签名
  20. 易之 - 我是个大师(2014年3月6日)

热门文章

  1. 【自我介绍】小白程序员的成神之路
  2. 圣诞节,教你用Python给微信头像添加一个圣诞帽
  3. 2-2.基金的投资交易与结算
  4. stub,存根是什么?
  5. 记录一次面试经历(深刻)
  6. ★关于人类体质弱化的分析
  7. AI智能尺寸测量仪简介(图像尺寸测量仪)
  8. 英文论文评审意见_怎样写英文审稿意见
  9. CentOS7 安装svn
  10. Mysql从入门到入魔——6. 表联结、组合查询