fusion-cli
Version:
89 lines (78 loc) • 3.38 kB
JavaScript
// @noflow
/* eslint-env node */
const fs = require('fs');
const {ResolverFactory} = require('enhanced-resolve');
const extensions = ['.js', '.json', '.ts', '.tsx', '.node'];
const nodeResolver = ResolverFactory.createResolver({
extensions,
fileSystem: fs,
useSyncFileSystemCalls: true,
mainFields: ['main'],
aliasFields: ['es2015', 'es2017'],
conditionNames: ['node', 'require'],
});
const browserResolver = ResolverFactory.createResolver({
extensions,
fileSystem: fs,
useSyncFileSystemCalls: true,
mainFields: ['main'],
aliasFields: ['browser', 'es2015', 'es2017'],
conditionNames: ['node', 'require'],
});
// The es5-ext package has files within a '#' directory. Ex. es5-ext/string/#/contains
//
// Enhanced-resolve will escape '#' characters by prefixing with a null terminator '\0'
// https://github.com/webpack/enhanced-resolve/pull/255/files
//
// Webpack will then find instances of this escape pattern and convert back to '#'
// this commit below shows how webpack is transitioning from regex replace to a new
// enhanced-resolve feature that provides an unescaped path.
// https://github.com/webpack/webpack/commit/0197867237cd1ef4c1e13d5fcafc71f4585bff9d
//
// This feature is only available on the async resolve method on Resolver.
// https://github.com/webpack/enhanced-resolve/blob/4b16e4c7ee9fc79f6a544a2018baaedb2f7a340f/lib/Resolver.js#L237
//
// Because this file uses the resolveSync method, the unescaped path is not available,
// it will take the webpack's original approach of regex replace.
function unescapePathFragment(resolverResult) {
if (typeof resolverResult === 'string') {
return resolverResult.replace(/\0/g, '');
}
return resolverResult;
}
module.exports = function createResolver({browser = false}) {
return function enhancedResolve(modulePath, opts) {
try {
if (browser === true) {
let browserResult = browserResolver.resolveSync(
{},
opts.basedir,
modulePath
);
if (browserResult !== false) {
return unescapePathFragment(browserResult);
}
// Fallback to non-browser field if enhanced-resolve produces `false`.
// Some packages (e.g. object-inspect) use falsy browser field values to
// indicate that no browser version exists.
// This isn't handled by enhanced-resolve.
// So we simply fall back to resolution without browser field in this case
}
const nodeResult = nodeResolver.resolveSync({}, opts.basedir, modulePath);
return unescapePathFragment(nodeResult);
} catch (err) {
// Upon failure to resolve, enhanced-resolve throws with a different
// error message than native Node and no error.code property.
// This breaks the heuristics of the "bindings" npm library used to
// locate native code by successively attempting to require potential paths
// Jest uses the resolver for overloading the native resolution used by
// the "bindings" libary.
// So we need to add an error code that "bindings" will recognize,
// otherwise it will just stop at the first path instead of trying
// all the possible paths
// https://github.com/TooTallNate/node-bindings/blob/c8033dcfc04c34397384e23f7399a30e6c13830d/bindings.js#L119
err.code = 'MODULE_NOT_FOUND';
throw err;
}
};
};