欢迎来到258分享网,纯净的网络源码分享基地!

258资源分享网

全部作品
全部作品
网站源码
微信源码
素材特效
源码插件
视频教程
建站学院
热门搜索: 织梦  农业种植  农业  安全设置  官方
258资源分享 > 建站学院 > 微信开发 > 记一次mpvue-loader源码探究

推荐下载

HTML5响应式自适应网咯设计

2020-05-12   浏览:789

HTML5自适应律师工作室类网

2020-04-04   浏览:654

高端HTML5响应式企业通用网

2020-05-06   浏览:560

html5响应式外贸网站英文版

2020-05-08   浏览:545

HTML5影视传媒文化公司类网

2020-05-12   浏览:543

记一次mpvue-loader源码探究

发布时间:2020-10-29  

本人技术栈偏向vue一些,所以之前写小程序的时候会考虑使用wepy,但是期间发现用起来有很多问题,然后又没有什么更好的替代品,直到有mpvue的出现,让我眼前一亮,完全意义上的用vue的语法写小程序,赞:+1:

踩坑之旅 起因

根据官网的文档,可以很迅速的完成 quick start ,之后很愉快地把自己写的tabbar组件搬了过来,首先先引入组件...

// script import { LTabbar, LTabbarItem } from '@/components/tabbar' export default { components: { LTabbar, LTabbarItem }, ... // file path components |----tabbar |----tabbar.vue |----tabbar-item.vue |----index.js ...

在vue上很常规的引入方式,然后使用...然后看效果...结果没有任何东西被渲染出来,查看console发现有一条警告

记一次mpvue-loader源码探究

有问题肯定得去解决是吧,然后就开始作死的mpvue源码探究之旅

定位问题

由于是基于实际问题出发的源码探究,所以本质是为了解决问题,那么就得先定位出该问题可能会产生的原因,并带着这个问题去阅读源码。从warning可以很明确的看出,是vue组件转化为wxml时发生的问题,而这件事应当是在loader的时候处理的,所以可以把问题的原因定位到 mpvue-loader ,先看一眼 mpvue-loader 的构成

├── component-normalizer.js ├── loader.js // loader入口 ├── mp-compiler // mp script解析相关文件夹 │ ├── index.js │ ├── parse.js // components & config parse babel插件 │ ├── templates.js // vue script部分转化成wxml的template │ └── util.js // 一些通用方法 ├── parser.js // parseComponent & generateSourceMap ├── selector.js ├── style-compiler // 样式解析相关文件夹 ├── template-compiler // 模板解析相关文件夹 └── utils

首先找到loader.js这个文件,找到关于script的解析部分,从这里看到调用了一个 compileMPScript 方法来解析components

script参数即为vue单文件的 <script></script> 包含部分

mpOptions mp相关配置参数

moduleId 用于模块唯一标识 moduleId = 'data-v-' + genId(filePath, context, options.hashKey)

// line 259 // <script> output += '/* script */\n' var script = parts.script if (script) { // for mp js // 需要解析组件的 components 给 wxml 生成用 script = compileMPScript.call(this, script, mpOptions, moduleId) ...

接下来看一下mp-compiler目录下的 compileMPScript 具体做了哪些事情

function compileMPScript (script, optioins, moduleId) { // 获得babelrc配置 const babelrc = optioins.globalBabelrc ? optioins.globalBabelrc : path.resolve('./.babelrc') // 写了一个parseComponentsDeps babel插件来遍历组件从而获取到组件的依赖(关键) const { metadata } = babel.transform(script.content, { extends: babelrc, plugins: [parseComponentsDeps] }) // metadata: importsMap, components const { importsMap, components: originComponents } = metadata // 处理子组件的信息 const components = {} if (originComponents) { const allP = Object.keys(originComponents).map(k => { return new Promise((resolve, reject) => { // originComponents[k] 为组件依赖的路径,格式如下: '@/components/xxx' // 通过this.resolve得到realSrc this.resolve(this.context, originComponents[k], (err, realSrc) => { if (err) return reject(err) // 将组件名由驼峰转化成中横线形式 const com = covertCCVar(k) // 根据真实路径获取到组件名(关键) const comName = getCompNameBySrc(realSrc) components[com] = { src: comName, name: comName } resolve() }) }) }) Promise.all(allP) .then(res => { components.isCompleted = true }) .catch(err => { console.error(err) components.isCompleted = true }) } else { components.isCompleted = true } const fileInfo = resolveTarget(this.resourcePath, optioins.mpInfo) cacheFileInfo(this.resourcePath, fileInfo, { importsMap, components, moduleId }) return script }

这段代码中有两处比较关键的部分

babel插件的转化究竟做了些什么事儿,组件的依赖是怎么样的形式?

组件的realSrc是否真的为我所需要的路径 那么首先先看一下babel插件究竟做了什么

parseComponentsDeps babel插件

首先我在看这份源码的时候对于babel这块的知识是零基础,所以着实废了不少功夫。

在看babel插件之前最好可以先阅览这些资料

Babel-handbook - 这份资料里面很详细地描述了如何写一个babel插件。

Babel-types相关 - 这里会涉及到AST节点类型

接下来看一下核心的源码部分,这里声明了一个components访问者:

Visitors(访问者)

当我们谈及“进入”一个节点,实际上是说我们在访问它们, 之所以使用这样的术语是因为有一个访问者模式(visitor)的概念。.