Magento 2 Project Directory Structure Thoughts (Quick Note)

There have been a number of questions about “what is the best way to set up source code management for a Magento 2 project”. We try to keep things open, so people can do what makes most sense for their own project, but here is what I have been doing recently for my personal “play” projects (and have been pretty happy with it so far). This may need further refinement before being used on full scale projects.

  • I am using a Docker image (“alankent/gsd”, available on DockerHub). The image is intended to help learn Magento with low barrier to entry. See https://alankent.me/gsd/introduction-to-docker/ for more details.
  • Any file I need to change in the default container I copy out to my desktop project directory tree using “docker cp”. This includes composer.json and composer.lock.
  • On Windows, I use WinSCP to watch my local directory tree and SFTP changed files into the Docker container – just type Ctrl-U to enter the copy-files-on-modification mode. (Lsyncd should do the same thing on Mac’s, but I have not tried it yet.)

The end results is a sparse project directory tree that is easy to put under source code management – no need for .gitignore files. To build a site from scratch, I can copy the composer.json and composer.lock files to an empty directory, run composer install, then copy the rest of the project directory tree over the top. Pretty easy to understand.

When using an IDE, since the official Magento source code does not change often, I copy the whole directory tree out of the container to another directory on disk, and tell the IDE about both my project directory and the copy of all the files. That way I have the files available locally for reference.

The approach is also Grunt/Gulp friendly. That is, when a file is changed it can trigger a Grunt or Gulp job – I have included the Snowdogapp/frontools Gulp project in the Docker container – just run “run-gulp.sh” inside the container to start it up.

Here is an example directory tree with a simple locally developed theme:

composer.json
composer.lock
app/
    design/
        frontend/
            AlanKent/
                magento-day/
                    composer.json
                    registration.php
                    theme.xml
                    Magento_Theme/
                        layout/
                            default.xml
                    web/
                        css/
                            orange.css

I grab the composer.json and composer.lock files out of the container as follows:

docker cp gsd:/magento2/composer.json .
docker cp gsd:/magento2/composer.lock .

I rerun these commands after adding any extensions to the project or running composer update to install a patch or similar.

If you want to go all the way and create a simple theme to try, here is a full set of files.

app/design/frontend/AlanKent/magento-day/composer.json

{
  "name": "alankent/theme-frontend-magento-day",
  "description": "Let’s be Orange!",
  "require": {
    "magento/theme-frontend-blank": "*"
  },
  "type": "magento2-theme",
  "version": "1.0.0",
  "license": [
    "OSL-3.0",
    "AFL-3.0"
  ],
  "autoload": {
    "files": [
      "registration.php"
    ]
  }
}

app/design/frontend/AlanKent/magento-day/theme.xml

<theme xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:noNamespaceSchemaLocation=
          "urn:magento:framework:Config/etc/theme.xsd">
  <title>International Magento Day</title>
  <parent>Magento/blank</parent>
</theme>

app/design/frontend/AlanKent/magento-day/registration.php

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::THEME,
    'frontend/AlanKent/magento-day',
    __DIR__
);

app/design/frontend/AlanKent/magento-day/Magento_Theme/layout/default.xml

<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation
        ="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
  <head>
    <css src="css/orange.css"/>
  </head>
</page>

app/design/frontend/AlanKent/magento-day/web/css/orange.css

body {
  background-color: #ff7f00;
}

This work came about due to a book I am working on (slowly!) on Magento 2 themes. So far I seem to have been spending more time getting the Docker image into shape than the actual book! But now the Docker image seems pretty stable, I am starting to spend more time on the book again.

As always, feedback or opinions is welcome!

7 comments

  1. Thanks for sharing. How feasible is debugging of generated files with this setup?

    1. Great question. I have been starting on themes. Php Storm is documented as supporting remote debugging with xdebug, but I have not tried it yet with the docker image – I probably have some settings to do first.

  2. Thanks for setting up this image. It’s the best solution for learning the geography of Magento 2 that I’ve found.

    I have a question specifically related to Docker. Using the SFTP method via PhpStorm to sync the file structure works perfectly. However, I also obviously need MySQL access to the Magento instance for development work. Can you point me to any instructions (or assist with any pointers of your own) to connect a tool such as Sequel Pro to the MySQL server in the Docker container?

    Thanks in advance.

    1. There are two strategies – which is better in your point of view?

      (1) Open up the MySQL port so you can connect remotely, then you can run the tool natively on your laptop

      (2) Install extra tools inside the Docker container and somehow run them there

      The first I could add to the image pretty easily. Both options you can do yourself by writing your own Docker image that inherits from mine and adds to it. E.g. for option 1, it might be something like

      DockerFile:
      FROM alankent/gsd:0.2
      MAINTAINER you
      EXPOSE 3306

      Then you run “docker build” to compile it. (Hmmm, I wonder if you just add “-p 3306:3306” to the “docker run” command line if that would just work without a new image.) I don’t have time to try just now, but let me know which way you think would be better.

      Oh, another problem someone raised was remote debugging with PHP Storm and generated code. I don’t have that answer yet as well. (It looks possible, I just have not got through the full experience yet.) Getting there!

      1. Thanks, Alan

        I think opening the MySQL port to connect directly from the host machine application is the best approach, but that may be personal preference. I’m thinking about the smoothest workflow of duplicating content and code between dev, stage, and prod environments.

        To that end, I’m also thinking through how to add Git into the container so that I can push work to a remote repo. Or, is Git already in the container?

        I can take a shot at making a new image…I’m quite new to Docker, though. I think it would be worthwhile to add into the container.

  3. Hey Alan,
    As I understand, you just have put everything into one container? This is exactly how you should not do with docker.

    There is a good example how this should be done for Magento 1: https://github.com/andreaskoch/dockerized-magento

    I have something like for Magento 2 with all services within individual container.

    1. I would never do it for production, but my goal is trivial dev experience – not productionization. Vagrant is a better fit in some ways, but docker toolbox is such a slick install experience it is hard to beat for simplicity.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.