Skip to content

Commit 0993f62

Browse files
afoxmangrabbou
andauthored
feat: move all metro logic and commands into a dedicated package (#1447)
* Move metro configuration and bundling logic into their own packages, making them available to external users. * Rename metro-config package to metro * Move cli-bundle-api package and bundle command (cli package) into metro. * Move resolveNodeModuleDir to cli-tools package * Move releaseChecker into cli-tools * Move hookStdout to cli-tools * Move start command into metro package * Rename 'metro' package to 'cli-plugin-metro'. * Update dependency * More renaming * Revert buildBundle to default export * Make exports explicit * Revert exports to default * PR feedback * refactor(structure): moved some files around to reflect the convention a bit better * Fix type bug, export missing funciton/type. Co-authored-by: Mike Grabowski <grabbou@gmail.com>
1 parent 0239244 commit 0993f62

39 files changed

+143
-51
lines changed
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "@react-native-community/cli-plugin-metro",
3+
"version": "6.0.0",
4+
"license": "MIT",
5+
"main": "build/index.js",
6+
"publishConfig": {
7+
"access": "public"
8+
},
9+
"dependencies": {
10+
"@react-native-community/cli-tools": "^6.0.0-rc.0",
11+
"@react-native-community/cli-server-api": "^6.0.0-rc.0",
12+
"chalk": "^3.0.0",
13+
"metro": "^0.66.1",
14+
"metro-config": "^0.66.1",
15+
"metro-core": "^0.66.1",
16+
"metro-react-native-babel-transformer": "^0.66.1",
17+
"metro-resolver": "^0.66.1",
18+
"metro-runtime": "^0.66.1",
19+
"mkdirp": "^0.5.1",
20+
"readline": "^1.3.0"
21+
},
22+
"devDependencies": {
23+
"@react-native-community/cli-types": "^6.0.0"
24+
},
25+
"files": [
26+
"build",
27+
"!*.map"
28+
],
29+
"homepage": "https://github.com/react-native-community/cli/tree/master/packages/cli-plugin-metro",
30+
"repository": {
31+
"type": "git",
32+
"url": "https://github.com/react-native-community/cli.git",
33+
"directory": "packages/cli-plugin-metro"
34+
}
35+
}

packages/cli/src/commands/bundle/buildBundle.ts packages/cli-plugin-metro/src/commands/bundle/buildBundle.ts

+19-3
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
// @ts-ignore - no typed definition for the package
1010
import Server from 'metro/src/Server';
1111
// @ts-ignore - no typed definition for the package
12-
import outputBundle from 'metro/src/shared/output/bundle';
12+
const outputBundle = require('metro/src/shared/output/bundle');
1313
import path from 'path';
1414
import chalk from 'chalk';
1515
import {CommandLineArgs} from './bundleCommandLineArgs';
16-
import {Config} from '@react-native-community/cli-types';
16+
import type {Config} from '@react-native-community/cli-types';
1717
import saveAssets from './saveAssets';
18-
import loadMetroConfig from '../../tools/loadMetroConfig';
18+
import {
19+
default as loadMetroConfig,
20+
MetroConfig,
21+
} from '../../tools/loadMetroConfig';
1922
import {logger} from '@react-native-community/cli-tools';
2023

2124
interface RequestOptions {
@@ -51,6 +54,19 @@ async function buildBundle(
5154
config: args.config,
5255
});
5356

