Mailspring/docs/PackageOverview.html
2015-10-03 13:11:25 -07:00

78 lines
7.5 KiB
HTML

---
layout: docs
title: Building a Package
edit_url: "https://github.com/nylas/N1/blob/a2c697754ad692e6a54629ffd93883dda79b0d78/docs/PackageOverview.md"
---
<p>Packages lie at the heart of N1. Each part of the core experience is a separate package that uses the Nylas Package API to add functionality to the client. Want to make a read-only mail client? Remove the core <code>Composer</code> package and you&#39;ll see reply buttons and composer functionality disappear.</p>
<p>Let&#39;s explore the files in a simple package that adds a Translate option to the Composer. When you tap the Translate button, we&#39;ll display a popup menu with a list of languages. When you pick a language, we&#39;ll make a web request and convert your reply into the desired language.</p>
<h3 id="package-structure">Package Structure</h3>
<p>Each package is defined by a <code>package.json</code> file that includes its name, version and dependencies. Packages may also declare dependencies which are loaded from npm - in this case, the <a href="https://github.com/request/request">request</a> library. You&#39;ll need to <code>npm install</code> these dependencies locally when developing the package.</p>
<pre><code>{
"<span class="hljs-attribute">name</span>": <span class="hljs-value"><span class="hljs-string">"translate"</span></span>,
"<span class="hljs-attribute">version</span>": <span class="hljs-value"><span class="hljs-string">"0.1.0"</span></span>,
"<span class="hljs-attribute">main</span>": <span class="hljs-value"><span class="hljs-string">"./lib/main"</span></span>,
"<span class="hljs-attribute">description</span>": <span class="hljs-value"><span class="hljs-string">"An example package for N1"</span></span>,
"<span class="hljs-attribute">license</span>": <span class="hljs-value"><span class="hljs-string">"Proprietary"</span></span>,
"<span class="hljs-attribute">engines</span>": <span class="hljs-value">{
"<span class="hljs-attribute">atom</span>": <span class="hljs-value"><span class="hljs-string">"*"</span>
</span>}</span>,
"<span class="hljs-attribute">dependencies</span>": <span class="hljs-value">{
"<span class="hljs-attribute">request</span>": <span class="hljs-value"><span class="hljs-string">"^2.53"</span>
</span>}
</span>}
</code></pre><p>Our package also contains source files, a spec file with complete tests for the behavior the package adds, and a stylesheet for CSS:</p>
<pre><code>-<span class="ruby"> package.json
</span>-<span class="ruby"> lib/
</span> -<span class="ruby"> main.coffee
</span> -<span class="ruby"> translate-button.cjsx
</span>-<span class="ruby"> spec/
</span> -<span class="ruby"> main-spec.coffee
</span>-<span class="ruby"> stylesheets/
</span> -<span class="ruby"> translate.less</span>
</code></pre><p><code>package.json</code> lists <code>lib/main</code> as the root file of our package. Since N1 runs NodeJS, we can <code>require</code> other source files, Node packages, etc.</p>
<p>N1 can read <code>js</code>, <code>coffee</code>, <code>jsx</code>, and <code>cjsx</code> files automatically.</p>
<p>Inside <code>main.coffee</code>, there are two important functions being exported:</p>
<pre><code class="lang-coffee"><span class="hljs-built_in">require</span> <span class="hljs-string">'./translate-button'</span>
<span class="hljs-built_in">module</span>.exports =
<span class="hljs-comment"># Activate is called when the package is loaded. If your package previously</span>
<span class="hljs-comment"># saved state using `serialize` it is provided.</span>
<span class="hljs-comment">#</span>
<span class="hljs-attribute">activate</span>: <span class="hljs-function"><span class="hljs-params">(<span class="hljs-property">@state</span>)</span> -&gt;</span>
ComponentRegistry.register TranslateButton,
<span class="hljs-attribute">role</span>: <span class="hljs-string">'Composer:ActionButton'</span>
<span class="hljs-comment"># Serialize is called when your package is about to be unmounted.</span>
<span class="hljs-comment"># You can return a state object that will be passed back to your package</span>
<span class="hljs-comment"># when it is re-activated.</span>
<span class="hljs-comment">#</span>
<span class="hljs-attribute">serialize</span>: <span class="hljs-function">-&gt;</span>
{}
<span class="hljs-comment"># This optional method is called when the window is shutting down,</span>
<span class="hljs-comment"># or when your package is being updated or disabled. If your package is</span>
<span class="hljs-comment"># watching any files, holding external resources, providing commands or</span>
<span class="hljs-comment"># subscribing to events, release them here.</span>
<span class="hljs-comment">#</span>
<span class="hljs-attribute">deactivate</span>: <span class="hljs-function">-&gt;</span>
ComponentRegistry.unregister(TranslateButton)
</code></pre>
<blockquote>
<p>N1 uses CJSX, a CoffeeScript version of JSX, which makes it easy to express Virtual DOM in React <code>render</code> methods! You may want to add the <a href="https://github.com/babel/babel-sublime">Babel</a> plugin to Sublime Text, or the <a href="https://atom.io/packages/language-cjsx">CJSX Language</a> for syntax highlighting.</p>
</blockquote>
<h3 id="package-stylesheets">Package Stylesheets</h3>
<p>Style sheets for your package should be placed in the <em>styles</em> directory. Any style sheets in this directory will be loaded and attached to the DOM when your package is activated. Style sheets can be written as CSS or <a href="http://lesscss.org/">Less</a>, but Less is recommended.</p>
<p>Ideally, you won&#39;t need much in the way of styling. We&#39;ve provided a standard set of components which define both the colors and UI elements for any package that fits into N1 seamlessly.</p>
<p>If you <em>do</em> need special styling, try to keep only structural styles in the package stylesheets. If you <em>must</em> specify colors and sizing, these should be taken from the active theme&#39;s [ui-variables.less][ui-variables]. For more information, see the [theme variables docs][theme-variables]. If you follow this guideline, your package will look good out of the box with any theme!</p>
<p>An optional <code>stylesheets</code> array in your <code>package.json</code> can list the style sheets by name to specify a loading order; otherwise, all style sheets are loaded.</p>
<h3 id="package-assets">Package Assets</h3>
<p>Many packages need other static files, like images. You can add static files anywhere in your package directory, and reference them at runtime using the <code>nylas://</code> url scheme:</p>
<pre><code>&lt;<span class="hljs-tag">img</span> src=<span class="hljs-string">"nylas://my-package-name/assets/goofy.png"</span>&gt;
<span class="hljs-tag">a</span> = new <span class="hljs-function"><span class="hljs-title">Audio</span><span class="hljs-params">()</span></span>
<span class="hljs-tag">a</span><span class="hljs-class">.src</span> = <span class="hljs-string">"nylas://my-package-name/sounds/bloop.mp3"</span>
<span class="hljs-tag">a</span>.<span class="hljs-function"><span class="hljs-title">play</span><span class="hljs-params">()</span></span>
</code></pre><h3 id="installing-a-package">Installing a Package</h3>
<p>N1 ships with many packages already bundled with the application. When the application launches, it looks for additional packages in <code>~/.nylas/dev/packages</code>. Each package you create belongs in its own directory inside this folder.</p>
<p>In the future, it will be possible to install packages directly from within the client.</p>