Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 25 additions & 57 deletions packages/cli-kit/src/public/node/custom-oclif-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {fileExistsSync} from './fs.js'
import {cwd, joinPath, sniffForPath} from './path.js'
import {isDevelopment} from './context/local.js'
import {execaSync} from 'execa'
import {Command, Config} from '@oclif/core'
import {Config} from '@oclif/core'
import {Options} from '@oclif/core/interfaces'

export class ShopifyConfig extends Config {
Expand All @@ -17,6 +17,7 @@ export class ShopifyConfig extends Config {
if (currentPathMightBeHydrogenMonorepo && !ignoreHydrogenMonorepo) {
path = execaSync('npm', ['prefix']).stdout.trim()
}

if (fileExistsSync(joinPath(path, 'package.json'))) {
// Hydrogen is bundled, but we still want to support loading it as an external plugin for two reasons:
// 1. To allow users to use an older version of Hydrogen. (to not force upgrades)
Expand All @@ -25,69 +26,36 @@ export class ShopifyConfig extends Config {
core: ['@shopify/cli-hydrogen'],
path,
}
// Force OCLIF to ignore manifests so commands are loaded dynamically
// to be replaced later
options.ignoreManifest = true
}
}

super(options)

if (isDevelopment()) {
// @ts-expect-error: This is a private method that we are overriding. OCLIF doesn't provide a way to extend it.
// eslint-disable-next-line @typescript-eslint/unbound-method
this.determinePriority = this.customPriority
}
}

customPriority(commands: Command.Loadable[]): Command.Loadable | undefined {
const oclifPlugins = this.pjson.oclif.plugins ?? []
const commandPlugins = commands.sort((aCommand, bCommand) => {
// eslint-disable-next-line no-restricted-syntax
const pluginAliasA = aCommand.pluginAlias ?? 'A-Cannot-Find-This'
// eslint-disable-next-line no-restricted-syntax
const pluginAliasB = bCommand.pluginAlias ?? 'B-Cannot-Find-This'
const aIndex = oclifPlugins.indexOf(pluginAliasA)
const bIndex = oclifPlugins.indexOf(pluginAliasB)

// If there is an external cli-hydrogen plugin, its commands should take priority over bundled ('core') commands
if (aCommand.pluginType === 'core' && bCommand.pluginAlias === '@shopify/cli-hydrogen') {
// If b is hydrogen and a is core sort b first
return 1
}

if (aCommand.pluginAlias === '@shopify/cli-hydrogen' && bCommand.pluginType === 'core') {
// If a is hydrogen and b is core sort a first
return -1
}

// All other cases are the default implementation from the private `determinePriority` method
// When both plugin types are 'core' plugins sort based on index
if (aCommand.pluginType === 'core' && bCommand.pluginType === 'core') {
// If b appears first in the pjson.plugins sort it first
return aIndex - bIndex
}

// if b is a core plugin and a is not sort b first
if (bCommand.pluginType === 'core' && aCommand.pluginType !== 'core') {
return 1
}

// if a is a core plugin and b is not sort a first
if (aCommand.pluginType === 'core' && bCommand.pluginType !== 'core') {
return -1
}

// if a is a jit plugin and b is not sort b first
if (aCommand.pluginType === 'jit' && bCommand.pluginType !== 'jit') {
return 1
}
async load(): Promise<void> {
await super.load()

// if b is a jit plugin and a is not sort a first
if (bCommand.pluginType === 'jit' && aCommand.pluginType !== 'jit') {
return -1
if (isDevelopment()) {
// Let OCLIF load all commands first, then manually replace bundled hydrogen
// commands with external ones after loading completes.
const externalHydrogenPlugin = Array.from(this.plugins.values()).find(
(plugin) => plugin.name === '@shopify/cli-hydrogen' && !plugin.isRoot,
)

if (externalHydrogenPlugin) {
for (const command of externalHydrogenPlugin.commands) {
if (command.id.startsWith('hydrogen')) {
// @ts-expect-error: _commands is private but we need to replace bundled commands
if (this._commands.has(command.id)) {
// @ts-expect-error: _commands is private but we need to replace bundled commands
this._commands.set(command.id, command)
}
}
}
}

// neither plugin is core, so do not change the order
return 0
})
return commandPlugins[0]
}
}
}
Loading