Applets framework WEpy documentation

DEMO of finished products

One is a standard demo generated using the wepy new demo command

One is a full demo of mobile phone recharge based on Wepy

One is based on the development of wepy open source imitation wechat chat interface (source code download)

The above three demos have been run on Android and IOS.

Quick start

Code specification:

1. Use camel name for variables and methods instead of starting with $. Methods or attributes that start with $are built-in methods or attributes and can be used. Please refer to the API documentation before using them.

2. Name entries, pages, and components with the suffix.wpy. External linked files can be other suffixes. Please refer to the WPY file description

3. Develop using ES6 syntax.

The framework was developed under ES6, so we also need to use ES6 to develop small programs. ES6 has a lot of syntax sugar to make our code more concise and efficient.

4. Use promises

The framework promises all apis provided by applets by default, and can even be developed directly with new features such as async/await.

Project creation and use

Install wepy

The following installations are installed through NPM

Note: In Tencent development website, NPM requires an agent. If you don’t use NPM agent, you are advised to use Tencent internal tool TNMP instead of NPM installation. For TNPM installation and use, please refer to alsotan G’s article.

1. Install the WEpy command line tool

npm install wepy-cli -g
Copy the code

2. Generate development DEMO in the development directory

wepy new myproject
Copy the code

3. Develop real-time builds

wepy build --watch
Copy the code

Project directory structure

dist
node_modules
src
 components
     com_a.wpy
     com_b.wpy
 pages
     index.wpy
     page2.wpy
app.wpy
package.json
Copy the code

Development instructions

1. Use wechat developer tools to create a project, and select dist directory for local development.

2. Wechat Developer Tools – > Project – > Close ES6 to ES5.

3. Run wepy build –watch in the local project root directory to enable real-time compilation.

Main problems solved:

1. Development mode transformation

In the original small program development mode of encapsulation, more close to the existing MVVM framework development mode. The framework was developed with reference to some of the features of the current framework and incorporated into it. Below is a comparison of the code before and after using Wepy.

Official DEMO code:

