Skip to content

Instantly share code, notes, and snippets.

@jonschlinkert
Created August 15, 2014 04:52
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save jonschlinkert/fd6ed82119768ddd8580 to your computer and use it in GitHub Desktop.

Project organization

Here is how I prefer to organize projects:

┌─ _dist/
├─ assets/
├─ content/
├─ data/
├─ styles/
├─ templates/
.gitignore
etc

In alphabetical order:

  • _dist - this directory is .gitignored from the main branch, and will ultimately contain most of the dest files specified in build config. This allows us to easily built to this directory, use watch, etc. and then easily deploy to that branch when ready. I usually prefer naming this directory _gh_pages, since that's where our site will end up and it's semantically explicit.
  • assets: this directory contains assets that can easily be copied directly to the assets or public directory in the production branch, e.g. _dist. It's generally a bad idea to have files that require any kind of processing in this directory. That makes things harder to maintain, because you need to start creating conditional logic, extra tasks, or more complicated glob patterns in the build config.
  • content - this directory has only markdown files. Primarily since this makes it easy for contributors to know where to go when adding documentation, blog posts, etc. But we also have helpers that automatically calculate paths to source files, so keeping this focused makes that easier to maintain.
  • data - this directory has two different "types" of files, metadata and scripts that are used to create metadata. Here is what it should contain:
    • metadata: these are JSON or YAML files that contain metadata that will ultimately be used to replace values in templates
    • metadata scripts: these are javascript files that are used to generated metadata that will ultimately be used to replace values in templates. For example, we have a script that pulls down a list of assemble projects from GitHub, which we then use to create "related projects" lists. Another script gets the package.json file from the main branch of the assemble/assemble repo, so we can use the data from that file in templates (e.g. latest version, project description, etc.)
  • styles: .less files that need to be pre-processed. Keeping styles segmented in their own directory keeps things clean and allows us to also implement "themes". More about that in a moment.
  • templates: alternatively named structure, this directory has both templates and any "extensions" required to build the templates. In other words, the structural elements of a site. For reasons described below, extensions are also stored in this directory, which (IMHO) makes it the most potentially confusing directory in the project, but after setting up and maintaining a number of assemble projects I believe this approach makes a lot of sense. For the most part, templates are organized geometrically. In other words, they are organized based on their replicability (think "repeating patterns"), reusability (think, "generic applicability"), recursability (think, "templates within templates"), their relationship to other patterns, and their similarity (think, "do they look alike, irrespective of scale?". It's tempting to call this "resemblance" so we have the "5 Rs", but they're really not the same thing.). Here is what this directory should contain:
    • extensions: I'm using the generic label "extensions", but this refers to template helpers, middleware, plugins, and so on. Because of their inclusion in a project, we can assume that templates rely on them, and without them would not build, or at least would not build correctly. This cohesive relationship to templates earns them a place in the templates directory. Sometimes I use an actual extensions directory, and inside that I organize helpers and plugins directories, sometimes I put helpers and plugins in the root of the templates directory. Whatever makes sense for the project.
    • layouts: "Turtles all the way down". Layouts are templates that are used to "wrap" the content of individual pages with common elements, and because of this they should be as generic as possible. In Assemble, every kind of template can use layouts, including layouts themselves, pages and (as of v0.6.0) even partials. Layouts are also differentiated from other templates by their ability to recurse. Layouts can nest as many levels deeps as you want.
    • pages: pages should be mostly structural; if it's mostly written word then it shouldn't be a "page", it should be a markdown file in the content directory. But if it's mostly HTML, then it qualifies as a template; and if it's a "unique" template that will have a one-to-one relationship with a URL that will be visited by a user on the live site, then it qualifies as a page. For this reason, projects will usually only have a few pages, like home, about, etc. However, a single page could also be used with data files and markdown files to generate any number of actual web pages, so the "one-to-one relationship rule" isn't really a rule, just a rule-of-thumb. Also, marketing blurbs, headings and the like would not qualify as content, but whether or not these things should be hard-coded into a page, or moved into data files depends on the case, quantity, balance and taste.
    • partials/includes: these are template fragments, or partial views that do not have a one-to-one relationship with a URL. Partials should be constructed to be as modular and re-usable as possible, but without sacrificing pragmatism. Sometimes it makes sense to create a partial that can easily be reused on any project, but we've all worked on projects where certain pages have content that will change very little over time, and it gets arduous to continually scroll past those sections to get to the things that do change. I like to move these sections into a partials sometimes. When I do, I call put those partials into a directory named sections.
    • snippets like partials, snippets are template fragments, but they are not partial views. Snippets are used for common site elements that will most likely never be seen by a website visitor, like analytics scripts, click trackers, sitemaps, and so on.

