uni-app 编译分析
uni-app 编译分析
目前已经有不少文章对 uni-app 的编译流程进行了分析,但大多数都是关于 Vue SFC 如何编译为微信小程序的 WXML/WXSS/JS 文件。很少有文章会从源码角度解析其整个流程。
最近越发难以忍受基于 WebPack 的 Vue2 uni-app,因此决定基于 RsPack 重新实现 uni-app(以插件形式),分析其整个流程就非常重要了。
我们以微信小程序为例,这也是 uni-app 最常用的平台。
当执行 pnpm run build:mp-weixin 命令时,实际发生了以下步骤:
-
环境变量设置:
cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin会设置两个关键环境变量:NODE_ENV=production: 确保构建在生产模式下进行,启用相应的优化和压缩。UNI_PLATFORM=mp-weixin: 明确指定目标平台为微信小程序。这是uni-app插件识别并应用小程序特有配置的关键。
-
Vue CLI 服务启动:
vue-cli-service uni-build命令启动 Vue CLI 服务,并指示其执行uni-build命令。
这里可以展开讲讲,vue-cli 有一套插件机制,其中有一类service插件,可以通过 vue-cli-service 命令来启动,uni-app 插件就是这样实现的。
-
加载
vue-cli-plugin-uni插件: Vue CLI 服务会加载vue-cli-plugin-uni插件。该插件的入口文件packages/vue-cli-plugin-uni/index.js会被执行。 -
注册
uni-build命令: 在index.js中,api.registerCommand('uni-build', ...)会注册uni-build命令的回调函数。当vue-cli-service uni-build被调用时,该回调函数会被触发。 -
执行
build.js中的build函数:uni-build命令的回调函数(位于packages/vue-cli-plugin-uni/commands/build.js)是核心执行逻辑。它会调用async function build(args, api, options)函数来启动实际的构建过程。 -
获取基础 Webpack 配置: 在
build函数内部,会调用getWebpackConfigs(最终调用getWebpackConfig)来获取一个基础的 Webpack 配置。这个基础配置是基于 Vue CLI 的默认配置和项目的vue.config.js文件生成的。 -
应用微信小程序平台特有配置: 这是最关键的一步。
vue-cli-plugin-uni插件通过api.configureWebpack和api.chainWebpack方法,加载并应用packages/vue-cli-plugin-uni/lib/mp/index.js中定义的针对微信小程序平台的 Webpack 配置和插件。这些配置包括:- 入口和输出: 设置小程序特有的入口文件(如
app.json和pages.json解析出的页面/组件入口)和输出路径。 - 模块解析: 配置
.js,.vue,.json等文件的解析规则,以及路径别名。 - Loader 配置: 为
.vue文件配置vue-loader,并传入小程序特有的compilerOptions;为样式文件配置mini-css-extract-plugin、css-loader、postcss-loader等;为 JavaScript 文件配置babel-loader。 - 插件集成: 引入一系列核心插件,例如:
WebpackUniAppPlugin: 处理uni-app特有逻辑,如页面和组件的转换。WebpackUniMPPlugin(通过createUniMPPlugin()): 针对小程序平台的 Webpack 插件,负责将 Vue/uni-app 代码转换为微信小程序原生代码结构(wxml,wxss,js,json)。webpack.DefinePlugin: 定义全局常量,注入process.env.NODE_ENV和process.env.UNI_PLATFORM等。CopyWebpackPlugin: 复制静态资源。MiniCssExtractPlugin: 提取 CSS 到单独文件。webpack.ProvidePlugin: 自动注入uni和uniCloud等全局对象。PreprocessAssetsPlugin: 处理构建产物中的wxss和js文件,例如添加公共runtime和vendor引用。
- 优化和压缩: 在生产环境下,对 CSS 和 JavaScript 进行优化和压缩。
- 入口和输出: 设置小程序特有的入口文件(如
-
执行 Webpack 编译:
build函数使用最终合并了基础配置和微信小程序特有配置的 Webpack 配置对象,调用webpack包进行实际的代码编译和打包。 -
输出构建产物: Webpack 将编译后的微信小程序代码(包含
wxml,wxss,js,json文件以及其他资源)输出到指定的构建目录(通常是dist/build/mp-weixin)。
简而言之,build:mp-weixin 命令是一个高度自动化的构建流程,它通过 Vue CLI 和 uni-app 插件的协同工作,将 uni-app 项目的源代码转换并优化为符合微信小程序运行规范的最终代码。
其他配置
uni-app 项目相较于标准的 Vue Web 项目,还有一些特殊的文件,这些也影响了构建:
pages.json:页面配置文件,用于配置路由、窗口表现、底部 tab 等。manifest.json:应用配置文件,用于配置应用名称、版本、权限等。postcss.config.js:PostCSS 配置文件,用于配置 PostCSS 插件,这个在 Web 项目中也有,但 uni-app 还有一个@dcloudio/vue-cli-plugin-uni/packages/postcss。主要用于处理各平台的样式兼容问题。babel.config.js:Babel 配置文件,用于配置 Babel 插件,这个在 Web 项目中也有,但 uni-app 还有一个@dcloudio/vue-cli-plugin-uni/packages/babel。主要也是处理兼容性问题(真坑啊)uni.promisify.adaptor.js:这玩意用来把 uni-app 早期设计的那些基于回调的 API 转换为 Promise 风格的 API。
总结
uni-app 虽然对 Vue 的运行时也进行了魔改,但核心还是这套编译机制。
这大概会是个系列文章,逐步分析这套编译机制和我的移植过程。