用户
 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,登录网站

小程序社区 首页 工具/框架 查看内容

深入wepy小程序组件化框架

Rolan 2017-8-7 00:44

wepy是一个优秀的微信小程序组件化框架,突破了小程序的限制,支持了npm包加载以及组件化方案,并且在性能优化方面也下了功夫,不管之后项目是否会使用到,该框架组件化编译方案都是值得学习和深入的。本文同步于个 ...

wepy是一个优秀的微信小程序组件化框架,突破了小程序的限制,支持了npm包加载以及组件化方案,并且在性能优化方面也下了功夫,不管之后项目是否会使用到,该框架组件化编译方案都是值得学习和深入的。

本文同步于个人博客 www.imhjm.com/article/597…

wepy文档: wepyjs.github.io/wepy/#/

github地址: github.com/wepyjs/wepy

我们先提出几个问题,让下面的分析更有针对性:

  1. wepy如何实现单文件组件.wpy编译?
  2. 如何隔离组件作用域?
  3. 如何实现组件通信?
  4. 如何实现加载外部npm包?

先从源码目录入手

我们可以先clone下 wepy的github目录

  • docs目录下是开发文档以及使用 docsify 生成的文档网站
  • packages目录下就是核心代码了,wepy是小程序端的框架,wepy-cli是脚手架(负责组件化编译等等),其他就是一些预处理编译插件、还有一些压缩插件等等
  • scripts是一些shell脚本,负责test等等一些操作
  • gulpfile.js主要负责将package中的src开发目录中js文件babel转换至lib目录供使用,并支持watch compile
  • 等等

我们就重点看wepy以及wepy-cli,接下来的文章也是围绕这两个展开

wepy-cli分析

目录结构

上面的bin/wepy.js是入口文件,其实就一句话引入lib中经过babel转换的文件

require('../lib/wepy');

编译构建流程

下图简单画出了整体wepy-cli的编译构建流程,忽略了部分细节

接下来答大体说下build的流程(可以跟着图看)

  • wepy-cli使用commander作为命令行工具,build命令执行调用compile build方法
  • 如果没有指定文件build,则获取src目录下所有文件,寻找没有引用的(指的是这种 <script src=""> ),调用compile方法开始编译,如果指定文件,则相应判断寻找父组件或者寻找引用去编译
  • compile方法根据文件后缀判断,调用不同文件的方法(下面就说wpy单文件组件)
  • compile-wpy调用resolveWpy方法(核心)

    • 替换内容中的attr(比如@tap => bindtap等等)
    • 使用 xmldom 放入内容,操作节点
    • 获取wpy中的包裹的config,放入rst.config
    • 将样式放入rst.style
    • 提前编译wxml,如果是jade/pug之类的
    • 获取文件中的import和components放入rst.template.components
    • 获取代码中components的属性,获取props以及events放入rst.script.code中
      rst.script.code = rst.script.code.replace(/[\s\r\n]components\s*=[\s\r\n]*/, (match, item, index) => {
                    return `$props = ${JSON.stringify(props)};\r\n$events = ${JSON.stringify(events)};\r\n${match}`;
                });
    • 最后拆解style、template、script构成一个rst文件
      let rst = {
            moduleId: moduleId,
            style: [],
            template: {
                code: '',
                src: '',
                type: '',
                components: {},
            },
            script: {
                code: '',
                src: '',
                type: '',
            },
           config: {},
        };
    • rst构建完成,开始逐个操作

      • rst.config写入xxx.json
      • rst.template
        • 经过compiler后再次使用 xmldom
        • updateSlot,替换内容
        • updateBind, 将{{}}以及attr中的加入组件前缀($prefix)
        • 将组件替换成相应xml
      • rst.style
        • 寻找require再进入compile-style
        • compiler预编译处理,并且置入依赖(@import)
      • rst.script

        • compiler处理
        • 假如不是npm包,则置入wepy框架初始化代码

          if (type !== 'npm') {
            if (type === 'page' || type === 'app') {
                code = code.replace(/exports\.default\s*=\s*(\w+);/ig, function (m, defaultExport) {
                    if (defaultExport === 'undefined') {
                        return '';
                    }
          
                    if (type === 'page') {
                        let pagePath = path.join(path.relative(appPath.dir, opath.dir), opath.name).replace(/\\/ig, '/');
                        return `\nPage(require('wepy').default.$createPage(${defaultExport} , '${pagePath}'));\n`;
                    } else {
                        appPath = opath;
                        let appConfig = JSON.stringify(config.appConfig);
                        return `\nApp(require('wepy').default.$createApp(${defaultExport}, ${appConfig}));\n`;
                    }
                });
            }
          }
        • resolveDeps(核心),根据require的形式,模仿node require加载机制,将文件拷贝到相应目录,修改require内容,这里包括外部npm包的拷贝加载
        • 假如是npm包,特殊处理部分代码
    • 均通过相应plugins顺序通过一遍,最后输出到dist目录

大体就像开发文档的图一样,现在看就很清晰了

核心方法

resolveWpy

这个方法用于生成rst,拆分wpy单文件组件,上面流程讲了大部分,这里就详细讲下props和event的提取

其实也不是很复杂,就是遍历元素,取出相应attributes,放入  邀请

鲜花
鲜花 (1)
鸡蛋
鸡蛋

刚表态过的朋友 (1 人)

分享至 : QQ空间
收藏
原作者: 小深刻的秋鼠 来自: 掘金

相关阅读