Skip to content

Commit 036ea36

Browse files
huntiefacebook-github-bot
authored andcommitted
Add DeltaCalculator graph invalidation for package exports (experimental)
Summary: Implements invalidation of dependencies (marks all graphs as dirty) whenever a `package.json` file is changed. The reasoning for this is that: - A package.json update that changes `"exports"` can change resolutions by entirely swapping out modules. - "Phantom dependencies" can exist when an `"exports"` subpath redirects an apparent subpath to another target file. If `"exports"` is updated to remove this mapping, any file(s) at the apparent subpath would need to be watched. **This is not a final approach, but is acceptable while the Package Exports feature is `unstable`**. Changelog: [Internal] Reviewed By: robhogan Differential Revision: D43394192 fbshipit-source-id: 0ba2c393d8e2b78144c5991d5f48eadd6c47204a
1 parent f0119a4 commit 036ea36

10 files changed

Lines changed: 212 additions & 102 deletions

File tree

packages/metro/src/DeltaBundler/DeltaCalculator.js

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
'use strict';
1313

14+
import path from 'path';
1415
import {Graph} from './Graph';
1516
import type {DeltaResult, Options} from './types.flow';
1617
import type {RootPerfLogger} from 'metro-config';
@@ -33,7 +34,7 @@ class DeltaCalculator<T> extends EventEmitter {
3334
_deletedFiles: Set<string> = new Set();
3435
_modifiedFiles: Set<string> = new Set();
3536
_addedFiles: Set<string> = new Set();
36-
_hasSymlinkChanges = false;
37+
_requiresReset = false;
3738

3839
_graph: Graph<T>;
3940

@@ -104,13 +105,13 @@ class DeltaCalculator<T> extends EventEmitter {
104105
this._deletedFiles = new Set();
105106
const addedFiles = this._addedFiles;
106107
this._addedFiles = new Set();
107-
const hasSymlinkChanges = this._hasSymlinkChanges;
108-
this._hasSymlinkChanges = false;
108+
const requiresReset = this._requiresReset;
109+
this._requiresReset = false;
109110

110-
// Revisit all files if changes include symlinks - resolutions may be
111+
// Revisit all files if changes require a graph reset - resolutions may be
111112
// invalidated but we don't yet know which. This should be optimized in the
112113
// future.
113-
if (hasSymlinkChanges) {
114+
if (requiresReset) {
114115
const markModified = (file: string) => {
115116
if (!addedFiles.has(file) && !deletedFiles.has(file)) {
116117
modifiedFiles.add(file);
@@ -207,10 +208,13 @@ class DeltaCalculator<T> extends EventEmitter {
207208
logger: ?RootPerfLogger,
208209
): mixed => {
209210
debug('Handling %s: %s (type: %s)', type, filePath, metadata.type);
210-
if (metadata.type === 'l') {
211-
this._hasSymlinkChanges = true;
211+
if (
212+
metadata.type === 'l' ||
213+
(this._options.unstable_enablePackageExports &&
214+
filePath.endsWith(path.sep + 'package.json'))
215+
) {
216+
this._requiresReset = true;
212217
this.emit('change', {logger});
213-
return;
214218
}
215219
let state: void | 'deleted' | 'modified' | 'added';
216220
if (this._deletedFiles.has(filePath)) {
@@ -281,13 +285,13 @@ class DeltaCalculator<T> extends EventEmitter {
281285
// If a file has been deleted, we want to invalidate any other file that
282286
// depends on it, so we can process it and correctly return an error.
283287
deletedFiles.forEach((filePath: string) => {
284-
for (const path of this._graph.getModifiedModulesForDeletedPath(
288+
for (const modifiedModulePath of this._graph.getModifiedModulesForDeletedPath(
285289
filePath,
286290
)) {
287291
// Only mark the inverse dependency as modified if it's not already
288292
// marked as deleted (in that case we can just ignore it).
289-
if (!deletedFiles.has(path)) {
290-
modifiedFiles.add(path);
293+
if (!deletedFiles.has(modifiedModulePath)) {
294+
modifiedFiles.add(modifiedModulePath);
291295
}
292296
}
293297
});

packages/metro/src/DeltaBundler/__tests__/DeltaBundler-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ describe('DeltaBundler', () => {
3030

3131
const options = {
3232
unstable_allowRequireContext: false,
33+
unstable_enablePackageExports: false,
3334
experimentalImportBundleSupport: false,
3435
onProgress: null,
3536
resolve: (from: string, to: string) => {

packages/metro/src/DeltaBundler/__tests__/DeltaCalculator-context-test.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ describe('DeltaCalculator + require.context', () => {
3838

3939
const options = {
4040
unstable_allowRequireContext: true,
41+
unstable_enablePackageExports: false,
4142
experimentalImportBundleSupport: false,
4243
onProgress: null,
4344
resolve: (from: string, to: string) => {

0 commit comments

Comments
 (0)