Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Starting a new Project Type

Kevin O'Sullivan edited this page Jul 8, 2021 · 9 revisions

Implementing a new project type

Implementing a new project type is easy.

First create a new folder lib/project_types/<type name>. This type name will setup how your project is loaded. For instance if you name your folder foo, it can be loaded by calling ProjectType.load_type(:foo). Inside your new project type create a cli.rb file with the following contents. (Foo can be replaced by your own namespace)

# frozen_string_literal: true
module Foo
  class Project < ShopifyCli::ProjectType
    # Project.project_filepath is used so that your filepaths will not break if
    # our setup changes. It defines the filepath, relative to your project type.
    require Project.project_filepath("messages/messages")
    # register_messages loads the output strings specific to this project
    register_messages(Foo::Messages::MESSAGES)
  end

  # define/autoload project specific Sub-Commands
  class Command < ShopifyCli::ProjectCommands
    # hidden_feature will hide these commands so that users
    # wont discover it while you are developing it.
    hidden_feature
    # hidden_feature(feature_set: :foo_project) can be used to conditionally show this project type

    # Project.project_filepath is used so that your filepaths will not break if
    # our setup changes. It defines the filepath, relative to your project type.
    subcommand :Create, "create", Project.project_filepath("commands/create")
    subcommand :Serve, "serve", Project.project_filepath("commands/serve")
    # subcommand :Build, Project.project_filepath("commands/build")
  end
  # now we register the "foo" command, with the above sub-commands, into the main
  # Commands framework
  ShopifyCli::Commands.register("Foo::Command", "foo")

  # define/autoload project-specific Tasks
  module Tasks
  end

  # define/autoload project-specific Forms
  module Forms
  end

  # define/autoload project specific service objects
  autoload :FooBuilder, Project.project_filepath('foo_builder')
end

Now you have defined a new project type and registered the top-level command foo for that project. We've indicated that it will have two sub-commands - create and serve. Lets implement the create command by implementing Foo::Command::Create which will be loaded from Project.project_filepath('commands/create'), which is lib/project_types/foo/commands/create.rb.

# lib/project_types/foo/commands/create.rb
module Foo
  class Command
    class Create < ShopifyCli::SubCommand
      def call(_args, _name)
        project_name = 'new_proj'
        @ctx.mkdir_p(project_name) # create the new directory
        @ctx.root = File.join(@ctx.root, project_name) # change our context to the new directory
        @ctx.write('index.html', '<body><h1>Hello World</h1></body>') # create a new file
        # write the .shopify-app-cli file with the foo app type
        # this will indicate that your project type `foo` should be loaded when in this directory
        ShopifyCli::Project.write(@ctx, 'foo')
      end

      def self.help
        <<~HELP
        {{command:#{ShopifyCli::TOOL_NAME} foo create}}: Creates a foo project.
          Usage: {{command:#{ShopifyCli::TOOL_NAME} foo create}}
        HELP
      end
    end
  end
end

If you have your development instance loaded in your console, you should be able to run shopify foo create. That will create a new directory with an index.html file inside of it as well as a .shopify-cli.yml file, indicating the project type.

To see more about hidden_feature please see the feature sets page

Clone this wiki locally