Skip to content

Commit

Permalink
Add resolver.enableGlobalPackages config option
Browse files Browse the repository at this point in the history
Summary:
Changelog:

* **[Feature]**: Add option to configure Metro's support for global package resolution (aka "Haste packages").

Metro supports a simple form of "workspace"-like resolution that ignores symlinks and folder structure, instead simply collecting all `package.json` files in the project into a global map. This will largely be superseded by symlink support when that ships as stable, but in advanced use cases, it can be desirable to disable this feature *independently* of whether symlinks are enabled. This diff makes the feature configurable (while leaving it on by default).

NOTE: This feature is known internally as "Haste package resolution" but it doesn't make sense to tie the external naming to Haste (an overloaded and poorly-understood term), so I'm going with the "global packages" naming that's already used in the test suite.

Reviewed By: robhogan

Differential Revision: D48349039

fbshipit-source-id: 417929516bcd7888219c10de7414bd7806b2a363
  • Loading branch information
motiz88 authored and facebook-github-bot committed Aug 16, 2023
1 parent cf7aa77 commit 8b80efb
Show file tree
Hide file tree
Showing 14 changed files with 424 additions and 269 deletions.
10 changes: 10 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,16 @@ Type: `string`
What module to use as the canonical "empty" module when one is needed. Defaults to using the one included in `metro-runtime`. You only need to change this if Metro is installed outside of your project.
#### `enableGlobalPackages`
Type: `boolean`.
Whether to automatically resolve references first-party packages (e.g. workspaces) in your project. Any `package.json` file with a valid `name` property within `projectRoot` or `watchFolders` (but outside of `node_modules`) counts as a package for this purpose. Defaults to `true`.
:::note
The default value of this option may change in a future version of Metro. If your project relies on it, it's recommended that you set it explicitly in your config file.
:::
#### `extraNodeModules`
Type: `{[string]: string}`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Object {
"dependencyExtractor": undefined,
"disableHierarchicalLookup": false,
"emptyModulePath": "metro-runtime/src/modules/empty-module",
"enableGlobalPackages": true,
"extraNodeModules": Object {},
"hasteImplModulePath": undefined,
"nodeModulesPaths": Array [],
Expand Down Expand Up @@ -226,6 +227,7 @@ Object {
"dependencyExtractor": undefined,
"disableHierarchicalLookup": false,
"emptyModulePath": "metro-runtime/src/modules/empty-module",
"enableGlobalPackages": true,
"extraNodeModules": Object {},
"hasteImplModulePath": undefined,
"nodeModulesPaths": Array [],
Expand Down Expand Up @@ -403,6 +405,7 @@ Object {
"dependencyExtractor": undefined,
"disableHierarchicalLookup": false,
"emptyModulePath": "metro-runtime/src/modules/empty-module",
"enableGlobalPackages": true,
"extraNodeModules": Object {},
"hasteImplModulePath": undefined,
"nodeModulesPaths": Array [],
Expand Down Expand Up @@ -580,6 +583,7 @@ Object {
"dependencyExtractor": undefined,
"disableHierarchicalLookup": false,
"emptyModulePath": "metro-runtime/src/modules/empty-module",
"enableGlobalPackages": true,
"extraNodeModules": Object {},
"hasteImplModulePath": undefined,
"nodeModulesPaths": Array [],
Expand Down
1 change: 1 addition & 0 deletions packages/metro-config/src/configTypes.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ type ResolverConfigT = {
disableHierarchicalLookup: boolean,
dependencyExtractor: ?string,
emptyModulePath: string,
enableGlobalPackages: boolean,
unstable_enableSymlinks: boolean,
extraNodeModules: {[name: string]: string, ...},
hasteImplModulePath: ?string,
Expand Down
1 change: 1 addition & 0 deletions packages/metro-config/src/defaults/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const getDefaultValues = (projectRoot: ?string): ConfigT => ({
emptyModulePath: require.resolve(
'metro-runtime/src/modules/empty-module.js',
),
enableGlobalPackages: true,
extraNodeModules: {},
hasteImplModulePath: undefined,
nodeModulesPaths: [],
Expand Down
1 change: 1 addition & 0 deletions packages/metro-config/types/configTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export interface ResolverConfigT {
disableHierarchicalLookup: boolean;
extraNodeModules: {[name: string]: string};
emptyModulePath: string;
enableGlobalPackages: boolean;
hasteImplModulePath?: string;
nodeModulesPaths: ReadonlyArray<string>;
platforms: ReadonlyArray<string>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const buildParameters: BuildParameters = {
computeDependencies: true,
computeSha1: true,
dependencyExtractor: null,
enableHastePackages: true,
enableSymlinks: false,
forceNodeFilesystemAPI: true,
ignorePattern: /ignored/,
Expand Down
1 change: 1 addition & 0 deletions packages/metro-file-map/src/flow-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export type {PerfLoggerFactory, PerfLogger};
export type BuildParameters = $ReadOnly<{
computeDependencies: boolean,
computeSha1: boolean,
enableHastePackages: boolean,
enableSymlinks: boolean,
extensions: $ReadOnlyArray<string>,
forceNodeFilesystemAPI: boolean,
Expand Down
4 changes: 3 additions & 1 deletion packages/metro-file-map/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ export type {
export type InputOptions = $ReadOnly<{
computeDependencies?: ?boolean,
computeSha1?: ?boolean,
enableHastePackages?: boolean,
enableSymlinks?: ?boolean,
extensions: $ReadOnlyArray<string>,
forceNodeFilesystemAPI?: ?boolean,
Expand Down Expand Up @@ -288,6 +289,7 @@ export default class FileMap extends EventEmitter {
: options.computeDependencies,
computeSha1: options.computeSha1 || false,
dependencyExtractor: options.dependencyExtractor ?? null,
enableHastePackages: options.enableHastePackages ?? true,
enableSymlinks: options.enableSymlinks || false,
extensions: options.extensions,
forceNodeFilesystemAPI: !!options.forceNodeFilesystemAPI,
Expand Down Expand Up @@ -653,7 +655,7 @@ export default class FileMap extends EventEmitter {
computeDependencies: this._options.computeDependencies,
computeSha1,
dependencyExtractor: this._options.dependencyExtractor,
enableHastePackages: true,
enableHastePackages: this._options.enableHastePackages,
filePath,
hasteImplModulePath: this._options.hasteImplModulePath,
readLink: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const buildParameters: BuildParameters = {
computeDependencies: false,
computeSha1: false,
dependencyExtractor: null,
enableHastePackages: true,
enableSymlinks: false,
extensions: ['a'],
forceNodeFilesystemAPI: false,
Expand Down Expand Up @@ -82,6 +83,7 @@ it('returns a distinct cache key for any change', () => {
// Boolean
case 'computeDependencies':
case 'computeSha1':
case 'enableHastePackages':
case 'enableSymlinks':
case 'forceNodeFilesystemAPI':
case 'retainAllFiles':
Expand Down
1 change: 1 addition & 0 deletions packages/metro-file-map/src/lib/rootRelativeCacheKeys.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export default function rootRelativeCacheKeys(
case 'extensions':
case 'computeDependencies':
case 'computeSha1':
case 'enableHastePackages':
case 'enableSymlinks':
case 'forceNodeFilesystemAPI':
case 'platforms':
Expand Down
1 change: 1 addition & 0 deletions packages/metro-file-map/types/flow-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type {PerfLoggerFactory, PerfLogger};
export type BuildParameters = Readonly<{
computeDependencies: boolean;
computeSha1: boolean;
enableHastePackages: boolean;
enableSymlinks: boolean;
extensions: ReadonlyArray<string>;
forceNodeFilesystemAPI: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,30 @@ None of these files exist:
3 | import bar from 'foo';"
`;

exports[`linux global packages uses the name in the package.json as the package name 1`] = `
exports[`linux global packages default config uses the name in the package.json as the package name 1`] = `
"Unable to resolve module aPackage from /root/index.js: aPackage could not be found within the project.
1 | import foo from 'bar';
> 2 | import a from 'aPackage';
| ^
3 | import bar from 'foo';"
`;

exports[`linux global packages explicitly disabled does not resolve global packages 1`] = `
"Unable to resolve module aPackage from /root/index.js: aPackage could not be found within the project.
> 1 |"
`;

exports[`linux global packages explicitly disabled does not resolve global packages 2`] = `
"Unable to resolve module aPackage/ from /root/index.js: aPackage/ could not be found within the project.
> 1 |"
`;

exports[`linux global packages explicitly disabled does not resolve global packages 3`] = `
"Unable to resolve module aPackage/other from /root/index.js: aPackage/other could not be found within the project.
> 1 |"
`;

exports[`linux global packages explicitly enabled uses the name in the package.json as the package name 1`] = `
"Unable to resolve module aPackage from /root/index.js: aPackage could not be found within the project.
1 | import foo from 'bar';
> 2 | import a from 'aPackage';
Expand Down Expand Up @@ -225,7 +248,30 @@ None of these files exist:
3 | import bar from 'foo';"
`;

exports[`win32 global packages uses the name in the package.json as the package name 1`] = `
exports[`win32 global packages default config uses the name in the package.json as the package name 1`] = `
"Unable to resolve module aPackage from C:\\\\root\\\\index.js: aPackage could not be found within the project.
1 | import foo from 'bar';
> 2 | import a from 'aPackage';
| ^
3 | import bar from 'foo';"
`;

exports[`win32 global packages explicitly disabled does not resolve global packages 1`] = `
"Unable to resolve module aPackage from C:\\\\root\\\\index.js: aPackage could not be found within the project.
> 1 |"
`;

exports[`win32 global packages explicitly disabled does not resolve global packages 2`] = `
"Unable to resolve module aPackage/ from C:\\\\root\\\\index.js: aPackage/ could not be found within the project.
> 1 |"
`;

exports[`win32 global packages explicitly disabled does not resolve global packages 3`] = `
"Unable to resolve module aPackage/other from C:\\\\root\\\\index.js: aPackage/other could not be found within the project.
> 1 |"
`;

exports[`win32 global packages explicitly enabled uses the name in the package.json as the package name 1`] = `
"Unable to resolve module aPackage from C:\\\\root\\\\index.js: aPackage could not be found within the project.
1 | import foo from 'bar';
> 2 | import a from 'aPackage';
Expand Down
Loading

0 comments on commit 8b80efb

Please sign in to comment.