Shopify CLI

repository·main·Indexed 20 days ago

https://github.com/shopify/cli

A command-line interface for developing Shopify apps, themes, and Hydrogen custom storefronts. It includes a plugin architecture based on @shopify/cli-kit, which provides a UI Kit for standardized terminal interactions, including prompts (select, confirmation, autocomplete, text), static output banners, and task visualizers for concurrent or sequential processes.

Tokens
136.1K
Snippets
430
Records
616
Agent score
71%

What's inside Shopify CLI

  1. Overview of Shopify CLI capabilities

    main

    The Shopify CLI is a command-line tool used to manage various aspects of the Shopify development lifecycle. It allows developers to:

    • Apps: Initialize, build, develop, and deploy Shopify apps, extensions, and functions.
    • Themes: Initialize, build, develop, and deploy Shopify themes.
    • Hydrogen: Build custom storefronts and manage their hosting.
  2. Overview of Shopify CLI and Plugin Architecture

    main

    The Shopify CLI is a terminal-based tool used by merchants, partners, and developers to interact with the Shopify platform.

    Its architecture is designed for horizontal feature expansion through plugins. Instead of a monolithic structure, specific capabilities are added via specialized packages that build on top of @shopify/cli-kit.

    Examples of existing plugins include:

    • @shopify/theme: For developing Shopify themes.
    • @shopify/app: For developing Shopify apps.
    • @shopify/cli-hydrogen: For developing Hydrogen custom storefronts.
  3. What is the CLI UI Kit?

    main

    The CLI UI Kit is a set of modules within the @shopify/cli-kit package designed for terminal interaction. It provides a standardized way to:

    1. Ask for user input via prompts (e.g., text, selection, confirmation).
    2. Render output to the terminal (e.g., banners, info messages, error messages).

    Using the UI Kit ensures that your CLI commands maintain a consistent look and feel with the rest of Shopify's tools and allows you to benefit from design improvements automatically without changing your code.

  4. How auto-update of extensions works

    main

    The useExtensionServerContext hook automatically manages extension state by listening to specific events. You do not need to manually subscribe to these to achieve the following behaviors:

    • Live reloading: Asset URLs for extensions are updated with a new timestamp whenever the JS bundle is rebuilt and an update event is dispatched.
    • Focus/Unfocus: The focused property in the context state is set to true or false based on focus and unfocus events.
    • Refresh: Asset URLs are updated with a new timestamp whenever a refresh event is dispatched.
  5. How `@shopify/create-app` bundles dependencies

    main

    The @shopify/create-app package builds a bundle at dist/commands/init.js.

    Unlike other packages, it bundles @shopify/cli-kit directly into the command bundle rather than treating it as an external dependency. This allows Rollup to perform tree-shaking, ensuring that only the specific elements of @shopify/cli-kit required for app creation are included in the final bundle, keeping the installation lightweight.

  6. Use reserved environment variables for specific flags

    main

    Certain flags are considered 'reserved' and must use a specific, pre-defined environment variable name. Do not attempt to create custom environment variable mappings for these reserved flags, as it will violate the command-reserved-flags rule.

    export default class Dev extends Command {
      static flags = {
        path: Flags.string({
          hidden: true,
          env: 'SHOPIFY_FLAG_APP_PATH', // Incorrect: It must be SHOPIFY_FLAG_PATH
        }),
      }
    }
  7. How Shopify CLI manages identifiers during development and deployment

    main

    To prevent accidental Git commits of sensitive or environment-specific identifiers, Shopify CLI uses two different persistence strategies depending on the workflow:

    Local Development

    During development (dev command), the application ID (API key) is stored in a global cache associated with the project's directory. This allows the ID to be reused across multiple runs without being written to project-level configuration files. Extension IDs are generated randomly and are tied to the lifecycle of the specific dev command run.

    Deployment

    During deployment, identifiers are persisted in a .env file at the root of the app. This ensures that all deployments target the same production Partners' App.

    Best Practices for Deployment IDs:

    • Git: Developers should decide whether to include the .env file in their Git repository (it is common to exclude it).
    • CI/CD: In automated environments, set the IDs using environment variables instead of relying on a .env file.
  8. Understand the Shopify CLI architecture and runtime

    main

    As of version 3.0, the Shopify CLI is a TypeScript-based tool that targets NodeJS as its primary runtime.

    Key architectural characteristics include:

    • Single Source of Truth: Projects use a single package.json at the root to manage dependencies for all app blocks, replacing scattered dependency management.
    • Deterministic Dependency Management: The CLI uses a dependency manager to resolve and pull a dependency graph, verifying compatibility with the Node environment.
    • Hybrid Runtime: While the core is TypeScript/NodeJS, certain components (specifically those depending on theme-check used in Rails-based projects) remain in Ruby. The CLI handles this by including the Ruby code within the NPM package and verifying that a Ruby interpreter is present in the user's environment before executing theme workflows.
    • Extensibility: The CLI is designed to support a plugin system and provides APIs for developers who want to bring their own custom workflows and setups.
  9. How the CLI UI Kit works

    main

    The UI Kit is built on a principle of abstraction. All public functions are defined in public/node/ui.tsx and accept simple JavaScript objects as parameters.

    Instead of requiring you to manage React components or JSX directly, the API allows you to focus on providing data structures (like tokens) to render functions. This abstraction allows the underlying implementation to be upgraded or restructured without breaking your command's public API.

  10. Understand the CLI UI Kit API categories

    main

    The CLI UI Kit public interface is divided into three categories based on how they handle execution and rendering:

    1. Static output: Stateless components that print output once. These functions are not promises and can be called in succession without await.
    2. Prompts: Interactive elements that interrupt the command flow to ask for user input. These must be awaited.
    3. Async tasks: Visualizers for running background processes. These must be awaited.

    CRITICAL: Do not call two Prompts or Async tasks in succession without awaiting them. Doing so will instantiate multiple React rendering instances, causing rendering conflicts.

  11. Classifying errors as environmental issues

    main

    The CLI uses two primary mechanisms to classify non-fatal errors as environmental issues:

    1. shouldReportErrorAsUnexpected: Determines if an error should be treated as a CLI bug.
    2. errorMessageImpliesEnvironmentIssue: Checks if an error message matches known environmental patterns.

    Common categories for environmental issues include:

    • File System Permission Issues: e.g., EACCES: permission denied.
    • Network Connectivity Issues: e.g., DNS failures or socket hang up.
    • Resource Contention: e.g., EBUSY: resource busy or locked.
    • External Tool Version Mismatches: e.g., Node/npm version incompatibilities.
    • Platform-Specific Issues: OS-level restrictions (Windows vs. POSIX).

    Guidelines for adding new patterns:

    • Be conservative: Only add highly generic, cross-cutting messages.
    • Ensure stability: Use precise substrings that are unlikely to change across Node.js versions or platforms.
    • Avoid business logic: Do not include strings related to Shopify APIs or specific business logic; those should be handled locally in the code where they occur.
    const environmentIssueMessages = [
      'EPERM: operation not permitted, scandir',
      'EPERM: operation not permitted, rename',
      'EACCES: permission denied',
      'EPERM: operation not permitted, symlink',
      'This version of npm supports the following node versions',
      'EBUSY: resource busy or locked',
      'ENOTEMPTY: directory not empty',
      'getaddrinfo ENOTFOUND',
      'Client network socket disconnected before secure TLS connection was established',
      'spawn EPERM',
      'socket hang up',
    ]
  12. Performance principles for dependencies

    main

    Because the CLI avoids heavy bundling tools (like ESBuild or Webpack) to keep the tooling stack lean and debugging simple, dependencies are not tree-shaken. This means importing a module often loads its entire dependency graph. To maintain performance, follow these guidelines:

    • Minimize dependencies: Avoid adding new ones unless strictly necessary.
    • Prefer modular interfaces: Choose dependencies that offer many small exports rather than a single monolithic module.
    • Use dynamic imports for large ESM dependencies: If a dependency is large, use await import("dependency-name") to load it only when needed. Note that this makes the dependent module's API asynchronous.
    • Fallback to CJS: As a last resort, if a dependency is a bottleneck, consider using its CommonJS (CJS) version or dynamic imports.