2019-10-06 12:36:15 +00:00
|
|
|
/*eslint-env node*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
const fs = require( 'fs' );
|
2020-03-26 12:39:54 +00:00
|
|
|
const path = require( 'path' );
|
2019-10-06 12:36:15 +00:00
|
|
|
|
|
|
|
// Note, this has some inspiration from the AliasPlugin and its implementation
|
|
|
|
// @see https://github.com/webpack/enhanced-resolve/blob/v4.1.0/lib/AliasPlugin.js
|
|
|
|
|
|
|
|
module.exports = class FallbackModuleDirectoryWebpackPlugin {
|
|
|
|
constructor( search, replacement, alias ) {
|
|
|
|
this.search = search;
|
|
|
|
this.replacement = replacement;
|
|
|
|
this.alias = this.parseAlias( alias );
|
|
|
|
this.hooks = [
|
|
|
|
[ 'described-resolve', 'resolve' ],
|
|
|
|
[ 'file', 'resolve' ],
|
|
|
|
];
|
|
|
|
this.applyFallback = this.applyFallback.bind( this );
|
|
|
|
this.doApply = this.doApply.bind( this );
|
|
|
|
}
|
|
|
|
|
|
|
|
parseAlias( alias ) {
|
|
|
|
if ( typeof alias === 'object' && ! Array.isArray( alias ) ) {
|
|
|
|
alias = Object.keys( alias ).map( ( key ) => {
|
|
|
|
let onlyModule = false;
|
|
|
|
let obj = alias[ key ];
|
|
|
|
if ( /\$$/.test( key ) ) {
|
|
|
|
onlyModule = true;
|
|
|
|
key = key.substr( 0, key.length - 1 );
|
|
|
|
}
|
|
|
|
if ( typeof obj === 'string' ) {
|
|
|
|
obj = {
|
|
|
|
alias: obj,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
obj = Object.assign(
|
|
|
|
{
|
|
|
|
name: key,
|
|
|
|
onlyModule,
|
|
|
|
},
|
|
|
|
obj
|
|
|
|
);
|
|
|
|
return obj;
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
return alias;
|
|
|
|
}
|
|
|
|
|
2020-03-26 12:39:54 +00:00
|
|
|
getPathWithExtension( pathString ) {
|
|
|
|
if ( ! Boolean( path.extname( pathString ) ) ) {
|
|
|
|
return pathString + '.js';
|
2019-10-06 12:36:15 +00:00
|
|
|
}
|
2020-03-26 12:39:54 +00:00
|
|
|
return pathString;
|
|
|
|
}
|
|
|
|
|
|
|
|
applyFallback( pathString ) {
|
|
|
|
if (
|
|
|
|
pathString.includes( this.search ) &&
|
|
|
|
! fs.existsSync( pathString ) &&
|
|
|
|
! fs.existsSync( this.getPathWithExtension( pathString ) )
|
|
|
|
) {
|
|
|
|
return pathString.replace( this.search, this.replacement );
|
|
|
|
}
|
|
|
|
return pathString;
|
2019-10-06 12:36:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
doApply( resolver, source, target, alias ) {
|
|
|
|
resolver
|
|
|
|
.getHook( source )
|
|
|
|
.tapAsync(
|
|
|
|
'FallbackModuleDirectoryWebpackPlugin',
|
|
|
|
( request, resolveContext, callback ) => {
|
|
|
|
const innerRequest = request.request || request.path;
|
|
|
|
|
|
|
|
if ( ! innerRequest ) return callback();
|
|
|
|
|
|
|
|
for ( const item of alias ) {
|
|
|
|
if (
|
|
|
|
innerRequest === item.name ||
|
|
|
|
( ! item.onlyModule &&
|
|
|
|
innerRequest.startsWith( item.name + '/' ) )
|
|
|
|
) {
|
|
|
|
if (
|
|
|
|
innerRequest !== item.alias &&
|
|
|
|
! innerRequest.startsWith( item.alias + '/' )
|
|
|
|
) {
|
|
|
|
const newRequestStr = this.applyFallback(
|
|
|
|
item.alias +
|
|
|
|
innerRequest.substr( item.name.length )
|
|
|
|
);
|
|
|
|
const obj = {
|
|
|
|
...request,
|
|
|
|
request: newRequestStr,
|
|
|
|
};
|
|
|
|
return resolver.doResolve(
|
|
|
|
target,
|
|
|
|
obj,
|
2020-03-26 12:39:54 +00:00
|
|
|
`aliased with mapping '${ item.name }' to '${ newRequestStr }'`,
|
2019-10-06 12:36:15 +00:00
|
|
|
resolveContext,
|
|
|
|
( err, result ) => {
|
|
|
|
if ( err ) return callback( err );
|
|
|
|
|
|
|
|
// Don't allow other aliasing or raw request
|
|
|
|
if ( result === undefined ) {
|
|
|
|
return callback( null, null );
|
|
|
|
}
|
|
|
|
callback( null, result );
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return callback();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
apply( resolver ) {
|
|
|
|
const alias = this.alias;
|
|
|
|
this.hooks.forEach( ( [ source, target ] ) => {
|
|
|
|
target = resolver.ensureHook( target );
|
|
|
|
this.doApply( resolver, source, target, alias );
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
};
|