Paul Smith
Paul Smith

Reputation: 91

Structuring multiple Play Framework (2.1) projects for inheritance

I am looking to create a number of sites using Play, but want to structure it in a way so that most of the code and routes can be shared. I have seen many examples of projects that depend on other projects and found that the 2.1 release candidate allowed for importing of routes, but am still lost as to how to setup the projects. The layers I want to achieve look like this:

Core - A single shared project which contains core routes, controllers, helpers, core static resources and views

Templates - A handful of template projects which contain template specific routes, controllers, static resources and views

Sites - A large number of sites which contain mostly css (scss) and config

A single running application will then consist of a Site building on top of a single template project which is built on top of the core.

The idea behind doing this is to be able to share as much code as possible across sites, and be able to quickly build them (assuming there is a template project that fits the bill already in the templates repository).

My original thought was to have a structure that looked like:

->core
->templates
       ->template1Project
       ->template2Project
->sites
       ->site1project
       ->site2project
       .
       .

I was then going create a symlink in the modules directory under each site pointing to the templates and core, which would allow me to have these as PlayProject dependencies in each site, but still maintain only a single of each.

It feels very wrong what I am doing, has anyone else achieved a similar project structure in a better way?

Upvotes: 2

Views: 547

Answers (1)

mor
mor

Reputation: 2313

I did have to build a multi-project Play application structure and here is what we ended up doing.

Scala Build Tool

Play projects or modules are basically sbt projects and sbt does not allow to import a module from a parent directory. If you want to import a project, it needs to be accessible from the project's root. Adding symlinks to parent directories does the trick but it is some kind of monkey patch.

Instead, you can use sbt to it's full extent and define project hierarchy and dependencies from a master project.

Super Project

The hierarchy you suggest in your question seems natural and just fine, what needs to be done is to define a project that will oversee all modules and projects. It will be the only entry-point of the application.

So this super module's file system should look like:

/core
/templates
  /template1
  /template2
  ...
/sites
  /site1
  /site2
  ...
/project           --> Normal Play config files
  Build.scala      
  build.properties
  plugins.sbt
/conf
  application.conf --> emtpy file so Play recognises it as a project.

The key here is to define all projects inside the Build.scala. Depending on your projects, it could look like this:

import sbt._
import Keys._
import play.Project._

object ApplicationBuild extends Build {
  val commonDependencies = Seq( javaCore, javaJdbc, javaEbean )

  val coreDeps = commonDependencies
  val core = play.Project("core", "1.0.0", coreDeps, path=file("core"))

  val template1Dependencies = comonDependencies

  // Define the template, note that the dependsOn() adds local dependencies
  // and the aggregate() asks to first compile the dependencies when building
  // this project.
  val template1 = play.Project("template1", "1.0.0", template1Dependencies,
                               path=file("templates/template1")).dependsOn(core)
                                                                .aggregate(core)

  val site1Deps = commonDependencies
  val site1 = play.Project("site1", "1.0.0", site1Deps,
                           path=file("sites/site1")).dependsOn(core, template1)
                                                    .aggregate(core, template1)

  val main = play.Project("master-project", appVersion)
}

Also note that none of your sub-modules will need to have a /project directory as everything is defined in the master Build.scala file. Only conf/application.conf will be needed for every sub-project.

Then all you need to do is load play from the master directory and select the project from the sbt prompt:

[master-project]> project site1
[site1]> compile
[site1]> run

the projects command will list all the projects you defined in the Build.scala file and the project <project name> command will switch to the desired project.

Upvotes: 1

Related Questions