Wednesday, February 12, 2014

Ploughing through the file structure

First question I asked myself was: What is the entry point?
Logical answer for a project written in html, css and JavaScript: index.html

So let's have a look at this index file... Don't worry, I won't display the source code of every file; just the few files that form the bootstrap of Brackets.

index.html

<html>
<head>
    <meta charset="utf-8">
    <title></title>

    <!-- CSS/LESS -->

    <!-- NOTE: All scripts must be external for Chrome App support: http://developer.chrome.com/apps/app_csp.html -->

    <!-- Warn about failed cross origin requests in Chrome -->
    <script type="application/javascript" src="xorigin.js"></script>

    <link rel="stylesheet" type="text/css" href="thirdparty/CodeMirror2/lib/codemirror.css">
    <!--(if target dev)><!-->
    <link rel="stylesheet" type="text/less" href="styles/brackets.less">
    <!--<!(endif)-->
    <!--(if target dist)>
    <link rel="stylesheet" type="text/css" href="styles/brackets.min.css">
    <!--<!(endif)-->
    
    <!-- JavaScript -->

    <!-- Pre-load third party scripts that cannot be async loaded. -->
    <!-- build:js thirdparty/thirdparty.min.js -->
    <script src="thirdparty/less-1.4.2.min.js"></script>
    <script src="thirdparty/mustache/mustache.js"></script>
    <script src="thirdparty/jquery-2.0.1.min.js"></script>
    <script src="thirdparty/CodeMirror2/lib/codemirror.js"></script>
    <script src="thirdparty/CodeMirror2/addon/fold/xml-fold.js"></script>
    <script src="thirdparty/CodeMirror2/addon/edit/matchtags.js"></script>
    <script src="thirdparty/CodeMirror2/addon/edit/matchbrackets.js"></script>
    <script src="thirdparty/CodeMirror2/addon/edit/closebrackets.js"></script>
    <script src="thirdparty/CodeMirror2/addon/edit/closetag.js"></script>
    <script src="thirdparty/CodeMirror2/addon/selection/active-line.js"></script>
    
    <!-- JS for CodeMirror multiplex and overlay mode support -->
    <script src="thirdparty/CodeMirror2/addon/mode/multiplex.js"></script>
    <script src="thirdparty/CodeMirror2/addon/mode/overlay.js"></script>

    <!-- JS for CodeMirror search support -->
    <script src="thirdparty/CodeMirror2/addon/search/searchcursor.js"></script>
    <!-- endbuild -->

</head>
<body>

    <!-- HTML content is dynamically loaded and rendered by brackets.js.
         Any modules that depend on or modify HTML during load should
         require the "utils/AppInit" module and install a callback for
         "htmlReady" (e.g. AppInit.htmlReady(handler)) before touching the DOM.
    -->
    
    <!-- All other scripts are loaded through require. -->
    <!-- build:js main.js -->
    <script src="thirdparty/requirejs/require.js" data-main="main"></script>
    <!-- endbuild -->

    <!-- Verify that all dependencies are loaded. -->
    <script src="dependencies.js"></script>

</body>
</html>

Hey! This is a normal html file! So what would happen if I point my browser to it?

Nope... No joy there. Someday you will be able to, but for now it runs inside the Brackets-shell which is also an open source project. You will need to dig a bit deeper into different languages though to get busy contributing there. According to github it consists of 59.2% Python, 22% C++, 9.0% Objective-C, 7.4% JavaScript, 1.6% C and 0.6% Shell.

Anyway, back to the task at hand and going straight to the core;
Line 55 is where the magic happens. RequireJS is being included and we tell it to load a main.js file in the same folder as the index page; that is where the bootstrap starts.

So we can now have a look at the main.js file.

main.js

require.config({
    paths: {
        "text"              : "thirdparty/text/text",
        "i18n"              : "thirdparty/i18n/i18n",
        
        // The file system implementation. Change this value to use different 
        // implementations (e.g. cloud-based storage).
        "fileSystemImpl"    : "filesystem/impls/appshell/AppshellFileSystem"
    }
});

// hack for r.js optimization, move locale to another config call

// Use custom brackets property until CEF sets the correct navigator.language
// NOTE: When we change to navigator.language here, we also should change to
// navigator.language in ExtensionLoader (when making require contexts for each
// extension).
require.config({
    locale: window.localStorage.getItem("locale") || (typeof (brackets) !== "undefined" ? brackets.app.language : navigator.language)
});

define(function (require, exports, module) {
    "use strict";
    
    // Load the brackets module. This is a self-running module that loads and runs the entire application.
    require("brackets");
});

Not too much to work through now is it? We can see it is setting up some configurations to load, mostly to do with localisation and the file system. Finally on line 26, the brackets module is being loaded. The file that makes up this module is brackets.js and it is located in the same folder as the index page.

The file is close to 400 lines so I won't display it here, but it is quite straight forward, the comment explains what the module does.

brackets.js

/**
 * brackets is the root of the Brackets codebase. This file pulls in all other modules as
 * dependencies (or dependencies thereof), initializes the UI, and binds global menus & keyboard
 * shortcuts to their Commands.
 *
 * Unlike other modules, this one can be accessed without an explicit require() because it exposes
 * a global object, window.brackets.
 */

So there we have it, the complete startup process. From there it should not be too difficult to get started hacking away, creating features, bug fixes.

No comments:

Post a Comment