The advantage of selecting between completely decoupled Drupal, gradually decoupled Drupal, and linked Drupal is that you can do whatever makes the most sense in each scenario. While I have built headless Drupal sites in the past, I haven't looked at decoupling Drupal. I decided that for this blog post, I would look into one popular method of Decoupling Drupal with the Tome module.
Some caveats to Decoupling Drupal with the Tome module
Before you get too excited and start planning your decoupled site with all the bells and whistles, you need to understand the limitations of this approach. You will not be able to use any dynamic content or forms. This means you can't use the Contact or Webform modules as they require an endpoint to call back to. Which won't exist in this setup. There will be no site for the forms to post back to.
Searching will also be a difficulty as you will not be able to use the built-in search or SearchAPI modules to provide this functionality. There is no way to use the default search forms on a static site as it will need something to call back to.
You also need to think about the editing experience of your site. Remember what we are doing here is separating Drupal and the front end theme. This means your editors need to know how to edit content, which means giving them access to some sort of hosting environment.
Installing a new site
The easiest way to get up and running with Tome is with a new project. Running the following command will create a default Drupal 9.1 codebase with the Tome module ready to go.
composer create-project drupal-tome/tome-project my_site --stability dev --no-interaction --no-install cd my_site
You can now commit this directory to a git repository as this will be your editor site source code.
To install Drupal you just need to run the tome:init command using Drush. This command will install Drupal locally as an SQLite install and allow you to select the install profile. It's probably a good idea to go for 'Standard' in this case.
Once the site is installed you will need to uninstall any modules that provide dynamic content or forms. Ultimately, this means uninstalling the search and contact modules as well as any tracking modules like history. These modules are installed as part of the standard install profile but can be uninstalled with a single command.
./vendor/bin/drush pmu search contact history -y
Now it's time for you to start creating content. You can easily start the site by using the Drush runserver command.
./vendor/bin/drush runserver 127.0.0.1:8888
As we have installed the site using the standard install profile we see the familiar Bartik theme.
After a few minutes of configuration, we now have a few pages of test content and have enabled the Olivero theme.
Once you have set up your site and created content, you will need to generate the static site. This is done using the tome:static Drush command. It is also a good idea to pass in the --uri flag to set the domain of the static site as without this you can create invalid links between pages. In the example below I am passing a local site for testing purposes but you should pass in whatever domain you will ultimately host the site on.
./vendor/bin/drush tome:static --uri=http://localhost:8999
Your content will be generated in the directory 'HTML by default. It isn't really possible to view the content statically as the content expects to be served through a web server. You can easily do this using the built-in PHP web server as a quick test. The following command runs the PHP web server and points the resource to the HTML directory, which is where the static site is kept.
php -S 0.0.0.0:8999 -t html
When you visit localhost:8999 you will see your static site.
There are still some things to do
As you can see from the screenshot there is a "log in" link on the top right-hand side of the page. With a static site, this obviously leads nowhere and should be removed from your local setup. Running a preview like this will show you where problems exist in your setup and allows you the opportunity to fix them.
The good thing about Tome is that it's always watching for changes to your site. Meaning, when you update a page or change some site configuration Tome will automatically export that to your file system to keep things in sync. When it comes to generating your static site content Tome uses these files to generate the static site. The upshot is if you change a single page on your site, Tome doesn't need to regenerate the entire site; it will only change the files that have changed. What was interesting is that you can rebuild the site from the configuration files that Tome creates, you don't necessarily need to save the database.
With the static site generated the next step is to put it on some form of hosting. Services like GitHub pages or Netlify are really useful for hosting static sites like this. All you need to do is copy the contents of the HTML directory to these services, probably by creating a git repository for that directory and pushing that upstream.
Installing on an existing site
I haven't had much success installing Tome on existing sites, and probably for good reason. Many sites are started out with dynamic content and interactivity in mind. As such the static content that Tome expects isn't really available and you tend to end up with non-working sites. I have tried converting exiting sites into Tome sites and faced a few issues.
To install Tome on an existing site you need to require Tome through composer and then install the tome_static module. This will install the Tome Base and Tome Static modules.
$ composer require drupal/tome $ ./vendor/bin/drush en tome_static -y
I should note if you want the automatic synchronisation of content and configuration we had the previous setup then you need to also install the Tome and Tome Sync modules.
An optional step is to set the output location of the static content. This is governed by the tome_static_directory setting, so if you want to change this to suit the site you are integrating against you just need to alter this setting. This defaults to './html' so if that's fine for your setup then there's no need to change this.
$settings['tome_static_directory'] = '../html';
As your site is already full of content the next step is to export the content as a static site. This is a good first step to see if your site is compatible with static generation.
./vendor/bin/drush tome:static --uri=http://localhost:8999
If you preview your site and you are redirected to your Drupal install this is a sign there is something incompatible with Tome's static site generation. With that in mind, you can start removing things that are causing this. I said before, the search and contact forms are a bit of a problem with static site generation, but modules like redirect or rabbit hole will also cause problems like this. You will need to remove anything that generates dynamic content or performs any redirects. I'm afraid it will just be a case of removing modules or functionality from the site and then regenerating things to see if it worked. The bottom line is, the more complex your Drupal setup is, the more problems you will have generating a static site from that setup.
Pros of decoupled Drupal
The biggest benefits of using a decoupled architecture like this are speed and security. As the sites are static HTML files then it's clear that serving them will always be faster than bootstrapping Drupal and rendering content out. Also, because the files are static then your security situation is pretty clear. As there is no code being run on the webserver then there is no chance of any exploits or other attacks being successful on the site. Even if your site is compromised you can just redeploy your static site and everything will be the same as it was before.
There is one thing that really stood out for me with Tome. The excellent quality of the documentation. It's crammed with lots of examples of setups, including some implementations and a list of compatible modules. It's worth a read if you want to get into using Tome.
Cons of decoupled Drupal
The biggest downside to running Drupal like this is that you cannot benefit from any dynamic content. Meaning, you can't have contact forms or any form of personalisation on the site. Well, that's not entirely true, it is possible to embed third-party forms and other libraries to provide contact forms and search features. It is even possible to deploy Drupal next door to your Tome generated site and have Drupal serve certain paths or pages on the site. This is an advanced setup though and might need some work to get things running correctly. For the most part, though, you will need to rely on static pages of content.
There is also the issue of the theme layer working against you with links to log in or registration links being present by default in a Drupal install. These are easily worked around but you'll need to spend time to make sure they aren't available. I have seen static sites on the internet created using Drupal that have Drupal links or forms in them that don't actually do anything. Tome is awesome at avoiding problems with these dynamic elements, but the solution it has it to defer to Drupal for the answers, which won't always be present. Tome will automatically link back to the homepage for any user login and registration links, so all you need to do is prevent the links from being shown.
Even before you start on your static site setup you will need to think about how to edit content and what your workflow will be. You need a Drupal site somewhere in the workflow so that you can edit create pages of content. As I have demonstrated above, it's pretty simple to install Tome locally, but if you want other people to write content then you'll need to host Drupal somewhere.