-
-
Notifications
You must be signed in to change notification settings - Fork 654
/
metro.config.js
95 lines (82 loc) · 3.41 KB
/
metro.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// @format
const path = require('path');
// Packages we might apply `yarn link` to.
// TODO compute what packages actually *are* under `yarn link` instead.
const linkablePackages = [
'@zulip/shared',
'zulip-markdown-parser',
// Add more as needed! See also .flowconfig and docs/howto/yarn-link.md .
];
// Most of the complexity here comes from teaching Metro to properly
// handle the case where we're using `yarn link` to get packages from
// worktrees outside the zulip-mobile tree: e.g., to make
// `node_modules/@zulip/shared` be a symlink into a zulip.git worktree.
//
// Out of the box, Metro (in e.g. the guise of `react-native start`)
// breaks in that situation in two ways:
// * Imports of modules in those packages fail.
// * Once that's fixed, imports *from* modules in those packages, of
// modules found in our node_modules, fail.
//
// In both cases, the symptom is a red-screen error in the (debug)
// app, and in Metro a stacktrace under a message saying "Unable to
// resolve module [...] does not exist in the Haste module map".
/** Absolute path to the directory at the root of the given package. */
const packagePath = packageName => path.dirname(require.resolve(`${packageName}/package.json`));
/** Direct (not transitive) dependencies of the given package. */
const packageDeps = packageName => Object.keys(require(`${packageName}/package.json`).dependencies);
// Backport of Object.fromEntries... backported to plain JS from our src/jsBackport.js.
function objectFromEntries(entries) {
const obj = {};
entries.forEach(entry => {
obj[entry[0]] = entry[1];
});
return obj;
}
// Backport of Array.flatMap.
function arrayFlatMap(a, f) {
return [].concat(...a.map(f));
}
module.exports = {
// This causes Metro to even look outside the zulip-mobile tree in
// the first place.
watchFolders: linkablePackages.map(packagePath),
resolver: {
// These are to help Metro find modules imported from files found
// outside our tree. Without it, Metro tries to resolve them from
// the ancestor directories of those files and doesn't look in our
// own node_modules.
extraNodeModules: objectFromEntries(
// @babel/runtime makes the list because our Babel config (?) causes
// files like @zulip/shared/lib/typing_status.js to need it, whereas
// it's not a dependency of @zulip/shared itself.
['@babel/runtime', ...arrayFlatMap(linkablePackages, packageDeps)].map(name => [
name,
packagePath(name),
]),
),
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: true,
},
}),
// Use 'metro-minify-terser' (the default minifier at Metro v0.73.0+,
// but we're not there yet) to get the keep_classnames option in the
// minifierConfig, below.
// TODO(react-native-71): Remove "not there yet" comment, and maybe
// leave this unspecified to accept the default.
minifierPath: 'metro-minify-terser',
minifierConfig: {
// Looking at the implementation, it seems that the "minifier config"
// is passed straight to the `terser` minifier (thanks to
// `minifierPath` being set to 'metro-minify-terser'), so we should
// use `terser`'s doc:
// https://github.com/terser/terser#minify-options
// Don't minify our custom Error class names (for logging's sake)
keep_classnames: /Error$/,
},
},
};