mirror of https://github.com/status-im/metro.git
metro-bundler: Server: report ambiguous module resolution better
Reviewed By: mjesun Differential Revision: D5444129 fbshipit-source-id: 311d20c7ee4c00ec2d4c52d83bd6c5a94221b552
This commit is contained in:
parent
3cbc2f3ec4
commit
3cc83da403
|
@ -26,6 +26,10 @@ const path = require('path');
|
||||||
const symbolicate = require('./symbolicate');
|
const symbolicate = require('./symbolicate');
|
||||||
const url = require('url');
|
const url = require('url');
|
||||||
|
|
||||||
|
const {
|
||||||
|
AmbiguousModuleResolutionError,
|
||||||
|
} = require('../node-haste/DependencyGraph/ResolutionRequest');
|
||||||
|
|
||||||
import type Module, {HasteImpl} from '../node-haste/Module';
|
import type Module, {HasteImpl} from '../node-haste/Module';
|
||||||
import type {IncomingMessage, ServerResponse} from 'http';
|
import type {IncomingMessage, ServerResponse} from 'http';
|
||||||
import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse';
|
import type ResolutionResponse from '../node-haste/DependencyGraph/ResolutionResponse';
|
||||||
|
@ -890,6 +894,22 @@ class Server {
|
||||||
'Content-Type': 'application/json; charset=UTF-8',
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (error instanceof AmbiguousModuleResolutionError) {
|
||||||
|
const he = error.hasteError;
|
||||||
|
const message =
|
||||||
|
"Ambiguous resolution: module '" +
|
||||||
|
`${error.fromModulePath}\' tries to require \'${he.hasteName}\', but ` +
|
||||||
|
`there are several files providing this module. You can delete or ` +
|
||||||
|
'fix them: \n\n' +
|
||||||
|
Object.keys(he.duplicatesSet)
|
||||||
|
.sort()
|
||||||
|
.map(dupFilePath => `${dupFilePath}`)
|
||||||
|
.join('\n\n');
|
||||||
|
res.end(JSON.stringify({message, errors: [{description: message}]}));
|
||||||
|
this._reporter.update({error, type: 'bundling_error'});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
error instanceof Error &&
|
error instanceof Error &&
|
||||||
(error.type === 'TransformError' ||
|
(error.type === 'TransformError' ||
|
||||||
|
|
|
@ -18,6 +18,10 @@ const reporting = require('./reporting');
|
||||||
const throttle = require('lodash/throttle');
|
const throttle = require('lodash/throttle');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
|
|
||||||
|
const {
|
||||||
|
AmbiguousModuleResolutionError,
|
||||||
|
} = require('../node-haste/DependencyGraph/ResolutionRequest');
|
||||||
|
|
||||||
import type Transformer from '../JSTransformer';
|
import type Transformer from '../JSTransformer';
|
||||||
import type {BundleOptions} from '../Server';
|
import type {BundleOptions} from '../Server';
|
||||||
import type Terminal from './Terminal';
|
import type Terminal from './Terminal';
|
||||||
|
@ -250,6 +254,21 @@ class TerminalReporter {
|
||||||
* is not actionable to end users.
|
* is not actionable to end users.
|
||||||
*/
|
*/
|
||||||
_logBundlingError(error: Error | Transformer.TransformError) {
|
_logBundlingError(error: Error | Transformer.TransformError) {
|
||||||
|
if (error instanceof AmbiguousModuleResolutionError) {
|
||||||
|
const he = error.hasteError;
|
||||||
|
const message =
|
||||||
|
'ambiguous resolution: module `' +
|
||||||
|
`${error.fromModulePath}\` tries to require \`${he.hasteName}\`, but ` +
|
||||||
|
`there are several files providing this module. You can delete or ` +
|
||||||
|
'fix them: \n\n' +
|
||||||
|
Object.keys(he.duplicatesSet)
|
||||||
|
.sort()
|
||||||
|
.map(dupFilePath => ` * \`${dupFilePath}\`\n`)
|
||||||
|
.join('');
|
||||||
|
this._logBundlingErrorMessage(message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//$FlowFixMe T19379628
|
//$FlowFixMe T19379628
|
||||||
let message = error.message;
|
let message = error.message;
|
||||||
//$FlowFixMe T19379628
|
//$FlowFixMe T19379628
|
||||||
|
@ -264,7 +283,11 @@ class TerminalReporter {
|
||||||
str += '\n' + error.snippet;
|
str += '\n' + error.snippet;
|
||||||
}
|
}
|
||||||
|
|
||||||
reporting.logError(this.terminal, 'bundling failed: %s', str);
|
this._logBundlingErrorMessage(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logBundlingErrorMessage(message: string) {
|
||||||
|
reporting.logError(this.terminal, 'bundling failed: %s', message);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logWorkerChunk(origin: 'stdout' | 'stderr', chunk: string) {
|
_logWorkerChunk(origin: 'stdout' | 'stderr', chunk: string) {
|
||||||
|
|
|
@ -20,6 +20,10 @@ const debug = require('debug')('Metro:DependencyGraph');
|
||||||
const isAbsolutePath = require('absolute-path');
|
const isAbsolutePath = require('absolute-path');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const {
|
||||||
|
DuplicateHasteCandidatesError,
|
||||||
|
} = require('jest-haste-map/build/module_map');
|
||||||
|
|
||||||
import type DependencyGraphHelpers from './DependencyGraphHelpers';
|
import type DependencyGraphHelpers from './DependencyGraphHelpers';
|
||||||
import type ResolutionResponse from './ResolutionResponse';
|
import type ResolutionResponse from './ResolutionResponse';
|
||||||
import type {Options as TransformWorkerOptions} from '../../JSTransformer/worker';
|
import type {Options as TransformWorkerOptions} from '../../JSTransformer/worker';
|
||||||
|
@ -68,6 +72,7 @@ type Options<TModule, TPackage> = {|
|
||||||
class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
|
class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
|
||||||
_immediateResolutionCache: {[key: string]: TModule};
|
_immediateResolutionCache: {[key: string]: TModule};
|
||||||
_options: Options<TModule, TPackage>;
|
_options: Options<TModule, TPackage>;
|
||||||
|
static AmbiguousModuleResolutionError: Class<AmbiguousModuleResolutionError>;
|
||||||
|
|
||||||
constructor(options: Options<TModule, TPackage>) {
|
constructor(options: Options<TModule, TPackage>) {
|
||||||
this._options = options;
|
this._options = options;
|
||||||
|
@ -95,8 +100,7 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
|
||||||
!(isRelativeImport(toModuleName) || isAbsolutePath(toModuleName))
|
!(isRelativeImport(toModuleName) || isAbsolutePath(toModuleName))
|
||||||
) {
|
) {
|
||||||
const result = ModuleResolution.tryResolveSync(
|
const result = ModuleResolution.tryResolveSync(
|
||||||
() =>
|
() => this._resolveHasteDependency(fromModule, toModuleName, platform),
|
||||||
resolver.resolveHasteDependency(fromModule, toModuleName, platform),
|
|
||||||
() =>
|
() =>
|
||||||
resolver.resolveNodeDependency(fromModule, toModuleName, platform),
|
resolver.resolveNodeDependency(fromModule, toModuleName, platform),
|
||||||
);
|
);
|
||||||
|
@ -108,6 +112,22 @@ class ResolutionRequest<TModule: Moduleish, TPackage: Packageish> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_resolveHasteDependency(
|
||||||
|
fromModule: TModule,
|
||||||
|
toModuleName: string,
|
||||||
|
platform: string | null,
|
||||||
|
): TModule {
|
||||||
|
const rs = this._options.moduleResolver;
|
||||||
|
try {
|
||||||
|
return rs.resolveHasteDependency(fromModule, toModuleName, platform);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof DuplicateHasteCandidatesError) {
|
||||||
|
throw new AmbiguousModuleResolutionError(fromModule.path, error);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resolveModuleDependencies(
|
resolveModuleDependencies(
|
||||||
module: TModule,
|
module: TModule,
|
||||||
dependencyNames: $ReadOnlyArray<string>,
|
dependencyNames: $ReadOnlyArray<string>,
|
||||||
|
@ -350,4 +370,20 @@ function resolutionHash(modulePath, depName) {
|
||||||
return `${path.resolve(modulePath)}:${depName}`;
|
return `${path.resolve(modulePath)}:${depName}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AmbiguousModuleResolutionError extends Error {
|
||||||
|
fromModulePath: string;
|
||||||
|
hasteError: DuplicateHasteCandidatesError;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
fromModulePath: string,
|
||||||
|
hasteError: DuplicateHasteCandidatesError,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.fromModulePath = fromModulePath;
|
||||||
|
this.hasteError = hasteError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolutionRequest.AmbiguousModuleResolutionError = AmbiguousModuleResolutionError;
|
||||||
|
|
||||||
module.exports = ResolutionRequest;
|
module.exports = ResolutionRequest;
|
||||||
|
|
|
@ -5295,9 +5295,9 @@ describe('DependencyGraph', function() {
|
||||||
throw new Error('expected `getOrderedDependenciesAsJSON` to fail');
|
throw new Error('expected `getOrderedDependenciesAsJSON` to fail');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const {
|
const {
|
||||||
DuplicateHasteCandidatesError,
|
AmbiguousModuleResolutionError,
|
||||||
} = require('jest-haste-map/build/module_map');
|
} = require('../DependencyGraph/ResolutionRequest');
|
||||||
if (!(error instanceof DuplicateHasteCandidatesError)) {
|
if (!(error instanceof AmbiguousModuleResolutionError)) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
expect(console.warn).toBeCalled();
|
expect(console.warn).toBeCalled();
|
||||||
|
|
Loading…
Reference in New Issue