metro 0.76.3 → 0.76.5
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 +24 -23
- package/src/Assets.js +35 -3
- package/src/Assets.js.flow +38 -3
- package/src/Bundler/util.js +0 -72
- package/src/Bundler/util.js.flow +0 -98
- package/src/DeltaBundler/DeltaCalculator.js +7 -0
- package/src/DeltaBundler/DeltaCalculator.js.flow +7 -0
- package/src/DeltaBundler/Graph.js +108 -26
- package/src/DeltaBundler/Graph.js.flow +119 -26
- package/src/DeltaBundler/Serializers/baseJSBundle.js +1 -0
- package/src/DeltaBundler/Serializers/baseJSBundle.js.flow +1 -0
- package/src/DeltaBundler/Serializers/getRamBundleInfo.js +1 -0
- package/src/DeltaBundler/Serializers/getRamBundleInfo.js.flow +3 -1
- package/src/DeltaBundler/Serializers/helpers/getSourceMapInfo.js +1 -0
- package/src/DeltaBundler/Serializers/helpers/getSourceMapInfo.js.flow +3 -0
- package/src/DeltaBundler/Serializers/helpers/js.js +4 -1
- package/src/DeltaBundler/Serializers/helpers/js.js.flow +4 -1
- package/src/DeltaBundler/Serializers/hmrJSBundle.js +2 -1
- package/src/DeltaBundler/Serializers/hmrJSBundle.js.flow +2 -1
- package/src/DeltaBundler/Serializers/sourceMapGenerator.js +1 -0
- package/src/DeltaBundler/Serializers/sourceMapGenerator.js.flow +10 -12
- package/src/DeltaBundler/Serializers/sourceMapObject.js.flow +3 -8
- package/src/DeltaBundler/Serializers/sourceMapString.js.flow +2 -4
- package/src/DeltaBundler/Transformer.js +1 -0
- package/src/DeltaBundler/Transformer.js.flow +1 -0
- package/src/DeltaBundler/types.d.ts +1 -0
- package/src/DeltaBundler/types.flow.js.flow +10 -7
- package/src/Server.js +52 -14
- package/src/Server.js.flow +61 -16
- package/src/lib/getAppendScripts.js +1 -0
- package/src/lib/getAppendScripts.js.flow +12 -10
- package/src/lib/parseOptionsFromUrl.js +4 -3
- package/src/lib/parseOptionsFromUrl.js.flow +4 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metro",
|
|
3
|
-
"version": "0.76.
|
|
3
|
+
"version": "0.76.5",
|
|
4
4
|
"description": "🚇 The JavaScript bundler for React Native.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": "src/cli.js",
|
|
@@ -30,26 +30,27 @@
|
|
|
30
30
|
"error-stack-parser": "^2.0.6",
|
|
31
31
|
"graceful-fs": "^4.2.4",
|
|
32
32
|
"hermes-parser": "0.8.0",
|
|
33
|
-
"image-size": "^0.
|
|
33
|
+
"image-size": "^1.0.2",
|
|
34
34
|
"invariant": "^2.2.4",
|
|
35
35
|
"jest-worker": "^27.2.0",
|
|
36
|
+
"jsc-safe-url": "^0.2.2",
|
|
36
37
|
"lodash.throttle": "^4.1.1",
|
|
37
|
-
"metro-babel-transformer": "0.76.
|
|
38
|
-
"metro-cache": "0.76.
|
|
39
|
-
"metro-cache-key": "0.76.
|
|
40
|
-
"metro-config": "0.76.
|
|
41
|
-
"metro-core": "0.76.
|
|
42
|
-
"metro-file-map": "0.76.
|
|
43
|
-
"metro-inspector-proxy": "0.76.
|
|
44
|
-
"metro-minify-terser": "0.76.
|
|
45
|
-
"metro-minify-uglify": "0.76.
|
|
46
|
-
"metro-react-native-babel-preset": "0.76.
|
|
47
|
-
"metro-resolver": "0.76.
|
|
48
|
-
"metro-runtime": "0.76.
|
|
49
|
-
"metro-source-map": "0.76.
|
|
50
|
-
"metro-symbolicate": "0.76.
|
|
51
|
-
"metro-transform-plugins": "0.76.
|
|
52
|
-
"metro-transform-worker": "0.76.
|
|
38
|
+
"metro-babel-transformer": "0.76.5",
|
|
39
|
+
"metro-cache": "0.76.5",
|
|
40
|
+
"metro-cache-key": "0.76.5",
|
|
41
|
+
"metro-config": "0.76.5",
|
|
42
|
+
"metro-core": "0.76.5",
|
|
43
|
+
"metro-file-map": "0.76.5",
|
|
44
|
+
"metro-inspector-proxy": "0.76.5",
|
|
45
|
+
"metro-minify-terser": "0.76.5",
|
|
46
|
+
"metro-minify-uglify": "0.76.5",
|
|
47
|
+
"metro-react-native-babel-preset": "0.76.5",
|
|
48
|
+
"metro-resolver": "0.76.5",
|
|
49
|
+
"metro-runtime": "0.76.5",
|
|
50
|
+
"metro-source-map": "0.76.5",
|
|
51
|
+
"metro-symbolicate": "0.76.5",
|
|
52
|
+
"metro-transform-plugins": "0.76.5",
|
|
53
|
+
"metro-transform-worker": "0.76.5",
|
|
53
54
|
"mime-types": "^2.1.27",
|
|
54
55
|
"node-fetch": "^2.2.0",
|
|
55
56
|
"nullthrows": "^1.1.1",
|
|
@@ -62,15 +63,15 @@
|
|
|
62
63
|
"yargs": "^17.6.2"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
|
-
"@babel/plugin-transform-flow-strip-types": "^7.
|
|
66
|
+
"@babel/plugin-transform-flow-strip-types": "^7.20.0",
|
|
66
67
|
"babel-jest": "^29.2.1",
|
|
67
68
|
"dedent": "^0.7.0",
|
|
68
69
|
"jest-snapshot": "^26.5.2",
|
|
69
70
|
"jest-snapshot-serializer-raw": "^1.2.0",
|
|
70
|
-
"metro-babel-register": "0.76.
|
|
71
|
-
"metro-memory-fs": "0.76.
|
|
72
|
-
"metro-react-native-babel-preset": "0.76.
|
|
73
|
-
"metro-react-native-babel-transformer": "0.76.
|
|
71
|
+
"metro-babel-register": "0.76.5",
|
|
72
|
+
"metro-memory-fs": "0.76.5",
|
|
73
|
+
"metro-react-native-babel-preset": "0.76.5",
|
|
74
|
+
"metro-react-native-babel-transformer": "0.76.5",
|
|
74
75
|
"mock-req": "^0.2.0",
|
|
75
76
|
"mock-res": "^0.6.0",
|
|
76
77
|
"stack-trace": "^0.0.10"
|
package/src/Assets.js
CHANGED
|
@@ -11,15 +11,45 @@
|
|
|
11
11
|
|
|
12
12
|
"use strict";
|
|
13
13
|
|
|
14
|
-
const { isAssetTypeAnImage } = require("./Bundler/util");
|
|
15
14
|
const AssetPaths = require("./node-haste/lib/AssetPaths");
|
|
16
15
|
const crypto = require("crypto");
|
|
17
16
|
const denodeify = require("denodeify");
|
|
18
17
|
const fs = require("fs");
|
|
19
|
-
const
|
|
18
|
+
const getImageSize = require("image-size");
|
|
20
19
|
const path = require("path");
|
|
21
20
|
const readDir = denodeify(fs.readdir);
|
|
22
21
|
const readFile = denodeify(fs.readFile);
|
|
22
|
+
// Test extension against all types supported by image-size module.
|
|
23
|
+
// If it's not one of these, we won't treat it as an image.
|
|
24
|
+
function isAssetTypeAnImage(type) {
|
|
25
|
+
return (
|
|
26
|
+
[
|
|
27
|
+
"png",
|
|
28
|
+
"jpg",
|
|
29
|
+
"jpeg",
|
|
30
|
+
"bmp",
|
|
31
|
+
"gif",
|
|
32
|
+
"webp",
|
|
33
|
+
"psd",
|
|
34
|
+
"svg",
|
|
35
|
+
"tiff",
|
|
36
|
+
"ktx",
|
|
37
|
+
].indexOf(type) !== -1
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
function getAssetSize(type, content, filePath) {
|
|
41
|
+
if (!isAssetTypeAnImage(type)) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
if (content.length === 0) {
|
|
45
|
+
throw new Error(`Image asset \`${filePath}\` cannot be an empty file.`);
|
|
46
|
+
}
|
|
47
|
+
const { width, height } = getImageSize(content);
|
|
48
|
+
return {
|
|
49
|
+
width,
|
|
50
|
+
height,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
23
53
|
const hashFiles = denodeify(function hashFilesCb(files, hash, callback) {
|
|
24
54
|
if (!files.length) {
|
|
25
55
|
callback(null);
|
|
@@ -141,7 +171,7 @@ async function getAssetData(
|
|
|
141
171
|
const isImageInput = assetInfo.files[0].includes(".zip/")
|
|
142
172
|
? fs.readFileSync(assetInfo.files[0])
|
|
143
173
|
: assetInfo.files[0];
|
|
144
|
-
const dimensions = isImage ?
|
|
174
|
+
const dimensions = isImage ? getImageSize(isImageInput) : null;
|
|
145
175
|
const scale = assetInfo.scales[0];
|
|
146
176
|
const assetData = {
|
|
147
177
|
__packager_asset: true,
|
|
@@ -227,6 +257,8 @@ function pathBelongsToRoots(pathToCheck, roots) {
|
|
|
227
257
|
}
|
|
228
258
|
module.exports = {
|
|
229
259
|
getAsset,
|
|
260
|
+
getAssetSize,
|
|
230
261
|
getAssetData,
|
|
231
262
|
getAssetFiles,
|
|
263
|
+
isAssetTypeAnImage,
|
|
232
264
|
};
|
package/src/Assets.js.flow
CHANGED
|
@@ -13,12 +13,11 @@
|
|
|
13
13
|
|
|
14
14
|
import type {AssetPath} from './node-haste/lib/AssetPaths';
|
|
15
15
|
|
|
16
|
-
const {isAssetTypeAnImage} = require('./Bundler/util');
|
|
17
16
|
const AssetPaths = require('./node-haste/lib/AssetPaths');
|
|
18
17
|
const crypto = require('crypto');
|
|
19
18
|
const denodeify = require('denodeify');
|
|
20
19
|
const fs = require('fs');
|
|
21
|
-
const
|
|
20
|
+
const getImageSize = require('image-size');
|
|
22
21
|
const path = require('path');
|
|
23
22
|
|
|
24
23
|
const readDir = denodeify(fs.readdir);
|
|
@@ -56,6 +55,40 @@ export type AssetDataFiltered = {
|
|
|
56
55
|
...
|
|
57
56
|
};
|
|
58
57
|
|
|
58
|
+
// Test extension against all types supported by image-size module.
|
|
59
|
+
// If it's not one of these, we won't treat it as an image.
|
|
60
|
+
function isAssetTypeAnImage(type: string): boolean {
|
|
61
|
+
return (
|
|
62
|
+
[
|
|
63
|
+
'png',
|
|
64
|
+
'jpg',
|
|
65
|
+
'jpeg',
|
|
66
|
+
'bmp',
|
|
67
|
+
'gif',
|
|
68
|
+
'webp',
|
|
69
|
+
'psd',
|
|
70
|
+
'svg',
|
|
71
|
+
'tiff',
|
|
72
|
+
'ktx',
|
|
73
|
+
].indexOf(type) !== -1
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getAssetSize(
|
|
78
|
+
type: string,
|
|
79
|
+
content: Buffer,
|
|
80
|
+
filePath: string,
|
|
81
|
+
): ?{+width: number, +height: number} {
|
|
82
|
+
if (!isAssetTypeAnImage(type)) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
if (content.length === 0) {
|
|
86
|
+
throw new Error(`Image asset \`${filePath}\` cannot be an empty file.`);
|
|
87
|
+
}
|
|
88
|
+
const {width, height} = getImageSize(content);
|
|
89
|
+
return {width, height};
|
|
90
|
+
}
|
|
91
|
+
|
|
59
92
|
export type AssetData = AssetDataWithoutFiles & {+files: Array<string>, ...};
|
|
60
93
|
|
|
61
94
|
export type AssetDataPlugin = (
|
|
@@ -209,7 +242,7 @@ async function getAssetData(
|
|
|
209
242
|
const isImageInput = assetInfo.files[0].includes('.zip/')
|
|
210
243
|
? fs.readFileSync(assetInfo.files[0])
|
|
211
244
|
: assetInfo.files[0];
|
|
212
|
-
const dimensions = isImage ?
|
|
245
|
+
const dimensions = isImage ? getImageSize(isImageInput) : null;
|
|
213
246
|
const scale = assetInfo.scales[0];
|
|
214
247
|
|
|
215
248
|
const assetData = {
|
|
@@ -317,6 +350,8 @@ function pathBelongsToRoots(
|
|
|
317
350
|
|
|
318
351
|
module.exports = {
|
|
319
352
|
getAsset,
|
|
353
|
+
getAssetSize,
|
|
320
354
|
getAssetData,
|
|
321
355
|
getAssetFiles,
|
|
356
|
+
isAssetTypeAnImage,
|
|
322
357
|
};
|
package/src/Bundler/util.js
CHANGED
|
@@ -14,10 +14,6 @@
|
|
|
14
14
|
const babylon = require("@babel/parser");
|
|
15
15
|
const template = require("@babel/template").default;
|
|
16
16
|
const babelTypes = require("@babel/types");
|
|
17
|
-
const nullthrows = require("nullthrows");
|
|
18
|
-
|
|
19
|
-
// Structure of the object: dir.name.scale = asset
|
|
20
|
-
|
|
21
17
|
const assetPropertyBlockList = new Set(["files", "fileSystemLocation", "path"]);
|
|
22
18
|
function generateAssetCodeFileAst(assetRegistryPath, assetDescriptor) {
|
|
23
19
|
const properDescriptor = filterObject(
|
|
@@ -44,72 +40,6 @@ function generateAssetCodeFileAst(assetRegistryPath, assetDescriptor) {
|
|
|
44
40
|
])
|
|
45
41
|
);
|
|
46
42
|
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Generates the code involved in requiring an asset, but to be loaded remotely.
|
|
50
|
-
* If the asset cannot be found within the map, then it falls back to the
|
|
51
|
-
* standard asset.
|
|
52
|
-
*/
|
|
53
|
-
function generateRemoteAssetCodeFileAst(
|
|
54
|
-
assetUtilsPath,
|
|
55
|
-
assetDescriptor,
|
|
56
|
-
remoteServer,
|
|
57
|
-
remoteFileMap
|
|
58
|
-
) {
|
|
59
|
-
const t = babelTypes;
|
|
60
|
-
const file = remoteFileMap[assetDescriptor.fileSystemLocation];
|
|
61
|
-
const descriptor = file && file[assetDescriptor.name];
|
|
62
|
-
const data = {};
|
|
63
|
-
if (!descriptor) {
|
|
64
|
-
return null;
|
|
65
|
-
}
|
|
66
|
-
for (const scale in descriptor) {
|
|
67
|
-
data[+scale] = descriptor[+scale].handle;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
// {2: 'path/to/image@2x', 3: 'path/to/image@3x', ...}
|
|
71
|
-
const astData = babylon.parseExpression(JSON.stringify(data));
|
|
72
|
-
|
|
73
|
-
// URI to remote server
|
|
74
|
-
const URI = t.stringLiteral(remoteServer);
|
|
75
|
-
|
|
76
|
-
// Size numbers.
|
|
77
|
-
const WIDTH = t.numericLiteral(nullthrows(assetDescriptor.width));
|
|
78
|
-
const HEIGHT = t.numericLiteral(nullthrows(assetDescriptor.height));
|
|
79
|
-
const buildRequire = template.program(`
|
|
80
|
-
const {pickScale, getUrlCacheBreaker}= require(ASSET_UTILS_PATH);
|
|
81
|
-
module.exports = {
|
|
82
|
-
"width": WIDTH,
|
|
83
|
-
"height": HEIGHT,
|
|
84
|
-
"uri": URI + OBJECT_AST[pickScale(SCALE_ARRAY)] + getUrlCacheBreaker()
|
|
85
|
-
};
|
|
86
|
-
`);
|
|
87
|
-
return t.file(
|
|
88
|
-
buildRequire({
|
|
89
|
-
WIDTH,
|
|
90
|
-
HEIGHT,
|
|
91
|
-
URI,
|
|
92
|
-
OBJECT_AST: astData,
|
|
93
|
-
ASSET_UTILS_PATH: t.stringLiteral(assetUtilsPath),
|
|
94
|
-
SCALE_ARRAY: t.arrayExpression(
|
|
95
|
-
Object.keys(descriptor)
|
|
96
|
-
.map(Number)
|
|
97
|
-
.sort((a, b) => a - b)
|
|
98
|
-
.map((scale) => t.numericLiteral(scale))
|
|
99
|
-
),
|
|
100
|
-
})
|
|
101
|
-
);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Test extension against all types supported by image-size module.
|
|
105
|
-
// If it's not one of these, we won't treat it as an image.
|
|
106
|
-
function isAssetTypeAnImage(type) {
|
|
107
|
-
return (
|
|
108
|
-
["png", "jpg", "jpeg", "bmp", "gif", "webp", "psd", "svg", "tiff"].indexOf(
|
|
109
|
-
type
|
|
110
|
-
) !== -1
|
|
111
|
-
);
|
|
112
|
-
}
|
|
113
43
|
function filterObject(object, blockList) {
|
|
114
44
|
const copied = {
|
|
115
45
|
...object,
|
|
@@ -190,6 +120,4 @@ class ArrayMap extends Map {
|
|
|
190
120
|
module.exports = {
|
|
191
121
|
createRamBundleGroups,
|
|
192
122
|
generateAssetCodeFileAst,
|
|
193
|
-
generateRemoteAssetCodeFileAst,
|
|
194
|
-
isAssetTypeAnImage,
|
|
195
123
|
};
|
package/src/Bundler/util.js.flow
CHANGED
|
@@ -18,31 +18,6 @@ import type {File} from '@babel/types';
|
|
|
18
18
|
const babylon = require('@babel/parser');
|
|
19
19
|
const template = require('@babel/template').default;
|
|
20
20
|
const babelTypes = require('@babel/types');
|
|
21
|
-
const nullthrows = require('nullthrows');
|
|
22
|
-
|
|
23
|
-
// Structure of the object: dir.name.scale = asset
|
|
24
|
-
export type RemoteFileMap = {
|
|
25
|
-
[string]: {
|
|
26
|
-
[string]: {
|
|
27
|
-
[number]: {
|
|
28
|
-
handle: string,
|
|
29
|
-
hash: string,
|
|
30
|
-
...
|
|
31
|
-
},
|
|
32
|
-
...
|
|
33
|
-
},
|
|
34
|
-
...
|
|
35
|
-
},
|
|
36
|
-
__proto__: null,
|
|
37
|
-
...
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
// Structure of the object: platform.dir.name.scale = asset
|
|
41
|
-
export type PlatformRemoteFileMap = {
|
|
42
|
-
[string]: RemoteFileMap,
|
|
43
|
-
__proto__: null,
|
|
44
|
-
...
|
|
45
|
-
};
|
|
46
21
|
|
|
47
22
|
type SubTree<T: ModuleTransportLike> = (
|
|
48
23
|
moduleTransport: T,
|
|
@@ -81,77 +56,6 @@ function generateAssetCodeFileAst(
|
|
|
81
56
|
);
|
|
82
57
|
}
|
|
83
58
|
|
|
84
|
-
/**
|
|
85
|
-
* Generates the code involved in requiring an asset, but to be loaded remotely.
|
|
86
|
-
* If the asset cannot be found within the map, then it falls back to the
|
|
87
|
-
* standard asset.
|
|
88
|
-
*/
|
|
89
|
-
function generateRemoteAssetCodeFileAst(
|
|
90
|
-
assetUtilsPath: string,
|
|
91
|
-
assetDescriptor: AssetDataWithoutFiles,
|
|
92
|
-
remoteServer: string,
|
|
93
|
-
remoteFileMap: RemoteFileMap,
|
|
94
|
-
): ?File {
|
|
95
|
-
const t = babelTypes;
|
|
96
|
-
|
|
97
|
-
const file = remoteFileMap[assetDescriptor.fileSystemLocation];
|
|
98
|
-
const descriptor = file && file[assetDescriptor.name];
|
|
99
|
-
const data: {[number]: string} = {};
|
|
100
|
-
|
|
101
|
-
if (!descriptor) {
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
for (const scale in descriptor) {
|
|
106
|
-
data[+scale] = descriptor[+scale].handle;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// {2: 'path/to/image@2x', 3: 'path/to/image@3x', ...}
|
|
110
|
-
const astData = babylon.parseExpression(JSON.stringify(data));
|
|
111
|
-
|
|
112
|
-
// URI to remote server
|
|
113
|
-
const URI = t.stringLiteral(remoteServer);
|
|
114
|
-
|
|
115
|
-
// Size numbers.
|
|
116
|
-
const WIDTH = t.numericLiteral(nullthrows(assetDescriptor.width));
|
|
117
|
-
const HEIGHT = t.numericLiteral(nullthrows(assetDescriptor.height));
|
|
118
|
-
|
|
119
|
-
const buildRequire = template.program(`
|
|
120
|
-
const {pickScale, getUrlCacheBreaker}= require(ASSET_UTILS_PATH);
|
|
121
|
-
module.exports = {
|
|
122
|
-
"width": WIDTH,
|
|
123
|
-
"height": HEIGHT,
|
|
124
|
-
"uri": URI + OBJECT_AST[pickScale(SCALE_ARRAY)] + getUrlCacheBreaker()
|
|
125
|
-
};
|
|
126
|
-
`);
|
|
127
|
-
|
|
128
|
-
return t.file(
|
|
129
|
-
buildRequire({
|
|
130
|
-
WIDTH,
|
|
131
|
-
HEIGHT,
|
|
132
|
-
URI,
|
|
133
|
-
OBJECT_AST: astData,
|
|
134
|
-
ASSET_UTILS_PATH: t.stringLiteral(assetUtilsPath),
|
|
135
|
-
SCALE_ARRAY: t.arrayExpression(
|
|
136
|
-
Object.keys(descriptor)
|
|
137
|
-
.map(Number)
|
|
138
|
-
.sort((a: number, b: number) => a - b)
|
|
139
|
-
.map((scale: number) => t.numericLiteral(scale)),
|
|
140
|
-
),
|
|
141
|
-
}),
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Test extension against all types supported by image-size module.
|
|
146
|
-
// If it's not one of these, we won't treat it as an image.
|
|
147
|
-
function isAssetTypeAnImage(type: string): boolean {
|
|
148
|
-
return (
|
|
149
|
-
['png', 'jpg', 'jpeg', 'bmp', 'gif', 'webp', 'psd', 'svg', 'tiff'].indexOf(
|
|
150
|
-
type,
|
|
151
|
-
) !== -1
|
|
152
|
-
);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
59
|
function filterObject(
|
|
156
60
|
object: AssetDataWithoutFiles,
|
|
157
61
|
blockList: Set<string>,
|
|
@@ -246,6 +150,4 @@ class ArrayMap<K, V> extends Map<K, Array<V>> {
|
|
|
246
150
|
module.exports = {
|
|
247
151
|
createRamBundleGroups,
|
|
248
152
|
generateAssetCodeFileAst,
|
|
249
|
-
generateRemoteAssetCodeFileAst,
|
|
250
|
-
isAssetTypeAnImage,
|
|
251
153
|
};
|
|
@@ -277,10 +277,17 @@ class DeltaCalculator extends EventEmitter {
|
|
|
277
277
|
reset: false,
|
|
278
278
|
};
|
|
279
279
|
}
|
|
280
|
+
debug("Traversing dependencies for %s paths", modifiedDependencies.length);
|
|
280
281
|
const { added, modified, deleted } = await this._graph.traverseDependencies(
|
|
281
282
|
modifiedDependencies,
|
|
282
283
|
this._options
|
|
283
284
|
);
|
|
285
|
+
debug(
|
|
286
|
+
"Calculated graph delta {added: %s, modified: %d, deleted: %d}",
|
|
287
|
+
added.size,
|
|
288
|
+
modified.size,
|
|
289
|
+
deleted.size
|
|
290
|
+
);
|
|
284
291
|
return {
|
|
285
292
|
added,
|
|
286
293
|
modified,
|
|
@@ -323,10 +323,17 @@ class DeltaCalculator<T> extends EventEmitter {
|
|
|
323
323
|
};
|
|
324
324
|
}
|
|
325
325
|
|
|
326
|
+
debug('Traversing dependencies for %s paths', modifiedDependencies.length);
|
|
326
327
|
const {added, modified, deleted} = await this._graph.traverseDependencies(
|
|
327
328
|
modifiedDependencies,
|
|
328
329
|
this._options,
|
|
329
330
|
);
|
|
331
|
+
debug(
|
|
332
|
+
'Calculated graph delta {added: %s, modified: %d, deleted: %d}',
|
|
333
|
+
added.size,
|
|
334
|
+
modified.size,
|
|
335
|
+
deleted.size,
|
|
336
|
+
);
|
|
330
337
|
|
|
331
338
|
return {
|
|
332
339
|
added,
|
|
@@ -134,10 +134,26 @@ class Graph {
|
|
|
134
134
|
earlyInverseDependencies: new Map(),
|
|
135
135
|
};
|
|
136
136
|
const internalOptions = getInternalOptions(options);
|
|
137
|
+
|
|
138
|
+
// Record the paths that are part of the dependency graph before we start
|
|
139
|
+
// traversing - we'll use this to ensure we don't report modules modified
|
|
140
|
+
// that only exist as part of the graph mid-traversal, and to eliminate
|
|
141
|
+
// modules that end up in the same state that they started from the delta.
|
|
142
|
+
const originalModules = new Map();
|
|
137
143
|
for (const path of paths) {
|
|
138
|
-
|
|
139
|
-
if (
|
|
140
|
-
|
|
144
|
+
const originalModule = this.dependencies.get(path);
|
|
145
|
+
if (originalModule) {
|
|
146
|
+
originalModules.set(path, originalModule);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
for (const [path] of originalModules) {
|
|
150
|
+
// Traverse over modules that are part of the dependency graph.
|
|
151
|
+
//
|
|
152
|
+
// Note: A given path may not be part of the graph *at this time*, in
|
|
153
|
+
// particular it may have been removed since we started traversing, but
|
|
154
|
+
// in that case the path will be visited if and when we add it back to
|
|
155
|
+
// the graph in a subsequent iteration.
|
|
156
|
+
if (this.dependencies.has(path)) {
|
|
141
157
|
await this._traverseDependenciesForSingleFile(
|
|
142
158
|
path,
|
|
143
159
|
delta,
|
|
@@ -151,10 +167,41 @@ class Graph {
|
|
|
151
167
|
added.set(path, nullthrows(this.dependencies.get(path)));
|
|
152
168
|
}
|
|
153
169
|
const modified = new Map();
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
170
|
+
|
|
171
|
+
// A path in delta.modified has been processed during this traversal,
|
|
172
|
+
// but may not actually differ, may be new, or may have been deleted after
|
|
173
|
+
// processing. The actually-modified modules are the intersection of
|
|
174
|
+
// delta.modified with the pre-existing paths, minus modules deleted.
|
|
175
|
+
for (const [path, originalModule] of originalModules) {
|
|
176
|
+
invariant(
|
|
177
|
+
!delta.added.has(path),
|
|
178
|
+
"delta.added has %s, but this path was already in the graph.",
|
|
179
|
+
path
|
|
180
|
+
);
|
|
181
|
+
if (delta.modified.has(path)) {
|
|
182
|
+
// It's expected that a module may be both modified and subsequently
|
|
183
|
+
// deleted - we'll only return it as deleted.
|
|
184
|
+
if (!delta.deleted.has(path)) {
|
|
185
|
+
// If a module existed before and has not been deleted, it must be
|
|
186
|
+
// in the dependencies map.
|
|
187
|
+
const newModule = nullthrows(this.dependencies.get(path));
|
|
188
|
+
if (
|
|
189
|
+
// Module.dependencies is mutable, so it's not obviously the case
|
|
190
|
+
// that referential equality implies no modification. However, we
|
|
191
|
+
// only mutate dependencies in two cases:
|
|
192
|
+
// 1. Within _processModule. In that case, we always mutate a new
|
|
193
|
+
// module and set a new reference in this.dependencies.
|
|
194
|
+
// 2. During _releaseModule, when recursively removing
|
|
195
|
+
// dependencies. In that case, we immediately discard the module
|
|
196
|
+
// object.
|
|
197
|
+
// TODO: Refactor for more explicit immutability
|
|
198
|
+
newModule !== originalModule ||
|
|
199
|
+
transfromOutputMayDiffer(newModule, originalModule) ||
|
|
200
|
+
!allDependenciesEqual(newModule, originalModule)
|
|
201
|
+
) {
|
|
202
|
+
modified.set(path, newModule);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
158
205
|
}
|
|
159
206
|
}
|
|
160
207
|
return {
|
|
@@ -203,6 +250,7 @@ class Graph {
|
|
|
203
250
|
}
|
|
204
251
|
async _processModule(path, delta, options) {
|
|
205
252
|
const resolvedContext = this.#resolvedContexts.get(path);
|
|
253
|
+
|
|
206
254
|
// Transform the file via the given option.
|
|
207
255
|
// TODO: Unbind the transform method from options
|
|
208
256
|
const result = await options.transform(path, resolvedContext);
|
|
@@ -214,47 +262,63 @@ class Graph {
|
|
|
214
262
|
result.dependencies,
|
|
215
263
|
options
|
|
216
264
|
);
|
|
217
|
-
const previousModule = this.dependencies.get(path)
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
...previousModule,
|
|
265
|
+
const previousModule = this.dependencies.get(path);
|
|
266
|
+
const previousDependencies = previousModule?.dependencies ?? new Map();
|
|
267
|
+
const nextModule = {
|
|
268
|
+
...(previousModule ?? {
|
|
269
|
+
inverseDependencies:
|
|
270
|
+
delta.earlyInverseDependencies.get(path) ??
|
|
271
|
+
new _CountingSet.default(),
|
|
272
|
+
path,
|
|
273
|
+
}),
|
|
227
274
|
dependencies: new Map(previousDependencies),
|
|
228
275
|
getSource: result.getSource,
|
|
229
276
|
output: result.output,
|
|
277
|
+
unstable_transformResultKey: result.unstable_transformResultKey,
|
|
230
278
|
};
|
|
231
|
-
|
|
279
|
+
|
|
280
|
+
// Update the module information.
|
|
281
|
+
this.dependencies.set(nextModule.path, nextModule);
|
|
232
282
|
|
|
233
283
|
// Diff dependencies (1/2): remove dependencies that have changed or been removed.
|
|
284
|
+
let dependenciesRemoved = false;
|
|
234
285
|
for (const [key, prevDependency] of previousDependencies) {
|
|
235
286
|
const curDependency = currentDependencies.get(key);
|
|
236
287
|
if (
|
|
237
288
|
!curDependency ||
|
|
238
289
|
!dependenciesEqual(prevDependency, curDependency, options)
|
|
239
290
|
) {
|
|
240
|
-
|
|
291
|
+
dependenciesRemoved = true;
|
|
292
|
+
this._removeDependency(nextModule, key, prevDependency, delta, options);
|
|
241
293
|
}
|
|
242
294
|
}
|
|
243
295
|
|
|
244
296
|
// Diff dependencies (2/2): add dependencies that have changed or been added.
|
|
245
|
-
const
|
|
297
|
+
const addDependencyPromises = [];
|
|
246
298
|
for (const [key, curDependency] of currentDependencies) {
|
|
247
299
|
const prevDependency = previousDependencies.get(key);
|
|
248
300
|
if (
|
|
249
301
|
!prevDependency ||
|
|
250
302
|
!dependenciesEqual(prevDependency, curDependency, options)
|
|
251
303
|
) {
|
|
252
|
-
|
|
253
|
-
this._addDependency(
|
|
304
|
+
addDependencyPromises.push(
|
|
305
|
+
this._addDependency(nextModule, key, curDependency, delta, options)
|
|
254
306
|
);
|
|
255
307
|
}
|
|
256
308
|
}
|
|
257
|
-
|
|
309
|
+
if (
|
|
310
|
+
previousModule &&
|
|
311
|
+
!transfromOutputMayDiffer(previousModule, nextModule) &&
|
|
312
|
+
!dependenciesRemoved &&
|
|
313
|
+
addDependencyPromises.length === 0
|
|
314
|
+
) {
|
|
315
|
+
// We have not operated on nextModule, so restore previousModule
|
|
316
|
+
// to aid diffing.
|
|
317
|
+
this.dependencies.set(previousModule.path, previousModule);
|
|
318
|
+
return previousModule;
|
|
319
|
+
}
|
|
320
|
+
delta.modified.add(path);
|
|
321
|
+
await Promise.all(addDependencyPromises);
|
|
258
322
|
|
|
259
323
|
// Replace dependencies with the correctly-ordered version. As long as all
|
|
260
324
|
// the above promises have resolved, this will be the same map but without
|
|
@@ -264,11 +328,11 @@ class Graph {
|
|
|
264
328
|
|
|
265
329
|
// Catch obvious errors with a cheap assertion.
|
|
266
330
|
invariant(
|
|
267
|
-
|
|
331
|
+
nextModule.dependencies.size === currentDependencies.size,
|
|
268
332
|
"Failed to add the correct dependencies"
|
|
269
333
|
);
|
|
270
|
-
|
|
271
|
-
return
|
|
334
|
+
nextModule.dependencies = currentDependencies;
|
|
335
|
+
return nextModule;
|
|
272
336
|
}
|
|
273
337
|
async _addDependency(parentModule, key, dependency, delta, options) {
|
|
274
338
|
const path = dependency.absolutePath;
|
|
@@ -659,6 +723,18 @@ function dependenciesEqual(a, b, options) {
|
|
|
659
723
|
contextParamsEqual(a.data.data.contextParams, b.data.data.contextParams))
|
|
660
724
|
);
|
|
661
725
|
}
|
|
726
|
+
function allDependenciesEqual(a, b, options) {
|
|
727
|
+
if (a.dependencies.size !== b.dependencies.size) {
|
|
728
|
+
return false;
|
|
729
|
+
}
|
|
730
|
+
for (const [key, depA] of a.dependencies) {
|
|
731
|
+
const depB = b.dependencies.get(key);
|
|
732
|
+
if (!depB || !dependenciesEqual(depA, depB, options)) {
|
|
733
|
+
return false;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
return true;
|
|
737
|
+
}
|
|
662
738
|
function contextParamsEqual(a, b) {
|
|
663
739
|
return (
|
|
664
740
|
a === b ||
|
|
@@ -671,3 +747,9 @@ function contextParamsEqual(a, b) {
|
|
|
671
747
|
a.mode === b.mode)
|
|
672
748
|
);
|
|
673
749
|
}
|
|
750
|
+
function transfromOutputMayDiffer(a, b) {
|
|
751
|
+
return (
|
|
752
|
+
a.unstable_transformResultKey == null ||
|
|
753
|
+
a.unstable_transformResultKey !== b.unstable_transformResultKey
|
|
754
|
+
);
|
|
755
|
+
}
|