You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
7.9 KiB

"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