-
Notifications
You must be signed in to change notification settings - Fork 601
/
Worker.js
124 lines (106 loc) 路 3.13 KB
/
Worker.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
*/
'use strict';
const crypto = require('crypto');
const fs = require('fs');
const path = require('path');
const traverse = require('@babel/traverse').default;
import type {TransformResult} from './types.flow';
import type {LogEntry} from 'metro-core/src/Logger';
import type {
JsTransformOptions,
JsTransformerConfig,
} from 'metro-transform-worker';
export type {JsTransformOptions as TransformOptions} from 'metro-transform-worker';
export type Worker = {|
+transform: typeof transform,
|};
type TransformerInterface = {
transform(
JsTransformerConfig,
string,
string,
Buffer,
JsTransformOptions,
): Promise<TransformResult<>>,
};
export type TransformerConfig = {
transformerPath: string,
transformerConfig: JsTransformerConfig,
...
};
type Data = $ReadOnly<{|
result: TransformResult<>,
sha1: string,
transformFileStartLogEntry: LogEntry,
transformFileEndLogEntry: LogEntry,
|}>;
async function transform(
filename: string,
transformOptions: JsTransformOptions,
projectRoot: string,
transformerConfig: TransformerConfig,
): Promise<Data> {
// eslint-disable-next-line no-useless-call
const Transformer = (require.call(
null,
transformerConfig.transformerPath,
): TransformerInterface);
const transformFileStartLogEntry = {
action_name: 'Transforming file',
action_phase: 'start',
file_name: filename,
log_entry_label: 'Transforming file',
start_timestamp: process.hrtime(),
};
const data = fs.readFileSync(path.resolve(projectRoot, filename));
const sha1 = crypto
.createHash('sha1')
.update(data)
.digest('hex');
const result = await Transformer.transform(
transformerConfig.transformerConfig,
projectRoot,
filename,
data,
transformOptions,
);
// The babel cache caches scopes and pathes for already traversed AST nodes.
// Clearing the cache here since the nodes of the transformed file are no longer referenced.
// This isn't stritcly necessary since the cache uses a WeakMap. However, WeakMap only permit
// that unreferenced keys are collected but the values still hold references to the Scope and NodePaths.
// Manually clearing the cache allows the GC to collect the Scope and NodePaths without checking if there
// exist any other references to the keys.
traverse.cache.clear();
const transformFileEndLogEntry = getEndLogEntry(
transformFileStartLogEntry,
filename,
);
return {
result,
sha1,
transformFileStartLogEntry,
transformFileEndLogEntry,
};
}
function getEndLogEntry(startLogEntry: LogEntry, filename: string): LogEntry {
const timeDelta = process.hrtime(startLogEntry.start_timestamp);
const duration_ms = Math.round((timeDelta[0] * 1e9 + timeDelta[1]) / 1e6);
return {
action_name: 'Transforming file',
action_phase: 'end',
file_name: filename,
duration_ms,
log_entry_label: 'Transforming file',
};
}
module.exports = ({
transform,
}: Worker);