UNPKG

babel-plugin-webpack-alias

Version:
252 lines (189 loc) 10.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); exports.default = function (_ref) { let t = _ref.types; return { visitor: { CallExpression(path, _ref2) { let filename = _ref2.file.opts.filename; var _ref2$opts = _ref2.opts; _ref2$opts = _ref2$opts === undefined ? {} : _ref2$opts; let configPath = _ref2$opts.config; var _ref2$opts$findConfig = _ref2$opts.findConfig; let findConfig = _ref2$opts$findConfig === undefined ? false : _ref2$opts$findConfig; var _ref2$opts$noOutputEx = _ref2$opts.noOutputExtension; let noOutputExtension = _ref2$opts$noOutputEx === undefined ? false : _ref2$opts$noOutputEx; const configPaths = configPath ? [configPath].concat(DEFAULT_CONFIG_NAMES) : DEFAULT_CONFIG_NAMES; // Get webpack config const confPath = getConfigPath(configPaths, findConfig); // If the config comes back as null, we didn't find it, so throw an exception. if (!confPath) { throw new Error(`Cannot find any of these configuration files: ${ configPaths.join(', ') }`); } // Because of babel-register, babel is actually run on webpack config files using themselves // as config, leading to odd errors if (filename === (0, _path.resolve)(confPath)) return; // Require the config let conf = require(confPath); // if the object is empty, we might be in a dependency of the config - bail without warning if (!Object.keys(conf).length) { return; } // In the case the webpack config is an es6 config, we need to get the default if (conf && conf.__esModule && conf.default) { conf = conf.default; } // exit if there's no alias config and the config is not an array if (!(conf.resolve && conf.resolve.alias) && !Array.isArray(conf)) { throw new Error('The resolved config file doesn\'t contain a resolve configuration'); } // Get the webpack alias config let aliasConf; let extensionsConf; if (Array.isArray(conf)) { // the exported webpack config is an array ... // (i.e., the project is using webpack's multicompile feature) ... // reduce the configs to a single alias object aliasConf = conf.reduce((prev, curr) => { const next = Object.assign({}, prev); if (curr.resolve && curr.resolve.alias) { Object.assign(next, curr.resolve.alias); } return next; }, {}); // if the object is empty, bail if (!Object.keys(aliasConf).length) { return; } // reduce the configs to a single extensions array extensionsConf = conf.reduce((prev, curr) => { const next = [].concat(prev); if (curr.resolve && curr.resolve.extensions && curr.resolve.extensions.length) { curr.resolve.extensions.forEach(ext => { if (next.indexOf(ext) === -1) { next.push(ext); } }); } return next; }, []); if (!extensionsConf.length) { extensionsConf = null; } } else { // the exported webpack config is a single object... // use it's resolve.alias property aliasConf = conf.resolve.alias; // use it's resolve.extensions property, if available extensionsConf = conf.resolve.extensions && conf.resolve.extensions.length ? conf.resolve.extensions : null; } var _path$node = path.node; const calleeName = _path$node.callee.name, args = _path$node.arguments; // Exit if it's not a require statement if (calleeName !== 'require' || !args.length || !t.isStringLiteral(args[0])) { return; } // Get the path of the StringLiteral var _args = _slicedToArray(args, 1); const filePath = _args[0].value; for (const aliasFrom in aliasConf) { if (aliasConf.hasOwnProperty(aliasFrom)) { let aliasTo = aliasConf[aliasFrom]; const regex = new RegExp(`^${ aliasFrom }(\/|$)`); // If the regex matches, replace by the right config if (regex.test(filePath)) { // notModuleRegExp from https://github.com/webpack/enhanced-resolve/blob/master/lib/Resolver.js const notModuleRegExp = /^\.$|^\.[\\\/]|^\.\.$|^\.\.[\/\\]|^\/|^[A-Z]:[\\\/]/i; const isModule = !notModuleRegExp.test(aliasTo); if (isModule) { path.node.arguments = [(0, _babelTypes.StringLiteral)(aliasTo)]; return; } // If the filepath is not absolute, make it absolute if (!(0, _path.isAbsolute)(aliasTo)) { aliasTo = (0, _path.join)(process.cwd(), aliasTo); } let relativeFilePath = (0, _path.relative)((0, _path.dirname)(filename), aliasTo).split(_path.sep).join('/'); // In case the file path is the root of the alias, need to put a dot to avoid having an absolute path if (relativeFilePath.length === 0) { relativeFilePath = '.'; } let requiredFilePath = filePath.replace(aliasFrom, relativeFilePath); // In the unfortunate case of a file requiring the current directory which is the alias, we need to add // an extra slash if (requiredFilePath === '.') { requiredFilePath = './'; } // In the case of a file requiring a child directory of the current directory, we need to add a dot slash if (['.', '/'].indexOf(requiredFilePath[0]) === -1) { requiredFilePath = `./${ requiredFilePath }`; } // In case the extension option is passed if (extensionsConf && !noOutputExtension) { // Get an absolute path to the file const absoluteRequire = (0, _path.join)(aliasTo, (0, _path.basename)(filePath)); let extension = null; (0, _lodash4.default)(extensionsConf, ext => { if (!ext) return; // If the file with this extension exists set it if (fileExists(absoluteRequire + ext)) { extension = ext; } return extension; }); // Set the extension to the file path, or keep the original one requiredFilePath += extension || ''; } path.node.arguments = [(0, _babelTypes.StringLiteral)(requiredFilePath)]; return; } } } } } }; }; var _path = require('path'); var _fs = require('fs'); var _fs2 = _interopRequireDefault(_fs); var _babelTypes = require('babel-types'); var _lodash = require('lodash.template'); var _lodash2 = _interopRequireDefault(_lodash); var _lodash3 = require('lodash.some'); var _lodash4 = _interopRequireDefault(_lodash3); var _findUp = require('find-up'); var _findUp2 = _interopRequireDefault(_findUp); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const DEFAULT_CONFIG_NAMES = ['webpack.config.js', 'webpack.config.babel.js']; function fileExists(path) { try { return !_fs2.default.accessSync(path, _fs2.default.F_OK); } catch (e) { return false; } } function getConfigPath(configPaths, findConfig) { let conf = null; // Try all config paths and return for the first found one (0, _lodash4.default)(configPaths, configPath => { if (!configPath) return; // Compile config using environment variables const compiledConfigPath = (0, _lodash2.default)(configPath)(process.env); let resolvedConfigPath; if (!findConfig) { // Get webpack config resolvedConfigPath = (0, _path.resolve)(process.cwd(), compiledConfigPath); } else { resolvedConfigPath = _findUp2.default.sync(compiledConfigPath); } if (resolvedConfigPath && fileExists(resolvedConfigPath)) { conf = resolvedConfigPath; } return conf; }); return conf; }