# FAQ

# 怎么理解框架的实现原理?

实现原理图 原理图

# 我想使用 CML,是否需要大刀阔斧的重构项目?

不需要,可以使用 CML 开发公用组件,导出到各端原有项目中使用。

# 用 CML 标准编写代码,是否增加调试成本?

我们实现了全面的语法检查功能,且在持续加强。理论上框架是降低调试成本,就像从原生 js 开发到 vuejs、reactjs 是否认为也增加了调试成本,见仁见智。

# 如何定位并解决 CML 开发中遇到的问题?

首先,当我们遇到一些问题的时候,第一步要定位问题,定位问题的基本思路如下

  • 初始化一个项目,以最基础、最简单的demo复现出现问题的基本场景
  • 通过在代码中插入debugger进行基本的断点调试
  • github-issues搜索是否有类似问题

# 如何调试工程化配置?

第一步:

cml -v 找到当前使用 chameleon-tool 的路径

第二步:

用编辑器打开该路径下源码,找到chameleon.js 文件,修改成如下


#! /usr/bin/env node --inspect-brk
require('./lib/index.js');

可以在源码目录中任何想调试的地方打上断点debugger

第三步:

修改chameleon.config.js

cml.utils.plugin('webpackConfig', function(params) {
  let { type, media, webpackConfig } = params;
  /*最终断点会进到这里,在这里可以看.
  type:编译端,web,wx,weex等
  media:编译类型 dev build
  webpackConfig:chameleon内置工程化配置
  */
  debugger;
  return { type, media, webpackConfig };
});

第四步:

执行相关的运行命令之后,比如 cml web dev 打开chrome://inspect

进入调试终端即可

# 各端包括小程序的接口更新频繁,如何保证框架编译的抽象度和稳定性?

1、自建输入语法标准 cml,编译输出结果自定的格式语法。 2、框架的 runtime 层实现匹配接收的编译输出代码,runtime 跟随小程序更新。 3、框架整体方向一致:mvvm 底层设计模式为标准设计接口。 基于以上三条,你可以理解为:我们设计了一个框架统一标准协议,再在各个端 runtime 分别实现这个框架,宏观的角度就像 nodejs 同时运行在 window 和 macOS 系统,就像 flutter 运行在 Android 和 iOS 一个道理。各端小程序接口更新除非遇到不向下兼容情况,否则不影响框架,如果真遇到不向下兼容更新,这种情况下是否用框架都需要改。

# 框架有多大,性能是否有影响?

1、小程序的主要运行性能瓶颈是 webview 和 js 虚拟机的传输性能,我们在这里会做优化,尽可能 diff 出修改的部分进行传输,性能会更好。 2、包大小,小程序有包大小限制,Web 端包大小也是工程师关心的点。首先基于多态协议,产出包纯净保留单端代码;其次框架的 api 和组件会按需打包。包大小是我们重点发力点,会持续优化到极致。目前 build 模式包大小测试结果如下: minimize | minimize + gzip

平台js总体积外部框架chameleon运行时代码其他代码
web 141.87kb | 43.72kb vue+vuex+vue-router
99.26kb | 33.89kb
35.96kb | 8.85kb 业务代码
weex135kb | 32.43kb vuex+vue-router
33.49kb | 17.96kb
25.23kb | 5.94kb 业务代码
wx101.66kb | 28.12kb mobx算在chameleon运行时中 98.75kb | 26.53kb 业务代码
baidu101.72kb | 28.13kb mobx算在chameleon运行时中 98.78kb | 26.61kb 业务代码
alipay102kb | 28.12kb mobx算在chameleon运行时中 99.15kb | 26.34kb 业务代码

# 我只想跨 web 和各类小程序,是否可以不使用 Flexbox 布局模型?

可以,如果你的项目不在快应用、React Native、Weex 等平台运行,可以更便捷开发项目,特别是 CSS 的限制更少:只跨 Web 和小程序的应用

# 一套代码运行多端,如何保证各个端充分的定制化空间?

基于多态协议,充分保证各端发挥,且保证最终一致性。

# 各端包括小程序的接口更新后,是否一定依赖框架更新?

