Migrating Wechaty v0.14 to v0.18 Guide - From Puppeteer To Padchat
Author: @lijiarui Founder of BotOrange, Author of Wechaty.
Wechaty has been updated to version 0.16(BETA) these days and begin to support all kinds of wechat solutions including web, ipad, ios, etc. My product based on wechaty has to migration from wechaty solution based on web to ipad solution.
This blog introduces how to porting code from wechaty puppeteer to padchat.
1. Puppeteer VS Padchat
Puppet System means to connect Wechaty API to any kinds of Puppets, including Web, iPad, Android, Windows Hook and ios. Different implements of these puppets are totally different, without the puppet, using one API to bridge all implement is very difficult, so we had Puppet System.
- Puppeteer
A solution based on Web Wechat - Padchat
A solution based on Ipad Wechat
You can find more in this blog: Wechaty New Version 0.16(BETA, with superpower) Released
2. How to run puppet-padchat
Wechaty will start with puppeteer(web solution) by default, if you want to change to padchat, you need to set the environmental variable.
See more in wechaty wiki: How to run a new wecahty-puppet-padchat
Start with Github repo
1. Pull the latest code:
git pull |
2. Get Token
Participate in our alpha test here: Wechaty v0.17 Padchat Testing: Win32/iPad/Android/iOS/API Puppets Support are coming! and Get WECHATY_PUPPET_PADCHAT_TOKEN
3. Set environment variable and run
Remeber to set WECHATY_PUPPET=padchat
to change from puppeteer to padchat
WECHATY_PUPPET_PADCHAT_TOKEN=your padchat token WECHATY_PUPPET=padchat node examples/ding-dong-bot.js |
NPM
1. Install
npm install wechaty@next |
2. Get token
Participate in our alpha test here: Wechaty v0.17 Padchat Testing: Win32/iPad/Android/iOS/API Puppets Support are coming! and Get WECHATY_PUPPET_PADCHAT_TOKEN
3. Set environment variable and run
Remeber to set WECHATY_PUPPET=padchat
to change from puppeteer to padchat
WECHATY_PUPPET_PADCHAT_TOKEN=your padchat token WECHATY_PUPPET=padchat node examples/ding-dong-bot.js |
Docker
1. Install
docker pull zixia/wechaty:latest |
2. Get Token
Participate in our alpha test here: Wechaty v0.17 Padchat Testing: Win32/iPad/Android/iOS/API Puppets Support are coming! and Get WECHATY_PUPPET_PADCHAT_TOKEN
3. Set environment variable and run
- Remeber to set
WECHATY_PUPPET=padchat
to change from puppeteer to padchat - Remove wechaty in
node_module
if exist.
docker run -t -i -e WECHATY_PUPPET="padchat" -e WECHATY_PUPPET_PADCHAT_TOKEN="your token" --volume="$(pwd)":/bot --name=wechaty zixia/wechaty:latest examples/ding-dong-bot.ts |
3. Check Code
Wechaty is written by typescript, all with strong typing. Since to change all wechaty code, I change my logic product to strong typing.
We need tools to help us check our code errors. I use TSLint to help me to check typescript code and use VS CODE as my IDE.
Why we need to check code
Maybe you think JavaScript is so flexible so it needs to be checked, but typescript has been able to check out a lot of problems when compiling. Why do we still need to check the code?
This is because TypeScript focuses on the type of match, not the code style. When there are more and more people on our team, the same logic may be totally different in different people:
- Four spaces indentation or two spaces indentation?
- Should we disable
var
? - Should all the interface name begin with
I
? - Should it be mandatory to use
===
instead of==
? - Should we need a semicolon?
TypeScript will not concern these problems, but these affect the efficiency of multi-person collaboration when developing, and how easy the code to read and maintain.
This blog explain why we need to check code in typescript.
In one word, though code errors are more important than the uniform code style when a project becomes bigger and more and more developers join in, the code style constraints are still very important.
Using TSLint
TSLint is an extensible static analysis tool that checks TypeScript code for readability, maintainability, and functionality errors. It is widely supported across modern editors & build systems and can be customized with your own lint rules, configurations, and formatters. Learn more in TSLint Website
1. Install
npm install --save-dev tslint |
2. Config File
Create config file tslint.json
I suggest to refer wechaty config about tslint
and tsconfig
Here are some tips about wehcaty config:
- “strict” : true
Enable all strict type checking options.
Enabling –strict enables –noImplicitAny, –noImplicitThis, –alwaysStrict, –strictNullChecks, –strictFunctionTypes and –strictPropertyInitialization - “noEmitOnError” : true
Do not emit outputs if any errors were reported. - “noUnusedLocals” : true
Report errors on unused locals. - “noImplicitReturns” : true
Report error when not all code paths in function return a value. - “noFallthroughCasesInSwitch” : true
Report errors for fallthrough cases in switch statement. - “strictNullChecks” : true
In strict null checking mode, the null and undefined values are not in the domain of every type and are only assignable to themselves and any (the one exception being that undefined is also assignable to void). - “noImplicitAny” : true
Raise error on expressions and declarations with an implied any type.
Related issue: ts-node 7.0 breaking change: Skipfiles
by default - “no-floating-promises”: true
Check the floating promise。Related issue: Prevent the Floating Promise in the Async/Await Code - “noUnusedParameters” : true
Report errors on unused parameters.。 - “noImplicitThis” : true
Raise error on this expression with an implied any type.
see more in official website
3. Add tslint script for package.json
{ |
-- project .
require all tslint to use tsconfig.json
configuration of the current directory to get the information.
Then run npm run lint
will check the whole code.
4. Add TSLint to VSCode
Search tslint
and install a plugin for vscode. It is enabled by default.
5. Sweet Tips
I also recommend another plugin in vscode: editorconfig
: EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs. see more: Official EditorConfig Website
You can find wechaty editorconfig in .editorconfig
4. BREAKING CHANGES
After upgrade wechaty, see more inblog. Although we are trying to minimize API changes, there are some breaking changes. I really suggest you reading CHANGE LOG. Also, I list some important changes here:
bot.init() change to bot.start()
bot.quit() change to bot.stop()
FriendRequest change to Friendship
FriendRequest
class refactored.
Before (v0.14 or below)
wechaty.on('friend', (contact, request) => { |
After (v0.16 or above)
wechaty.on('friendship', request => { |
Related link:
- friend-bot.ts
- BREAKING CHANGE: v0.16 on(‘friend`) arguments changed!
- BREAKING CHANGES v0.16: FriendRequest class will be replaced with Friendship
Message.content() change to Message.text()
From v0.16, Message.content() will be deprecated.
From v0.18, Message.content() will be removed.
Related Link:
Remove MediaMessage
class
From v0.16, MediaMessage will be deprecated.
From v0.18, MediaMessage will be removed.
Use Message instead.
Migration Example- bot.say(new MediaMessage('/image.png')
+ bot.say(new Message('/image.png')
Related issue
A useful tip to send the image
FileBox, FileBox is a virtual container for packing a file data into it for future readers, and easily transport between servers with the least payload, no mater than where it is (local path, remote URL, or cloud storage).
const fileBox = FileBox.fromStream( |
Wechaty self() change to Wechaty.userSelf()
Related issue:
Contact.personal() and Contact.official() change to Contact.type()
Before
const isPersonal = contact.personal() |
After
/** |
Related issue
Room.add() return from Promise to Promise
Related issue:
Room.topic() change from Sycn to Async
Before
const topic = room.topic() |
After
const topic = await room.topic() |
Related issue:
Room.alias(contact) change from Sycn to Async
Before
const alias = room.alias(contact) |
After
const alias = await room.alias(contact) |
Related issue:
Room.memberList() change from Sycn to Async
Before
const memberList = room.memberList() |
After
const memberList = await room.memberList() |
Related Issue:
Room.member() from sync to async
Before
const contact = room.member('Huan') |
After
- const contact = room.member('Huan') |
Related Issue:
Room.has(contact) change from Sycn to Async
WARNING: This change will let us make more mistakes:
if (room.has(contact)) { |
Before
const exist = room.has(contact) |
After
const exist = await room.has(contact) |
Related Link:
- BREAKING CHANGE: v0.16
Room.has(contact)
change from Sycn to Async - Detect missing await in TypeScript
Message.mention() change from Sync to Async
BREAKING CHANGE: v0.16 Message.mention()
change from sync
to async
Before
const mentionList = message.mention() |
After
- const mentionList = message.mention() |
Related issue:
scan
Event args will become different
The good news is: the old code seems will run without problem, because it will just do nothing:
const loginUrl = url.replace(/\/qrcode\//, '/l/')
Before
After
Notice that we deleted the const loginUrl = url.replace(/\/qrcode\//, '/l/')
Related Issues:
Class cannot be instantiated directly!
Error Message
- Error: the class cannot be instantiated directly!
- Error: must not use the global Message/Contact/Room. use a cloned child via clone class instead
Currently, the Contact
, FriendRequest
, Message
, and Room
classes will not be able to instantiate directly, because they must attach with a Puppet.
They need to be cloneClass()
-ed first, then attach the puppet, and at last they will be ready for use by:
wechaty.Contact
, orpuppet.Contact
, etc.
~Do Not~
import { Room } from 'wechaty' |
The above code will throw an error.
Do
- import { Room } from 'wechaty' |
So does Contact, FriendRequest, and Message.
Related Link
- Wechaty Multi-Instance Support #518
- NPM clone-class
- https://github.com/zixia/node-clone-class/issues/5
Related issue
- Error: class can not be instanciated directly!
- BREAKING CHANGE v0.16 Contact, FriendRequest, Message, and Room classes will not be able to instantiate directly
- Error: static puppet not found
- Wechaty Multi-Instance Suport
- NPM clone-class
- https://github.com/zixia/node-clone-class/issues/5
Message.ext() return ‘.ext’ instead of ‘ext’ before
According to the ext()
methods behavior in Node/Python/C# etc, the ext()
always return the filename extension that including the dot(.
).
So the following BREAKING CHANGE was made in v0.15:
const ext = message.ext() |
Before (v0.14 or earlieer)
assert(ext === 'txt')
After (v0.16 or later)
assert(ext === '.txt')
Related Link
Hmmm… That’s all and wish you can have a good coding experience, thanks!