Var app = getApp() Page({data: {motto: 'Hello World', userInfo: {}}, function bindViewTap: {motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World', motto: 'Hello World') function() { console.log('button clicked') }, onLoad: function () { console.log('onLoad') } })Copy the code

Implementation based on Wepy:

import wepy from 'wepy'; export default class Index extends wepy.page { data = { motto: 'Hello World', userInfo: {} }; methods = { bindViewTap () { console.log('button clicked'); }}; onLoad() { console.log('onLoad'); }; }Copy the code

2. Support componentized development

See section: Components

Sample code:

// index.wpy <template> <view> <component id="pannel" path="pannel"></component> <component id="counter1" path="counter"></component> <component id="counter2" path="counter"></component> <component id="list" path="list"></component> </view> </template> <script> import wepy from 'wepy'; import List from '.. /components/list'; import Panel from '.. /components/panel'; import Counter from '.. /components/counter'; export default class Index extends wepy.page { config = { "navigationBarTitleText": "test" }; components = { panel: Panel, counter1: Counter, counter2: Counter, list: List }; } </script>Copy the code

3. Supports loading external NPM packages.

During compilation, require is recursively iterated through the code and the dependency files are copied from node_modules, and require is changed to a relative path to support external NPM packages. The diagram below:

4. Single-file mode, making the directory structure clearer.

Json, app.js, and app.wxss. The page has 4 files: index.json, index.js, index.wxml, and index.wxss. And the file must have the same name.

Therefore, the comparison of development directories before and after wepy development is as follows:

Official DEMO:

project
    pages
        index
        index.json
        index.js
        index.wxml
        index.wxss
    log
        log.json
        log.wxml
        log.js
        log.wxss
    app.js
    app.json
    app.wxss
Copy the code

Directory structure with the Wepy framework:

project
    src
    pages
        index.wpy
        log.wpy
    app.wpy
Copy the code

Compiled using Babel by default, some new features of ES6/7 are supported.

Users can configure their familiar Babel environment for development by modifying the wepy.config.js configuration file. Default enabled uses new features like Promise, async/await, etc.

Sample code:

import wepy from 'wepy';

export default class Index extends wepy.page {

  getData() {
      return new Promise((resolve, reject) => {
          setTimeout(() => {
              resolve({data: 123});
          }, 3000);
      });
  };
  async onLoad() {
      let data = await this.getData();
      console.log(data.data);
  };
}
Copy the code

5. Optimize for native apis

Promise processing to the existing API, and fix some existing API flaws such as wx.request concurrency issues.

Original code:

onLoad = function () { var self = this; wx.login({ success: function (data) { wx.getUserInfo({ success: function (userinfo) { self.setData({userInfo: userinfo}); }}); }}); }Copy the code

Implementation code based on WEpy:

async onLoad() {
  await wx.login();
  this.userInfo = await wx.getUserInfo();
}
Copy the code

When testing 10 requests simultaneously:

Do not use wepy:

After using Wepy:

Advanced instructions

Wepy.config. js configuration file description

After wepy New Demo is executed, a similar configuration file is generated.

let prod = process.env.NODE_ENV === 'production'; module.exports = { "wpyExt": ".wpy", "babel": { "presets": [ "es2015", "stage-1" ], "plugins": [ "transform-export-extensions", "syntax-export-extensions", "transform-runtime" ] } }; Exports ['sass'] = {"outputStyle": "compressed"}; Exports [' exports '] = {" exports ": true}; // Compress js module.exports.plugins = {'UglifyJsPlugin': {filter: /\.js$/, config: {{compress: {warning: false } } }, 'TestPlugin': { filter: /\.wxml$/, config: { } } }; }Copy the code

WpyExt: The default value is’. Wpy ‘, the IDE does not highlight this file type by default, you can change all files to the. Vue suffix (because it is the same as vue highlighting rules), then change this option to. Vue to solve some IDE code highlighting problems.

Sass: SASS compilation and configuration, see here

Less: Less compilation and configuration. For details, see here

Babel: Babel compilation configuration, see here

Plugins: Plugins for 1.1.6 after the function, currently support JS compression and image compression, continuous development……

Wpy file description

The wpy file is compiled as follows:

A.wpy file is divided into three parts:

corresponds to the original WXSS

Template
corresponds to the original WXML

Code corresponds to the original JS

The entry file app.wpy does not require template, so it is ignored during compilation. All three tags support the type and SRC attributes. Type determines the compilation process of their code, and SRC determines whether to externalize the code. If the SRC attribute exists and is valid, the inlining code is ignored, as shown in the following example:

<style type="less" src="page1.less"></style>
<template type="wxml" src="page1.wxml"></template>
<script>
  // some code
</script>
Copy the code

The label type values are as follows:

| | | tag type, a default value type support value | | -- - | -- - | -- - | | style | | CSS CSS, less and sass (pending) | | template | WXML | WXML, XML, HTML (pending) | | script | js | js, | TypeScript (pending)Copy the code

The script that

Program entry app.wpy

<style type="less">
/** less **/
</style>
<script>
import wepy from 'wepy';
export default class extends wepy.app {
  config = {
      "pages":[
      "pages/index/index"
  ],
  "window":{
      "backgroundTextStyle": "light",
      "navigationBarBackgroundColor": "#fff",
      "navigationBarTitleText": "WeChat",
      "navigationBarTextStyle": "black"
  }
  };
  onLaunch() {
      console.log(this);
  }
}
</script>
Copy the code

The entry app.wpy inherits from wepy.app and contains a config property with its global properties, methods, and events. The config attribute corresponds to the original app.json file, which will be generated according to the config during compilation. If you need to modify the content in config, use the API provided by the system.

The index page. Wpy

<style type="less"> /** less **/ </style> <template type="wxml"> <view> </view> <component id="counter1" path="counter"></component> </template> <script> import wepy form 'wepy'; import Counter from '.. /components/counter'; export default class Index extends wepy.page { config = {}; components = {counter1: Counter}; data = {}; methods = {}; events = {}; onLoad() {}; // Other properties } </script>Copy the code

The page entry inherits from wepy.page and its main properties are described as follows:

Com components. Wpy

<style type="less">
/** less **/
</style>
<template type="wxml">
  <view> </view>
</template>
<script>
import wepy form 'wepy';
export default class Com extends wepy.component {

  components = {};

  data = {};
  methods = {};

  events = {};
  // Other properties
}
</script>
Copy the code

The page entry inherits from Wepy.component and has the same properties as the page properties, except that it does not require config and some page-specific applet events, etc.

component

In the small program, JS modularization and WXML template can be used to divide business modules to achieve the following effects:

However, different module code and event interactions are handled in the same page space. For example, if an ADD response event exists in moduleA and moduleB, it needs to be defined as moduleA_add in HTML and moduleB_add in JS. The complexity of business modules becomes difficult to develop and maintain.

In WEpy, this kind of problem can be solved by using the componentization feature, as shown below:

The data in between ComA and ComB are isolated from events, and each can have its own Add event.

A component reference

When a page or component needs to import a child component, assign the component a unique ID to the components in the page or script, and add a < Component > tag to the template, such as index.wpy

The Index page introduces three components A, B, and C, and components A and B have their own sub-components D, E, F, G, and H.

Component communication and interaction

The wepy.component.ponent class provides three methods: $broadcast, $emit, and $invoke, so any page or component can call these three methods to communicate and interact with each other.

$this.$emit('some-event', 1, 2, 3, 4);
Copy the code

The component’s event listener needs to be written under the Events property, as in:

import wepy form 'wepy';
export default class Com extends wepy.component {

  components = {};

  data = {};
  methods = {};

  events = {
      'some-event': ($event, ...args) {
          console.log(`${this.name} receive ${$event.name} from ${$event.source.name}`);
      }
  };
  // Other properties
}
Copy the code

1. The $broadcast $broadcast event is initiated by the parent component. All child components receive the broadcast event unless the event is manually cancelled. Events are broadcast in breadth-first search order. If Page_Index initiates A $broadcast event, events are received in the order of A, B, C, D, E, F, G, and H. The diagram below:

2 .$emit

$emit is the opposite of $broadcast. The parent of the event emitting component receives $emit events in sequence, as shown in the figure above. If E initiates A $emit event, the event will be received in the order of A, Page_Index. The diagram below:

3 .$invoke

$invoke is a direct call from one component to another, finding the corresponding component through the component path passed in, and invoking its methods.

If you want to call A method of component A in Page_Index:

this.$invoke('ComA', 'someMethod', 'someArgs');
Copy the code

If you want to call A method of component G from component A:

this.$invoke('./.. /ComB/ComG', 'someMethod', 'someArgs');Copy the code

hybrid

Mixing can separate reusable portions between groups so that mixed data, events, and methods can be injected into a component when mixing is used in the component. Mixing is divided into two types:

  • Default blending

  • Compatible mixing

Default blending

Default blending is used for component data, components, events events, and other custom methods, that is, if the component does not declare the data, component, event, custom method, etc., then the options from the blending object are injected into the component. Options already declared for components are not affected.

// mixins/test.js
import wepy from 'wepy';

export default class TestMixin extends wepy.page {
    data = {
        foo: 'foo defined by page',
        bar: 'bar defined by testMix'
    };
    methods: {
        tap () {
            console.log('mix tap');
        }
    }
}

// pages/index.wpy
import wepy from 'wepy';
import TestMixin from './mixins/test';

export default class Index extends wepy.mixin {
    data = {
        foo: 'foo defined by index'
    };
    mixins = [TestMixin ];
    onShow() {
        console.log(this.foo); // foo defined by index.
        console.log(this.bar); // foo defined by testMix.
    }
}
Copy the code

Compatible mixing

Compatibility mixing is adopted for component methods response events and applet page events, that is, responding to the response events of the component itself first, and then responding to the response events in the mixed object.

// mixins/test.js import wepy from 'wepy'; export default class TestMixin extends wepy.page { methods = { tap () { console.log('mix tap'); }}; onShow() { console.log('mix onshow'); } } // pages/index.wpy import wepy from 'wepy'; import TestMixin from './mixins/test'; export default class Index extends wepy.mixin { mixins = [TestMixin]; methods = { tap () { console.log('index tap'); }}; onShow() { console.log('index onshow'); } } // index onshow // mix onshow // ----- when tap // index tap // mix tapCopy the code

Data binding

Applets data binding mode

Applets use setData methods provided by Page to unbind data, such as:

this.setData({title: 'this is title'});
Copy the code

Because of the applets architecture itself, the page rendering layer and THE JS logic layer are separated, and the setData operation is actually the communication between the JS logic layer and the page rendering layer, so if the setData operation is executed several times in the same running cycle, then the number of communication is once or many times? After confirming with the small program team, we learned that multiple setData will execute multiple communications.

Wepy data binding

Wepy uses the dirty data check to encapsulate setData, and performs the dirty data check at the end of the function running cycle. On the one hand, it does not need to worry about whether setData will have performance problems on the page multiple times. On the other hand, it can be more concise to modify the data to achieve binding, and it does not need to write the setData method repeatedly. The code is as follows:

this.title = 'this is title';
Copy the code

Note, however, that modifying data in functions outside of the function’s run cycle requires a manual call to the $apply method. Such as:

setTimeout(() => {
  this.title = 'this is title';
  this.$apply();
}, 3000);
Copy the code

Wepy dirty data check process

When performing dirty data checks, this.? Phase identifies the current check status and ensures that only one dirty data check process is running in a concurrent process. The following is a flow chart for performing a dirty data check:

Other optimization details

1. Wx. request Accepts parameter modification

Click here for official documentation

Wx. request({url: 'XXX ', success: function (data) {console.log(data); }}); Wx.request (' XXXX '). Then ((d) => console.log(d));Copy the code

2. Optimize event parameter transmission

Click here for official documentation

<view id="tapTest" data-hi="WeChat" bindtap="tapName"> WeChat <view id="tapTest" data-hi="WeChat" bindtap="tapName"> </view> Page({ tapName: function(event) { console.log(event.currentTarget.hi)// output: WeChat } }); <view id="tapTest" data-wepy-params="1-wepy-something" bindtap="tapName"> Click me! </view> events: { tapName (event, id, title, other) { console.log(id, title, other)// output: 1, wepy, something } }Copy the code

3. Change the data binding mode

Retain the setData method, but do not recommend using setData to perform binding, fix the bug of passing undefined, and modify the input parameter support:

  • this.setData(target, value)

  • this.setData(object)

Click here for official documentation

OnLoad: function () {this.setData({message: 'hello world'}); } // wepy <view> {{ message }} </view> onLoad () { this.message = 'hello world'; }Copy the code

4. Components replace templates and modules

Click here for official documentation

Official / / <! -- item.wxml --> <template name="item"> <text>{{text}}</text> </template> <! -- index.wxml --> <import src="item.wxml"/> <template is="item" data="{{text: 'forbar'}}"/> <! -- index.js --> var item = require('item.js') // wepy <! -- /components/item.wpy --> <text>{{text}}</text> <! -- index.wpy --> <template> <component id="item"></component> </template> <script> import wepy from 'wepy'; import Item from '.. /components/item'; export default class Index extends wepy.page { components = { Item } } </script>Copy the code

API

wepy.event

wepy.component

wepy.page

wepy.app

CHANGELOG

1.3.1 (2016-12-16)

  • Added support for third-party Compiler

  • Added puG compiler

  • Reorganize the code structure to maintain different NPM packages using LerNA

  • Re-process the Plugins, again to a third-party package

  • Added logic to check if the dependent Compiler or Plugins are missing at compile-time and install them if they are missing

  • Added the cli tool version check function

1.1.9 (2016-12-14)

  • Added the wepy upgrade command to upgrade wepyJS

  • Added support for third-party components

  • Added third party components [wepy-com-toast]

  • Add the Toast component test to the template

1.1.8 (2016-12-08)

  • Fixed a BUG with script using SRC external chain

  • Fixed a BUG where LESS compilation would call SASS

  • Optimized event transmission parameters to support direct parameter transmission

  • Joined Travis-CI and Coveralls

  • Fix other detail bugs

1.1.7 (2016-12-06)

  • The script/template/style attributes support both type and lang

  • Add mixins support

1.1.6 (2016-12-02)

  • Fixed an issue where component IDS could not be identified in uppercase

  • Added support for all response events on applet pages

  • Modify wepy.config.js to support plugins

  • Add UglifyJsPlugin to compress all generated JS files at compile time

  • Add ImageMinPlugin(not recommended, problems with large images)

  • Add the wepy build –no-cache parameter to recompile all dependent files at compile time

  • When wepy new demo, instead of generating projects in the current directory, create a demo directory, and then regenerate projects

  • Update Generate Demo to support the latest functions

1.1.4 (2016-12-01)

  • Added support for other page events in applet

  • Change the default configuration file wepyrc to wepy.config.js for future extension. (Compatible with old configuration files)

1.1.3 (2016-11-28)

  • Fix SASS compilation exception cause watch end BUG

  • Fixed BUG where child component changes do not trigger parent component updates

  • Repair $invoke (‘.. Bugs/’)

  • Fix page onLoad event pass parameter BUG

1.1.1 (2016-11-23)

  • Added compilation support for SASS/SCSS

  • Wepyrc added support for less/ sASS configuration

  • Wepyrc adds the wpyExt option

  • Updating the Build template

Finally, thanks to @BrianLiu, @XMagicwu and other members of the team for their help in the development process.