2018-11-08
Metro 整体上采用 C/S 结构,它对外暴露一个 Metro Server 类。Server 会在构造的时候接受一个结构,用于配置它内部的行为,这个结构是我们操纵 Server 内部行为的主要途径。
因此想要正确控制打包器的话,首先要创建正确的配置结构,这个结构在 Metro 中称为 ConfigT。它定义于 metro-config 包的 configTypes.flow.js 中。
在这篇文章中,我们来梳理一下 ConfigT 结构。
ConfigT 非常复杂,从整体上,它分为以下几个子结构:
其中:
因此,configT 从整体上看结构如下:
{ resolver: { // ResolverConfigT }, server: { // ServerConfigT }, serializer: { // SerializerConfigT }, transformer: { // TransformerConfigT }, // MetalConfigT 在跟层展开 }
在 node_modules/metro-config/src/defaults/index.js 下有一份默认值。
MetalConfigT 包含以下字段:
字段 | 说明 |
---|---|
cacheStores | 缓存类 |
cacheVersion | 缓存版本 |
maxWorkers | 并发构建时数 |
projectRoot | 项目根目录 |
stickyWorkers | |
transformerPath | transformer 路径 |
reporter | 日志记录器 |
resetCache | 是否清空缓存 |
watchFolders | 源文件的全集 |
cacheStores 是缓存类,默认值是 FileStore。其中 FileStore 定义在 metro-cache 包中。
cacheVersion 是缓存版本,默认值是 '1.0'。
项目根目录,如果没指定的话,默认是从脚本运行 metro 所在的位置向上两个层级作为根目录。
用于 node_modules/metro/src/DeltaBundler/WorkerFarm.js 的 JestWorker。
默认是 metro/src/JSTransformer/worker.js。
transformer 的功能是编译源文件,内部通过调用 babel 来实现编译功能。
默认值是 TerminalReporter,位于 packages/metro/src/lib/TerminalReporter.js。
定义源文件的全集,打包构建工作将在这个全集中执行。
如果一个文件在构建时发现它不在 watchFolders 中,将会构建失败(sha-1 计算错误)。
ResolverConfigT 包含以下字段:
字段 | 说明 |
---|---|
assetExts | 资源文件扩展名 |
blacklistRE | 模块路径的忽略规则 |
extraNodeModules | |
hasteImplModulePath | |
platforms | 所解析的平台 |
providesModuleNodeModules | |
resolverMainFields | |
resolveRequest | |
sourceExts | 代码文件后缀 |
useWatchman | 是否启用 Watchman |
资源文件扩展名,默认值为:
exports.assetExts = [
// Image formats
'bmp', 'gif', 'jpg', 'jpeg',
'png', 'psd', 'svg', 'webp',
// Video formats
'm4v', 'mov', 'mp4',
'mpeg', 'mpg', 'webm',
// Audio formats
'aac', 'aiff', 'caf',
'm4a', 'mp3', 'wav',
// Document formats
'html', 'pdf',
// Font formats
'otf', 'ttf',
];
如果一个文件的后缀在 assetExts 中,就被认为是一个资源文件。
模块路径的忽略规则,定义在 node_modules/metro-config/src/defaults/blacklist.js 中。
默认规则执行后的值为:
/\\(node_modules\\[\\\\/\\\\\\\\\\]react\\[\\\\/\\\\\\\\\\]dist\\[\\\\/\\\\\\\\\\]\\.\\*\\|website\\\\/node_modules\\\\/\\.\\*\\|heapCapture\\\\/bundle\\\\\\.js\\|\\.\\*\\\\/__tests__\\\\/\\.\\*\\)\\$/
默认值是 undefined。(在 react-native 的 local-cli/core/index.js 中,它指向路径 ../../jest/hasteImpl,即 react-native 的 jest/hasteImpl.js)。
所解析的平台。默认值:
exports.platforms = ['ios', 'android', 'windows', 'web'];
默认值:
exports.providesModuleNodeModules = ['react-native', 'react-native-windows'];
默认值:
resolverMainFields: ['browser', 'main']
默认值:null。
代码文件后缀。默认值:
exports.sourceExts = ['js', 'json', 'ts', 'tsx'];
ServerConfigT 包含以下字段:
字段 | 说明 |
---|---|
enableVisualizer | 是否启用可视化器(?还有这功能?) |
enhanceMiddleware | 应用中间件(?还有这功能?) |
useGlobalHotkey | (?) |
port | 端口号 |
SerializerConfigT 包含以下字段:
字段 | 说明 |
---|---|
createModuleIdFactory | 创建 module id 的工厂 |
experimentalSerializerHook | ? |
getModulesRunBeforeMainModule | 指定在主模块前运行的模块 |
getPolyfills | 获取 Polyfills |
getRunModuleStatement | |
polyfillModuleNames | |
postProcessBundleSourcemap | |
processModuleFilter |
创建 module id 的工厂,方法签名:
() => (path: string) => number
不知道干什么的,方法签名:
(graph: Graph<>, delta: DeltaResult<>) => mixed
指定在主模块前运行的模块,方法签名:
(entryFilePath: string) => Array<string>
默认值:
getModulesRunBeforeMainModule: () => []
获取 Polyfills,方法签名:
getPolyfills: ({platform: ?string}) => $ReadOnlyArray<string>
默认值:
() => []
方法签名:
(number | string) => string
默认值:
getRunModuleStatement: moduleId => `__r(${JSON.stringify(moduleId)});`
默认值:[]
。
默认值:
postProcessBundleSourcemap: ({code, map, outFileName}) => ({code, map})
默认值:
processModuleFilter: module => true,
SerializerConfigT 包含以下字段:
字段 | 说明 |
---|---|
assetPlugins | 资源插件 |
assetRegistryPath | |
asyncRequireModulePath | |
babelTransformerPath | |
dynamicDepsInPackages | |
enableBabelRCLookup | |
enableBabelRuntime | |
minifierConfig | 压缩混淆器设置 |
minifierPath | 压缩混淆器路径 |
optimizationSizeLimit | |
getTransformOptions | |
postMinifyProcess | |
transformVariants | |
workerPath |
资源插件。默认值:[]
。
默认值:'missing-asset-registry-path'
默认值:'metro/src/lib/bundle-modules/asyncRequire'
默认值:'metro/src/defaultTransformer'
默认值:'throwAtRuntime'
默认值:true。
默认值:true。
默认值:
minifierConfig: { mangle: { toplevel: false, }, output: { ascii_only: true, quote_style: 3, wrap_iife: true, }, sourceMap: { includeSources: false, }, toplevel: false, compress: { // reduce_funcs inlines single-use functions, which cause perf regressions. reduce_funcs: false, }, }
默认值:'metro-minify-uglify'
默认值:150 * 1024, // 150 KiB.
默认值:
getTransformOptions: async () => ({
transform: {experimentalImportSupport: false, inlineRequires: false},
preloadedModules: false,
ramGroups: [],
})
默认值:
postMinifyProcess: x => x
默认值:
transformVariants: {default: {}}
默认值:
workerPath: 'metro/src/DeltaBundler/Worker'
以上就是 ConfigT 的所有设置项,可以看出数量非常多,这也说明了 Metro Server 的工程是非常丰富的。
其中很多选项我还不知道他们的含义是什么,后续随着认识的加深,我会回来再继续补全。