57+
return buildBundleWithConfig(args, config, output);
58+
}
59+
60+
/**
61+
* Create a bundle using a pre-loaded Metro config. The config can be
62+
* re-used for several bundling calls if multiple platforms are being
63+
* bundled.
64+
*/
65+
export async function buildBundleWithConfig(
66+
args: CommandLineArgs,
67+
config: MetroConfig,
68+
output: typeof outputBundle = outputBundle,
69+
) {
5470
if (config.resolver.platforms.indexOf(args.platform) === -1) {
5571
logger.error(
5672
`Invalid platform ${

packages/cli/src/commands/bundle/bundle.ts packages/cli-plugin-metro/src/commands/bundle/bundle.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*
77
*/
8-
import {Config} from '@react-native-community/cli-types';
8+
import type {Config} from '@react-native-community/cli-types';
99
import buildBundle from './buildBundle';
1010
import bundleCommandLineArgs, {CommandLineArgs} from './bundleCommandLineArgs';
1111

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export {default as bundleCommand} from './bundle';
2+
export {buildBundleWithConfig} from './buildBundle';
3+
export type {CommandLineArgs} from './bundleCommandLineArgs';
4+
export {default as ramBundleCommand} from './ramBundle';

packages/cli/src/commands/bundle/ramBundle.ts packages/cli-plugin-metro/src/commands/bundle/ramBundle.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import outputUnbundle from 'metro/src/shared/output/RamBundle';
1010
import {withOutput as bundleWithOutput} from './bundle';
1111
import bundleCommandLineArgs, {CommandLineArgs} from './bundleCommandLineArgs';
12-
import {Config} from '@react-native-community/cli-types';
12+
import type {Config} from '@react-native-community/cli-types';
1313

1414
/**
1515
* Builds the bundle starting to look for dependencies at the given entry path.
@@ -30,3 +30,5 @@ export default {
3030
default: false,
3131
}),
3232
};
33+
34+
export {ramBundle};

packages/cli/src/commands/bundle/saveAssets.ts packages/cli-plugin-metro/src/commands/bundle/saveAssets.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import filterPlatformAssetScales from './filterPlatformAssetScales';
1414
import getAssetDestPathAndroid from './getAssetDestPathAndroid';
1515
import getAssetDestPathIOS from './getAssetDestPathIOS';
1616
import {logger} from '@react-native-community/cli-tools';
17-
import {AssetData} from './buildBundle';
17+
import type {AssetData} from './buildBundle';
1818

1919
interface CopiedFiles {
2020
[src: string]: string;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import {bundleCommand, ramBundleCommand} from './bundle';
2+
import startCommand from './start';
3+
4+
export default [bundleCommand, ramBundleCommand, startCommand];
5+
export {buildBundleWithConfig} from './bundle';
6+
export type {CommandLineArgs} from './bundle';

packages/cli/src/commands/start/runServer.ts packages/cli-plugin-metro/src/commands/start/runServer.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
import {Config} from '@react-native-community/cli-types';
1818

1919
import loadMetroConfig from '../../tools/loadMetroConfig';
20-
import releaseChecker from '../../tools/releaseChecker';
20+
import {releaseChecker} from '@react-native-community/cli-tools';
2121
import enableWatchMode from './watchMode';
2222

2323
export type Args = {
@@ -128,7 +128,7 @@ function getReporterImpl(customLogReporterPath: string | undefined) {
128128
// as expected. eg: require('my-package/reporter');
129129
return require(customLogReporterPath);
130130
} catch (e) {
131-
if (e.code !== 'MODULE_NOT_FOUND') {
131+
if ((<any>e).code !== 'MODULE_NOT_FOUND') {
132132
throw e;
133133
}
134134
// If that doesn't work, then we next try relative to the cwd, eg:

packages/cli/src/commands/start/watchMode.ts packages/cli-plugin-metro/src/commands/start/watchMode.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import readline from 'readline';
2-
import hookStdout from '../../tools/hookStdout';
3-
import {logger} from '@react-native-community/cli-tools';
2+
import {logger, hookStdout} from '@react-native-community/cli-tools';
43

54
function printWatchModeInstructions() {
65
logger.log(
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export {
2+
Config,
3+
ConfigLoadingContext,
4+
MetroConfig,
5+
getDefaultConfig,
6+
default as loadMetroConfig,
7+
} from './tools/loadMetroConfig';
8+
export {
9+
default as commands,
10+
buildBundleWithConfig,
11+
CommandLineArgs,
12+
} from './commands';

packages/cli/src/tools/__tests__/loadMetroConfig-test.ts packages/cli-plugin-metro/src/tools/__tests__/loadMetroConfig-test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ describe('getDefaultConfig', () => {
88
const config = getDefaultConfig({
99
root: '/',
1010
reactNativePath: '',
11+
// @ts-ignore
1112
platforms: {},
1213
});
1314

packages/cli/src/tools/loadMetroConfig.ts packages/cli-plugin-metro/src/tools/loadMetroConfig.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import path from 'path';
55
// @ts-ignore - no typed definition for the package
66
import {loadConfig} from 'metro-config';
7-
import {Config} from '@react-native-community/cli-types';
7+
import type {Config} from '@react-native-community/cli-types';
88
import {reactNativePlatformResolver} from './metroPlatformResolver';
99

1010
const INTERNAL_CALLSITES_REGEX = new RegExp(
@@ -20,7 +20,9 @@ const INTERNAL_CALLSITES_REGEX = new RegExp(
2020
].join('|'),
2121
);
2222

23-
type ConfigLoadingContext = Pick<
23+
export type {Config};
24+
25+
export type ConfigLoadingContext = Pick<
2426
Config,
2527
'root' | 'reactNativePath' | 'platforms'
2628
>;
@@ -141,7 +143,7 @@ export interface ConfigOptionsT {
141143
*
142144
* This allows the CLI to always overwrite the file settings.
143145
*/
144-
export default function load(
146+
export default function loadMetroConfig(
145147
ctx: ConfigLoadingContext,
146148
options?: ConfigOptionsT,
147149
): Promise<MetroConfig> {
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
"compilerOptions": {
4+
"rootDir": "src",
5+
"outDir": "build"
6+
},
7+
"references": [
8+
{"path": "../cli-types"},
9+
{"path": "../cli-server-api"},
10+
{"path": "../tools"},
11+
]
12+
}

packages/cli/package.json

+1-6
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"@react-native-community/cli-server-api": "^6.0.0-rc.0",
3030
"@react-native-community/cli-tools": "^6.0.0-rc.0",
3131
"@react-native-community/cli-types": "^6.0.0",
32+
"@react-native-community/cli-plugin-metro": "^6.0.0",
3233
"appdirsjs": "^1.2.4",
3334
"chalk": "^3.0.0",
3435
"command-exists": "^1.2.8",
@@ -44,12 +45,6 @@
4445
"joi": "^17.2.1",
4546
"leven": "^3.1.0",
4647
"lodash": "^4.17.15",
47-
"metro": "^0.66.1",
48-
"metro-config": "^0.66.1",
49-
"metro-core": "^0.66.1",
50-
"metro-react-native-babel-transformer": "^0.66.1",
51-
"metro-resolver": "^0.66.1",
52-
"metro-runtime": "^0.66.1",
5348
"minimist": "^1.2.0",
5449
"mkdirp": "^0.5.1",
5550
"node-stream-zip": "^1.9.1",

packages/cli/src/commands/index.ts

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import {Command, DetachedCommand} from '@react-native-community/cli-types';
2-
import start from './start/start';
3-
import bundle from './bundle/bundle';
4-
import ramBundle from './bundle/ramBundle';
2+
import {commands as metroCommands} from '@react-native-community/cli-plugin-metro';
53
import link from './link/link';
64
import unlink from './link/unlink';
75
import install from './install/install';
@@ -14,9 +12,7 @@ import doctor from './doctor';
1412
import profileHermes from '@react-native-community/cli-hermes';
1513

1614
export const projectCommands = [
17-
start,
18-
bundle,
19-
ramBundle,
15+
...metroCommands,
2016
link,
2117
unlink,
2218
install,

packages/cli/src/commands/info/info.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77

88
// @ts-ignore untyped
99
import getEnvironmentInfo from '../../tools/envinfo';
10-
import {logger} from '@react-native-community/cli-tools';
10+
import {logger, releaseChecker} from '@react-native-community/cli-tools';
1111
import {Config} from '@react-native-community/cli-types';
12-
import releaseChecker from '../../tools/releaseChecker';
1312

1413
const info = async function getInfo(_argv: Array<string>, ctx: Config) {
1514
try {

packages/cli/src/tools/config/__tests__/findDependencies-test.ts

-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import {
55
getTempDirectory,
66
} from '../../../../../../jest/helpers';
77

8-
jest.mock('../resolveNodeModuleDir');
9-
108
beforeEach(async () => {
119
await cleanup(DIR);
1210
jest.resetModules();
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,2 @@
1-
import path from 'path';
2-
3-
/**
4-
* Finds a path inside `node_modules`
5-
*/
6-
export default function resolveNodeModuleDir(
7-
root: string,
8-
packageName: string,
9-
): string {
10-
return path.dirname(
11-
require.resolve(path.join(packageName, 'package.json'), {
12-
paths: [root],
13-
}),
14-
);
15-
}
1+
import {resolveNodeModuleDir} from '@react-native-community/cli-tools';
2+
export default resolveNodeModuleDir;

packages/cli/tsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
{"path": "../cli-types"},
1010
{"path": "../debugger-ui"},
1111
{"path": "../cli-server-api"},
12-
{"path": "../cli-hermes"}
12+
{"path": "../cli-hermes"},
13+
{"path": "../cli-plugin-metro"},
1314
]
1415
}

packages/tools/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
"access": "public"
88
},
99
"dependencies": {
10+
"appdirsjs": "^1.2.4",
1011
"chalk": "^3.0.0",
1112
"lodash": "^4.17.15",
13+
"mkdirp": "^0.5.1",
1214
"mime": "^2.4.1",
1315
"node-fetch": "^2.6.0",
1416
"open": "^6.2.0",
15-
"shell-quote": "1.6.1"
17+
"shell-quote": "1.6.1",
18+
"semver": "^6.3.0"
1619
},
1720
"devDependencies": {
1821
"@types/lodash": "^4.14.149",
File renamed without changes.

packages/tools/src/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,8 @@ export {fetch, fetchToTemp} from './fetch';
66
export {default as launchDefaultBrowser} from './launchDefaultBrowser';
77
export {default as launchDebugger} from './launchDebugger';
88
export {default as launchEditor} from './launchEditor';
9+
export {default as releaseChecker} from './releaseChecker';
10+
export {default as resolveNodeModuleDir} from './resolveNodeModuleDir';
11+
export {default as hookStdout} from './hookStdout';
912

1013
export * from './errors';

packages/cli/src/tools/releaseChecker/getLatestRelease.ts packages/tools/src/releaseChecker/getLatestRelease.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import semver from 'semver';
22
import cacheManager from './releaseCacheManager';
3-
import {fetch, logger} from '@react-native-community/cli-tools';
3+
import {fetch} from '../fetch';
4+
import logger from '../logger';
45

56
export type Release = {
67
version: string;

packages/cli/src/tools/releaseChecker/index.ts packages/tools/src/releaseChecker/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import path from 'path';
2-
import {logger} from '@react-native-community/cli-tools';
2+
import logger from '../logger';
33
// @ts-ignore - JS file
4-
import resolveNodeModuleDir from '../config/resolveNodeModuleDir';
4+
import resolveNodeModuleDir from '../resolveNodeModuleDir';
55
import getLatestRelease from './getLatestRelease';
66
import printNewRelease from './printNewRelease';
77

packages/cli/src/tools/releaseChecker/printNewRelease.ts packages/tools/src/releaseChecker/printNewRelease.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import chalk from 'chalk';
2-
import {logger} from '@react-native-community/cli-tools';
2+
import logger from '../logger';
33
import {Release} from './getLatestRelease';
44
import cacheManager from './releaseCacheManager';
55

packages/cli/src/tools/releaseChecker/releaseCacheManager.ts packages/tools/src/releaseChecker/releaseCacheManager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import fs from 'fs';
33
import os from 'os';
44
import appDirs from 'appdirsjs';
55
import mkdirp from 'mkdirp';
6-
import {logger} from '@react-native-community/cli-tools';
6+
import logger from '../logger';
77

88
type ReleaseCacheKey = 'eTag' | 'lastChecked' | 'latestVersion';
99
type Cache = {[key in ReleaseCacheKey]?: string};
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import path from 'path';
2+
3+
/**
4+
* Finds a path inside `node_modules`
5+
*/
6+
export default function resolveNodeModuleDir(
7+
root: string,
8+
packageName: string,
9+
): string {
10+
return path.dirname(
11+
require.resolve(path.join(packageName, 'package.json'), {
12+
paths: [root],
13+
}),
14+
);
15+
}

yarn.lock

+5
Original file line numberDiff line numberDiff line change
@@ -10167,6 +10167,11 @@ readdirp@~3.3.0:
1016710167
dependencies:
1016810168
picomatch "^2.0.7"
1016910169

10170+
readline@^1.3.0:
10171+
version "1.3.0"
10172+
resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c"
10173+
integrity sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=
10174+
1017010175
realpath-native@^2.0.0:
1017110176
version "2.0.0"
1017210177
resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-2.0.0.tgz#7377ac429b6e1fd599dc38d08ed942d0d7beb866"

0 commit comments

Comments
 (0)