Easy fix for phantom duplicate custom module files (due to Composer) in popular IDEs

Published January 4, 2023

When writing Drupal custom modules, best practice dictates that the module should be written in the project root's /modules/ directory - so that composer require can be used add the custom module as a dependency to the project (with a little help from the composer/installers plugin, of course). In most cases, the module's code is then symlinked from the /modules/ directory to the /web/modules/custom/ directory.

One potential pitfall of this approach is that both PhpStorm and Visual Studio Code will see both the "copies" of the files in the custom modules, leading to duplicates in IDE search results, code quality tools, and other places. 

Luckily, it is an easy fix for both PhpStorm and Visual Studio Code.

The following is an excerpt from the curriculum of Professional Module Development, a 90-hour, best-practice focused course from DrupalEasy.

Visual Studio Code

This issue can be mitigated in Visual Studio Code by navigating to "Preferences | Settings" then searching for "symlink" and disabling "Search: Follow symlinks". Note that Visual Studio Code has per-user and per-workspace (project) settings, so consider disabling this feature for one or both.

Visual Studio Code screenshot showing symlink setting.



This issue can also be mitigated in PhpStorm by marking duplicate directories as "Excluded". This can be done by right-clicking on the directory to be excluded in the project browser and selecting "Mark directory as… | Excluded". For example, to exclude the entire web/modules/custom/ directory:

PhpStorm screenshot to mark directories as excluded.



Genuinely the first time I've heard about this practice of custom modules living outside the docroot directory and being symlinked into web/modules/custom. I wonder if you can share a bit more about this practice? I don't think I've worked on any projects where this has been the case and have been building Drupal sites of all sizes for well over 10 years. Every day is a school day, as the saying goes!


Submitted by Welly (not verified) on Thu, 01/19/2023 - 07:20

"best practice dictates that the module should be written in the project root's /modules/ directory"

Why is this, and where is it documented? I've never come across this before, I've always just put custom modules straight into /web/modules/custom/ . Perhaps it's something to do with making custom modules their own packages for composer to install, but surely then they should just live in their own repos anyway, rather than having copies in two places?

Submitted by James Williams (not verified) on Thu, 01/19/2023 - 07:55

Author comment

Perhaps "best practice" was too strong of a phrase, but the reason I do it that way (and see many others do the same) is that with a few additional tweaks, it makes it so that the entire web (docroot) directory is "disposable" - that is one can delete it, run "composer install" and get it recreated.

Interesting! I'm curious - why can that be a useful / good thing, at least with custom modules? (If I had a need to do that, I would probably just lean on git to be able to easily restore my custom modules within the docroot, rather than having them appear in multiple places.)

I sometimes find a need to reinstall contrib modules etc, but I can still easily do that by deleting those (and/or the vendor directory) and running 'composer install'. But making the whole docroot disposable is new on me.

If you've written a post about this method of storing custom modules outside the docroot, it'd be useful to link to it. If you haven't, you might consider doing one.

Submitted by Guest (not verified) on Thu, 01/19/2023 - 13:07

This is the first I've heard of such a method. We ise composer.json file to place our files in the right directories (custom dir in /modules/custom) and seems to work just fine with the teardown/install that you have mentioned as one of the benefits of the articles benefits. I'm a bit confused.

Submitted by Prine (not verified) on Sat, 01/21/2023 - 13:45

Sign up to receive email notifications of whenever we publish a new blog post or quicktip!