前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >1. 「uniapp 如何支持微信小程序环境开发」初探uniapp为此做了哪些努力?

1. 「uniapp 如何支持微信小程序环境开发」初探uniapp为此做了哪些努力?

作者头像
tinyant
发布2023-03-06 14:52:45
1K0
发布2023-03-06 14:52:45
举报

uniapp 是什么?

uni-app 是一个使用 Vue.js 开发所有前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/飞书/QQ/快手/钉钉/淘宝)、快应用等多个平台。

我们当前项目中使用unaipp进行微信小程序的开发,版本是2.0.1-32920211122003。好奇uniapp是如何做到这层转换的。因此从uniapp中抠出了核心逻辑(做了很多简化工作,为了你能更好的理解啊),并写了一个简易demo,来一探究竟。

mock的所有代码已上传到个人github,见mock-uniapp-for-wxmp

构建前后的目录结构对比

构建前

构建后

1. 看到除了App.vue 这个vue文件,其他的vue文件如 todo-item.vue,home/main.vue,sell/index.vue 都被转换成了小程序的页面结构(wxml、js、wxss、json)。 2. 其他的一些应用配置文件(app.json等)还是保留着在(为了简化整体构建过程而做的努力)。实际上在官方脚手架中是pages.json + manifest.json => app.json、project.config.json。 3. app.js和app.wxss来自哪❓,common/main.js,runime.js,vendor.js又是什么❓

uniapp底层是基于webpack进行构建的,我们只需要在调用webpack方法之前拿到配置,并分析每个配置中的作用,就基本能还原大致的过程了。构建的实际入口在下面文件中

代码语言:javascript
复制
// node_modules/@dcloudio/vue-cli-plugin-uni/commands/build.js
async function build (args, api, options) {
  //....
    
  return new Promise((resolve, reject) => {
    webpack(webpackConfigs, (err, stats) => { /*..*/ })
  })
}

我们项目中的配置如下:

image.png
image.png

下面分析下核心的配置

entry

代码语言:javascript
复制
{
    common/main: "/Users/songyu/tencent/doctor-uni/src/main.js",
    pages/home/main: "/Users/songyu/tencent/doctor-uni/src/main.js?{\"page\":\"pages%2Fhome%2Fmain\"}"
}

