metro 0.71.3 → 0.72.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/package.json +23 -21
  2. package/src/Assets.js +3 -2
  3. package/src/Assets.js.flow +3 -2
  4. package/src/Bundler.js +11 -2
  5. package/src/Bundler.js.flow +7 -1
  6. package/src/DeltaBundler/DeltaCalculator.js +83 -21
  7. package/src/DeltaBundler/DeltaCalculator.js.flow +61 -8
  8. package/src/DeltaBundler/Serializers/baseBytecodeBundle.js +3 -2
  9. package/src/DeltaBundler/Serializers/baseBytecodeBundle.js.flow +2 -1
  10. package/src/DeltaBundler/Serializers/helpers/bytecode.js +2 -2
  11. package/src/DeltaBundler/Serializers/helpers/bytecode.js.flow +2 -1
  12. package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +1 -3
  13. package/src/DeltaBundler/Transformer.js +27 -4
  14. package/src/DeltaBundler/Transformer.js.flow +18 -2
  15. package/src/DeltaBundler/Worker.flow.js +45 -1
  16. package/src/DeltaBundler/Worker.flow.js.flow +42 -1
  17. package/src/DeltaBundler/WorkerFarm.js +3 -2
  18. package/src/DeltaBundler/WorkerFarm.js.flow +3 -1
  19. package/src/DeltaBundler/graphOperations.js +170 -63
  20. package/src/DeltaBundler/graphOperations.js.flow +144 -64
  21. package/src/DeltaBundler/types.flow.js.flow +11 -5
  22. package/src/DeltaBundler.js.flow +1 -1
  23. package/src/HmrServer.js +11 -5
  24. package/src/HmrServer.js.flow +11 -4
  25. package/src/IncrementalBundler.js +22 -4
  26. package/src/IncrementalBundler.js.flow +23 -4
  27. package/src/ModuleGraph/node-haste/HasteFS.js.flow +1 -1
  28. package/src/ModuleGraph/node-haste/Package.js.flow +5 -5
  29. package/src/ModuleGraph/node-haste/node-haste.js +19 -8
  30. package/src/ModuleGraph/node-haste/node-haste.js.flow +43 -16
  31. package/src/ModuleGraph/output/indexed-ram-bundle.js.flow +5 -13
  32. package/src/ModuleGraph/output/multiple-files-ram-bundle.js.flow +4 -14
  33. package/src/ModuleGraph/output/util.js +3 -4
  34. package/src/ModuleGraph/output/util.js.flow +3 -3
  35. package/src/ModuleGraph/types.flow.js.flow +28 -5
  36. package/src/ModuleGraph/worker/collectDependencies.js +19 -30
  37. package/src/ModuleGraph/worker/collectDependencies.js.flow +23 -41
  38. package/src/Server.js +90 -32
  39. package/src/Server.js.flow +143 -44
  40. package/src/cli-utils.js.flow +1 -1
  41. package/src/commands/build.js +1 -2
  42. package/src/commands/build.js.flow +6 -9
  43. package/src/commands/dependencies.js +1 -1
  44. package/src/commands/serve.js +2 -1
  45. package/src/commands/serve.js.flow +7 -8
  46. package/src/index.flow.js +27 -16
  47. package/src/index.flow.js.flow +24 -15
  48. package/src/integration_tests/basic_bundle/require-context/conflict.js +25 -0
  49. package/src/integration_tests/basic_bundle/require-context/conflict.js.flow +27 -0
  50. package/src/integration_tests/basic_bundle/require-context/empty.js +29 -0
  51. package/src/integration_tests/basic_bundle/require-context/empty.js.flow +26 -0
  52. package/src/integration_tests/basic_bundle/require-context/matching.js +26 -0
  53. package/src/integration_tests/basic_bundle/require-context/matching.js.flow +27 -0
  54. package/src/integration_tests/basic_bundle/require-context/mode-eager.js +22 -0
  55. package/src/integration_tests/basic_bundle/require-context/mode-eager.js.flow +24 -0
  56. package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js +22 -0
  57. package/src/integration_tests/basic_bundle/require-context/mode-lazy-once.js.flow +24 -0
  58. package/src/integration_tests/basic_bundle/require-context/mode-lazy.js +22 -0
  59. package/src/integration_tests/basic_bundle/require-context/mode-lazy.js.flow +24 -0
  60. package/src/integration_tests/basic_bundle/require-context/mode-sync.js +20 -0
  61. package/src/integration_tests/basic_bundle/require-context/mode-sync.js.flow +22 -0
  62. package/src/integration_tests/basic_bundle/require-context/subdir/a.js +12 -0
  63. package/src/integration_tests/basic_bundle/require-context/subdir/a.js.flow +11 -0
  64. package/src/integration_tests/basic_bundle/require-context/subdir/b.js +18 -0
  65. package/src/integration_tests/basic_bundle/require-context/subdir/b.js.flow +11 -0
  66. package/src/integration_tests/basic_bundle/require-context/subdir/c.js +12 -0
  67. package/src/integration_tests/basic_bundle/require-context/subdir/c.js.flow +11 -0
  68. package/src/integration_tests/basic_bundle/require-context/subdir/nested/d.js +12 -0
  69. package/src/integration_tests/basic_bundle/require-context/subdir/nested/d.js.flow +11 -0
  70. package/src/integration_tests/basic_bundle/require-context/subdir-conflict/index.js +12 -0
  71. package/src/integration_tests/basic_bundle/require-context/subdir-conflict/index.js.flow +11 -0
  72. package/src/integration_tests/basic_bundle/require-context/utils.js +29 -0
  73. package/src/integration_tests/basic_bundle/require-context/utils.js.flow +44 -0
  74. package/src/lib/CountingSet.js +1 -0
  75. package/src/lib/CountingSet.js.flow +1 -0
  76. package/src/lib/RamBundleParser.js +1 -0
  77. package/src/lib/RamBundleParser.js.flow +1 -0
  78. package/src/lib/bundleToBytecode.js +3 -2
  79. package/src/lib/bundleToBytecode.js.flow +2 -2
  80. package/src/lib/contextModule.js +80 -0
  81. package/src/lib/contextModule.js.flow +86 -0
  82. package/src/lib/contextModuleTemplates.js +186 -0
  83. package/src/lib/contextModuleTemplates.js.flow +148 -0
  84. package/src/lib/getGraphId.js +17 -3
  85. package/src/lib/getGraphId.js.flow +12 -9
  86. package/src/lib/getPrependedScripts.js +15 -5
  87. package/src/lib/getPrependedScripts.js.flow +8 -1
  88. package/src/lib/parseCustomResolverOptions.js +26 -0
  89. package/src/lib/parseCustomResolverOptions.js.flow +38 -0
  90. package/src/lib/parseOptionsFromUrl.js +3 -0
  91. package/src/lib/parseOptionsFromUrl.js.flow +9 -18
  92. package/src/lib/splitBundleOptions.js +3 -0
  93. package/src/lib/splitBundleOptions.js.flow +3 -0
  94. package/src/lib/transformHelpers.js +68 -22
  95. package/src/lib/transformHelpers.js.flow +73 -16
  96. package/src/node-haste/DependencyGraph/ModuleResolution.js +19 -2
  97. package/src/node-haste/DependencyGraph/ModuleResolution.js.flow +8 -2
  98. package/src/node-haste/DependencyGraph/createHasteMap.js +7 -1
  99. package/src/node-haste/DependencyGraph/createHasteMap.js.flow +7 -1
  100. package/src/node-haste/DependencyGraph.js +39 -9
  101. package/src/node-haste/DependencyGraph.js.flow +63 -12
  102. package/src/node-haste/Module.js +1 -0
  103. package/src/node-haste/Module.js.flow +1 -0
  104. package/src/shared/output/bundle.flow.js +67 -0
  105. package/src/shared/output/bundle.flow.js.flow +89 -0
  106. package/src/shared/output/bundle.js +8 -55
  107. package/src/shared/output/bundle.js.flow +8 -75
  108. package/src/shared/types.flow.js.flow +7 -0
@@ -13,6 +13,7 @@
13
13
  import type Bundler from '../Bundler';
14
14
  import type DeltaBundler, {Module} from '../DeltaBundler';
15
15
  import type {TransformInputOptions} from '../DeltaBundler/types.flow';
16
+ import type {ResolverInputOptions} from '../shared/types.flow';
16
17
  import type {ConfigT} from 'metro-config/src/configTypes.flow';
17
18
 
18
19
  import CountingSet from './CountingSet';
@@ -21,7 +22,6 @@ const countLines = require('./countLines');
21
22
  const getPreludeCode = require('./getPreludeCode');
22
23
  const transformHelpers = require('./transformHelpers');
23
24
  const defaults = require('metro-config/src/defaults/defaults');
24
- const {compile} = require('metro-hermes-compiler');
25
25
 
26
26
  async function getPrependedScripts(
27
27
  config: ConfigT,
@@ -29,6 +29,7 @@ async function getPrependedScripts(
29
29
  TransformInputOptions,
30
30
  {type: $PropertyType<TransformInputOptions, 'type'>, ...},
31
31
  >,
32
+ resolverOptions: ResolverInputOptions,
32
33
  bundler: Bundler,
33
34
  deltaBundler: DeltaBundler<>,
34
35
  ): Promise<$ReadOnlyArray<Module<>>> {
@@ -51,6 +52,7 @@ async function getPrependedScripts(
51
52
  resolve: await transformHelpers.getResolveDependencyFn(
52
53
  bundler,
53
54
  options.platform,
55
+ resolverOptions,
54
56
  ),
55
57
  transform: await transformHelpers.getTransformFn(
56
58
  [defaults.moduleSystem, ...polyfillModuleNames],
@@ -58,7 +60,10 @@ async function getPrependedScripts(
58
60
  deltaBundler,
59
61
  config,
60
62
  transformOptions,
63
+ resolverOptions,
61
64
  ),
65
+ unstable_allowRequireContext:
66
+ config.transformer.unstable_allowRequireContext,
62
67
  transformOptions,
63
68
  onProgress: null,
64
69
  experimentalImportBundleSupport:
@@ -87,6 +92,8 @@ function _getPrelude({
87
92
  requireCycleIgnorePatterns: $ReadOnlyArray<RegExp>,
88
93
  ...
89
94
  }): Module<> {
95
+ const {compile} = require('metro-hermes-compiler');
96
+
90
97
  const code = getPreludeCode({
91
98
  isDev: dev,
92
99
  globalPrefix,
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails oncall+metro_bundler
8
+ * @format
9
+ *
10
+ */
11
+ "use strict";
12
+
13
+ const nullthrows = require("nullthrows");
14
+
15
+ const PREFIX = "resolver.";
16
+
17
+ module.exports = function parseCustomResolverOptions(urlObj) {
18
+ const customResolverOptions = Object.create(null);
19
+ const query = nullthrows(urlObj.query);
20
+ Object.keys(query).forEach((key) => {
21
+ if (key.startsWith(PREFIX)) {
22
+ customResolverOptions[key.substr(PREFIX.length)] = query[key];
23
+ }
24
+ });
25
+ return customResolverOptions;
26
+ };
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ * @emails oncall+metro_bundler
8
+ * @format
9
+ * @flow strict-local
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ import type {CustomResolverOptions} from '../../../metro-resolver/src/types';
15
+
16
+ const nullthrows = require('nullthrows');
17
+
18
+ const PREFIX = 'resolver.';
19
+
20
+ module.exports = function parseCustomResolverOptions(urlObj: {
21
+ +query?: {[string]: string, ...},
22
+ ...
23
+ }): CustomResolverOptions {
24
+ const customResolverOptions: {
25
+ __proto__: null,
26
+ [string]: mixed,
27
+ ...
28
+ } = Object.create(null);
29
+ const query = nullthrows(urlObj.query);
30
+
31
+ Object.keys(query).forEach((key: string) => {
32
+ if (key.startsWith(PREFIX)) {
33
+ customResolverOptions[key.substr(PREFIX.length)] = query[key];
34
+ }
35
+ });
36
+
37
+ return customResolverOptions;
38
+ };
@@ -11,6 +11,8 @@
11
11
 
12
12
  const parsePlatformFilePath = require("../node-haste/lib/parsePlatformFilePath");
13
13
 
14
+ const parseCustomResolverOptions = require("./parseCustomResolverOptions");
15
+
14
16
  const parseCustomTransformOptions = require("./parseCustomTransformOptions");
15
17
 
16
18
  const nullthrows = require("nullthrows");
@@ -60,6 +62,7 @@ module.exports = function parseOptionsFromUrl(
60
62
  bundleType,
61
63
  runtimeBytecodeVersion:
62
64
  bytecodeVersion === runtimeBytecodeVersion ? bytecodeVersion : null,
65
+ customResolverOptions: parseCustomResolverOptions(parsedURL),
63
66
  customTransformOptions: parseCustomTransformOptions(parsedURL),
64
67
  dev: getBoolean(query, "dev", true),
65
68
  entryFile: pathname.replace(/^(?:\.?\/)?/, "./").replace(/\.[^/.]+$/, ""),
@@ -11,23 +11,18 @@
11
11
  'use strict';
12
12
 
13
13
  import type {BundleOptions} from '../shared/types.flow';
14
+ import type {TransformProfile} from 'metro-babel-transformer';
14
15
 
15
16
  const parsePlatformFilePath = require('../node-haste/lib/parsePlatformFilePath');
17
+ const parseCustomResolverOptions = require('./parseCustomResolverOptions');
16
18
  const parseCustomTransformOptions = require('./parseCustomTransformOptions');
17
19
  const nullthrows = require('nullthrows');
18
20
  const path = require('path');
19
21
  const url = require('url');
20
22
 
21
23
  const getBoolean = (
22
- query: {[string]: string},
23
- opt:
24
- | $TEMPORARY$string<'dev'>
25
- | $TEMPORARY$string<'excludeSource'>
26
- | $TEMPORARY$string<'inlineSourceMap'>
27
- | $TEMPORARY$string<'minify'>
28
- | $TEMPORARY$string<'modulesOnly'>
29
- | $TEMPORARY$string<'runModule'>
30
- | $TEMPORARY$string<'shallow'>,
24
+ query: $ReadOnly<{[opt: string]: string}>,
25
+ opt: string,
31
26
  defaultValue: boolean,
32
27
  ) =>
33
28
  query[opt] == null
@@ -35,23 +30,18 @@ const getBoolean = (
35
30
  : query[opt] === 'true' || query[opt] === '1';
36
31
 
37
32
  const getNumber = (
38
- query: {[string]: string},
39
- opt: $TEMPORARY$string<'runtimeBytecodeVersion'>,
33
+ query: $ReadOnly<{[opt: string]: string}>,
34
+ opt: string,
40
35
  defaultValue: null,
41
36
  ) => {
42
37
  const number = parseInt(query[opt], 10);
43
38
  return Number.isNaN(number) ? defaultValue : number;
44
39
  };
45
40
 
46
- const getBundleType = (bundleType: string | $TEMPORARY$string<'map'>) =>
41
+ const getBundleType = (bundleType: string): 'map' | 'bundle' =>
47
42
  bundleType === 'map' ? bundleType : 'bundle';
48
43
 
49
- const getTransformProfile = (
50
- transformProfile:
51
- | string
52
- | $TEMPORARY$string<'hermes-canary'>
53
- | $TEMPORARY$string<'hermes-stable'>,
54
- ) =>
44
+ const getTransformProfile = (transformProfile: string): TransformProfile =>
55
45
  transformProfile === 'hermes-stable' || transformProfile === 'hermes-canary'
56
46
  ? transformProfile
57
47
  : 'default';
@@ -79,6 +69,7 @@ module.exports = function parseOptionsFromUrl(
79
69
  bundleType,
80
70
  runtimeBytecodeVersion:
81
71
  bytecodeVersion === runtimeBytecodeVersion ? bytecodeVersion : null,
72
+ customResolverOptions: parseCustomResolverOptions(parsedURL),
82
73
  customTransformOptions: parseCustomTransformOptions(parsedURL),
83
74
  dev: getBoolean(query, 'dev', true),
84
75
  entryFile: pathname.replace(/^(?:\.?\/)?/, './').replace(/\.[^/.]+$/, ''),
@@ -15,6 +15,9 @@
15
15
  function splitBundleOptions(options) {
16
16
  return {
17
17
  entryFile: options.entryFile,
18
+ resolverOptions: {
19
+ customResolverOptions: options.customResolverOptions,
20
+ },
18
21
  transformOptions: {
19
22
  customTransformOptions: options.customTransformOptions,
20
23
  dev: options.dev,
@@ -18,6 +18,9 @@ import type {BundleOptions, SplitBundleOptions} from '../shared/types.flow';
18
18
  function splitBundleOptions(options: BundleOptions): SplitBundleOptions {
19
19
  return {
20
20
  entryFile: options.entryFile,
21
+ resolverOptions: {
22
+ customResolverOptions: options.customResolverOptions,
23
+ },
21
24
  transformOptions: {
22
25
  customTransformOptions: options.customTransformOptions,
23
26
  dev: options.dev,
@@ -9,6 +9,8 @@
9
9
  */
10
10
  "use strict";
11
11
 
12
+ var _contextModuleTemplates = require("./contextModuleTemplates");
13
+
12
14
  const path = require("path");
13
15
 
14
16
  const baseIgnoredInlineRequires = ["React", "react", "react-native"];
@@ -18,7 +20,8 @@ async function calcTransformerOptions(
18
20
  bundler,
19
21
  deltaBundler,
20
22
  config,
21
- options
23
+ options,
24
+ resolverOptions
22
25
  ) {
23
26
  const baseOptions = {
24
27
  customTransformOptions: options.customTransformOptions,
@@ -40,15 +43,25 @@ async function calcTransformerOptions(
40
43
 
41
44
  const getDependencies = async (path) => {
42
45
  const dependencies = await deltaBundler.getDependencies([path], {
43
- resolve: await getResolveDependencyFn(bundler, options.platform),
44
- transform: await getTransformFn([path], bundler, deltaBundler, config, {
45
- ...options,
46
- minify: false,
47
- }),
46
+ resolve: await getResolveDependencyFn(
47
+ bundler,
48
+ options.platform,
49
+ resolverOptions
50
+ ),
51
+ transform: await getTransformFn(
52
+ [path],
53
+ bundler,
54
+ deltaBundler,
55
+ config,
56
+ { ...options, minify: false },
57
+ resolverOptions
58
+ ),
48
59
  transformOptions: options,
49
60
  onProgress: null,
50
61
  experimentalImportBundleSupport:
51
62
  config.transformer.experimentalImportBundleSupport,
63
+ unstable_allowRequireContext:
64
+ config.transformer.unstable_allowRequireContext,
52
65
  shallow: false,
53
66
  });
54
67
  return Array.from(dependencies.keys());
@@ -88,24 +101,54 @@ async function getTransformFn(
88
101
  bundler,
89
102
  deltaBundler,
90
103
  config,
91
- options
104
+ options,
105
+ resolverOptions
92
106
  ) {
93
107
  const { inlineRequires, ...transformOptions } = await calcTransformerOptions(
94
108
  entryFiles,
95
109
  bundler,
96
110
  deltaBundler,
97
111
  config,
98
- options
112
+ options,
113
+ resolverOptions
99
114
  );
100
- return async (path) => {
101
- return await bundler.transformFile(path, {
102
- ...transformOptions,
103
- type: getType(transformOptions.type, path, config.resolver.assetExts),
104
- inlineRequires: removeInlineRequiresBlockListFromOptions(
105
- path,
106
- inlineRequires
107
- ),
108
- });
115
+ return async (modulePath, requireContext) => {
116
+ let templateBuffer;
117
+
118
+ if (requireContext) {
119
+ const graph = await bundler.getDependencyGraph(); // TODO: Check delta changes to avoid having to look over all files each time
120
+ // this is a massive performance boost.
121
+ // Search against all files, this is very expensive.
122
+ // TODO: Maybe we could let the user specify which root to check against.
123
+
124
+ const files = graph.matchFilesWithContext(requireContext.from, {
125
+ filter: requireContext.filter,
126
+ recursive: requireContext.recursive,
127
+ });
128
+ const template = (0, _contextModuleTemplates.getContextModuleTemplate)(
129
+ requireContext.mode,
130
+ requireContext.from,
131
+ files
132
+ );
133
+ templateBuffer = Buffer.from(template);
134
+ }
135
+
136
+ return await bundler.transformFile(
137
+ modulePath,
138
+ {
139
+ ...transformOptions,
140
+ type: getType(
141
+ transformOptions.type,
142
+ modulePath,
143
+ config.resolver.assetExts
144
+ ),
145
+ inlineRequires: removeInlineRequiresBlockListFromOptions(
146
+ modulePath,
147
+ inlineRequires
148
+ ),
149
+ },
150
+ templateBuffer
151
+ );
109
152
  };
110
153
  }
111
154
 
@@ -121,12 +164,15 @@ function getType(type, filePath, assetExts) {
121
164
  return "module";
122
165
  }
123
166
 
124
- async function getResolveDependencyFn(bundler, platform) {
167
+ async function getResolveDependencyFn(bundler, platform, resolverOptions) {
125
168
  const dependencyGraph = await await bundler.getDependencyGraph();
126
- return (
127
- from,
128
- to // $FlowFixMe[incompatible-call]
129
- ) => dependencyGraph.resolveDependency(from, to, platform);
169
+ return (from, to) =>
170
+ dependencyGraph.resolveDependency(
171
+ from,
172
+ to,
173
+ platform !== null && platform !== void 0 ? platform : null,
174
+ resolverOptions
175
+ );
130
176
  }
131
177
 
132
178
  module.exports = {
@@ -16,8 +16,12 @@ import type {TransformInputOptions} from '../DeltaBundler/types.flow';
16
16
  import type {TransformOptions} from '../DeltaBundler/Worker';
17
17
  import type {ConfigT} from 'metro-config/src/configTypes.flow';
18
18
  import type {Type} from 'metro-transform-worker';
19
+ import type {RequireContext} from './contextModule';
20
+
21
+ import {getContextModuleTemplate} from './contextModuleTemplates';
19
22
 
20
23
  const path = require('path');
24
+ import type {ResolverInputOptions} from '../shared/types.flow';
21
25
 
22
26
  type InlineRequiresRaw = {+blockList: {[string]: true, ...}, ...} | boolean;
23
27
 
@@ -34,6 +38,7 @@ async function calcTransformerOptions(
34
38
  deltaBundler: DeltaBundler<>,
35
39
  config: ConfigT,
36
40
  options: TransformInputOptions,
41
+ resolverOptions: ResolverInputOptions,
37
42
  ): Promise<TransformOptionsWithRawInlines> {
38
43
  const baseOptions = {
39
44
  customTransformOptions: options.customTransformOptions,
@@ -59,15 +64,28 @@ async function calcTransformerOptions(
59
64
 
60
65
  const getDependencies = async (path: string) => {
61
66
  const dependencies = await deltaBundler.getDependencies([path], {
62
- resolve: await getResolveDependencyFn(bundler, options.platform),
63
- transform: await getTransformFn([path], bundler, deltaBundler, config, {
64
- ...options,
65
- minify: false,
66
- }),
67
+ resolve: await getResolveDependencyFn(
68
+ bundler,
69
+ options.platform,
70
+ resolverOptions,
71
+ ),
72
+ transform: await getTransformFn(
73
+ [path],
74
+ bundler,
75
+ deltaBundler,
76
+ config,
77
+ {
78
+ ...options,
79
+ minify: false,
80
+ },
81
+ resolverOptions,
82
+ ),
67
83
  transformOptions: options,
68
84
  onProgress: null,
69
85
  experimentalImportBundleSupport:
70
86
  config.transformer.experimentalImportBundleSupport,
87
+ unstable_allowRequireContext:
88
+ config.transformer.unstable_allowRequireContext,
71
89
  shallow: false,
72
90
  });
73
91
 
@@ -109,6 +127,7 @@ async function getTransformFn(
109
127
  deltaBundler: DeltaBundler<>,
110
128
  config: ConfigT,
111
129
  options: TransformInputOptions,
130
+ resolverOptions: ResolverInputOptions,
112
131
  ): Promise<TransformFn<>> {
113
132
  const {inlineRequires, ...transformOptions} = await calcTransformerOptions(
114
133
  entryFiles,
@@ -116,17 +135,50 @@ async function getTransformFn(
116
135
  deltaBundler,
117
136
  config,
118
137
  options,
138
+ resolverOptions,
119
139
  );
120
140
 
121
- return async (path: string) => {
122
- return await bundler.transformFile(path, {
123
- ...transformOptions,
124
- type: getType(transformOptions.type, path, config.resolver.assetExts),
125
- inlineRequires: removeInlineRequiresBlockListFromOptions(
126
- path,
127
- inlineRequires,
128
- ),
129
- });
141
+ return async (modulePath: string, requireContext: ?RequireContext) => {
142
+ let templateBuffer: Buffer;
143
+
144
+ if (requireContext) {
145
+ const graph = await bundler.getDependencyGraph();
146
+
147
+ // TODO: Check delta changes to avoid having to look over all files each time
148
+ // this is a massive performance boost.
149
+
150
+ // Search against all files, this is very expensive.
151
+ // TODO: Maybe we could let the user specify which root to check against.
152
+ const files = graph.matchFilesWithContext(requireContext.from, {
153
+ filter: requireContext.filter,
154
+ recursive: requireContext.recursive,
155
+ });
156
+
157
+ const template = getContextModuleTemplate(
158
+ requireContext.mode,
159
+ requireContext.from,
160
+ files,
161
+ );
162
+
163
+ templateBuffer = Buffer.from(template);
164
+ }
165
+
166
+ return await bundler.transformFile(
167
+ modulePath,
168
+ {
169
+ ...transformOptions,
170
+ type: getType(
171
+ transformOptions.type,
172
+ modulePath,
173
+ config.resolver.assetExts,
174
+ ),
175
+ inlineRequires: removeInlineRequiresBlockListFromOptions(
176
+ modulePath,
177
+ inlineRequires,
178
+ ),
179
+ },
180
+ templateBuffer,
181
+ );
130
182
  };
131
183
  }
132
184
 
@@ -149,12 +201,17 @@ function getType(
149
201
  async function getResolveDependencyFn(
150
202
  bundler: Bundler,
151
203
  platform: ?string,
204
+ resolverOptions: ResolverInputOptions,
152
205
  ): Promise<(from: string, to: string) => string> {
153
206
  const dependencyGraph = await await bundler.getDependencyGraph();
154
207
 
155
208
  return (from: string, to: string) =>
156
- // $FlowFixMe[incompatible-call]
157
- dependencyGraph.resolveDependency(from, to, platform);
209
+ dependencyGraph.resolveDependency(
210
+ from,
211
+ to,
212
+ platform ?? null,
213
+ resolverOptions,
214
+ );
158
215
  }
159
216
 
160
217
  module.exports = {
@@ -24,6 +24,7 @@ const util = require("util");
24
24
  class ModuleResolver {
25
25
  // A module representing the project root, used as the origin when resolving `emptyModulePath`.
26
26
  // An empty module, the result of resolving `emptyModulePath` from the project root.
27
+ // $FlowFixMe[missing-local-annot]
27
28
  constructor(options) {
28
29
  this._options = options;
29
30
  const { projectRoot, moduleCache } = this._options;
@@ -50,7 +51,9 @@ class ModuleResolver {
50
51
  this._projectRootFakeModule,
51
52
  this._options.emptyModulePath,
52
53
  false,
53
- null
54
+ null,
55
+ /* resolverOptions */
56
+ {}
54
57
  );
55
58
  this._cachedEmptyModule = emptyModule;
56
59
  }
@@ -110,11 +113,24 @@ class ModuleResolver {
110
113
  return modulePath;
111
114
  }
112
115
 
113
- resolveDependency(fromModule, moduleName, allowHaste, platform) {
116
+ resolveDependency(
117
+ fromModule,
118
+ moduleName,
119
+ allowHaste,
120
+ platform,
121
+ resolverOptions
122
+ ) {
114
123
  try {
124
+ var _resolverOptions$cust;
125
+
115
126
  const result = Resolver.resolve(
116
127
  {
117
128
  ...this._options,
129
+ customResolverOptions:
130
+ (_resolverOptions$cust = resolverOptions.customResolverOptions) !==
131
+ null && _resolverOptions$cust !== void 0
132
+ ? _resolverOptions$cust
133
+ : {},
118
134
  originModulePath: fromModule.path,
119
135
  redirectModulePath: (modulePath) =>
120
136
  this._redirectRequire(fromModule, modulePath),
@@ -199,6 +215,7 @@ class ModuleResolver {
199
215
  return this._options.moduleCache.getModule(arbitrary);
200
216
 
201
217
  case "empty":
218
+ // $FlowFixMe[incompatible-return]
202
219
  return this._getEmptyModule();
203
220
 
204
221
  default:
@@ -26,6 +26,7 @@ const invariant = require('invariant');
26
26
  const Resolver = require('metro-resolver');
27
27
  const path = require('path');
28
28
  const util = require('util');
29
+ import type {ResolverInputOptions} from '../../shared/types.flow';
29
30
 
30
31
  export type DirExistsFn = (filePath: string) => boolean;
31
32
 
@@ -78,6 +79,7 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
78
79
  // An empty module, the result of resolving `emptyModulePath` from the project root.
79
80
  _cachedEmptyModule: ?TModule;
80
81
 
82
+ // $FlowFixMe[missing-local-annot]
81
83
  constructor(options: Options<TModule, TPackage>) {
82
84
  this._options = options;
83
85
  const {projectRoot, moduleCache} = this._options;
@@ -94,7 +96,7 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
94
96
  };
95
97
  }
96
98
 
97
- _getEmptyModule() {
99
+ _getEmptyModule(): TModule | Moduleish {
98
100
  let emptyModule = this._cachedEmptyModule;
99
101
  if (!emptyModule) {
100
102
  emptyModule = this.resolveDependency(
@@ -102,6 +104,7 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
102
104
  this._options.emptyModulePath,
103
105
  false,
104
106
  null,
107
+ /* resolverOptions */ {},
105
108
  );
106
109
  this._cachedEmptyModule = emptyModule;
107
110
  }
@@ -166,11 +169,13 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
166
169
  moduleName: string,
167
170
  allowHaste: boolean,
168
171
  platform: string | null,
172
+ resolverOptions: ResolverInputOptions,
169
173
  ): TModule {
170
174
  try {
171
175
  const result = Resolver.resolve(
172
176
  {
173
177
  ...this._options,
178
+ customResolverOptions: resolverOptions.customResolverOptions ?? {},
174
179
  originModulePath: fromModule.path,
175
180
  redirectModulePath: (modulePath: string) =>
176
181
  this._redirectRequire(fromModule, modulePath),
@@ -252,6 +257,7 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
252
257
  invariant(arbitrary != null, 'invalid asset resolution');
253
258
  return this._options.moduleCache.getModule(arbitrary);
254
259
  case 'empty':
260
+ // $FlowFixMe[incompatible-return]
255
261
  return this._getEmptyModule();
256
262
  default:
257
263
  (resolution.type: empty);
@@ -259,7 +265,7 @@ class ModuleResolver<TModule: Moduleish, TPackage: Packageish> {
259
265
  }
260
266
  }
261
267
 
262
- _removeRoot(candidates: FileCandidates) {
268
+ _removeRoot(candidates: FileCandidates): FileCandidates {
263
269
  if (candidates.filePathPrefix) {
264
270
  candidates.filePathPrefix = path.relative(
265
271
  this._options.projectRoot,
@@ -129,7 +129,13 @@ function createHasteMap(config, options) {
129
129
  computeDependencies,
130
130
  computeSha1: true,
131
131
  dependencyExtractor: config.resolver.dependencyExtractor,
132
- extensions: config.resolver.sourceExts.concat(config.resolver.assetExts),
132
+ extensions: Array.from(
133
+ new Set([
134
+ ...config.resolver.sourceExts,
135
+ ...config.resolver.assetExts,
136
+ ...config.watcher.additionalExts,
137
+ ])
138
+ ),
133
139
  forceNodeFilesystemAPI: !config.resolver.useWatchman,
134
140
  hasteImplModulePath: config.resolver.hasteImplModulePath,
135
141
  ignorePattern: getIgnorePattern(config),
@@ -69,7 +69,13 @@ function createHasteMap(
69
69
  computeDependencies,
70
70
  computeSha1: true,
71
71
  dependencyExtractor: config.resolver.dependencyExtractor,
72
- extensions: config.resolver.sourceExts.concat(config.resolver.assetExts),
72
+ extensions: Array.from(
73
+ new Set([
74
+ ...config.resolver.sourceExts,
75
+ ...config.resolver.assetExts,
76
+ ...config.watcher.additionalExts,
77
+ ]),
78
+ ),
73
79
  forceNodeFilesystemAPI: !config.resolver.useWatchman,
74
80
  hasteImplModulePath: config.resolver.hasteImplModulePath,
75
81
  ignorePattern: getIgnorePattern(config),