A Quick Tour of Expansive

This is a quick beginners tour of Expansive. It will show you how to get started using Expansive for easily creating web sites. Before you start, make sure you have read the Quick Start and that you have ESP downloaded and installed on your system.

Creating a New Web Site

We first need to create a directory for the web site. We'll call this "blog"

$ mkdir blog $ cd blog $ expansive init [Create] expansive.json

This will create the required standard Expansive files and directories including:

Name Description
contents Source content for the web site including web pages, images and assets.
dist Distribution directory where the final public documents of the web site will be placed.
expansive.json Expansive configuration file.
layouts Directory for master page layouts.
package.json Web site package description file.
partials Directory for partial pages.

As you install packages using the Pak package manager, the following directories will be created as needed.

Name Description
paks Installed packages — full contents.
contents/lib Exported package library files.

First Page

To create a web page, use your favorite editor and create a page named index.html under the contents directory.

<html> <head> <title>First Page</title> </head> <body> <h1>Hello World</h1> </body> </html>

Running Expansive

Now you can run expansive to create the new site.

$ expansive render [Created] index.html

This process all the files under contents and creates a complete, rendered web site under the dist directory. You can also render and then serve the content while dynamically watching for any changes to the input sources by invoking expansive without any other arguments.

$ expansive serve
    [Listen] 127.0.0.1:4000
    [Render] Initial render ...
   [Created] index.html
  [Watching] for changes every 1 sec ...

Expansive will first render the files under contents and create the web site under the dist directory. It will then listen on port 4000 for browser requests. So open your browser and go to http://localhost:4000 to see your new page.

Creating Layouts

Most pages share a similar layout with other pages and replicating that layout from page to page is slow and difficult to keep each page in sync. Expansive provides layout pages that define the common elements of pages so that content pages can focus on the unique aspects of the page.

Layout pages provide the outer contents. Expansive automatically blends the layout page with the content page to create a final composite page. Let's extract the layout from the first page and create a master layout page in layouts/default.html.exp.

<html>
<head>
    <title><@= meta.title @></title>
    <@ renderStyles() @>
</head>
<body>
    <@ content @>
    <@ renderScripts() @>
</body>
</html>

The .exp extension indicates that this page contains embedded Expansive script that must be processed. More on this a little later on. The renderScripts() and renderStyles() calls will generate the required script HTML elements and stylesheet references. To use these functions, we need to install two Expansive plugins: exp-css and exp-js.

pak install exp-css exp-js

Now we can change the contents/index.html home page to remove the layout HTML and focus just on the unique content for this page:

{
    title: 'Hello World'
}    

<h1>Hello World with Layouts</h1>

If you kept Expansive running from before, it will detect the new layout and automatically render the new dist/index.html. Reload your browser to see the new content.

The special area between the braces at the top of the content page is called Meta data. It provides meta data values that can be accessed in layout pages using the special @= Expansive sequence. This is how you can control and customize layout pages from within content pages.

Packages

Expansive can be extended by installable packages to provide content, functionality and quick-start skeletons. Expansive leverages the Pak package manager and the online Pak Catalog of packages. The Pak utility is used to install, manage, upgrade and uninstall packages. Expansive has a wide variety of pre-integrated plugins to make your development go faster.

For example, to install jQuery using Pak:

$ pak install jquery
[Install] jquery 1.11.1

Behinds the scenes, Pak has downloaded jquery into your local Pak cache (typically ~/.paks), installed jQuery into the paks directory, and added jQuery to the list of dependencies in the package.json. When Expansive next renders the site, it will notice that jQuery asks for the jquery.js file to be added to the Expansive scripts collection via its package.json file. Expansive automatically generates a reference for jquery.js via the renderScripts() statement in the layout file. In this way, many Expansive extension paks, can just be installed and they self-configure into your application.

This is what the dist/index.html home page now looks like:

<html>
<head>
    <title>Blog</title>
</head>
<body>
    <h1>Hello World with Layouts</h1>
    <script src="lib/jquery/jquery.js"></script>
</body>
</html>

See the Pak Catalog for more Expansive plugins and packages, including: Bootstrap, Angular, Font Awesome, Semantic UI, and Sass.

Plugins

Plugins are a special class of extension that provides core processing for the Expansive pipeline. Plugins provide services that are used to transform a file from one extension to another. For example: the exp-md plugin provides the compile-markdown-html service that transforms .md files into standard .html files.

Skeletons

Expansive skeletons are integrated collections of Paks that are excellent starting points for web sites. Skeletons include all required dependencies and provide an easy, one-step creation of your web site.

For example, to create a web site that will use Semantic-UI, a modern alternative to Bootstrap, use this command in an empty directory:

$ pak -i install exp-semantic-skeleton
[Install] jquery 1.11.1
[Install] semantic 0.50.0
[Install] exp-semantic-skeleton 0.1.0

This installs Semanic-UI, jQuery, the semantic skeleton, and a set of Expansive plugins to process Less and CSS stylesheets and scripts, as show by the pak list command.

