UNPKG

react-native-monorepo-helper

Version:

A helper library that makes React Native development in monorepo projects easier.

485 lines 38.4 kB
import chalk from 'chalk'; import cp from 'child_process'; import fs from 'fs'; import glob from 'glob'; import path from 'path'; import resolve from 'resolve'; export var Metro; (function (Metro) { let ResolutionType; (function (ResolutionType) { ResolutionType["ASSET"] = "asset"; ResolutionType["SOURCE_FILE"] = "sourceFile"; })(ResolutionType = Metro.ResolutionType || (Metro.ResolutionType = {})); })(Metro || (Metro = {})); // --- function tryParseJsonFile(filename) { if (fs.existsSync(filename)) { const jsonFile = fs.readFileSync(filename); const json = JSON.parse(jsonFile.toString()); if (typeof json === 'object') return json; } return undefined; } function readPackageGlobs(globs, options) { const cwd = options.cwd; const ignoredFolders = options.ignoredFolders || [`**/node_modules`]; let results = []; const globbedIgnoredFolders = ignoredFolders .map(ignoredFolder => glob.sync(ignoredFolder, { cwd })) .reduce((accum, elem) => { accum.push(...elem); return accum; }, []); for (const globStr of globs) { if (typeof globStr !== 'string') continue; const roots = glob .sync(`${globStr}/package.json`, { cwd, nodir: true }) .map(root => path.dirname(root)) .filter(root => !globbedIgnoredFolders.some(folder => root.startsWith(folder))); results = results.concat(roots); } return results; } function unique(array) { return array.filter((value, index, self) => self.indexOf(value) === index); } class MetroConfigHelper { constructor(options) { this.mapByFolderFollowingSymlink = (pathname) => { let stat = fs.existsSync(pathname) ? fs.statSync(pathname) : null; if (stat && stat.isSymbolicLink()) { pathname = fs.realpathSync(pathname); stat = fs.existsSync(pathname) ? fs.statSync(pathname) : null; } if (stat && stat.isDirectory()) return pathname; return ''; }; this.filterByNonEmptyString = (pathname) => { return typeof pathname === 'string' && !!pathname; }; options = options || {}; this.logger_ = options.logger || console; this.defaultConfig_ = options.defaultConfig || {}; this.monorepoFinders_ = []; this.projectRoot_ = options.projectRoot; this.watchFolders_ = []; this.watchFolders_ = []; this.typeScript_ = false; this.monorepoFinder(...(options.monorepoFinders || [])); } projectRoot(newProjectRoot) { if (newProjectRoot) { this.projectRoot_ = newProjectRoot; return this; } if (!this.projectRoot_) throw new Error("Project's root folder not set."); return this.projectRoot_; } monorepoFinder(...finder) { this.monorepoFinders_ = this.monorepoFinders_.concat(finder.filter(f => typeof f === 'function')); return this; } findMonorepo() { for (const monorepoFinder of this.monorepoFinders_) { const monorepo = monorepoFinder(this.projectRoot(), this); if (monorepo) return monorepo; } return undefined; } logger(newLogger) { if (newLogger) { this.logger_ = newLogger; return this; } if (!this.logger_) throw new Error("Logger not set."); return this.logger_; } defaultConfig(newDefaultConfig) { if (newDefaultConfig) { this.defaultConfig_ = newDefaultConfig; return this; } if (!this.defaultConfig_) throw new Error("Default config not set."); return this.defaultConfig_; } monorepo(newMonorepoInfo) { if (newMonorepoInfo) { this.monorepo_ = newMonorepoInfo; return this; } else if (!this.monorepo_) { this.monorepo_ = this.findMonorepo(); } if (!this.monorepo_) throw new Error("Monorepo not set."); return this.monorepo_; } typeScript(enabled) { if (enabled === true) { this.typeScript_ = defaultTypeScriptConfig; return this; } else if (typeof enabled === "string") { if (!enabled) throw new Error("Transformer module name cannot be empty."); this.typeScript_ = { ...defaultTypeScriptConfig, transformerModuleName: enabled, }; return this; } else if (typeof enabled === "object" && enabled !== null) { this.typeScript_ = { ...defaultTypeScriptConfig, ...enabled, }; } return this.typeScript_; } watchFolder(...folder) { this.watchFolders_ = this.watchFolders_.concat(folder); return this; } packageRoots() { return this.monorepo().packages.map(packageInfo => packageInfo.root); } watchFolders() { return unique([ this.monorepo().root, ...this.packageRoots(), ...this.watchFolders_, ]); } customResolver(newResolver) { if (newResolver) { this.customResolver_ = newResolver; return this; } else if (!this.customResolver_) { this.customResolver_ = this.createCustomResolver(); } if (!this.customResolver_) throw new Error("Custom resolver not set."); return this.customResolver_; } createCustomResolver() { return (metro, moduleName, platform) => { const context = { metro, moduleName, platform, }; const sourceExts = context.metro.sourceExts; const assetExts = context.metro.assetExts || []; const resolution = this.resolveInProject(context, Metro.ResolutionType.SOURCE_FILE, sourceExts) || this.resolveInProject(context, Metro.ResolutionType.ASSET, assetExts) || null; return resolution; }; } config(newConfig) { if (newConfig) { this.config_ = newConfig; return this; } else if (!this.config_) { this.config_ = this.generate(); } if (!this.config_) throw new Error("Custom resolver not set."); return this.config_; } generate() { const config = { ...this.defaultConfig(), watchFolders: [ ...(this.defaultConfig().watchFolders || []), ...this.watchFolders() .map(this.mapByFolderFollowingSymlink) .filter(this.filterByNonEmptyString), ], resolver: { ...(this.defaultConfig().resolver || {}), resolveRequest: this.customResolver(), }, }; const typeScript = this.typeScript(); if (this.isTypeScriptConfig(typeScript)) { config.getTransformModulePath = config.getTransformModulePath || (() => require.resolve(typeScript.transformerModuleName)); config.sourceExts = [ ...(config.sourceExts || []), ...typeScript.fileExtensions, ]; } return config; } resolveInProject(context, type, extensions) { const originModulePath = context.metro.originModulePath; const moduleName = context.moduleName; const packageFilter = (pkg) => { for (const mainField of context.metro.mainFields || []) { if (typeof pkg[mainField] === 'string') { pkg.main = pkg[mainField]; break; } } return pkg; }; extensions = this.generateComplementaryExtensions(context, extensions); let resolvedName; let originModuleDir; // Expectations: // - originModulePath exists // - originModulePath is an absolute (or completely // resolved, to some degree) path in the filesystem. if (this.isDirectory(originModulePath)) { originModuleDir = originModulePath; } else { originModuleDir = path.dirname(originModulePath); } // For some reason, `resolve` can't resolve relative-path modules... // TODO Use resolve.sync() instead (if possible; if someone understands why/how) if (moduleName.startsWith('./') || moduleName.startsWith('../')) { let basename = path.resolve(originModuleDir, moduleName); if (this.fileModuleExists(basename)) { resolvedName = basename; } else if (this.isDirectory(basename)) { basename = path.resolve(basename, 'index'); } if (!resolvedName) { for (const extension of extensions) { const pathname = `${basename}.${extension}`; if (this.fileModuleExists(pathname)) { resolvedName = pathname; break; } } } if (!resolvedName) { this.logger().trace(`Could not resolve local-path module '${moduleName}'!` + ` includedIn='${originModulePath}'` + `, basedir='${originModuleDir}'` + `, fileExtensions=${JSON.stringify(extensions)}!`); } } if (!resolvedName) { originModuleDir = this.projectRoot(); try { resolvedName = resolve.sync(moduleName, { extensions, packageFilter, basedir: originModuleDir, }); } catch (error) { } if (!resolvedName) { this.logger().trace(`Could not resolve module '${moduleName}'!` + ` includedIn='${originModulePath}'` + `, basedir='${originModuleDir}'` + `, fileExtensions=${JSON.stringify(extensions)}!`); } } if (resolvedName) { return { type, filePath: resolvedName }; } return undefined; } fileModuleExists(pathname) { if (fs.existsSync(pathname)) { const stat = fs.lstatSync(pathname); if (stat.isFile() || stat.isFIFO()) { return true; } } return false; } isDirectory(pathname) { return fs.existsSync(pathname) && fs.lstatSync(pathname).isDirectory(); } generateComplementaryExtensions(context, baseExtensions) { let filePaths = []; for (const baseExt of baseExtensions) { filePaths = filePaths.concat([ `${context.platform}.${baseExt}`, `${baseExt}`, ]); } return filePaths; } isTypeScriptConfig(value) { return typeof value === 'object' && value !== null; } } export function findLernaMonorepo(projectRoot, helper) { let packageRoots = []; let found = false; let monorepoRoot = projectRoot; while (true) { helper.logger().debug(`Searching for lerna monorepo at '${monorepoRoot}'...`); const lernaJsonFilename = path.resolve(monorepoRoot, "lerna.json"); const lernaJson = tryParseJsonFile(lernaJsonFilename); if (lernaJson) { found = true; if (lernaJson.useWorkspaces === true && lernaJson.npmClient === 'yarn') { const packageJsonFilename = path.resolve(monorepoRoot, "package.json"); const packageJson = tryParseJsonFile(packageJsonFilename); if (packageJson) { const workspaces = packageJson.workspaces; if (workspaces instanceof Array) { const paths = readPackageGlobs(workspaces, { cwd: monorepoRoot }); packageRoots = packageRoots.concat(paths); } else if (typeof workspaces === 'object' && workspaces.packages instanceof Array) { const paths = readPackageGlobs(workspaces.packages, { cwd: monorepoRoot }); packageRoots = packageRoots.concat(paths); } } } else if (lernaJson.packages instanceof Array) { const paths = readPackageGlobs(lernaJson.packages, { cwd: monorepoRoot }); packageRoots = packageRoots.concat(paths); } } if (found) break; monorepoRoot = path.dirname(monorepoRoot); if (path.parse(monorepoRoot).root === monorepoRoot) break; } if (!found) { helper.logger().debug(`Could not find lerna monorepo starting at project root '${projectRoot}'.`); return null; } const info = { packages: packageRoots.map(root => ({ root: path.resolve(monorepoRoot, root), })), project: { root: projectRoot, }, root: monorepoRoot, }; helper.logger().debug(`Found lerna monorepo.`, info); return info; } export function findYarnMonorepo(projectRoot, helper) { let packageRoots = []; let found = false; let monorepoRoot = projectRoot; const YARN = process.env.YARN || 'yarn'; let yarnInPath = true; try { cp.execFileSync(YARN, ['--version']); } catch (err) { yarnInPath = false; helper.logger().debug(`** It seems you don't have yarn in your path.` + ` Reverting to glob-based package root resolution...`); } while (true) { helper.logger().debug(`Searching for yarn monorepo at '${monorepoRoot}'...`); const packageJsonFilename = path.resolve(monorepoRoot, "package.json"); const yarnPackageJson = tryParseJsonFile(packageJsonFilename); const yarnWorkspaces = yarnPackageJson ? yarnPackageJson.workspaces : {}; if (yarnWorkspaces && 'packages' in yarnWorkspaces) { if (yarnInPath) { let workspaceInfoJson; try { // Unless something is terribly wrong with yarn or the project layout/configuration, // yarn will fail in this only when the current search folder is not a workspace root. // We should continue our search upwards in the filesystem tree if the folder is not // a workspace, hence the try-catch. workspaceInfoJson = cp.execFileSync(YARN, ['workspaces', 'info', '--silent'], { cwd: monorepoRoot, }).toString(); } catch (err) { } if (workspaceInfoJson) { const workspaceInfo = JSON.parse(workspaceInfoJson); packageRoots = Object.keys(workspaceInfo) .map(packageName => `${monorepoRoot}/${workspaceInfo[packageName].location}`); } } else { const packageJson = tryParseJsonFile(packageJsonFilename); if (packageJson) { const workspaces = packageJson.workspaces; if (workspaces instanceof Array) { const paths = readPackageGlobs(workspaces, { cwd: monorepoRoot }); packageRoots = packageRoots.concat(paths); } else if (typeof workspaces === 'object' && workspaces.packages instanceof Array) { const paths = readPackageGlobs(workspaces.packages, { cwd: monorepoRoot }); packageRoots = packageRoots.concat(paths); } } } if (packageRoots && packageRoots.length > 0) { found = true; } } if (found) break; monorepoRoot = path.dirname(monorepoRoot); if (path.parse(monorepoRoot).root === monorepoRoot) break; } if (!found) { helper.logger().debug(`Could not find lerna monorepo starting at project root '${projectRoot}'.`); return null; } const info = { root: monorepoRoot, packages: packageRoots.map(root => ({ root: path.resolve(monorepoRoot, root), })), project: { root: projectRoot, }, }; helper.logger().debug(`Found yarn monorepo.`, info); return info; } export const nullLogger = { trace: () => { }, debug: () => { }, error: () => { }, }; /* tslint:disable no-console */ export const consoleLogger = { trace: (...args) => console.debug(chalk.yellow("[MonorepoHelper|TRACE] "), ...args), debug: (...args) => console.debug(chalk.yellowBright("[MonorepoHelper|DEBUG] "), ...args), error: (...args) => console.error(chalk.bgRed.whiteBright("[MonorepoHelper|ERROR] "), ...args), }; /* tslint:enable no-console */ export const defaultHelperOptions = { logger: { trace: nullLogger.trace, debug: consoleLogger.debug, error: consoleLogger.error, }, monorepoFinders: [findLernaMonorepo, findYarnMonorepo], }; export const defaultTypeScriptConfig = { fileExtensions: ["ts", "tsx"], transformerModuleName: "react-native-typescript-transformer", }; export function metroConfigHelper(projectRoot, options) { return new MetroConfigHelper(options || defaultHelperOptions) .projectRoot(projectRoot); } export function metroConfig(projectRoot) { return metroConfigHelper(projectRoot).generate(); } export default metroConfig; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvQixPQUFPLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDcEIsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQ3hCLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUN4QixPQUFPLE9BQU8sTUFBTSxTQUFTLENBQUM7QUFROUIsTUFBTSxLQUFXLEtBQUssQ0FtQ3JCO0FBbkNELFdBQWlCLEtBQUs7SUFFbEIsSUFBWSxjQUdYO0lBSEQsV0FBWSxjQUFjO1FBQ3RCLGlDQUFlLENBQUE7UUFDZiw0Q0FBMEIsQ0FBQTtJQUM5QixDQUFDLEVBSFcsY0FBYyxHQUFkLG9CQUFjLEtBQWQsb0JBQWMsUUFHekI7QUE4QkwsQ0FBQyxFQW5DZ0IsS0FBSyxLQUFMLEtBQUssUUFtQ3JCO0FBaUNELE1BQU07QUFHTixTQUFTLGdCQUFnQixDQUF5QixRQUFnQjtJQUM5RCxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEVBQUU7UUFDekIsTUFBTSxRQUFRLEdBQUcsRUFBRSxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUMzQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1FBQzdDLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUTtZQUFFLE9BQU8sSUFBUyxDQUFDO0tBQ2xEO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDckIsQ0FBQztBQUVELFNBQVMsZ0JBQWdCLENBQ3JCLEtBQVksRUFDWixPQUdDO0lBRUQsTUFBTSxHQUFHLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQztJQUN4QixNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsY0FB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