In my last post, I outlined a method that can be used to develop compilable-ExtJS 4 applications, with minimal configuration, that leverage a common, global location for shared assets and libraries. This approach works fine if you are merely “compiling” the application (e.g., only the JS part). However, if you do the full “build” you’ll quickly run into a number of issues.

The most significant of the issues is that the full build process will attempt to compile the theme for your app via the compass compile command. Since our approach decouples the app from the library, AND because we didn’t exactly deal with the SASS/theme bits whatsoever, the errors just roll and roll when building the app.

Fortunately, the fix is pretty easy. In the following, I’ll outline some necessary pre-requisites you’ll need to get setup before building, and then I’ll suggest a few options for how to do this.

Another Virtual Directory

Since we’re primarily interested in styles–particularly images–we need another virtual directory that will point to the images for our theme.

In httpd.conf, I’ve added the following:

Alias /sencha/testapp/resources/images "/Users/{username}/sencha/extjs/resources/themes/images"

NOTE: If you are developing your own custom theme that will be app-specific, you can skip this step and just put the theme images in your app’s main directory, at “resources/images/{themename}”. In this example, I want to just use the globally-available “default” theme, so I’ll need the virtual directory.

Theme.html

If you look in in your app folder at /resources/theme/default/, you’ll see a theme.html file. Go ahead and open it up in a browser (preferably via the site’s hostname). You’ll notice that it pretty helpfully shows you all the components in ExtJS that will be “sliced” when your app (and theme) are built. Incidentally, if you are making major changes to your theme, this is a great spot to see how your styles will be applied.

The downside of this file in its current state, however, is that we have a relative path to the ExtJS library (“../../ext/ext-all.js”). While this works perfectly fine for previewing our theme as an HTML file, this will cause our build to fail as the build process will not be able to cope with the virtual directory to “ext”.

So there are a few options here.

Option 1: Generate Path from New Theme

The first is to use Sencha Cmd to generate a new theme. Starting at the root of your app, enter the following:

sencha generate theme {somethemename}

Once this completes, you should see new folders in the resources/css, resources/sass, and resources/theme folder bearing the name of your new theme. If you open up the theme.html file in your new theme, you should see that the path to ext-all.js is now a fully realized relative path to the global library. If you re-run the build, this should work. You can now copy the relative path from the new theme, put it in your old theme, and delete the new theme (if you don’t want it).

The downside, of course, is that if you try to preview your theme in the browser from your app’s host name, the ExtJS library will fail to load, since the path is no longer valid from your app’s host name.

Option 2: Full Host Path to Library

The second option is something of a cheat, but it works. In your theme.html file, simply replace the relative path to ext-all.js with one that points to a resolve-able host path that contains the file. So for example, you could set up a test hostname on your own machine (e.g., dev.assets.com) or just use the CDN path. As long as you are using an accessible host path, both the build AND the preview of the theme.html will succeed. I prefer the second.

Config.rb

In /testapp/resources/sass/default/, you’ll find a config.rb file. We need to adjust the $ext_path variable to point to the absolute root of our desired ExtJS library, since the build process will not understand the default relative path (which is pointing to a virtual directory in our example).

I set mine to:

$ext_path = '/Users/{username}/sencha/extjs/ext-4.1.1a'

Utlis.rb

There is a long-standing bug in one of the files used by the theme slicer that needs to be corrected. In the root of your global ExtJS library, open the utlis.rb file in resources/themes/lib/. There are a few changes to make.

First, find where the relative_path variable is being set. Change it to:

relative_path = "../../images/"

Next, find this line:

images_path = File.join($ext_path, 'resources', 'themes', 'images', theme)
Change it to:
images_path = relative_path
Finally, find the definition for the theme_image_exists method. Replace it with this:
def theme_image_exists(path)
   result = false
   # Set absolute replacement path for theme images; since all our theme images are off-root to this project
   # we need to check the off-root folder to see if the images exist
   # Ultimately, this stops those pesky "image doesn't exist" errors
   abs_path = File.join($ext_path, 'resources', 'themes', 'images')
   # replace "images" selector with our absolute path to our theme images
   where_to_look = path.value.gsub('../../images', abs_path)
   if where_to_look && FileTest.exists?("#{where_to_look}")
      result = true
   end
   return Sass::Script::Bool.new(result)
end

Build-Impl.xml

The last step (I promise!) is to adjust the build-impl.xml file in /testapp/.sencha/app/.

The reason for this is pretty straightforward. If we had our theme images in our /testapp/resources/ folder, this ANT script would automatically copy them into our build output folder. However, now that we’ve got our theme images being included via a virtual directory, the ANT script has no idea about them, and so will not copy them into our build output folder. The addition we’re making, then, is a simply a directive to ANT to go to our external ExtJS library and copy the files that we need.

Add the following at line 176 (or so), after the existing <copy> directive:

<!-- get theme images from root extjs source -->
<copy todir="${build.dir}/resources/images/">
    <fileset dir="${ext.dir}/resources/themes/images/" includes="default/**/*"/>
</copy>

Let’s Build Something!

Now that the craziness is over, we can actually build the app. To do this, simply open Terminal, navigate to your application’s root, and enter the following:

sencha app build

That’s it. If everything worked, you should now be able to browse to /testapp/build/testapp/production and see your fully-built app. All JS, CSS, and image assets should be included properly, and their paths should all be properly relative to the context of the index.html file that you are currently viewing.

Wrapping Up

I know what you’re thinking: that’s a crap-load of steps. Is it worth it? Maybe, maybe not; it depends on how you’re doing things and whether making copies of ExtJS files and assets over and over and over is a simpler approach than a few repeatable configuration steps.

It does get better, though. In my next post, I’ll show how you can knock out most, if not all, of these steps by modifying Sencha Cmd itself. Cue dramatic music :)