"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createBabelLoaderFromEnvironment = void 0; const core_1 = require("@babel/core"); const paths_1 = require("@expo/config/paths"); const chalk_1 = __importDefault(require("chalk")); const fs_extra_1 = __importDefault(require("fs-extra")); const getenv_1 = require("getenv"); const path_1 = __importDefault(require("path")); const resolve_from_1 = __importDefault(require("resolve-from")); const env_1 = require("../env"); // Source maps are resource heavy and can cause out of memory issue for large source files. const shouldUseSourceMap = (0, getenv_1.boolish)('GENERATE_SOURCEMAP', true); const getModule = (name) => path_1.default.join('node_modules', name); // Only compile files from the react ecosystem. const includeModulesThatContainPaths = [ getModule('react-native'), getModule('react-navigation'), getModule('expo'), getModule('unimodules'), getModule('@react'), getModule('@expo'), getModule('@use-expo'), getModule('@unimodules'), getModule('native-base'), getModule('styled-components'), ]; const excludedRootPaths = [ '/node_modules', '/bower_components', '/.expo/', // Prevent transpiling webpack generated files. '(webpack)', ]; const parsedPackageNames = []; // TODO: Bacon: Support internal packages. ex: react/fbjs function packageNameFromPath(inputPath) { const modules = inputPath.split('node_modules/'); const libAndFile = modules.pop(); if (!libAndFile) return null; if (libAndFile.charAt(0) === '@') { const [org, lib] = libAndFile.split('/'); return org + '/' + lib; } else { const components = libAndFile.split('/'); const first = components.shift(); return first || null; } } function logPackage(packageName) { if (!parsedPackageNames.includes(packageName)) { parsedPackageNames.push(packageName); console.log(chalk_1.default.cyan('\nCompiling module: ' + chalk_1.default.bold(packageName))); } } function ensureRoot(possibleProjectRoot) { if (typeof possibleProjectRoot === 'string') { return path_1.default.resolve(possibleProjectRoot); } return (0, paths_1.getPossibleProjectRoot)(); } function generateCacheIdentifier(projectRoot, version = '1') { const filename = path_1.default.join(projectRoot, 'foobar.js'); const cacheKey = `babel-cache-${version}-`; const partial = (0, core_1.loadPartialConfig)({ filename, cwd: projectRoot, sourceFileName: filename, }); return `${cacheKey}${JSON.stringify(partial.options)}`; } /** * Creates a Rule for loading Application code and packages from the Expo ecosystem. * This method attempts to recreate how Metro loads ES modules in the `node_modules` folder. * * @param env * @internal */ function createBabelLoaderFromEnvironment(env) { var _a; const mode = (0, env_1.getMode)(env); const locations = env.locations || (0, env_1.getPaths)(env.projectRoot, env); const appConfig = env.config || (0, env_1.getConfig)(env); const { build = {} } = appConfig.web; const { babel = {} } = build; return createBabelLoader({ projectRoot: locations.root, mode, platform: env.platform, babelProjectRoot: babel.root || locations.root, verbose: babel.verbose, include: [...(babel.include || []), ...(((_a = env.babel) === null || _a === void 0 ? void 0 : _a.dangerouslyAddModulePathsToTranspile) || [])], use: babel.use, }); } exports.createBabelLoaderFromEnvironment = createBabelLoaderFromEnvironment; /** * A complex babel loader which uses the project's `babel.config.js` * to resolve all of the Unimodules which are shipped as ES modules (early 2019). * @category loaders */ function createBabelLoader({ /** * The webpack mode: `"production" | "development"` */ mode, projectRoot: inputProjectRoot, babelProjectRoot, include = [], verbose, platform = 'web', useCustom, ...options } = {}) { const ensuredProjectRoot = ensureRoot(babelProjectRoot); const modules = [...includeModulesThatContainPaths, ...include]; const customUse = options.use || {}; const customUseOptions = customUse.options || {}; const isProduction = mode === 'production'; const projectRoot = inputProjectRoot || (0, paths_1.getPossibleProjectRoot)(); let presetOptions = { // Explicitly use babel.config.js instead of .babelrc babelrc: false, // Attempt to use local babel.config.js file for compiling project. configFile: true, }; if (!fs_extra_1.default.existsSync(path_1.default.join(projectRoot, 'babel.config.js')) && !fs_extra_1.default.existsSync(path_1.default.join(projectRoot, '.babelrc'))) { // If no babel config exists then fallback on the default `babel-preset-expo` // which is installed with `expo`. const modulePath = resolve_from_1.default.silent(projectRoot, 'babel-preset-expo'); if (modulePath) { presetOptions = { babelrc: false, configFile: false, presets: [modulePath], }; } else { console.log(chalk_1.default.yellow('\u203A Webpack failed to locate a valid Babel config')); } } presetOptions = { ...presetOptions, ...(customUseOptions || {}), sourceType: 'unambiguous', root: ensuredProjectRoot, compact: isProduction, // Babel sourcemaps are needed for debugging into node_modules // code. Without the options below, debuggers like VSCode // show incorrect code and set breakpoints on the wrong lines. sourceMaps: shouldUseSourceMap, inputSourceMap: shouldUseSourceMap, }; let cacheIdentifier = customUseOptions.cacheIdentifier; if (!cacheIdentifier) { try { cacheIdentifier = generateCacheIdentifier(ensuredProjectRoot); } catch (error) { console.log(chalk_1.default.black.bgRed(`The project's Babel config is invalid: ${error.message}`)); throw error; } } presetOptions.cacheIdentifier = cacheIdentifier; presetOptions.cacheCompression = false; presetOptions.cacheDirectory = customUseOptions.cacheDirectory || path_1.default.join(ensuredProjectRoot, '.expo', platform, 'cache', mode || 'development', 'babel-loader'); presetOptions.caller = { __dangerous_rule_id: 'expo-babel-loader', bundler: 'webpack', platform, mode, }; return { test: /\.(mjs|[jt]sx?)$/, // Can only clobber test // Prevent clobbering the `include` and `use` values. ...options, include(inputPath) { for (const possibleModule of modules) { if (inputPath.includes(path_1.default.normalize(possibleModule))) { if (verbose) { const packageName = packageNameFromPath(inputPath); if (packageName) logPackage(packageName); } return true; } } // Is inside the project and is not one of designated modules if (inputPath.includes(ensuredProjectRoot)) { for (const excluded of excludedRootPaths) { if (inputPath.includes(path_1.default.normalize(excluded))) { return false; } } return true; } return false; }, use: { ...customUse, loader: require.resolve('babel-loader'), options: presetOptions, }, }; } exports.default = createBabelLoader; //# sourceMappingURL=createBabelLoader.js.map