Themes

I mentioned themes earlier. Here, themes are more like style variations for different sections of a site, like how the home page might be styled versus the blog, but the following conventions could easily apply to other definitions of the word "theme" as well.

Here is how I like to manage themes.

├── components/
├── mixins/
├── themes/
├── utilities/
└── vendor/
index.less
variables.less

Main files

The root of the styles directory contains the following files:

  • index.less: this file lists @import statements for all of the common, generically applicable files that can be used with any theme.
  • variables.less: this file contains all of the generic variables that can be used with any of the files listed in index.less.
  • Any other files that are generically applicable to all areas of the site. This might include a README.md for the styles directory, JSON files for linting CSS (e.g. .csslintrc), and so on.

basic index.less example

// Core variables and mixins
@import "variables.less";
@import "mixins/index.less";

// Theme components
// ----------------------------------------

// Typography & Code
@import "typography.less";

// Layout and structure
@import "grid.less";

// Navigation
@import "nav.less";
@import "navbar.less";
@import "sidebar.less";
@import "paginate.less";

// Informational
@import "alert.less";
@import "banner.less";
@import "callout.less";

// Buttons
@import "button.less";
@import "dismiss.less";

// Vendor
// ----------------------------------------

@import "vendor/open-iconic.less";
@import "vendor/chosen.less";

// Theme
// ----------------------------------------

@import "themes/@{theme}/index.less";

// Utilities and overrides (must be last!)
// ----------------------------------------

// Utilities
@import "utilities/index.less";

Main folders

Like templates, styles are organized geometrically into the following directories:

  • components: styles for user interface patterns, such as navbar.less and banner.less, but
  • mixins: mixins that can generically be used within any styles in a project.
  • utilities: utilities that can either 1) generically be used in any HTML in a project, usually during prototyping since styles like .pull-left ought to be replaced by properties defined in a more semantic equivalent, or 2) referred to by another selector - e.g. by using the @import (reference) directive, or :extend()
  • vendor: These are styles, and only the styles (e.g. not scripts, or other project files), that belong to a third-party module, framework or component used in the project, like bootstrap.less, open-iconic.less, or normalize.css. If it's in the vendor directory, don't edit it, consider it off-limits and locked down to the version that was initially copied to that directory. If you need to edit it, either move it somewhere else if you plan to substantially edit the styles - as you might with a framework, or when only minor adjustments will be made, add an overrides.less file to the root of the vendor directory for special styles, and add @import "vendor/overrides.less" to index.less.

And lastly, but not by alphabetical order or importance:

  • themes: Each theme has it's own folder in the theme directory, and themes themselves follow the exact same organizational pattern as their parent folder - styles, with some exceptions.
    1. utilities: should never be in a theme directory
    2. mixins: should be specific to a theme. For example, you may have a unique button pattern for a theme that you need to replicate 10 times (for all of the size, color and state variants), mixins are great for this. If the mixins are generic enough, add them to the main mixins directory, otherwise, put them in a theme's mixins directory.
    3. vendor: when you override vendor styles for a theme, add an overrides.less file to the root of the theme's vendor directory to store special styles.

Example theme:

A typical theme directory might look something like this:

├── components/
└── mixins/
index.less
variables.less

And this is how a complete project might look:

┌── _dist/
├── assets/
├── content/
├── data/
├── styles/
│    ├── components/
│    ├── mixins/
│    ├── themes/
│    ├── utilities/
│    └── vendor/
│    index.less
│    variables.less
│
├── templates/
│    ├── helpers/
│    ├── middleware/
│    ├── includes/
│    ├── layouts/
│    ├── pages/
│    └── snippets/
│
.gitignore
README.md
etc

Here is a fully expanded version with multiple themes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment