什么是Taro
Taro 是一套遵循多端开发的解决方案。只需要一套代码,就可以编译转换成 RN、H5、小程序、快应用多端的运行代码,其运转流程主要分为编译时,运行时两个阶段。
Taro2(重编译,轻运行)
- 编译时:通过taro工具将Taro源代码转换成目标代码
- 运行时:目标代码运行时,通过运行时的库去适配不同端
Taro3(轻编译,重运行)
Taro3主要通过在小程序端模拟实现 DOM、BOM API 来让前端框架直接运行在小程序环境中,而对于生命周期、组件库、API、路由等差异,通过定义统一标准,在运⾏时会提供 React 和 Vue 对应的适配器进⾏适配,然后调⽤Taro提供的 DOM 和 BOM API, 最后把整个程序渲染到所有的⼩程序端上⾯。
编译流程
Taro本质上是进行多端编译和运行,而Taro的编译主要依赖于webpack配置,Taro则通过mini-runner完成webpack配置的组装,然后根据 webpack 配置生成编译后的代码。
tarojs/mini-runner的作用
- 负责根据开发者的编译配置调整 webpack 配置
- 注入自定义的 插件 和 loader
- 调用 webpack 开启编译
- 修改 webpack 的编译产物,调整最终的编译结果
目录结构
主流程(index)
主要分为两个流程,根据项目配置生产webpack的构建配置,利用webpack进行代码编译。
基础配置
base.config.ts 文件记录基本配置信息,主要是Taro 构建过程中一部分 webpack 配置的初始化工作(包括文件扩展名、模块解析路径、别名等)。
自定义配置
buildConf.conf.ts 中主要负责配置一些构建过程中所需的插件、常量和选项,确保构建过程中能够根据配置进行适当的处理和优化。
合并webpack配置
合并webpack配置,确保小程序项目在构建时能够按照用户的配置和需求生成合适的 Webpack 配置。
分析配置
通过分析主包来进一步了解tarojs/mini-runner在其中的作用。
查看config配置
- projectName: 项目名称
- date: 项目创建日期
- designWidth: 设计稿宽度,用于进行适配
- deviceRatio: 不同设备宽度的适配比例
- sourceRoot: 源代码目录
- outputRoot: 输出目录,根据环境变量进行不同的配置
- plugins: 配置Taro框架使用的插件
- env: 环境变量配置
- defineConstants: 常量配置
- copy: 复制文件的配置,将一些静态文件复制到输出目录
- framework: 项目框架
- mini: 针对小程序的配置
- h5: 针对H5平台的配置
- alias: 路径别名配置,简化在代码中的引用路径
defineConstants
defineConstants 主要进行常量的相关配置。
首先将环境变量,静态常量,运行时常量合并为一个常量对象definePlugin,通过getDefinePlugin 函数返回了一个配置好的 DefinePlugin 实例,definePlugin是Webpack的一个内置插件,用于替换代码中的变量为其对应的值。
通过这个配置,Webpack 在构建时会将代码中的 APPNAME 替换为 process.env.APPNAME 的值。同样,其他常量也会按照相应的方式被替换。
copy
copy复制文件的配置,将一些静态文件复制到输出目录,
- patterns: 一个数组,指定了需要拷贝的文件或目录的规则
- options: 配置选项
不同环境拷贝不同的目标路径,主要用于对地图的适配。
在 patterns 数组中添加了一个额外的拷贝规则,将 plugin/doc 目录拷贝到输出目录的 doc 目录下,如果配置中存在copy 调取getCopyWebPackPlugin。
getCopyWebpackPlugin 函数接收一个包含 copy 配置的对象以及应用程序路径 appPath。通过 CopyWebpackPlugin 创建实例,配置 patterns,将配置项中的相对路径转换为绝对路径,确保正确的拷贝。返回创建的 CopyWebpackPlugin 实例。
alias
alias主要用于简化在代码中的引用路径。
resolve 是一个配置选项,用于指定解析模块请求的规则。alias 配置会被合并到 resolve 中。
在构建过程中,Webpack 将会使用这些别名来解析模块的引入路径。例如,当代码中出现 import '@/ecoExpress/someModule' 时,Webpack 将会解析为 path.resolve(__dirname, '..', 'src/ecoExpress/someModule')。
mini
postcss
pxtransform 配置:
- enable: true 表示开启对 CSS 中的 px 单位进行转换
- config: 可以用于配置 pxtransform 的详细选项,比如配置项的转换规则
url 配置: - enable: true 表示开启对样式文件中的图片、字体等资源的 URL 转换
- config: { limit: 1024 } 限制转换的资源大小,超过这个大小的资源将被单独输出文件,小于这个大小的资源将被转换成 base64 编码并嵌入样式文件中
这个配置的目的是将小图片、字体等资源直接转换成 base64 编码,减少网络请求,提高小程序的加载速度。
cssModules 配置:
- enable: false 表示不开启 CSS Modules 功能。
- config: 可以配置一些关于 CSS Modules 的选项,包括命名规则等
开启了 CSS Modules,可以通过配置项进行定制化,CSS Modules 允许将 CSS 样式作用域限制在组件内,避免全局样式的污染。
查看config基础配置,进行了一些预处理。
webpackChain
在 webpack 中,webpackChain 通常指的是一种链式调用的方式来配置 Webpack 的构建过程。在 Taro 中,webpackChain 主要是用于自定义和扩展 Webpack 配置的工具。
Taro 封装了 webpack 的配置,提供了一些默认的配置,同时也允许开发者通过 webpackChain 自定义和扩展这些配置。这种链式调用的方式可以更方便地对 Webpack 配置进行修改和增强。
如下代码可知,mini-runner 将内部 webpackChain 和开发者配置的 webpackChain 相结合,得到最终的webpackChain。
针对小程序进行配置。
先查看mini中的webpackChain,查看第一个插件 hitchFeCompontsImportPlugin,可以得出主要功能是匹配不同依赖路径确定不同的配置。
multiPlatformPlugin,接着看下一个函数,这个方法的作用是为 Taro 项目配置 Webpack 的解析插件,限制只解析以 '@hb/' 开头的模块路径,以支持 Taro 项目的多平台打包需求。
使用 webpack-bundle-analyzer 插件,并传递一个空数组 [] 作为配置(webpack-chain中 use的第二个参数,作为插件的配置,可以不填,但必须要是数组)。
使用自定义的 Stats 类创建的插件。这个插件的作用是在 Webpack 构建完成后将统计信息写入一个文件(stats.json),以供进一步分析和处理。
- 使用 chain.optimization 配置 Webpack 的优化
- 调用 .minimizer() 方法,传递一个包含 TerserPlugin 实例的数组。TerserPlugin 用于压缩 JavaScript 代码
- extractComments: false,配置了禁止提取注释的选项,以防止将注释提取到单独的文件中
optimizeMainPackage
配置项 optimizeMainPackage 控制了主包的优化,只有在构建目标环境是微信小程序(TARO_ENV === 'weapp')时才启用。主要的目的是在微信小程序中优化主包的构建。
判断 optimizeMainPackage.enable 是否为 true,如果为 true,则使用 getMiniSplitChunksPlugin 函数创建了一个插件实例,并将其配置合并了 optimizeMainPackage 和 fileType。这个插件的作用是对小程序主包进行分包优化。
Webpack 提供了 SplitChunkPlugin 进行分包优化。SplitChunksPlugin 插件可以将应用程序中共享的代码拆分成单独的块,以便将其从应用程序代码中分离出来,从而提高性能和加载速度。
miniCssExtractPluginOption
miniCssExtractPluginOption用于指定 Mini CSS Extract 插件的选项。,其中 ignoreOrder 主要是为了避免关于样式引入顺序的警告。当为 true 时,表示忽略 CSS 文件的引入顺序,不会抛出关于引入顺序的警告。
baseLevel
对于不支持模板递归的小程序(微信、QQ、京东小程序),在 DOM 层级达到一定数量后,Taro 会使用原生自定义组件协助递归。
简单理解就是 DOM 结构超过 N 层后,会使用原生自定义组件进行渲染。N 默认是 16 层,可以通过修改配置项 修改 N。
H5
再查看下H5中webpackChain的作用
首先跟小程序配置类似,先调用multiPlatformPlugin这个方法的作用是为 Taro 项目配置 Webpack 的解析插件,限制只解析以 '@hb/' 开头的模块路径,以支持 Taro 项目的多平台打包需求。
然后chain.module.rules.get('script').exclude.clear().add([...]);:这一段代码涉及到对 Webpack 规则的修改
- chain.module.rules.get('script') 表示获取名为 'script' 的规则
- exclude.clear() 清空原有的排除规则
- add([...]) 添加新的排除规则,其中传入的函数用于判断是否应该排除某个文件
这个规则的目的是排除一些特定的文件,包括 @tarojs/components 目录下的文件,以满足一定条件的 node_modules 下的文件,但不包括包含 taro 和 @hb/ 的文件。为了定制 Taro 在 H5 平台的构建规则。
然后调用hitchFeCompontsImportPlugin。
总结
总的来说在编译方面,mini-runner 支持多端开发,使开发者能够通过一套代码适配不同的小程序平台。还提供了默认的构建配置,包括 loader、plugin、resolve 规则等,以满足 Taro 框架的开发需求,并允许开发者通过配置文件或插件进行对构建过程的定制和扩展。
在对webpack配置方面,mini-runner 提供了webpackChain方法,使得开发者可以在 Webpack 配置中进行链式调用,方便自定义和增强配置。封装了一套默认的 Webpack 配置,以适应 Taro 框架的特性和小程序平台的要求。此外,mini-runner 控制构建过程,提供一些配置项,例如是否监听文件变化、是否启用 source map 等。
附录 - (mini-runner 部分源码解析)
目录结构
主流程(index)
主要分为两个流程,根据项目配置生产webpack的构建配置,利用webpack进行代码编译。
基础配置
进入 buildConf 函数,由代码可知,首先调用了 getBaseConf ,进入该函数查看配置。
查看该配置,主要是Taro 构建过程中一部分 webpack 配置的初始化工作(包括文件扩展名、模块解析路径、别名等)。通过配置解析选项和引入 MultiPlatformPlugin 插件,支持跨平台文件。
- 源文件使用的扩展名,这里包括 '.js', '.jsx', '.ts', '.tsx', '.mjs', '.vue'
- 指定导入模块时使用 package.json 中的哪个字段,这里的配置将优先使用 browser 属性解析文件,其次是 module,最后是 main
- symlink
- 告诉 webpack 解析模块时应该搜索的目录,这里对应的就是 node_modules 目录
- 解析 webpack loader 包,指定 node_modules 目录
- 代码包是包含副作用的,不希望被 tree shaking 优化
- 配置node环境,在构建过程中对 fs(文件系统模块)和 path(路径模块)的引用替换为一个空对象,从而在浏览器环境中模拟文件系统和路径操作,在浏览器环境中,一些 Node.js 特定的模块是不可用的,因此需要通过这种方式进行处理
- 添加MultiPlatformPlugin 插件,支持跨平台文件
自定义配置
查看 buildConf 的其余配置,这段代码主要负责初始化和配置一些构建过程中所需的插件、常量和选项,确保构建过程中能够根据配置进行适当的处理和优化
- 如果是构建插件(isBuildPlugin 为真),就会处理复制文件的逻辑。如果存在 copy 对象,则将其现有的 patterns 属性提取出来,如果不存在,则创建一个空数组。随后,将插件相关的文件夹路径加入这个数组。最后,使用 Object.assign 将更新后的 patterns 放回到 copy 对象中。这样,如果之前已经有一些复制规则,现在就添加了插件相关的复制规则
- 配置插件,将 copy 属性解析为 copy-webpack-plugin 插件,加入到 webpack 中
- 设置环境变量
- 预备构建过程中所需的常量和入口文件的配置。首先,通过 getRuntimeConstants(runtime) 获取运行时常量,其中可能包含运行时所需的配置或环境常量。接着,通过 mergeOption([processEnvOption(env), defineConstants, runtimeConstants]) 合并来自不同来源的常量选项,包括从环境变量提取的配置、预定义的常量以及之前获取的运行时常量。最后,通过 getEntry({ sourceDir, entry, isBuildPlugin }) 获取项目的入口文件配置,其中包括源代码目录、入口文件的配置以及构建是否为插件
- 配置共享的代码块(Common Chunks)以用于构建。首先,根据是否构建插件来设置默认的共享代码块列表 defaultCommonChunks,其中包括了运行时、第三方库、Taro 框架和通用代码块。接着,通过一系列条件语句,允许用户自定义共享代码块的配置。如果 commonChunks 是一个函数,则调用它,将默认的共享代码块传递给它,允许用户根据需要修改或替换默认的配置。如果 commonChunks 是一个非空数组,则将其用作自定义的共享代码块配置。最后,通过调用 getDefinePlugin([constantsReplaceList]) 获取定义插件的配置,其中包括了前面整理好的常量替换列表。有利于灵活地配置和生成最终的共享代码块配置,以便在构建过程中进行优化
- 判断是否开启了主包优化,如果开启了就配置相应的分割插件
Taro 构建过程中 webpack 配置的核心部分,通过链式调用 webpack-chain 库的方法逐步配置了 webpack 的各项参数,包括模式、入口、出口、目标、解析规则、插件、优化等
- mode:提供 mode 配置选项,告知 webpack 使用相应模式的内置优化。
- devtool:控制是否生成 source-map。
- entry:入口文件,也就是 app.js。
- output:定义代码编译后的生产目录。
- target:指定目标(target)环境。
- resolve:合并 alias 别名选项。
- module:配置 module,这里主要是配置一些不同的 loader。
- plugin:配置 plugin 插件。
- optimization:手动配置了一些编译选项优化。
webpack 代码编译
webpack 的编译过程,支持 watch 模式,并提供了一些回调函数用于处理编译结果。
(本文作者:刘健)