同上一个问题,基于多态协议,可自己直接调用新的底层接口。

# 怎么使用微信小程序的原生 button?

同类问题:

1、怎么使用微信授权登录?

2、怎么使用小程序登录?

这个功能是微信小程序等特有的功能,所以不建议写在公用跨端部分,用多态组件封装适合自己业务的 <passport>组件,在 passport.wx.cml 里面使用 <origin-button>来调用微信小程序原生组件。

CML 框架方为什么不直接提供组件?

目前提供的封装的组件都是可跨所有端。而微信小程序的免密授权登录功能时小程序所特有的功能,在 Web 端时用户可能需要用账号密码登录,各个公司业务的登录功能设计不一致,平台无法提供统一的 passport 组件;所以在你第一次使用 CML 时需要自己用多态组件封装一次<passport>登录组件,后续所有项目都可以使用这个<passport>登录组件.

# 现在提供的组件是针对三端通用,很多小程序特有功能不能使用,后续有什么改进规划吗?

目前我们正在开发只针对小程序的组件库,用户可以直接使用各类小程序统一版本的登录组件库。 同时基于多态组件的重载能力可以重载登录组件的 Web 端实现,这样既能在各类小程序使用统一登录,又能定制化 Web 端等登录能力。

# 我的项目只运行微信小程序端,官方提供的某个组件灵活性不够?

不仅仅是微信小程序端,任意端想实现自己想要的功能时皆可适用。 找到改组件原来的代码,使用多态组件的重载能力 或者多态接口的重载能力重新实现微信小程序端的实现,实现自己定制化能力。

# 是否支持类似 vue 的 ref?

目前暂不支持;

# 小程序端分包大小超过 2M 的限制改如何优化?

具体优化步骤参考:使用分包issue332

# 模板中支持函数吗?

<view>getText()</view>

由于小程序端语法限制,不支持函数自执行,参考 issue100

# 如何引用字体图标 inonfont?

具体参考 issue77

# 使用 c-tabbar 后,发现其他 cml 组建中的 created 方法不执行,只执行 c-tabbar 页面中的 created,请问该怎么解决这个问题?

具体参考 issue301 开发者需要注意一点,c-tabbar 仅仅是一个组件,和微信原生的配置的 tabbar 并不一样;

# 如何使用原生tabbar?

如果要使用小程序端原生的tabbar,我们也提供了支持

具体demo 参考

但是需要注意一点,原生小程序的支持情况,web/weex端是没有对应支持的能力的。

# 支持第三方 ui 库吗?

支持,具体参考 issue119

# 怎么在多态接口中定义一个含可选属性的对象

具体参考 issue327

# image 组件如何调用 error 方法

具体参考 issue348

# build 模式下图片静态资源地址找不到?

具体参考 publicPath

# process.env 获取不到值

首先要了解 webpack 中 DefinePlugin 的作用,可以参考官网

所以当我们取值的时候,只能取到该插件已经声明的值;

# 数据存储有同步方法吗?

store 部分请参考:MutationAction

备注:mutation 是数据的同步操作,action 是数据的异步操作。

# 为什么图片切换有延迟?

可以参考:图片 base64,将图片改为 base64 的形式。

# build 模式不支持传参,导致无法灵活区分环境

如果我们需要多套构建配置,可以自定义一个构建类型,具体参考项目配置-自定义配置

假如你在构建微信小程序端,一个构建模式下要求不压缩代码,一个构建模式下要求显示模块名字,那么可以如下配置

cml.config.merge({
  wx: {
    build: {
      minimize: true,//对打包结果进行压缩
      moduleIdType: "id" //编译的模块结果以模块名字显示
    }
    custom: {
      minimize: false,//对打包结果进行压缩
      moduleIdType: "name" //编译的模块结果以模块名字显示
    }
  }
})

执行 cml wx build 则打包的代码会进行压缩以及模块名以 id 取名;

执行 cml wx custom 则打包的代码不会压缩,模块名以该模块对应的 name 取名

# v-model 不支持对象的属性吗?

目前不支持对象的属性;参考 issue340

# Web 端页面切换动画怎么加?

参考 issue234