入口是main.js和所有的${page}.vue(所有的页面,而不是组件,当然也不包括App.vue

optimization

代码语言:javascript
复制
{
  "splitChunks": {
    "cacheGroups": {
      "default": false,
      "vendors": false,
      "commons": {
        "minChunks": 1,
        "name": "common/vendor",
        "chunks": "all",
        "test": function (module) { ... }
      }
    }
  },
  "runtimeChunk": {
    "name": "common/runtime"
  }
}

这个配置实际上解释了产物中的common/runtime.jscommon/vendor.js的来源了。

module

image.png
image.png

module.noParse

代码语言:javascript
复制
/^(vue|vue-router|vuex|vuex-router-sync)$/

Prevent webpack from parsing any files matching the given regular expression(s). Ignored files should not have calls to importrequiredefine or any other importing mechanism. This can boost build performance when ignoring large libraries.

module.rules

test、resourceQuery

name

remark(关键?)

[/.vue$/, /.nvue$/]

@dcloudio/vue-cli-plugin-uni/packages/vue-loader/lib/index.js:vue-loader @15.8.3

uniapp改造了vue-loader,并通过options.compiler来自定义模板编译部分。✅

/.m?jsx?$/

babel-loader: @8.2.2 @dcloudio/vue-cli-plugin-uni/packages/webpack-preprocess-loader

what is babel: convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments。✅ what is webpack-preprocess-loader : Bring the awesome "Conditional Compilation" to the Webpack, and more.

.../src/pages.json

babel-loader @dcloudio/webpack-uni-pages-loader

后者:生成小程序需要的app.json、project.config.json。✅

.../src/main.js

wrap-loader @dcloudio/webpack-uni-mp-loader/lib/main

前者:Adds custom content before and after the loaded source。✅ 后者:1. 从main.js中提取全局组件。2. 向${page}.vue和main.js注入代码(运行时需要)。✅

/vue&type=script/

@dcloudio/webpack-uni-mp-loader/lib/script

收集来自App.vue和${page}.vue中的组件并缓存起来到xxx.json(全局或者局部组件,usingComponents)✅

/vue&type=template/

@dcloudio/vue-cli-plugin-uni/packages/webpack-preprocess-loader

条件编译

/vue&type=template/

@dcloudio/webpack-uni-mp-loader/lib/template @dcloudio/vue-cli-plugin-uni/packages/webpack-uni-app-loader/page-meta

前者:收集全局组件包括main.js和pages.json中声明的✅,而后传递给vue-loader.options,目的是在模板解析过程中需要判断用到了哪些全局组件(为了支持其它不支持全局组件的场景,微信小程序不需要) 后者:支持微信小程序<page-meta>特性

/type=uni-cache-loader-template/

ident: "uni-cache-loader-template-options",loader: cache-loader

The cache-loader allow to Caches the result of following loaders on disk (default) or in the database.

[/lang=wxs/, /lang=filter/, /lang=sjs/, /blockType=wxs/, /blockType=filter/, /blockType=sjs/]

@dcloudio/vue-cli-plugin-uni/packages/webpack-uni-filter-loader/index.js

支持微信小程序WXS特性

还有很多和静态资源以及样式相关的rules,显然对于整体的构建流程没什么用,必须忽略啊。

image.png
image.png

plugins

image.png
image.png

plugin

remark

VueLoaderPlugin

和上面说到的vue-loader是配合使用的✅

MiniCssExtractPlugin

This plugin extracts CSS into separate files. It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps.

内置插件: WebpackUniAppPlugin

easycom 特性相关

内置插件: WebpackUniMPPlugin

app.js、app.wxss、app.json、${component/page}.json输出;添加小程序组件的自动注册逻辑。✅

webpack.DefinePlugin

replaces variables in your code with other values or expressions at compile time.

webpack.ProvidePlugin

Automatically load modules instead of having to import or require them everywhere.

CopyWebpackPlugin

Copies individual files or entire directories, which already exist, to the build directory.

FriendlyErrorsWebpackPlugin

recognizes certain classes of webpack errors and cleans, aggregates and prioritizes them to provide a better Developer Experience.

CaseSensitivePathsPlugin

This Webpack plugin enforces the entire path of all required modules match the exact case of the actual path on disk. Using this plugin helps alleviate cases where developers working on OSX, which does not follow strict path case sensitivity, will cause conflicts with other developers or build boxes running other operating systems which require correctly cased paths.

webpack.SourceMapDevToolPlugin

This plugin enables more fine grained control of source map generation. It is also enabled automatically by certain settings of the devtool configuration option.

resolve & resolveLoader

resolveresolveLoader webpack构建过程所有加载的资源都需要转化为本地路况,有一个专门的模块enhanced-reolve(可以参考enhanced-reolve源码分析),来解析资源路径,资源会区分普通的模块和loader场景,resolve和resoveLoader就用来辅助解析的。

代码语言:javascript
复制
// resolve
{
    alias: {
        //...
        vue$: "@dcloudio/vue-cli-plugin-uni/packages/mp-vue",
        vuex: "@dcloudio/vue-cli-plugin-uni/packages/vuex3/dist/vuex.common.js"
    }
}

// resolveLoader
{
    alias: {
        //...
        vue-loader: "@dcloudio/vue-cli-plugin-uni/packages/vue-loader/lib/index.js"
    }
}

由于小程序环境和web环境差异比较大,不能直接使用web环境的运行时,小程序中的vue时是被改造过的(其实主要是阉割虚拟DOM部分,修改patch函数,patch函数从dom-diff变为了data-diff),因此通过resolve.alias来指向修改后的文件。比如这样就会将import Vue from 'vue'从默认查找node_modules/vue变更为查找@dcloudio/vue-cli-plugin-uni/packages/vuex3/dist/vuex.common.js

uniapp也对很多第三方库进行了修改,在node_modules/@dcloudio/vue-cli-plugin-uni/packages路径下面,包括vue-loader@vue/component-compiler-utilsvuex等等。

但是在我们在配置loader时如vue-loader时,是如下写法:

代码语言:javascript
复制
{
    loader: "vue-loader",
}

但是此时希望被查找的是被改后的vue-loader,因此通过resolveLoader.alias配置指向修改后的vue-loader@dcloudio/vue-cli-plugin-uni/packages/vue-loader/lib/index.js

另外还有一个有趣的点,如被修改后vue-loader也引用了被修改后的第三方库如vue-template-compiler等,此时的这些模块的查找并不会走webpack,而后走node自己的模块查找机制,显然默认情况下肯定是找的node_modules下安装的模块,因此uniapp在初始化的时候会通过module-alias这个库来修改node的默认查找规则。

代码语言:javascript
复制
// node_modules/@dcloudio/vue-cli-plugin-uni/lib/env.js
const moduleAlias = require('module-alias')
//...
moduleAlias.addAlias('vue-template-compiler', '@dcloudio/vue-cli-plugin-uni/packages/vue-template-compiler')
//...

module-alias:Create aliases of directories and register custom module paths in NodeJS like a boss!

总结

实际上想了解或者实现uniapp如何做到支持构建到小程序环境的,涉及到对小程序webpackvue多个方向的熟悉,包含了运行和构建两个大的方向。

当前小节只是通过webpack的关键配置项如entrymodule.rulesplugins来初步了解uniapp为了做了哪些事情。下一小节重点分析我简化后的配置,以及做了哪些变更。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-03-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • entry
  • optimization
  • module
    • module.noParse
      • module.rules
      • plugins
      • resolve & resolveLoader
      • 总结
      相关产品与服务
      云开发 CloudBase
      云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档