New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@qihoo/wx2qh

Package Overview
Dependencies
Maintainers
4
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@qihoo/wx2qh

360小程序迁移工具

  • 1.0.6
  • latest
  • npm
  • Socket score

Version published
Weekly downloads
0
decreased by-100%
Maintainers
4
Weekly downloads
 
Created
Source

wx2qh

wx2qh 是用来将微信小程序迁移到 360 小程序的转化工具,它基于 AST,然后按照一定的规则静态分析来抹平平台之间的语法差异,简化迁移微信小程序到 360 小程序流程。

  • wx2qh 解决了平台之间的语法差异,而运行时的差异需要进行二次开发来修复
  • 不支持迁移第三方框架开发的微信小程序

切记:

转换完成后,需要切换到转化后生成目录(dest 指定目录)安装 @qihoo/seapp-builder来构建转化后的代码

目录

CLI

切记:转换完成后,需要切换到转化后生成目录(dest 指定目录)安装 @qihoo/seapp-builder来构建转化后的代码

安装

建议全局安装。

 npm i -g @qihoo/wx2qh

项目内安装:

  npm i @qihoo/wx2qh

命令行参数如下:

wx2qh \<source\> \<output\>    transform the files in source directory to dest
  wx2qh version              output version number
  wx2qh help                 output usage infomation

  options:
    -f,--file   set files pattern  \<glob\>
    -i,--ignore set ignore files pattern  \<glob\>
    -p,--preset set preset config \<string\>
    -r,--ratio  set rpx2px ratio  \<number\>