# 我想通过别名引用项目中的资源,该如何配置?

可以通过CML 提供的回调函数,对 webpack 进行配置;利用 resolve.alias 选项;具体参考 webpack-resolvealias

比如想提供一个对于 src 目录的访问别名 修改 chameleon.config.js

const path = require('path');
cml.utils.plugin('webpackConfig', function(params) {
  let { type, media, webpackConfig } = params;
  //这里新增 SRC 别名;
  webpackConfig.resolve.alias &&
    (webpackConfig.resolve.alias.SRC = path.resolve(__dirname, 'src/'));
  return { type, media, webpackConfig };
});

假如项目目录中有src/utils/utils.js这个模块,那么在项目中可以直接

import utils from 'SRC/utils/utils.js';

注意:CML 内置了一些别名

'$CMLPROJECT';
'/components';
'$PROJECT';
'$ROUTER_CONFIG';

# 如何支持 sass?

可以自定义扩展 webpack 配置,具体配置可以参考 issue128

# 如何给 CML 项目增加 eslint?

如果是新初始化的项目,可以根据 issue358中《如何使用 eslint 规范 CML 项目》部分进行配置;

如果是已开发一段时间的 CML 项目,想渐进式的对项目进行 eslint 规范,那么可以参考 issue358中《如何使用 eslint 校验本次提交》部分进行配置;

# 微信预览为什么显示不了图片

首先参考:资源定位上线指南

在 build 模式下会定位到配置的 publicPath 路径下,所以如果要预览的话,务必配置正确的 publicPath

# Web 端开发模式下,如何修改资源协议?

cml web dev 之后,我们可以在 node_modules/.chameleon 文件夹中看到资源的具体内容

可以通过以下配置修改协议

cml.utils.plugin('webpackConfig', function(params) {
  let { type, media, webpackConfig } = params;
  if (type === 'web' && media === 'dev') {
    //这里修改 publicPath 即可,dev模式下默认是 http://本机ip:port/
    webpackConfig.output.publicPath = webpackConfig.output.publicPath.replace(/http:/, '');
  }
  return { type, media, webpackConfig };
});

# 如何将 Weex 端输出的文件打包成 apk

测试的话可以把 jsbundle 放到 Android 工程 App 模块的 assets 目录下,clone 并参考:https://github.com/chameleon-team/chameleon-sdk-android

这里有 Demo 工程示例的 jsbundle,直接读取 assets 目录下并渲染:https://github.com/chameleon-team/chameleon-sdk-android/tree/master/app/src/main/assets

另,这里的 Android 相关文章建议先读一遍。

# 支付宝端的store如何复用?

由于alipay小程序的限制,不支持分包之间的实例共享,导致不能共用store实例

我们提供了一个使用demo给大家参考来解决这个问题,demo地址如下

https://github.com/chameleon-team/cml-store-demo

# 如何支持路由根据各平台按需配置

chameleon-tool@1.0.6-alpha.1版本支持了路由按需配置,即开发者可以根据平台自定义配置某个路由在哪个端显示

usedPlatforms:['web','weex','wx','baidu','alipay','tt','qq']

{
  "mode": "history",
  "domain": "https://www.chameleon.com",
  "routes":[
    {
      "url": "/cml/h5/index",
      "path": "/pages/index/index",
      "name": "首页",
      "mock": "index.php",
      "usedPlatforms":["web","wx"]
    },
    {
      "url": "/cml/h5/index1",
      "path": "/pages/index/index1",
      "name": "首页",
      "mock": "index.php",
      "usedPlatforms":["web"]
    },
    {
      "url": "/cml/h5/index2",
      "path": "/pages/index/index2",
      "name": "首页",
      "mock": "index.php",
      "usedPlatforms":["wx"]
    },
    {
      "url": "/cml/h5/index3",
      "path": "/pages/index/index3",
      "name": "首页",
      "mock": "index.php",
      "usedPlatforms":["weex"]
    }
  ]
}

# 如何支持weex多bundle的构建?

具体参考

# 如何使用web端跨域

chameleon-tool@1.0.6-alpha.6 之前的版本可以通过 charles 代理进行跨域

  • 如果遇到浏览器的跨域问题,也可以通过设置代理的方式进行解决,比如网上随便搜下charles 代理设置跨域,都能找到解决方案。

charles如何设置代理跨域

chameleon-tool@1.0.6-alpha.6 开始支持通过chameleon.config.js配置的形式进行跨域

具体使用参考

# 如何在构建阶段告警同一个npm包引入了多个不同的版本

我们在项目构建中,可能由于某种情况会引入同一个npm包的不同版本,导致包体积无谓的变大

具体的解决方案可以参考 cml-warn-info

# 如何增强 html-webpack-plugin 的使用?

# 背景

某些场景下,我们需要在 html-webpack-plugin 生成的 html 文件中的 script 标签上增加某些属性,比如 async defer 等等,由于 该插件没有提供对应的能力,我们需要使用某些手段增强该插件能力

比如 script-ext-html-webpack-plugin 这个插件就提供了这样的能力。

具体其他配置参考官网

# CML项目中如何使用

需要注意点就是

The order is important - the plugin(script-ext-html-webpack-plugin)must come after HtmlWebpackPlugin.

也就是说 script-ext-html-webpack-plugin 插件必须在 webpack 配置的插件数组中 HtmlWebpackPlugin 插件之后;

# 第一步,安装改插件

npm install script-ext-html-webpack-plugin@1.8.8

# 第二步,修改chameleon.config.js

const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin');
//...
cml.utils.plugin('webpackConfig', function({ type, media, webpackConfig }, cb) {
  // cb函数用于设置修改后的配置
  debugger;
  const extHtmlWebpackPlugin = new ScriptExtHtmlWebpackPlugin({
    custom: {
      test: /\.js$/,
      attribute: 'crossorigin',
      value: 'anonymous'
    }
  });
  if(type === 'web'){
    let HtmlWebpackPluginIndex = webpackConfig.plugins.findIndex((plugin) => {
      return plugin.constructor && plugin.constructor.name === 'HtmlWebpackPlugin'
    });
    webpackConfig.plugins.splice(HtmlWebpackPluginIndex+1,0,extHtmlWebpackPlugin);
  }
  cb({
    type,
    media,
    webpackConfig
  });
});

cml web build 之后查看构建结果

<script type="text/javascript" src="//www.static.chameleon.com/cml/web/static/js/manifest_3cbfbd4a61bd303d57dc.js" crossorigin="anonymous"></script>

<script type="text/javascript" src="//www.static.chameleon.com/cml/web/static/js/vender_904bcc7cfa7b18b85ac0.js" crossorigin="anonymous"></script>

<script type="text/javascript" src="//www.static.chameleon.com/cml/web/static/js/cml-script-extension_091bce493315100f43ad.js" crossorigin="anonymous"></script>

可以发现会在 script 标签上增加了 crossorigin="anonymous" 属性。

cml-script-extension

# 升级chameleon-tool@1.0.6,默认删除了调试信息

在 chameleon-tool@1.0.6 之后为了尽可能减少包体积,在build模式下默认删除了console.log这样的调试信息,如果有开发者就是想要保留调试信息,可以在回调里通过配置自定义

wx: {
  dev: {
    minimize:true,
  },
  build: {
    minimize:true,
    moduleIdType:'name',
    apiPrefix
  }
},
cml.utils.plugin('webpackConfig', function({ type, media, webpackConfig }, cb) {
  // cb函数用于设置修改后的配置
  debugger;

  if(type === 'wx' && media === 'dev'){
    webpackConfig.plugins.forEach((plugin) => {
      if(plugin.constructor.name === 'UglifyJsPlugin'){
        plugin.options = {}
      }
    })
  }
  cb({
    type,
    media,
    webpackConfig
  });
});

# 如何使用store?

官方文档参考

另外我们也提供了一个demo,方便开发者学习以及开发。

# 如何正确安装nvm?

平时我们在项目开发中,用nvm管理node版本是一个比较专业的选择,通过nvm可以方便我们切换node版本,管理不同终端命令等

nvm的使用可以参考:nvm-sh

Chameleon社区也有人准备了一个安装nvm通俗易懂的步骤,大家可以参考这个