$ pak list
exp-semantic-skeleton 0.1.0 installed
jquery 1.11.1 installed
semantic 0.50.0 installed
exp-js 0.2.0 cached
exp-less 0.2.0 cached
exp-css 0.2.0 cached

The exp-js plugin processes script files to minify and compress. The exp-less plugin processes Less stylesheets to compile into CSS files. The exp-css plugin manages browser css prefixes and minifies CSS stylesheets. These plugins are automatically invoked for the appropriate file extensions. Although, you can modify this behavior via the expansive.json configuration file.

Processing Pipeline

So far, we have processed simply HTML pages, but Expansive can render other file types such as Markdown or ESP. To process Markdown files, first install the Markdown plugin.

$ pak install exp-md
[Cached] exp-md 0.2.0

Now create a sample markdown page, create a document called contents/greeting.html.md with the following content:

# Greetings
Expansive **expands** your mind.

Expansive will render this and create dist/greeting.html which will look like:

<html>
<head>
    <title>Blog</title>
</head>
<body>
    <h1 id="greetings">Greetings</h1>
    <p>Expansive expands your mind.</p>
    <script src="lib/jquery/jquery.js"></script>
</body>
</html>

Expansive renders the web site by processing all files in the contents directory. It interprets the all file's extensions, one by one. For example: if a file were named page.html.md it would invoke the markdown processor for the .md extension, then it would invoke the .html processor before saving the final result under the dist directory. A file can have any number of extensions and they will be processed from the outside-inwards.

Scripting

Expansive supports powerful scripting for files with a .exp extension. Expansive uses the Ejscript Javascript language for embedded scripts that are processed at "render-time". This means that static web pages can use dynamic scripting without a run-time penalty when the site is live.

If a source page, layout or partial has a .exp extension, it will be processed by the Expansive Ejscript service. Javascript code is defined between the <@ code @> tags. For example:

<p>Today's date is <@= Date() @>

The <@= sequence means run the Javascript expression and paste the result here. The <@ sequence (without the equals) means run the Javascript code and do not paste any result. This is useful to iterate over html elements. For example:

<ul>
<@ for (i = 0; i < 10; i++) { @>
    <li> Item <@= i @> </li>
<@ } @>
</ul>

This will emit ten item lines

The <@= sequence means run the Javascript expression and paste the result here.

<ul>
    <li> Item 0 </li>
    <li> Item 1 </li>
    <li> Item 2 </li>
    <li> Item 3 </li>
    <li> Item 4 </li>
    <li> Item 5 </li>
    <li> Item 6 </li>
    <li> Item 7 </li>
    <li> Item 8 </li>
    <li> Item 9 </li>
</ul>

Short Forms

Because variable substitution is so common, Expansive provides some convenient short forms:

Configuration

Expansive is configured by an expansive.json configuration file that controls the initial meta data, directory names, file patterns to process, ports to serve and processing instructions. Expansive uses sensible defaults so you typically do not need to configure much. Here is a typical expansive.json file:

{
  meta: {
    site: 'https://www.embedthis.com/',
  },
  control: {
    copy: [ 'images' ],
  },
  services: {
    'compress':  false,
    'minify-js':  false,
    'minify-css': false
 }
}
        

The Meta property section defines the default public URL for the site via the site property. The control.copy property provides a hint to Expansive that anything under the 'images' directory should be copied and not processed by the Expansive pipeline. The services property set provides configuration for the plugin services to control their operation and enable/disable minification and compression services.

If you require a scripted configuration, you can alternatively use an expansive.es script file instead of the expansive.json. For more details, see the reference configuration section.

Queries and Collections

Expansive provides a Collections facility for managing lists of items. It uses collections to manage a list of required stylesheets and scripts. However you can create your own collections. To create a collection via the configuration file:

{
  control: {
    collections: {
      styles: [
        'css/all.css',
      ],
      downloads: [
        'public/*.gz',
      ]
    }
  }
}

This adds the css/all.css stylesheet to the existing 'styles' collection. The downloads collection does not exist, so it is created.

You can also use the APIs: addItems(collection, items), getItems(collection) and removeItems(collection, items) in Expansive script code to access collection data.

Queries

Expansive provides a powerful query API to work with files to be rendered in the contents directory. The getFiles API can query the meta data of source files.

<@ var list = getFiles({ isPublic: true }) @>

This will return a list of filenames for documents that have meta data isPublic set to true.

Release Modes

Expansive can render web sites according to a configured mode. This mode may be set to debug, test, release, or any string value you like. The mode is stored in the mode property in the package.json file and is accessed by Expansive when rendering the site. For example:

{
  "debug": {
    "services": {
      "gzip": false,
      "css": false,
      "js": false,
    }
  },
  "release": {
    "services": {
      "css": true
    }
  }
}

This defines two modes: debug and release. In debug mode, minification of CSS and script files is disabled and compression via the exp-gzip plugin is disabled. In release mode, minification is enabled for scripts by default and is explicitly enabled for CSS files.

The mode may be conveniently set via:

pak mode debug
  or
pak mode release

Deployment

When deploying Expansive web sites, you should configure the appropriate mode and run expansive render. All the files you need for your site will be under the dist directory.

© Embedthis Software. All rights reserved.