You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

251 lines
12 KiB

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Setting up Emacs for JavaScript (part #2)</title>
<meta name="description" content="This is the second part of my series of articles describing how to make Emacs a great JavaScript development environment. This time we’ll focus on getting go...">
<link rel="shortcut icon" type="image/png" href="/favicon.png"/>
<link href="https://fonts.googleapis.com/css?family=Fira+Mono|Gentium+Book+Basic|Lato" rel="stylesheet">
<link rel="stylesheet" href="/assets/main.css">
<link rel="stylesheet" href="/css/cafe.css">
<link rel="canonical" href="https://emacs.cafe/emacs/javascript/setup/2017/05/09/emacs-setup-javascript-2.html">
<link rel="alternate" type="application/rss+xml" title="Emacs café" href="/feed.xml">
</head>
<body>
<header class="site-header" role="banner">
<div class="wrapper">
<a class="site-title" href="/"><img src="/img/emacscafe.png"/>Emacs café</a>
<nav class="site-nav">
<input type="checkbox" id="nav-trigger" class="nav-trigger" />
<label for="nav-trigger">
<span class="menu-icon">
<svg viewBox="0 0 18 15" width="18px" height="15px">
<path fill="#424242" d="M18,1.484c0,0.82-0.665,1.484-1.484,1.484H1.484C0.665,2.969,0,2.304,0,1.484l0,0C0,0.665,0.665,0,1.484,0 h15.031C17.335,0,18,0.665,18,1.484L18,1.484z"/>
<path fill="#424242" d="M18,7.516C18,8.335,17.335,9,16.516,9H1.484C0.665,9,0,8.335,0,7.516l0,0c0-0.82,0.665-1.484,1.484-1.484 h15.031C17.335,6.031,18,6.696,18,7.516L18,7.516z"/>
<path fill="#424242" d="M18,13.516C18,14.335,17.335,15,16.516,15H1.484C0.665,15,0,14.335,0,13.516l0,0 c0-0.82,0.665-1.484,1.484-1.484h15.031C17.335,12.031,18,12.696,18,13.516L18,13.516z"/>
</svg>
</span>
</label>
<div class="trigger">
<a class="page-link" href="/about/">About Emacs café</a>
</div>
</nav>
</div>
</header>
<main class="page-content" aria-label="Content">
<div class="wrapper">
<article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<header class="post-header">
<h1 class="post-title" itemprop="name headline">Setting up Emacs for JavaScript (part #2)</h1>
<p class="post-meta">
<time datetime="2017-05-09T17:00:00+02:00" itemprop="datePublished">
May 9, 2017
</time>
<span itemprop="author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">Nicolas Petton</span></span>
</p>
</header>
<div class="post-content" itemprop="articleBody">
<p>This is the second part of my series of articles describing how to make Emacs a
great JavaScript development environment. This time we’ll focus on getting good
auto-completion with type inference.</p>
<p>If you haven’t read it yet, you should jump to
the <a href="/emacs/javascript/setup/2017/04/23/emacs-setup-javascript.html">first post</a>
first to get things started.</p>
<h2 id="setting-up-tern--company-mode-for-auto-completion">Setting up Tern &amp; company-mode for auto-completion</h2>
<p><a href="https://ternjs.net">Tern</a> is a great tool once setup correctly. It parses
JavaScript files in a project and does type inference to provide meaningful
completion (with type hints) and support for cross-references.</p>
<p>Unfortunately, cross-references with tern never reliably worked for me, that’s
why I have always been
using <a href="https://github.com/nicolaspetton/xref-js2">xref-js2</a> instead for that
(see <a href="/emacs/javascript/setup/2017/04/23/emacs-setup-javascript.html">part #1</a>).</p>
<p>For auto-completion, we’ll be using company-mode with tern. Let’s go ahead and
install tern:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>$ sudo npm install -g tern
</code></pre>
</div>
<p>Now let’s install the Emacs packages:</p>
<div class="highlighter-rouge"><pre class="highlight"><code>M-x package-install RET company-tern RET
</code></pre>
</div>
<p>The Emacs configuration is straight-forward, we simply enable company-mode with
the tern backend for JavaScript buffers:</p>
<figure class="highlight"><pre><code class="language-elisp" data-lang="elisp"><span class="p">(</span><span class="nb">require</span> <span class="ss">'company-mode</span><span class="p">)</span>
<span class="p">(</span><span class="nb">require</span> <span class="ss">'company-tern</span><span class="p">)</span>
<span class="p">(</span><span class="nv">add-to-list</span> <span class="ss">'company-backends</span> <span class="ss">'company-tern</span><span class="p">)</span>
<span class="p">(</span><span class="nv">add-hook</span> <span class="ss">'js2-mode-hook</span> <span class="p">(</span><span class="k">lambda</span> <span class="p">()</span>
<span class="p">(</span><span class="nv">tern-mode</span><span class="p">)</span>
<span class="p">(</span><span class="nv">company-mode</span><span class="p">)))</span>
<span class="c1">;; Disable completion keybindings, as we use xref-js2 instead</span>
<span class="p">(</span><span class="nv">define-key</span> <span class="nv">tern-mode-keymap</span> <span class="p">(</span><span class="nv">kbd</span> <span class="s">"M-."</span><span class="p">)</span> <span class="no">nil</span><span class="p">)</span>
<span class="p">(</span><span class="nv">define-key</span> <span class="nv">tern-mode-keymap</span> <span class="p">(</span><span class="nv">kbd</span> <span class="s">"M-,"</span><span class="p">)</span> <span class="no">nil</span><span class="p">)</span></code></pre></figure>
<p>Now, depending on your JavaScript project, you might want to setup tern to work
with your project structure. If completion doesn’t work out of the box using
tern defaults you will have to set it up using a <code class="highlighter-rouge">.tern-project</code> placed in the
root folder containing your JavaScript files.</p>
<p>Here’s an example setup for a project that uses <code class="highlighter-rouge">requirejs</code> and <code class="highlighter-rouge">jQuery</code>,
ignoring files from the <code class="highlighter-rouge">bower_components</code> directory:</p>
<figure class="highlight"><pre><code class="language-json" data-lang="json"><span class="p">{</span><span class="w">
</span><span class="nt">"libs"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"jquery"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nt">"loadEagerly"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"./**/*.js"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nt">"dontLoad"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"./bower_components/"</span><span class="w">
</span><span class="p">],</span><span class="w">
</span><span class="nt">"plugins"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nt">"requirejs"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nt">"baseURL"</span><span class="p">:</span><span class="w"> </span><span class="s2">"./"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span></code></pre></figure>
<p>Once setup, tern offers superb completion. Together with company-mode, you get
great context-based completion with type inference.</p>
<p><img src="/img/tern-company-mode.png" alt="Ternjs" /></p>
<p>When completing a function, you can hit <code class="highlighter-rouge">&lt;F1&gt;</code> to get its documentation:</p>
<p><img src="/img/tern-documentation.png" alt="Ternjs documentation" /></p>
<h2 id="until-next-time">Until next time</h2>
<p>In the next articles I’ll cover linting with Flycheck, <code class="highlighter-rouge">gulp</code> and <code class="highlighter-rouge">grunt</code>
integration into Emacs, and of course how to setup and
use <a href="https://indium.readthedocs.io">Indium</a>.</p>
</div>
<div id="disqus_thread"></div>
<script>
/* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
var disqus_shortname = 'emacs-cafe';
/* * * DON'T EDIT BELOW THIS LINE * * */
(function() {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript" rel="nofollow">comments powered by Disqus.</a></noscript>
</article>
</div>
</main>
<footer class="site-footer">
<div class="wrapper">
<h2 class="footer-heading">Emacs café</h2>
<div class="footer-col-wrapper">
<div class="footer-col footer-col-1">
<ul class="contact-list">
<li>
Emacs café
</li>
<li><a href="mailto:nicolas@petton.fr">nicolas@petton.fr</a></li>
</ul>
</div>
<div class="footer-col footer-col-2">
<ul class="social-media-list">
<li>
<a href="https://github.com/NicolasPetton"><span class="icon icon--github"><svg viewBox="0 0 16 16" width="16px" height="16px"><path fill="#828282" d="M7.999,0.431c-4.285,0-7.76,3.474-7.76,7.761 c0,3.428,2.223,6.337,5.307,7.363c0.388,0.071,0.53-0.168,0.53-0.374c0-0.184-0.007-0.672-0.01-1.32 c-2.159,0.469-2.614-1.04-2.614-1.04c-0.353-0.896-0.862-1.135-0.862-1.135c-0.705-0.481,0.053-0.472,0.053-0.472 c0.779,0.055,1.189,0.8,1.189,0.8c0.692,1.186,1.816,0.843,2.258,0.645c0.071-0.502,0.271-0.843,0.493-1.037 C4.86,11.425,3.049,10.76,3.049,7.786c0-0.847,0.302-1.54,0.799-2.082C3.768,5.507,3.501,4.718,3.924,3.65 c0,0,0.652-0.209,2.134,0.796C6.677,4.273,7.34,4.187,8,4.184c0.659,0.003,1.323,0.089,1.943,0.261 c1.482-1.004,2.132-0.796,2.132-0.796c0.423,1.068,0.157,1.857,0.077,2.054c0.497,0.542,0.798,1.235,0.798,2.082 c0,2.981-1.814,3.637-3.543,3.829c0.279,0.24,0.527,0.713,0.527,1.437c0,1.037-0.01,1.874-0.01,2.129 c0,0.208,0.14,0.449,0.534,0.373c3.081-1.028,5.302-3.935,5.302-7.362C15.76,3.906,12.285,0.431,7.999,0.431z"/></svg>
</span><span class="username">NicolasPetton</span></a>
</li>
<li>
<a href="https://twitter.com/NicolasPetton"><span class="icon icon--twitter"><svg viewBox="0 0 16 16" width="16px" height="16px"><path fill="#828282" d="M15.969,3.058c-0.586,0.26-1.217,0.436-1.878,0.515c0.675-0.405,1.194-1.045,1.438-1.809c-0.632,0.375-1.332,0.647-2.076,0.793c-0.596-0.636-1.446-1.033-2.387-1.033c-1.806,0-3.27,1.464-3.27,3.27 c0,0.256,0.029,0.506,0.085,0.745C5.163,5.404,2.753,4.102,1.14,2.124C0.859,2.607,0.698,3.168,0.698,3.767 c0,1.134,0.577,2.135,1.455,2.722C1.616,6.472,1.112,6.325,0.671,6.08c0,0.014,0,0.027,0,0.041c0,1.584,1.127,2.906,2.623,3.206 C3.02,9.402,2.731,9.442,2.433,9.442c-0.211,0-0.416-0.021-0.615-0.059c0.416,1.299,1.624,2.245,3.055,2.271 c-1.119,0.877-2.529,1.4-4.061,1.4c-0.264,0-0.524-0.015-0.78-0.046c1.447,0.928,3.166,1.469,5.013,1.469 c6.015,0,9.304-4.983,9.304-9.304c0-0.142-0.003-0.283-0.009-0.423C14.976,4.29,15.531,3.714,15.969,3.058z"/></svg>
</span><span class="username">NicolasPetton</span></a>
</li>
</ul>
</div>
<div class="footer-col footer-col-3">
<p>A blog about Emacs, mostly focused on JavaScript development, by Nicolas Petton.
</p>
</div>
</div>
</div>
</footer>
</body>
</html>