From 6daa45904446dba41f73984de4f4dc28500575ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Tue, 10 Mar 2020 18:27:09 +0100 Subject: [PATCH] remove findSymlinkedModules --- CONTRIBUTING.md | 8 + .../__tests__/findSymlinkedModules-test.js | 354 ------------------ .../cli/src/tools/findSymlinkedModules.ts | 106 ------ packages/cli/src/tools/loadMetroConfig.ts | 10 +- 4 files changed, 10 insertions(+), 468 deletions(-) delete mode 100644 packages/cli/src/tools/__tests__/findSymlinkedModules-test.js delete mode 100644 packages/cli/src/tools/findSymlinkedModules.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 90f9a2132a..d8a14edc82 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -89,6 +89,14 @@ react-native init --version ${RN_VERSION} npm config set registry https://registry.npmjs.org/ ``` +## Running `start` command + +In order for linked dependencies to work correctly when running `start` locally, set `--watchFolders` with a path to the root folder of the CLI project: + +``` +node path/to/cli/packages/cli/build/bin.js start --watchFolders path/to/cli +``` + ## Running CLI with React Native from the source First make sure you have RN repo checked out and CLI repo checked out and built. Then you can start a new RN project with local version of CLI and RN without publishing or proxy: diff --git a/packages/cli/src/tools/__tests__/findSymlinkedModules-test.js b/packages/cli/src/tools/__tests__/findSymlinkedModules-test.js deleted file mode 100644 index f283917d3b..0000000000 --- a/packages/cli/src/tools/__tests__/findSymlinkedModules-test.js +++ /dev/null @@ -1,354 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @emails oncall+javascript_foundation - */ - -import findSymlinkedModules from '../findSymlinkedModules'; - -jest.mock('path'); -jest.mock('fs'); - -const fs = require('fs'); - -describe('findSymlinksForProjectRoot', () => { - it('correctly finds normal module symlinks', () => { - fs.__setMockFilesystem({ - root: { - projectA: { - 'package.json': JSON.stringify({ - name: 'projectA', - main: 'main.js', - }), - node_modules: { - depFoo: { - 'package.json': JSON.stringify({ - name: 'depFoo', - main: 'main.js', - }), - }, - projectB: { - SYMLINK: '/root/projectB', - }, - }, - }, - projectB: { - 'package.json': JSON.stringify({ - name: 'projectB', - main: 'main.js', - }), - node_modules: { - depBar: { - 'package.json': JSON.stringify({ - name: 'depBar', - main: 'main.js', - }), - }, - }, - }, - }, - }); - - const symlinkedModules = findSymlinkedModules('/root/projectA', []); - expect(symlinkedModules).toEqual(['/root/projectB']); - }); - - it('correctly finds scoped module symlinks', () => { - fs.__setMockFilesystem({ - root: { - projectA: { - 'package.json': JSON.stringify({ - name: 'projectA', - main: 'main.js', - }), - node_modules: { - depFoo: { - 'package.json': JSON.stringify({ - name: 'depFoo', - main: 'main.js', - }), - }, - '@scoped': { - projectC: { - SYMLINK: '/root/@scoped/projectC', - }, - }, - projectB: { - SYMLINK: '/root/projectB', - }, - }, - }, - projectB: { - 'package.json': JSON.stringify({ - name: 'projectB', - main: 'main.js', - }), - node_modules: { - depBar: { - 'package.json': JSON.stringify({ - name: 'depBar', - main: 'main.js', - }), - }, - }, - }, - '@scoped': { - projectC: { - 'package.json': JSON.stringify({ - name: '@scoped/projectC', - main: 'main.js', - }), - }, - }, - }, - }); - - const symlinkedModules = findSymlinkedModules('/root/projectA', []); - expect(symlinkedModules).toEqual([ - '/root/@scoped/projectC', - '/root/projectB', - ]); - }); - - it('correctly finds module symlinks within other module symlinks', () => { - fs.__setMockFilesystem({ - root: { - projectA: { - 'package.json': JSON.stringify({ - name: 'projectA', - main: 'main.js', - }), - node_modules: { - depFoo: { - 'package.json': JSON.stringify({ - name: 'depFoo', - main: 'main.js', - }), - }, - '@scoped': { - projectC: { - SYMLINK: '/root/@scoped/projectC', - }, - }, - projectB: { - SYMLINK: '/root/projectB', - }, - }, - }, - projectB: { - 'package.json': JSON.stringify({ - name: 'projectB', - main: 'main.js', - }), - node_modules: { - depBar: { - 'package.json': JSON.stringify({ - name: 'depBar', - main: 'main.js', - }), - }, - projectD: { - SYMLINK: '/root/projectD', - }, - }, - }, - '@scoped': { - projectC: { - 'package.json': JSON.stringify({ - name: '@scoped/projectC', - main: 'main.js', - }), - }, - }, - projectD: { - 'package.json': JSON.stringify({ - name: 'projectD', - main: 'main.js', - }), - }, - }, - }); - - const symlinkedModules = findSymlinkedModules('/root/projectA', []); - expect(symlinkedModules).toEqual([ - '/root/@scoped/projectC', - '/root/projectB', - '/root/projectD', - ]); - }); - - it('correctly handles duplicate symlink paths', () => { - // projectA -> - // -> projectC - // -> projectB -> projectC - // Final list should only contain projectC once - fs.__setMockFilesystem({ - root: { - projectA: { - 'package.json': JSON.stringify({ - name: 'projectA', - main: 'main.js', - }), - node_modules: { - depFoo: { - 'package.json': JSON.stringify({ - name: 'depFoo', - main: 'main.js', - }), - }, - '@scoped': { - projectC: { - SYMLINK: '/root/@scoped/projectC', - }, - }, - projectB: { - SYMLINK: '/root/projectB', - }, - }, - }, - projectB: { - 'package.json': JSON.stringify({ - name: 'projectB', - main: 'main.js', - }), - node_modules: { - depBar: { - 'package.json': JSON.stringify({ - name: 'depBar', - main: 'main.js', - }), - }, - '@scoped': { - projectC: { - SYMLINK: '/root/@scoped/projectC', - }, - }, - }, - }, - '@scoped': { - projectC: { - 'package.json': JSON.stringify({ - name: '@scoped/projectC', - main: 'main.js', - }), - }, - }, - }, - }); - - const symlinkedModules = findSymlinkedModules('/root/projectA', []); - expect(symlinkedModules).toEqual([ - '/root/@scoped/projectC', - '/root/projectB', - ]); - }); - - it('correctly handles symlink recursion', () => { - // projectA -> - // -> projectC -> projectD -> projectA - // -> projectB -> projectC -> projectA - // -> projectD -> projectC -> projectA - // Should not infinite loop, should not contain projectA - fs.__setMockFilesystem({ - root: { - projectA: { - 'package.json': JSON.stringify({ - name: 'projectA', - main: 'main.js', - }), - node_modules: { - depFoo: { - 'package.json': JSON.stringify({ - name: 'depFoo', - main: 'main.js', - }), - }, - '@scoped': { - projectC: { - SYMLINK: '/root/@scoped/projectC', - }, - }, - projectB: { - SYMLINK: '/root/projectB', - }, - }, - }, - projectB: { - 'package.json': JSON.stringify({ - name: 'projectB', - main: 'main.js', - }), - node_modules: { - depBar: { - 'package.json': JSON.stringify({ - name: 'depBar', - main: 'main.js', - }), - }, - projectD: { - SYMLINK: '/root/projectD', - }, - '@scoped': { - projectC: { - SYMLINK: '/root/@scoped/projectC', - }, - }, - }, - }, - '@scoped': { - projectC: { - 'package.json': JSON.stringify({ - name: '@scoped/projectC', - main: 'main.js', - }), - node_modules: { - projectA: { - SYMLINK: '/root/projectA', - }, - projectD: { - SYMLINK: '/root/projectD', - }, - projectE: { - SYMLINK: '/root/projectE', - }, - }, - }, - }, - projectD: { - 'package.json': JSON.stringify({ - name: 'projectD', - main: 'main.js', - }), - node_modules: { - '@scoped': { - projectC: { - SYMLINK: '/root/@scoped/projectC', - }, - }, - projectE: { - SYMLINK: '/root/projectE', - }, - }, - }, - projectE: { - 'package.json': JSON.stringify({ - name: 'projectD', - main: 'main.js', - }), - }, - }, - }); - - const symlinkedModules = findSymlinkedModules('/root/projectA'); - expect(symlinkedModules).toEqual([ - '/root/@scoped/projectC', - '/root/projectB', - '/root/projectD', - '/root/projectE', - ]); - }); -}); diff --git a/packages/cli/src/tools/findSymlinkedModules.ts b/packages/cli/src/tools/findSymlinkedModules.ts deleted file mode 100644 index 0e7befe6ce..0000000000 --- a/packages/cli/src/tools/findSymlinkedModules.ts +++ /dev/null @@ -1,106 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import path from 'path'; -import fs from 'fs'; - -/** - * Find symlinked modules inside "node_modules." - * - * Naively, we could just perform a depth-first search of all folders in - * node_modules, recursing when we find a symlink. - * - * We can be smarter than this due to our knowledge of how npm/Yarn lays out - * "node_modules" / how tools that build on top of npm/Yarn (such as Lerna) - * install dependencies. - * - * Starting from a given root node_modules folder, this algorithm will look at - * both the top level descendants of the node_modules folder or second level - * descendants of folders that start with "@" (which indicates a scoped - * package). If any of those folders is a symlink, it will recurse into the - * link, and perform the same search in the linked folder. - * - * The end result should be a list of all resolved module symlinks for a given - * root. - */ -export default function findSymlinkedModules( - projectRoot: string, - ignoredRoots: Array = [], -) { - const nodeModuleRoot = path.join(projectRoot, 'node_modules'); - const resolvedSymlinks = findModuleSymlinks(nodeModuleRoot, [ - ...ignoredRoots, - projectRoot, - ]); - return resolvedSymlinks; -} - -function findModuleSymlinks( - modulesPath: string, - ignoredPaths: Array = [], -): Array { - if (!fs.existsSync(modulesPath)) { - return []; - } - - // Find module symlinks - const moduleFolders = fs.readdirSync(modulesPath); - const symlinks = moduleFolders.reduce( - (links, folderName) => { - const folderPath = path.join(modulesPath, folderName); - const maybeSymlinkPaths = []; - if (folderName.startsWith('@')) { - const scopedModuleFolders = fs.readdirSync(folderPath); - maybeSymlinkPaths.push( - ...scopedModuleFolders.map(name => path.join(folderPath, name)), - ); - } else { - maybeSymlinkPaths.push(folderPath); - } - return links.concat(resolveSymlinkPaths(maybeSymlinkPaths, ignoredPaths)); - }, - [] as string[], - ); - - // For any symlinks found, look in _that_ modules node_modules directory - // and find any symlinked modules - const nestedSymlinks = symlinks.reduce( - (links, symlinkPath) => - links.concat( - // We ignore any found symlinks or anything from the ignored list, - // to prevent infinite recursion - findModuleSymlinks(path.join(symlinkPath, 'node_modules'), [ - ...ignoredPaths, - ...symlinks, - ]), - ), - [] as string[], - ); - - return [...new Set([...symlinks, ...nestedSymlinks])]; -} - -function resolveSymlinkPaths( - maybeSymlinkPaths: string[], - ignoredPaths: string[], -) { - return maybeSymlinkPaths.reduce( - (links, maybeSymlinkPath) => { - if (fs.lstatSync(maybeSymlinkPath).isSymbolicLink()) { - const resolved = path.resolve( - path.dirname(maybeSymlinkPath), - fs.readlinkSync(maybeSymlinkPath), - ); - if (ignoredPaths.indexOf(resolved) === -1 && fs.existsSync(resolved)) { - links.push(resolved); - } - } - return links; - }, - [] as string[], - ); -} diff --git a/packages/cli/src/tools/loadMetroConfig.ts b/packages/cli/src/tools/loadMetroConfig.ts index 8ffdbd8cd6..fc244de120 100644 --- a/packages/cli/src/tools/loadMetroConfig.ts +++ b/packages/cli/src/tools/loadMetroConfig.ts @@ -5,14 +5,6 @@ import path from 'path'; // @ts-ignore - no typed definition for the package import {loadConfig} from 'metro-config'; import {Config} from '@react-native-community/cli-types'; -import findSymlinkedModules from './findSymlinkedModules'; - -function resolveSymlinksForRoots(roots: string[]): string[] { - return roots.reduce( - (arr, rootPath) => arr.concat(findSymlinkedModules(rootPath, roots)), - [...roots], - ); -} const INTERNAL_CALLSITES_REGEX = new RegExp( [ @@ -49,6 +41,7 @@ export interface MetroConfig { assetRegistryPath: string; assetPlugins?: Array; }; + watchFolders: string[]; reporter?: any; } @@ -85,6 +78,7 @@ export const getDefaultConfig = (ctx: Config): MetroConfig => { return {collapse}; }, }, + watchFolders: [], transformer: { babelTransformerPath: require.resolve( 'metro-react-native-babel-transformer',