参数说明:

  • source 待迁移微信小程序项目路径(必填)
  • output 迁移后,360 小程序的生成目录(默认值为 . 即当前目录)
  • -f,--file 指定要转化的文件(glob: dir/*.wxml)
  • -i, --ignore 忽略要转化的文件
  • -p, --preset 指定预设配置文件路径,详情见使用 preset
  • -r, --ratio 指定 rpx2px 的转化比例(默认:2, 2rpx => 1px)

编译整个项目

编译整个 wxApp 目录下的文件并输出到 360mp 目录,这个时候会对 已存在的 360mp 目录做二次确认,防止因为路径填写错误 覆盖原有文件,360mp 目录不存在则没有二次确认。

  wx2qh ./wxApp ./360mp
? The output directory `/work/360mp` is existed, Pick an action: (Use arrow keys)
\> Overwrite // 删除 360mp 目录,然后写入
  Merge      // 直接写入
  Cancel     // 取消

编译选定文件

可以通过设置 file(f) 选项编译符合这个规则的文件,值是 glob 类型。

  wx2qh ./wxApp ./360mp -f=*.wxml

忽略某些文件

可以通过设置 ignore(i) 选项忽略符合这个规则的文件,值是 glob 类型。

  wx2qh ./wxApp ./360mp -i=*.test.js

使用 preset

可以通过设置 preset(p) 选项设置预设值,从而可以拓展和修改 wx2qh 的一些内置配置、插件等。preset 的路径支持情况如下:

  • 本地路径:preset.startsWith('.')
  • 绝对路径:path.isAbsolute(preset)
  • npm package:preset.startsWith('wx2qh-plugin-')
  • 默认:wxApp 目录下的 .wx2qhrc.json
  wx2qh ./wxApp ./360mp -p ./wx2qh-plugin-preset

常见转化问题

  • 转换 getApp() 在所有调用 getApp 的地方改写成如下:
let app = null
Page({
  beforeCreate() {
    app = getApp()
  }
})
  • 确认 app.json 中添加 sdkversion 字段()
{
  "sdkversion": "1.0.0"
}

API

Props

  • transformer
    • object
    • 转换 processor 执行器
  • compilation
    • map
    • 内置 processorParserCompiler 存储容器
  • output
    • string
    • 编译后文件的输出路径
  • options
    • object
    • 配置选项,包括 cli 选项,prettier 配置等。等同于 PRESET
  • ticks
    • set
    • api.nexttick 传入回调的存储容器
  • files
    • array
    • vfile 存储容器

Methods

api.processor(name[, matcher])

参数
  • name (string | object) processor 名称
    • object 需要满足 { name, matcher }
  • matcher (string | regexp | function) 过滤 files 中的 vfile
    • string 强制转换成正则
    • function 自定义过滤规则,参数是 vfile
返回值

processor 定义文本处理流程,详情请见processor

例子
module.exports = function(api) {
  // 1. (name: string, matcher: string): Processor {}
  const processor = api.processor('demo', '*.wxml')

  // 2. (name: string, matcher: RegExp): Processor {}
  const processor = api.processor('demo', /\*.wxml/)

  // 3. (name: string, matcher: function): Processor {}
  const processor = api.processor('demo', file => file.path === 'index.wxml')

  // 4. (name: object): processor {}
  const processor = api.processor({ name: 'demo', matcher: '*.wxml' })

  return processor
}

api.nextTick(callback)

参数
  • callback (function) 持有 filesMap 上下文的回调函数,该 callback 会在输出文件之前串行调用
例子
module.exports = function(api) {
  api.nextTick(callback)

  function callback(filesmap) {
    // some handling process...
  }
}

api.logger(type, log[, canSave])

参数
  • type (string) 日志类型
    • error 错误日志
    • warn 警告日志
    • info 信息日志
    • done 完成日志
  • log (string|object) 日志内容
    • object { file, row, column, message }, 会在 canSave=true 打印位置等其他信息
  • canSave (boolean, optional) [default: false] 是否存入 logStore
例子
module.exports = function demoProcessor(api) {
  // 1. (type: string, log: string): void {}
  api.logger('error', 'I am a error log')
  api.logger('warn', 'I am a warning log')
  // 2. (type: string, log: object, canSave: boolean): void {}
  api.logger(
    'info',
    {
      file: 'app.json',
      message: 'has sdkversion prop',
      row: 10,
      colum: 4
    },
    true
  )
}

Processor

关于 processor,下面只列出一些常用接口,更详细文档请参考 unifiedjs

processor.use(plugin[, options])

使用 use 方法为 processor 配置插件,并可以可选的传入配置项

场景
  • processor.use(plugin[, options])
  • processor.use(preset)
  • processor.use(list)
参数
  • plugin (Attacher)
  • options (*, optional) 插件的配置选项
  • preset (object) { settings: {}, plugins: [] },都是可选属性
  • list (array) [plugin, preset, [plugin, options]]
返回值

processor 返回当前调用 use 的调用者,可链式调用

例子
module.exports = function demoProcessor() {
  const processor = api.processor('demo', 'index.wxml')

  processor
    // plugin with options:
    .use(plugin, {})
    // Plugins:
    .use([plugin, pluginB])
    // Two plugins, the second with options:
    .use([plugin, [pluginB, {}]])
    // Preset with plugins and settings:
    .use({
      settings: [(position: false)],
      plugins: [plugin, [pluginB, {}]]
    })
    // Settings only:
    .use({ settings: { position: false } })

  function plugin() {}
  function pluginB() {}

  return processor
}

Attacher

processor 插件仅仅是一种概念,而 attacherprocessor 插件的实现,它可以访问和修改 processor 的属性和方法,尤其是可以为 processor 添加必要的 ParserCompiler 从而实现 textast 的反序列化,asttext 的序列化。

例子

demoProcessor.js:

module.exports = function demoProcessor(api) {
  const processor = api.processor('demo', 'demo.wxml')

  // 获取内置的 compilation ,可以用来处理 xml 类型文件
  const wxmlCompilation = api.compilation.get('wxml2vue')

  processor
    // 自定义
    // .use([parser, compiler])
    // 内置
    .use(wxmlCompilation)
    .use(demoAttacher)

  return processor
}
function demoAttacher(options) {
  return span2div

  function span2div(tree) {
    // process tree...
    const spanElement = tree.children[0]
    const spanText = spanElement.children[0]
    spanElement.tagName = 'div'
    spanText.value = `I am a div`
  }
}
// 自定义 Parser ,也可以使用第三方 Parser 以及 内置的
function parser(settings) {
  this.Parser = parser

  function parser(doc) {
    return {
      type: 'default',
      contents: String(doc),
      toString() {
        return this.contents
      }
    }
  }
}
// 自定义 Compiler ,也可以使用第三方 Parser 以及 内置的
function compiler() {
  this.Compiler = compiler

  function compiler(tree) {
    return tree.toString()
  }
}

demo.wxml:

<span>I am a span</span>

cmd:

  wx2qh ./demo.wxml ./360mp -p ./demoProcessor.js

output 360mp/index.wxml:

<div>I am a div</div>

function attacher([options])

context

上下文对象(this)指向 processor

参数
  • options (*, optional) 配置选项
返回值

transformer 可选

function transformer(node, file[, next])

参数
  • node (node) 经过 Parser 转换后的语法树
  • file (vfile) 正在被 processor 处理的 file
  • next (function, optional)
返回值
  • void 如果返回时是 void,当前处理的 node 将继续流入下一个 transform
  • Error 如果返回 Errorprocessor 将停止工作。
  • node 如果返回 node,返回的 node 将流入下一个 transformer
  • Promise 如果返回的是 Promise,将会等到 Promise 达到最终状态,然后将返回值流入下一个 transformer 或者中断 processor
function next(err[, tree[, file]])
参数
  • err (Error, optional)
  • tree (node, optional)
  • file (vfile, optional)

Preset

preset 配置如下:

  // 是否需要合并内置 options
  root: true, // boolean
  // === wx2qh cli options ===
  file: '**',
  ignore: [],
  preset: undefined,
  ratio: 2,
  // ====
  // === prettier config ===
  // 是否开启 使用 prettier 格式化代码
  prettier: true,
  // prettier 配置
  prettierrc: {
    // 默认 parser
    parser: 'babel',
    // 根据条件选择合适的 parser
    parserEntries: [
      [/\.js$/, 'babel'],
      [/\.wxss$/, 'scss'],
      [/\.wxml$/, 'html'],
      [/\.json$/, 'json']
    ],
    printWidth: 80,
    trailingComma: 'none',
    tabWidth: 2,
    semi: false,
    singleQuote: true,
    useTabs: false,
    bracketSpacing: true,
    insertPragma: false,
    arrowParens: 'avoid',
    htmlWhitespaceSensitivity: 'ignore'
  },
  // ===
  // 插件列表 processor
  plugins: [
    require('wxml2vue'),
    require('wxjs2vue'),
    require('wxss2css'),
    require('wx2qh-plugin-preset')
  ]

CHANGELOG

v1.0.1

FEATURE
  • 插件化重构
  • 根据文件后缀格式化代码(prettier)
  • 支持在行内样式中转换 rpx2px
  • 支持 hidden=x 转为 v-show="false"
  • app.json 配置默认添加 sdkversion 字段

v0.1.2-alpha.0

FEATURE
  • 支持样式比例转换
  • 支持 template 标签转换
  • 支持 include 和 import 标签转换
  • 自动生成添加了 360 小程序构建工具 latest 版本依赖的 package.json 文件
FIX
  • css 迁移时 @keyframes 100% 没有正确转化 100% => .is_100%

能力

我们将以下几个方面来阐述 wx2qh 的迁移能力,您能够了解到它做了什么

视图

wxml 语法转换为 vue 语法

转化关系对应
一、attrs

将微信小程序标签上的属性绑定语法变为 360 小程序绑定语法,如:

微信小程序360 小程序
id="item"id="item"
id=" {{item}} ":id="item"
二、components

将微信小程序组件转换为 360 小程序组件。如果 360 小程序组件没有该组件,则不转换且给出提示。

目前支持组件转换的列表如下:

微信小程序360 小程序
movable-viewse-movable-view
movable-arease-movable-area
scroll-viewse-scroll-view
swiperse-swiper
swiper-itemse-swiper-item
viewse-view
iconse-icon
progressse-progress
rich-textse-rich-text
textse-text
buttonse-button
checkboxse-checkbox
checkbox-groupse-checkbox-group
formse-form
inputse-input
radiose-radio
radio-groupse-radio-group
sliderse-slider
switchse-switch
audiose-audio
imagese-image
videose-video
adse-ad
blocktemplate
三、directives

将微信小程序的指令转换为 360 小程序指令:

微信小程序360 小程序
wx:for="{{array}}" wx:for-item="xxx" wx:for-index="yyy"v-for="(xxx, yyy) in array"
wx:ifv-if
wx:elifv-else-if
wx:elsev-else
四、template

将微信小程序的 template 转换成 360 小程序中的 component,目前仅支持 template 的内容转换。微信小程序源码中,通过<import src="a.wxml"/><include src="header.wxml"/> 这两种方式引用的地方需要将转换后的内容手动添加过来。

template 模版内容转换

转换前:

<template name="A">
    <div wx:for="{{ array }}" wx:for-item="it" wx:for-index="$index">{{it}}{{$index}}</div>
    <template name="B">
      <div class="x-{{ ccc }}">{{ bbb }} {{ array.length }}</div>
    </template>
    <template is="C" data="{{ ...xxx, x: xxx[eee + 'c'] ? ccc : 22 }}"></template>
</template>

转换后:

<template name="A" scope="{ array, ccc, eee, xxx }">
    <div v-for="(it, $index) in array">{{it}}{{$index}}</div>
    <template name="B" scope="{ array, bbb, ccc }">
      <div :class="\`x-\${ccc}\`">{{ bbb }} {{ array.length }}</div>
    </template>
    <component is="C" v-bind="{ ...xxx, x: xxx[eee + 'c'] ? ccc : 22 }"></component>
</template>
template 引用转换

转换前:

<template is="{{staffName}}" data="{{...staffA}}"></template>

转换后:

<component :is="staffName" v-bind="{ ...staffA }"></component>

样式

基础组件标签转换
  1. wx 小程序里有,但 360 小程序里没有的基础组件标签:不用转换,直接将该节点转化为注释节点。
  2. wx 小程序里有,但 360 小程序里没有且与 html 原生标签同名的基础组件:不做处理,直接使用原生标签。
  3. wx 小程序里有,且 360 小程序里也有的基础组件标签:统一转换为 class 选择器形式,.is_[基础组件标签名]。
单位转换

遍历所有 css 属性,将 wx 小程序的 rpx 转化为 px

框架

由于我们底层是基于 Vue 的,文档从 Vue 的角度说明迁移后的能力支持

接口支持情况如下,其他的 选项(option) 请参考能力支持表格

  • App
    • 支持 data 和 methods 直接定义在 选项(options) 根级别上
App({
  func1: function() {},
  data1: 111
})
  • getApp
    • 由于框架实现差异,getApp 只能在 beforeCreate 或之后的 vue 生命周期中获取
let app = null
Page({
  beforeCreate() {
    app = getApp()
  }
})
  • Page
    • 支持 this.setData
  • getCurrentPages
    • 暂不支持(需要开发者二次开发改写)
  • Component
    • 选项(options)支持情况见下表格
  • Behavior
    • 暂不支持(需要开发者二次开发改写)
能力支持

注意格式问题

  • - 代表待定,目前不支持,未来可能支持
  • N 代表遗弃,现在和未来都不支持
  • Y 代表已支持,(框架支持)
微信小程序描述SeappVersion
App: onLaunchlifecycle-监听小程序初始化beforeCreate created beforeMount mounted
App: onShowlifecycle-监听小程序启动或切前台-
App: onHidelifecycle-监听小程序切后台-
App: onError错误监听函数-
App: onPageNotFound页面不存在监听函数-
Page: data页面的初始数据data
Page: onLoadlifecycle-监听页面加载mounted
Page: onShowlifecycle-监听页面显示onShow
Page: onReadylifecycle-监听页面初次渲染完成onReady
Page: onHidelifecycle-监听页面隐藏onHide
Page: onUnloadlifecycle-监听页面卸载beforeDestroy destroy
Page: onPullDownRefresh监听用户下拉动作-
Page: onReachBottom页面上拉触底事件的处理函数-
Page: onShareAppMessage用户点击右上角转发-
Page: onPageScroll页面滚动触发事件的处理函数-
Page: onResize页面尺寸改变时触发-
Page: onTabItemTap当前是 tab 页时,点击 tab 时触发-
Component: properties组件的对外属性props
Component: data组件的内部数据data
Component: observers组件数据字段监听器watch2.6.1
Component: methods组件的方法methods
Component: behaviors类似于 mixins 和 traitsmixins
Component: createdlifecycle-在组建实例创建时执行,不能调用 setDatabeforeCreate created
Component: attachedlifecycle-在组件实例进入页面节点树时执行beforeMount
Component: readylifecycle-在组件布局完成后执行mounted
Component: movedlifecycle-在组件实例被移动到节点树另一个位置时执行-
Component: detachedlifecycle-在组件实例被从页面节点树移除时执行destroy
Component: relations组件间关系定义-
Component: externalClasses组件接受的外部样式类Y
Component: options一些选项(文档中介绍相关特性时会涉及具体的选项设置)-
Component: lifetimes组件生命周期生命对象 (权重 > normal)Y2.2.3
Component: pageLifetimes组件所在页面的生命周期声明对象-2.2.3
Component: definitionFilter定义段过滤器,用于自定义组件扩展-2.2.3
All: 其他开发者可以添加任意的函数或数据到 Object 参数中,在页面的函数中用 this 可以访问Y

接口

由于 360 小程序 api 与微信小程序 api 无论是方法名,参数形式基本保持一致,所以 360 小程序实现了的 api 迁移后都支持

360 小程序 api 文档

Keywords

FAQs

Package last updated on 16 Dec 2019

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc