metro-transform-worker 0.66.0 → 0.68.0
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.
- package/package.json +15 -15
- package/src/__mocks__/index.js +2 -2
- package/src/index.js +448 -273
- package/src/index.js.flow +517 -284
- package/src/utils/assetTransformer.js +6 -6
- package/src/utils/assetTransformer.js.flow +4 -5
- package/src/utils/getMinifier.js +1 -1
- package/src/utils/getMinifier.js.flow +1 -1
- package/src.real/__mocks__/index.js +2 -2
- package/src.real/__tests__/__snapshots__/index-test.js.snap +40 -0
- package/src.real/__tests__/index-test.js +296 -18
- package/src.real/index.js +517 -284
- package/src.real/utils/assetTransformer.js +4 -5
- package/src.real/utils/getMinifier.js +1 -1
package/src/index.js.flow
CHANGED
|
@@ -1,52 +1,59 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Copyright (c)
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
|
-
* @flow
|
|
7
|
+
* @flow strict-local
|
|
8
8
|
* @format
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
import type {
|
|
14
|
+
BabelTransformer,
|
|
15
|
+
BabelTransformerArgs,
|
|
16
|
+
CustomTransformOptions,
|
|
17
|
+
TransformProfile,
|
|
18
|
+
} from 'metro-babel-transformer';
|
|
19
|
+
import type {
|
|
20
|
+
HermesCompilerResult,
|
|
21
|
+
Options as HermesCompilerOptions,
|
|
22
|
+
} from 'metro-hermes-compiler';
|
|
23
|
+
import type {
|
|
24
|
+
BasicSourceMap,
|
|
25
|
+
FBSourceFunctionMap,
|
|
26
|
+
MetroSourceMapSegmentTuple,
|
|
27
|
+
} from 'metro-source-map';
|
|
28
|
+
import type {TransformResultDependency} from 'metro/src/DeltaBundler';
|
|
29
|
+
import type {AllowOptionalDependencies} from 'metro/src/DeltaBundler/types.flow.js';
|
|
30
|
+
import type {
|
|
31
|
+
DependencyTransformer,
|
|
32
|
+
DynamicRequiresBehavior,
|
|
33
|
+
} from 'metro/src/ModuleGraph/worker/collectDependencies';
|
|
34
|
+
import typeof CollectDependenciesFn from 'metro/src/ModuleGraph/worker/collectDependencies';
|
|
15
35
|
|
|
16
|
-
const babylon = require('@babel/parser');
|
|
17
|
-
const collectDependencies = require('metro/src/ModuleGraph/worker/collectDependencies');
|
|
18
|
-
const generateImportNames = require('metro/src/ModuleGraph/worker/generateImportNames');
|
|
19
|
-
const generate = require('@babel/generator').default;
|
|
20
|
-
const getCacheKey = require('metro-cache-key');
|
|
21
36
|
const getMinifier = require('./utils/getMinifier');
|
|
22
|
-
const metroTransformPlugins = require('metro-transform-plugins');
|
|
23
37
|
const {transformFromAstSync} = require('@babel/core');
|
|
24
|
-
const
|
|
38
|
+
const generate = require('@babel/generator').default;
|
|
39
|
+
const babylon = require('@babel/parser');
|
|
25
40
|
const types = require('@babel/types');
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
41
|
+
const {stableHash} = require('metro-cache');
|
|
42
|
+
const getCacheKey = require('metro-cache-key');
|
|
43
|
+
const HermesCompiler = require('metro-hermes-compiler');
|
|
29
44
|
const {
|
|
30
45
|
fromRawMappings,
|
|
31
46
|
toBabelSegments,
|
|
32
47
|
toSegmentTuple,
|
|
33
48
|
} = require('metro-source-map');
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
import type {
|
|
43
|
-
HermesCompilerResult,
|
|
44
|
-
Options as HermesCompilerOptions,
|
|
45
|
-
} from 'metro-hermes-compiler';
|
|
46
|
-
import type {
|
|
47
|
-
CustomTransformOptions,
|
|
48
|
-
TransformProfile,
|
|
49
|
-
} from 'metro-babel-transformer';
|
|
49
|
+
const metroTransformPlugins = require('metro-transform-plugins');
|
|
50
|
+
const countLines = require('metro/src/lib/countLines');
|
|
51
|
+
const {
|
|
52
|
+
InvalidRequireCallError: InternalInvalidRequireCallError,
|
|
53
|
+
} = require('metro/src/ModuleGraph/worker/collectDependencies');
|
|
54
|
+
const generateImportNames = require('metro/src/ModuleGraph/worker/generateImportNames');
|
|
55
|
+
const JsFileWrapping = require('metro/src/ModuleGraph/worker/JsFileWrapping');
|
|
56
|
+
const nullthrows = require('nullthrows');
|
|
50
57
|
|
|
51
58
|
type MinifierConfig = $ReadOnly<{[string]: mixed, ...}>;
|
|
52
59
|
|
|
@@ -65,7 +72,9 @@ export type MinifierResult = {
|
|
|
65
72
|
...
|
|
66
73
|
};
|
|
67
74
|
|
|
68
|
-
export type Minifier = MinifierOptions =>
|
|
75
|
+
export type Minifier = MinifierOptions =>
|
|
76
|
+
| MinifierResult
|
|
77
|
+
| Promise<MinifierResult>;
|
|
69
78
|
|
|
70
79
|
export type Type = 'script' | 'module' | 'asset';
|
|
71
80
|
|
|
@@ -79,11 +88,17 @@ export type JsTransformerConfig = $ReadOnly<{|
|
|
|
79
88
|
enableBabelRuntime: boolean,
|
|
80
89
|
experimentalImportBundleSupport: boolean,
|
|
81
90
|
globalPrefix: string,
|
|
91
|
+
hermesParser: boolean,
|
|
82
92
|
minifierConfig: MinifierConfig,
|
|
83
93
|
minifierPath: string,
|
|
84
94
|
optimizationSizeLimit: number,
|
|
85
95
|
publicPath: string,
|
|
86
96
|
allowOptionalDependencies: AllowOptionalDependencies,
|
|
97
|
+
unstable_collectDependenciesPath: string,
|
|
98
|
+
unstable_dependencyMapReservedName: ?string,
|
|
99
|
+
unstable_disableModuleWrapping: boolean,
|
|
100
|
+
unstable_disableNormalizePseudoGlobals: boolean,
|
|
101
|
+
unstable_compactOutput: boolean,
|
|
87
102
|
|}>;
|
|
88
103
|
|
|
89
104
|
export type {CustomTransformOptions} from 'metro-babel-transformer';
|
|
@@ -104,6 +119,44 @@ export type JsTransformOptions = $ReadOnly<{|
|
|
|
104
119
|
unstable_transformProfile: TransformProfile,
|
|
105
120
|
|}>;
|
|
106
121
|
|
|
122
|
+
export type BytecodeFileType =
|
|
123
|
+
| 'bytecode/module'
|
|
124
|
+
| 'bytecode/module/asset'
|
|
125
|
+
| 'bytecode/script';
|
|
126
|
+
|
|
127
|
+
opaque type Path = string;
|
|
128
|
+
|
|
129
|
+
type BaseFile = $ReadOnly<{
|
|
130
|
+
code: string,
|
|
131
|
+
filename: Path,
|
|
132
|
+
inputFileSize: number,
|
|
133
|
+
}>;
|
|
134
|
+
|
|
135
|
+
type AssetFile = $ReadOnly<{
|
|
136
|
+
...BaseFile,
|
|
137
|
+
type: 'asset',
|
|
138
|
+
}>;
|
|
139
|
+
|
|
140
|
+
type JSFileType = 'js/script' | 'js/module' | 'js/module/asset';
|
|
141
|
+
|
|
142
|
+
type JSFile = $ReadOnly<{
|
|
143
|
+
...BaseFile,
|
|
144
|
+
ast?: ?BabelNodeFile,
|
|
145
|
+
type: JSFileType,
|
|
146
|
+
functionMap: FBSourceFunctionMap | null,
|
|
147
|
+
}>;
|
|
148
|
+
|
|
149
|
+
type JSONFile = {
|
|
150
|
+
...BaseFile,
|
|
151
|
+
type: Type,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
type TransformationContext = $ReadOnly<{
|
|
155
|
+
config: JsTransformerConfig,
|
|
156
|
+
projectRoot: Path,
|
|
157
|
+
options: JsTransformOptions,
|
|
158
|
+
}>;
|
|
159
|
+
|
|
107
160
|
export type JsOutput = $ReadOnly<{|
|
|
108
161
|
data: $ReadOnly<{|
|
|
109
162
|
code: string,
|
|
@@ -111,18 +164,23 @@ export type JsOutput = $ReadOnly<{|
|
|
|
111
164
|
map: Array<MetroSourceMapSegmentTuple>,
|
|
112
165
|
functionMap: ?FBSourceFunctionMap,
|
|
113
166
|
|}>,
|
|
114
|
-
type:
|
|
167
|
+
type: JSFileType,
|
|
115
168
|
|}>;
|
|
116
169
|
|
|
117
170
|
export type BytecodeOutput = $ReadOnly<{|
|
|
118
171
|
data: HermesCompilerResult,
|
|
119
|
-
type:
|
|
172
|
+
type: BytecodeFileType,
|
|
120
173
|
|}>;
|
|
121
174
|
|
|
122
|
-
type
|
|
175
|
+
type DependencySplitCondition = $PropertyType<
|
|
176
|
+
$PropertyType<TransformResultDependency, 'data'>,
|
|
177
|
+
'splitCondition',
|
|
178
|
+
>;
|
|
179
|
+
|
|
180
|
+
type TransformResponse = $ReadOnly<{
|
|
123
181
|
dependencies: $ReadOnlyArray<TransformResultDependency>,
|
|
124
182
|
output: $ReadOnlyArray<JsOutput | BytecodeOutput>,
|
|
125
|
-
|
|
183
|
+
}>;
|
|
126
184
|
|
|
127
185
|
function getDynamicDepsBehavior(
|
|
128
186
|
inPackages: DynamicRequiresBehavior,
|
|
@@ -162,7 +220,7 @@ const minifyCode = async (
|
|
|
162
220
|
const minify = getMinifier(config.minifierPath);
|
|
163
221
|
|
|
164
222
|
try {
|
|
165
|
-
const minified = minify({
|
|
223
|
+
const minified = await minify({
|
|
166
224
|
code,
|
|
167
225
|
map: sourceMap,
|
|
168
226
|
filename,
|
|
@@ -188,10 +246,11 @@ const minifyCode = async (
|
|
|
188
246
|
};
|
|
189
247
|
|
|
190
248
|
const compileToBytecode = (
|
|
191
|
-
|
|
249
|
+
rawCode: string,
|
|
192
250
|
type: string,
|
|
193
251
|
options: HermesCompilerOptions,
|
|
194
252
|
): HermesCompilerResult => {
|
|
253
|
+
let code = rawCode;
|
|
195
254
|
if (type.startsWith('js/module')) {
|
|
196
255
|
const index = code.lastIndexOf(')');
|
|
197
256
|
code =
|
|
@@ -202,175 +261,97 @@ const compileToBytecode = (
|
|
|
202
261
|
return HermesCompiler.compile(code, options);
|
|
203
262
|
};
|
|
204
263
|
|
|
264
|
+
const disabledDependencyTransformer: DependencyTransformer<mixed> = {
|
|
265
|
+
transformSyncRequire: () => void 0,
|
|
266
|
+
transformImportCall: () => void 0,
|
|
267
|
+
transformJSResource: () => void 0,
|
|
268
|
+
transformPrefetch: () => void 0,
|
|
269
|
+
transformIllegalDynamicRequire: () => void 0,
|
|
270
|
+
};
|
|
271
|
+
|
|
205
272
|
class InvalidRequireCallError extends Error {
|
|
206
|
-
innerError:
|
|
273
|
+
innerError: InternalInvalidRequireCallError;
|
|
207
274
|
filename: string;
|
|
208
275
|
|
|
209
|
-
constructor(
|
|
210
|
-
innerError: collectDependencies.InvalidRequireCallError,
|
|
211
|
-
filename: string,
|
|
212
|
-
) {
|
|
276
|
+
constructor(innerError: InternalInvalidRequireCallError, filename: string) {
|
|
213
277
|
super(`${filename}:${innerError.message}`);
|
|
214
278
|
this.innerError = innerError;
|
|
215
279
|
this.filename = filename;
|
|
216
280
|
}
|
|
217
281
|
}
|
|
218
282
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
): Promise<Result> => {
|
|
227
|
-
const sourceCode = data.toString('utf8');
|
|
228
|
-
let type = 'js/module';
|
|
229
|
-
let bytecodeType = 'bytecode/module';
|
|
283
|
+
async function transformJS(
|
|
284
|
+
file: JSFile,
|
|
285
|
+
{config, options, projectRoot}: TransformationContext,
|
|
286
|
+
): Promise<TransformResponse> {
|
|
287
|
+
// Transformers can output null ASTs (if they ignore the file). In that case
|
|
288
|
+
// we need to parse the module source code to get their AST.
|
|
289
|
+
let ast = file.ast ?? babylon.parse(file.code, {sourceType: 'unambiguous'});
|
|
230
290
|
|
|
231
|
-
|
|
232
|
-
type = 'js/module/asset';
|
|
233
|
-
bytecodeType = 'bytecode/module/asset';
|
|
234
|
-
}
|
|
235
|
-
if (options.type === 'script') {
|
|
236
|
-
type = 'js/script';
|
|
237
|
-
bytecodeType = 'bytecode/script';
|
|
238
|
-
}
|
|
291
|
+
const {importDefault, importAll} = generateImportNames(ast);
|
|
239
292
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
if (options.minify) {
|
|
245
|
-
({map, code} = await minifyCode(
|
|
246
|
-
config,
|
|
247
|
-
projectRoot,
|
|
248
|
-
filename,
|
|
249
|
-
code,
|
|
250
|
-
sourceCode,
|
|
251
|
-
map,
|
|
252
|
-
));
|
|
253
|
-
}
|
|
293
|
+
// Add "use strict" if the file was parsed as a module, and the directive did
|
|
294
|
+
// not exist yet.
|
|
295
|
+
const {directives} = ast.program;
|
|
254
296
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
output.push({
|
|
263
|
-
data: (compileToBytecode(code, type, {
|
|
264
|
-
sourceURL: filename,
|
|
265
|
-
sourceMap: fromRawMappings([
|
|
266
|
-
{
|
|
267
|
-
code,
|
|
268
|
-
source: sourceCode,
|
|
269
|
-
map,
|
|
270
|
-
functionMap: null,
|
|
271
|
-
path: filename,
|
|
272
|
-
},
|
|
273
|
-
]).toString(),
|
|
274
|
-
}): HermesCompilerResult),
|
|
275
|
-
type: bytecodeType,
|
|
276
|
-
});
|
|
277
|
-
}
|
|
297
|
+
if (
|
|
298
|
+
ast.program.sourceType === 'module' &&
|
|
299
|
+
directives != null &&
|
|
300
|
+
directives.findIndex(d => d.value.value === 'use strict') === -1
|
|
301
|
+
) {
|
|
302
|
+
directives.push(types.directive(types.directiveLiteral('use strict')));
|
|
303
|
+
}
|
|
278
304
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
305
|
+
// Perform the import-export transform (in case it's still needed), then
|
|
306
|
+
// fold requires and perform constant folding (if in dev).
|
|
307
|
+
const plugins = [];
|
|
308
|
+
const babelPluginOpts = {
|
|
309
|
+
...options,
|
|
310
|
+
inlineableCalls: [importDefault, importAll],
|
|
311
|
+
importDefault,
|
|
312
|
+
importAll,
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
if (options.experimentalImportSupport === true) {
|
|
316
|
+
plugins.push([metroTransformPlugins.importExportPlugin, babelPluginOpts]);
|
|
317
|
+
}
|
|
284
318
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
// Inline requires are now performed at a secondary step. We cannot
|
|
293
|
-
// unfortunately remove it from the internal transformer, since this one
|
|
294
|
-
// is used by other tooling, and this would affect it.
|
|
295
|
-
inlineRequires: false,
|
|
296
|
-
nonInlinedRequires: [],
|
|
297
|
-
projectRoot,
|
|
298
|
-
publicPath: config.publicPath,
|
|
319
|
+
if (options.inlineRequires) {
|
|
320
|
+
plugins.push([
|
|
321
|
+
// $FlowFixMe[untyped-import] untyped module
|
|
322
|
+
require('babel-preset-fbjs/plugins/inline-requires'),
|
|
323
|
+
{
|
|
324
|
+
...babelPluginOpts,
|
|
325
|
+
ignoredRequires: options.nonInlinedRequires,
|
|
299
326
|
},
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
let transformResult;
|
|
305
|
-
|
|
306
|
-
if (type === 'js/module/asset') {
|
|
307
|
-
const assetTransformer = require('./utils/assetTransformer');
|
|
308
|
-
|
|
309
|
-
transformResult = {
|
|
310
|
-
...(await assetTransformer.transform(
|
|
311
|
-
transformerArgs,
|
|
312
|
-
config.assetRegistryPath,
|
|
313
|
-
config.assetPlugins,
|
|
314
|
-
)),
|
|
315
|
-
functionMap: null,
|
|
316
|
-
};
|
|
317
|
-
} else {
|
|
318
|
-
// $FlowFixMe TODO t26372934 Plugin system
|
|
319
|
-
const transformer: Transformer<*> = require(config.babelTransformerPath);
|
|
320
|
-
transformResult = await transformer.transform(transformerArgs);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// Transformers can output null ASTs (if they ignore the file). In that case
|
|
324
|
-
// we need to parse the module source code to get their AST.
|
|
325
|
-
let ast =
|
|
326
|
-
transformResult.ast ||
|
|
327
|
-
babylon.parse(sourceCode, {sourceType: 'unambiguous'});
|
|
328
|
-
|
|
329
|
-
const {importDefault, importAll} = generateImportNames(ast);
|
|
330
|
-
|
|
331
|
-
// Add "use strict" if the file was parsed as a module, and the directive did
|
|
332
|
-
// not exist yet.
|
|
333
|
-
const {directives} = ast.program;
|
|
334
|
-
|
|
335
|
-
if (
|
|
336
|
-
ast.program.sourceType === 'module' &&
|
|
337
|
-
// $FlowFixMe[incompatible-use]
|
|
338
|
-
directives.findIndex(d => d.value.value === 'use strict') === -1
|
|
339
|
-
) {
|
|
340
|
-
// $FlowFixMe[incompatible-use]
|
|
341
|
-
directives.push(types.directive(types.directiveLiteral('use strict')));
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Perform the import-export transform (in case it's still needed), then
|
|
345
|
-
// fold requires and perform constant folding (if in dev).
|
|
346
|
-
const plugins = [];
|
|
347
|
-
const opts = {
|
|
348
|
-
...options,
|
|
349
|
-
inlineableCalls: [importDefault, importAll],
|
|
350
|
-
importDefault,
|
|
351
|
-
importAll,
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
if (options.experimentalImportSupport) {
|
|
355
|
-
plugins.push([metroTransformPlugins.importExportPlugin, opts]);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (options.inlineRequires) {
|
|
359
|
-
plugins.push([
|
|
360
|
-
require('babel-preset-fbjs/plugins/inline-requires'),
|
|
361
|
-
{
|
|
362
|
-
...opts,
|
|
363
|
-
ignoredRequires: options.nonInlinedRequires,
|
|
364
|
-
},
|
|
365
|
-
]);
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (!options.dev) {
|
|
369
|
-
plugins.push([metroTransformPlugins.constantFoldingPlugin, opts]);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
plugins.push([metroTransformPlugins.inlinePlugin, opts]);
|
|
327
|
+
]);
|
|
328
|
+
}
|
|
373
329
|
|
|
330
|
+
plugins.push([metroTransformPlugins.inlinePlugin, babelPluginOpts]);
|
|
331
|
+
|
|
332
|
+
ast = nullthrows(
|
|
333
|
+
transformFromAstSync(ast, '', {
|
|
334
|
+
ast: true,
|
|
335
|
+
babelrc: false,
|
|
336
|
+
code: false,
|
|
337
|
+
configFile: false,
|
|
338
|
+
comments: false,
|
|
339
|
+
filename: file.filename,
|
|
340
|
+
plugins,
|
|
341
|
+
sourceMaps: false,
|
|
342
|
+
// Not-Cloning the input AST here should be safe because other code paths above this call
|
|
343
|
+
// are mutating the AST as well and no code is depending on the original AST.
|
|
344
|
+
// However, switching the flag to false caused issues with ES Modules if `experimentalImportSupport` isn't used https://github.com/facebook/metro/issues/641
|
|
345
|
+
// either because one of the plugins is doing something funky or Babel messes up some caches.
|
|
346
|
+
// Make sure to test the above mentioned case before flipping the flag back to false.
|
|
347
|
+
cloneInputAst: true,
|
|
348
|
+
}).ast,
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
if (!options.dev) {
|
|
352
|
+
// Run the constant folding plugin in its own pass, avoiding race conditions
|
|
353
|
+
// with other plugins that have exit() visitors on Program (e.g. the ESM
|
|
354
|
+
// transform).
|
|
374
355
|
ast = nullthrows(
|
|
375
356
|
transformFromAstSync(ast, '', {
|
|
376
357
|
ast: true,
|
|
@@ -378,53 +359,57 @@ module.exports = {
|
|
|
378
359
|
code: false,
|
|
379
360
|
configFile: false,
|
|
380
361
|
comments: false,
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
362
|
+
filename: file.filename,
|
|
363
|
+
plugins: [
|
|
364
|
+
[metroTransformPlugins.constantFoldingPlugin, babelPluginOpts],
|
|
365
|
+
],
|
|
384
366
|
sourceMaps: false,
|
|
385
|
-
|
|
386
|
-
// are mutating the AST as well and no code is depending on the original AST.
|
|
387
|
-
// However, switching the flag to false caused issues with ES Modules if `experimentalImportSupport` isn't used https://github.com/facebook/metro/issues/641
|
|
388
|
-
// either because one of the plugins is doing something funky or Babel messes up some caches.
|
|
389
|
-
// Make sure to test the above mentioned case before flipping the flag back to false.
|
|
390
|
-
cloneInputAst: true,
|
|
367
|
+
cloneInputAst: false,
|
|
391
368
|
}).ast,
|
|
392
369
|
);
|
|
370
|
+
}
|
|
393
371
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
372
|
+
let dependencyMapName = '';
|
|
373
|
+
let dependencies;
|
|
374
|
+
let wrappedAst;
|
|
375
|
+
|
|
376
|
+
// If the module to transform is a script (meaning that is not part of the
|
|
377
|
+
// dependency graph and it code will just be prepended to the bundle modules),
|
|
378
|
+
// we need to wrap it differently than a commonJS module (also, scripts do
|
|
379
|
+
// not have dependencies).
|
|
380
|
+
if (file.type === 'js/script') {
|
|
381
|
+
dependencies = [];
|
|
382
|
+
wrappedAst = JsFileWrapping.wrapPolyfill(ast);
|
|
383
|
+
} else {
|
|
384
|
+
try {
|
|
385
|
+
const opts = {
|
|
386
|
+
asyncRequireModulePath: config.asyncRequireModulePath,
|
|
387
|
+
dependencyTransformer:
|
|
388
|
+
config.unstable_disableModuleWrapping === true
|
|
389
|
+
? disabledDependencyTransformer
|
|
390
|
+
: undefined,
|
|
391
|
+
dynamicRequires: getDynamicDepsBehavior(
|
|
392
|
+
config.dynamicDepsInPackages,
|
|
393
|
+
file.filename,
|
|
394
|
+
),
|
|
395
|
+
inlineableCalls: [importDefault, importAll],
|
|
396
|
+
keepRequireNames: options.dev,
|
|
397
|
+
allowOptionalDependencies: config.allowOptionalDependencies,
|
|
398
|
+
dependencyMapName: config.unstable_dependencyMapReservedName,
|
|
399
|
+
};
|
|
400
|
+
// $FlowFixMe[unsupported-syntax] dynamic require
|
|
401
|
+
const collectDependencies: CollectDependenciesFn<DependencySplitCondition> = require(config.unstable_collectDependenciesPath);
|
|
402
|
+
({ast, dependencies, dependencyMapName} = collectDependencies(ast, opts));
|
|
403
|
+
} catch (error) {
|
|
404
|
+
if (error instanceof InternalInvalidRequireCallError) {
|
|
405
|
+
throw new InvalidRequireCallError(error, file.filename);
|
|
426
406
|
}
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
427
409
|
|
|
410
|
+
if (config.unstable_disableModuleWrapping === true) {
|
|
411
|
+
wrappedAst = ast;
|
|
412
|
+
} else {
|
|
428
413
|
({ast: wrappedAst} = JsFileWrapping.wrapModule(
|
|
429
414
|
ast,
|
|
430
415
|
importDefault,
|
|
@@ -433,79 +418,327 @@ module.exports = {
|
|
|
433
418
|
config.globalPrefix,
|
|
434
419
|
));
|
|
435
420
|
}
|
|
421
|
+
}
|
|
436
422
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
423
|
+
const minify =
|
|
424
|
+
options.minify &&
|
|
425
|
+
options.unstable_transformProfile !== 'hermes-canary' &&
|
|
426
|
+
options.unstable_transformProfile !== 'hermes-stable';
|
|
441
427
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
428
|
+
const reserved = [];
|
|
429
|
+
if (config.unstable_dependencyMapReservedName != null) {
|
|
430
|
+
reserved.push(config.unstable_dependencyMapReservedName);
|
|
431
|
+
}
|
|
432
|
+
if (
|
|
433
|
+
minify &&
|
|
434
|
+
file.inputFileSize <= config.optimizationSizeLimit &&
|
|
435
|
+
!config.unstable_disableNormalizePseudoGlobals
|
|
436
|
+
) {
|
|
437
|
+
reserved.push(
|
|
438
|
+
...metroTransformPlugins.normalizePseudoGlobals(wrappedAst, {
|
|
439
|
+
reservedNames: reserved,
|
|
440
|
+
}),
|
|
453
441
|
);
|
|
442
|
+
}
|
|
454
443
|
|
|
455
|
-
|
|
456
|
-
|
|
444
|
+
const result = generate(
|
|
445
|
+
wrappedAst,
|
|
446
|
+
{
|
|
447
|
+
comments: false,
|
|
448
|
+
compact: config.unstable_compactOutput,
|
|
449
|
+
filename: file.filename,
|
|
450
|
+
retainLines: false,
|
|
451
|
+
sourceFileName: file.filename,
|
|
452
|
+
sourceMaps: true,
|
|
453
|
+
},
|
|
454
|
+
file.code,
|
|
455
|
+
);
|
|
456
|
+
|
|
457
|
+
let map = result.rawMappings ? result.rawMappings.map(toSegmentTuple) : [];
|
|
458
|
+
let code = result.code;
|
|
459
|
+
|
|
460
|
+
if (minify) {
|
|
461
|
+
({map, code} = await minifyCode(
|
|
462
|
+
config,
|
|
463
|
+
projectRoot,
|
|
464
|
+
file.filename,
|
|
465
|
+
result.code,
|
|
466
|
+
file.code,
|
|
467
|
+
map,
|
|
468
|
+
reserved,
|
|
469
|
+
));
|
|
470
|
+
}
|
|
457
471
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
result.code,
|
|
464
|
-
sourceCode,
|
|
472
|
+
const output = [
|
|
473
|
+
{
|
|
474
|
+
data: {
|
|
475
|
+
code,
|
|
476
|
+
lineCount: countLines(code),
|
|
465
477
|
map,
|
|
466
|
-
|
|
467
|
-
|
|
478
|
+
functionMap: file.functionMap,
|
|
479
|
+
},
|
|
480
|
+
type: file.type,
|
|
481
|
+
},
|
|
482
|
+
];
|
|
483
|
+
|
|
484
|
+
if (options.runtimeBytecodeVersion != null) {
|
|
485
|
+
output.push({
|
|
486
|
+
data: (compileToBytecode(code, file.type, {
|
|
487
|
+
sourceURL: file.filename,
|
|
488
|
+
sourceMap: fromRawMappings([
|
|
489
|
+
{
|
|
490
|
+
code,
|
|
491
|
+
source: file.code,
|
|
492
|
+
map,
|
|
493
|
+
functionMap: null,
|
|
494
|
+
path: file.filename,
|
|
495
|
+
},
|
|
496
|
+
]).toString(),
|
|
497
|
+
}): HermesCompilerResult),
|
|
498
|
+
type: getBytecodeFileType(file.type),
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
return {
|
|
503
|
+
dependencies,
|
|
504
|
+
output,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Transforms an asset file
|
|
510
|
+
*/
|
|
511
|
+
async function transformAsset(
|
|
512
|
+
file: AssetFile,
|
|
513
|
+
context: TransformationContext,
|
|
514
|
+
): Promise<TransformResponse> {
|
|
515
|
+
const assetTransformer = require('./utils/assetTransformer');
|
|
516
|
+
const {assetRegistryPath, assetPlugins} = context.config;
|
|
517
|
+
|
|
518
|
+
const result = await assetTransformer.transform(
|
|
519
|
+
getBabelTransformArgs(file, context),
|
|
520
|
+
assetRegistryPath,
|
|
521
|
+
assetPlugins,
|
|
522
|
+
);
|
|
523
|
+
|
|
524
|
+
const jsFile = {
|
|
525
|
+
...file,
|
|
526
|
+
type: 'js/module/asset',
|
|
527
|
+
ast: result.ast,
|
|
528
|
+
functionMap: null,
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
return transformJS(jsFile, context);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
/**
|
|
535
|
+
* Transforms a JavaScript file with Babel before processing the file with
|
|
536
|
+
* the generic JavaScript transformation.
|
|
537
|
+
*/
|
|
538
|
+
async function transformJSWithBabel(
|
|
539
|
+
file: JSFile,
|
|
540
|
+
context: TransformationContext,
|
|
541
|
+
): Promise<TransformResponse> {
|
|
542
|
+
const {babelTransformerPath} = context.config;
|
|
543
|
+
// $FlowFixMe[unsupported-syntax] dynamic require
|
|
544
|
+
const transformer: BabelTransformer = require(babelTransformerPath);
|
|
545
|
+
|
|
546
|
+
const transformResult = await transformer.transform(
|
|
547
|
+
getBabelTransformArgs(file, context),
|
|
548
|
+
);
|
|
549
|
+
|
|
550
|
+
const jsFile: JSFile = {
|
|
551
|
+
...file,
|
|
552
|
+
ast: transformResult.ast,
|
|
553
|
+
functionMap: transformResult.functionMap ?? null,
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
return await transformJS(jsFile, context);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
async function transformJSON(
|
|
560
|
+
file: JSONFile,
|
|
561
|
+
{options, config, projectRoot}: TransformationContext,
|
|
562
|
+
): Promise<TransformResponse> {
|
|
563
|
+
let code =
|
|
564
|
+
config.unstable_disableModuleWrapping === true
|
|
565
|
+
? JsFileWrapping.jsonToCommonJS(file.code)
|
|
566
|
+
: JsFileWrapping.wrapJson(file.code, config.globalPrefix);
|
|
567
|
+
let map = [];
|
|
568
|
+
|
|
569
|
+
// TODO: When we can reuse transformJS for JSON, we should not derive `minify` separately.
|
|
570
|
+
const minify =
|
|
571
|
+
options.minify &&
|
|
572
|
+
options.unstable_transformProfile !== 'hermes-canary' &&
|
|
573
|
+
options.unstable_transformProfile !== 'hermes-stable';
|
|
574
|
+
|
|
575
|
+
if (minify) {
|
|
576
|
+
({map, code} = await minifyCode(
|
|
577
|
+
config,
|
|
578
|
+
projectRoot,
|
|
579
|
+
file.filename,
|
|
580
|
+
code,
|
|
581
|
+
file.code,
|
|
582
|
+
map,
|
|
583
|
+
));
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
let jsType: JSFileType;
|
|
587
|
+
|
|
588
|
+
if (file.type === 'asset') {
|
|
589
|
+
jsType = 'js/module/asset';
|
|
590
|
+
} else if (file.type === 'script') {
|
|
591
|
+
jsType = 'js/script';
|
|
592
|
+
} else {
|
|
593
|
+
jsType = 'js/module';
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
const output = [
|
|
597
|
+
{
|
|
598
|
+
data: {code, lineCount: countLines(code), map, functionMap: null},
|
|
599
|
+
type: jsType,
|
|
600
|
+
},
|
|
601
|
+
];
|
|
602
|
+
|
|
603
|
+
if (options.runtimeBytecodeVersion != null) {
|
|
604
|
+
output.push({
|
|
605
|
+
data: (compileToBytecode(code, jsType, {
|
|
606
|
+
sourceURL: file.filename,
|
|
607
|
+
sourceMap: fromRawMappings([
|
|
608
|
+
{
|
|
609
|
+
code,
|
|
610
|
+
source: file.code,
|
|
611
|
+
map,
|
|
612
|
+
functionMap: null,
|
|
613
|
+
path: file.filename,
|
|
614
|
+
},
|
|
615
|
+
]).toString(),
|
|
616
|
+
}): HermesCompilerResult),
|
|
617
|
+
type: getBytecodeFileType(jsType),
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return {
|
|
622
|
+
dependencies: [],
|
|
623
|
+
output,
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Returns the bytecode type for a file type
|
|
629
|
+
*/
|
|
630
|
+
function getBytecodeFileType(type: JSFileType): BytecodeFileType {
|
|
631
|
+
switch (type) {
|
|
632
|
+
case 'js/module/asset':
|
|
633
|
+
return 'bytecode/module/asset';
|
|
634
|
+
case 'js/script':
|
|
635
|
+
return 'bytecode/script';
|
|
636
|
+
default:
|
|
637
|
+
(type: 'js/module');
|
|
638
|
+
return 'bytecode/module';
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
function getBabelTransformArgs(
|
|
643
|
+
file: $ReadOnly<{filename: Path, code: string, ...}>,
|
|
644
|
+
{options, config, projectRoot}: TransformationContext,
|
|
645
|
+
): BabelTransformerArgs {
|
|
646
|
+
return {
|
|
647
|
+
filename: file.filename,
|
|
648
|
+
options: {
|
|
649
|
+
...options,
|
|
650
|
+
enableBabelRCLookup: config.enableBabelRCLookup,
|
|
651
|
+
enableBabelRuntime: config.enableBabelRuntime,
|
|
652
|
+
globalPrefix: config.globalPrefix,
|
|
653
|
+
hermesParser: config.hermesParser,
|
|
654
|
+
// Inline requires are now performed at a secondary step. We cannot
|
|
655
|
+
// unfortunately remove it from the internal transformer, since this one
|
|
656
|
+
// is used by other tooling, and this would affect it.
|
|
657
|
+
inlineRequires: false,
|
|
658
|
+
nonInlinedRequires: [],
|
|
659
|
+
projectRoot,
|
|
660
|
+
publicPath: config.publicPath,
|
|
661
|
+
},
|
|
662
|
+
plugins: [],
|
|
663
|
+
src: file.code,
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
module.exports = {
|
|
668
|
+
transform: async (
|
|
669
|
+
config: JsTransformerConfig,
|
|
670
|
+
projectRoot: string,
|
|
671
|
+
filename: string,
|
|
672
|
+
data: Buffer,
|
|
673
|
+
options: JsTransformOptions,
|
|
674
|
+
): Promise<TransformResponse> => {
|
|
675
|
+
const context: TransformationContext = {
|
|
676
|
+
config,
|
|
677
|
+
projectRoot,
|
|
678
|
+
options,
|
|
679
|
+
};
|
|
680
|
+
const sourceCode = data.toString('utf8');
|
|
681
|
+
|
|
682
|
+
const {unstable_dependencyMapReservedName} = config;
|
|
683
|
+
if (unstable_dependencyMapReservedName != null) {
|
|
684
|
+
const position = sourceCode.indexOf(unstable_dependencyMapReservedName);
|
|
685
|
+
if (position > -1) {
|
|
686
|
+
throw new SyntaxError(
|
|
687
|
+
'Source code contains the reserved string `' +
|
|
688
|
+
unstable_dependencyMapReservedName +
|
|
689
|
+
'` at character offset ' +
|
|
690
|
+
position,
|
|
691
|
+
);
|
|
692
|
+
}
|
|
468
693
|
}
|
|
469
694
|
|
|
470
|
-
|
|
471
|
-
{
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
},
|
|
480
|
-
];
|
|
481
|
-
|
|
482
|
-
if (options.runtimeBytecodeVersion) {
|
|
483
|
-
output.push({
|
|
484
|
-
data: (compileToBytecode(code, type, {
|
|
485
|
-
sourceURL: filename,
|
|
486
|
-
sourceMap: fromRawMappings([
|
|
487
|
-
{code, source: sourceCode, map, functionMap: null, path: filename},
|
|
488
|
-
]).toString(),
|
|
489
|
-
}): HermesCompilerResult),
|
|
490
|
-
type: bytecodeType,
|
|
491
|
-
});
|
|
695
|
+
if (filename.endsWith('.json')) {
|
|
696
|
+
const jsonFile: JSONFile = {
|
|
697
|
+
filename,
|
|
698
|
+
inputFileSize: data.length,
|
|
699
|
+
code: sourceCode,
|
|
700
|
+
type: options.type,
|
|
701
|
+
};
|
|
702
|
+
|
|
703
|
+
return await transformJSON(jsonFile, context);
|
|
492
704
|
}
|
|
493
705
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
706
|
+
if (options.type === 'asset') {
|
|
707
|
+
const file: AssetFile = {
|
|
708
|
+
filename,
|
|
709
|
+
inputFileSize: data.length,
|
|
710
|
+
code: sourceCode,
|
|
711
|
+
type: options.type,
|
|
712
|
+
};
|
|
713
|
+
|
|
714
|
+
return await transformAsset(file, context);
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
const file: JSFile = {
|
|
718
|
+
filename,
|
|
719
|
+
inputFileSize: data.length,
|
|
720
|
+
code: sourceCode,
|
|
721
|
+
type: options.type === 'script' ? 'js/script' : 'js/module',
|
|
722
|
+
functionMap: null,
|
|
497
723
|
};
|
|
724
|
+
|
|
725
|
+
return await transformJSWithBabel(file, context);
|
|
498
726
|
},
|
|
499
727
|
|
|
500
728
|
getCacheKey: (config: JsTransformerConfig): string => {
|
|
501
|
-
const {
|
|
729
|
+
const {
|
|
730
|
+
babelTransformerPath,
|
|
731
|
+
minifierPath,
|
|
732
|
+
unstable_collectDependenciesPath,
|
|
733
|
+
...remainingConfig
|
|
734
|
+
} = config;
|
|
502
735
|
|
|
503
736
|
const filesKey = getCacheKey([
|
|
504
737
|
require.resolve(babelTransformerPath),
|
|
505
738
|
require.resolve(minifierPath),
|
|
506
739
|
require.resolve('./utils/getMinifier'),
|
|
507
740
|
require.resolve('./utils/assetTransformer'),
|
|
508
|
-
require.resolve(
|
|
741
|
+
require.resolve(unstable_collectDependenciesPath),
|
|
509
742
|
require.resolve('metro/src/ModuleGraph/worker/generateImportNames'),
|
|
510
743
|
require.resolve('metro/src/ModuleGraph/worker/JsFileWrapping'),
|
|
511
744
|
...metroTransformPlugins.getTransformPluginCacheKeyFiles(),
|