This repository has been archived on 2024-10-22. You can view files and clone it, but cannot push or open issues or pull requests.
spacemacs/layers/+lang/javascript/README.org
Matthew Leach b18c87c832
[javascript] add npm-mode (#14347)
* [javascript] add npm-mode

Add npm mode to the javascript layer.  This allows easy execution of npm
commands at the project root from any javascript file in the project.

* [javascript] defer loading of npm-mode

Defer loading of the npm-mode package.

* [javascript] remove superfluous `progn'

The `:init' command is only a single command and thus doesn't need to be wrapped
in a `progn'.

* [javascript] fix typo in npm-mode docs

s/avilable/available/

* [javascript] add additional npm-mode commands

Add and document missing commands from npm-mode.
2021-02-07 07:46:06 +01:00

434 lines
20 KiB
Org Mode
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#+TITLE: JavaScript layer
#+TAGS: general|js|layer|multi-paradigm|programming
[[file:img/javascript.png]]
* Table of Contents :TOC_5_gh:noexport:
- [[#description][Description]]
- [[#features][Features:]]
- [[#install][Install]]
- [[#error-checking--linting][Error checking / linting]]
- [[#web-beautify][web-beautify]]
- [[#prettier][prettier]]
- [[#import-js][import-js]]
- [[#choosing-a-backend][Choosing a backend]]
- [[#choosing-a-formatter][Choosing a formatter]]
- [[#format-buffer-before-saving][Format buffer before saving]]
- [[#backends][Backends]]
- [[#tern][Tern]]
- [[#tide][Tide]]
- [[#language-server-protocol][Language Server Protocol]]
- [[#typescript][TypeScript]]
- [[#flow][Flow]]
- [[#debugger-dap-integration][Debugger (dap integration)]]
- [[#configuration][Configuration]]
- [[#indentation][Indentation]]
- [[#repl][REPL]]
- [[#browser-based-repl][Browser based REPL]]
- [[#server-based-repl][Server based REPL]]
- [[#node][Node]]
- [[#node-modules][Node Modules]]
- [[#node-externs][Node Externs]]
- [[#flowtypescript][Flow/Typescript]]
- [[#key-bindings][Key bindings]]
- [[#js2-mode][js2-mode]]
- [[#folding-js2-mode][Folding (js2-mode)]]
- [[#running-npm-npm-mode][Running NPM (npm-mode)]]
- [[#importing-import-js][Importing (import-js)]]
- [[#refactoring-js2-refactor][Refactoring (js2-refactor)]]
- [[#documentation-js-doc][Documentation (js-doc)]]
- [[#browser-based-repl-skewer-mode][Browser based REPL (skewer-mode)]]
- [[#server-based-repl-nodejs-repl][Server based REPL (nodejs-repl)]]
- [[#debugger-dap-mode][debugger (dap mode)]]
* Description
This layer adds support for the JavaScript language using [[https://github.com/mooz/js2-mode][js2-mode]].
** Features:
- Multiple backends support: Tern and LSP
- Smart code folding
- Refactoring: done using [[https://github.com/magnars/js2-refactor.el][js2-refactor]].
- Auto-completion and documentation
- Browser based REPL available via [[https://github.com/skeeto/skewer-mode][skewer-mode]] and [[https://github.com/pandeiro/livid-mode][livid-mode]]
- Server based REPL with [[https://github.com/abicky/nodejs-repl.el][nodejs-repl]]
- Formatting with [[https://github.com/yasuyk/web-beautify][web-beautify]] or [[https://github.com/prettier/prettier][prettier]]
- Interactive debugger using [[https://github.com/emacs-lsp/dap-mode][dap-mode]]
- Display Flow & Typescript type information
* Install
To use this configuration layer, add it to your =~/.spacemacs=. You will need to
add =javascript= to the existing =dotspacemacs-configuration-layers= list in
this file.
** Error checking / linting
To activate error checking / linting using flycheck, install on your system one of the [[http://www.flycheck.org/en/latest/languages.html#javascript][available linters]]
such as =ESLint=, =JSHint= or =StandardJS=:
#+BEGIN_SRC sh
$ npm install -g eslint
# or
$ npm install -g jshint
# or
$ npm install -g standard
#+END_SRC
If you install these in non-standard locations, add the following to your
=dotspacemacs/user-init= function:
#+BEGIN_SRC elisp
(add-to-list 'exec-path "/path/to/node/bins" t)
#+END_SRC
Finally, you will want to turn off js2-mode warnings, since they might be
in conflict with the linter you are using via flycheck:
#+BEGIN_SRC elisp
(javascript :variables js2-mode-show-strict-warnings nil)
#+END_SRC
** web-beautify
See [[file:../../+tools/web-beautify/README.org][web-beautify layer]] documentation.
** prettier
See [[file:../../+tools/prettier/README.org][prettier layer]] documentation.
** import-js
See [[file:../../+tools/import-js/README.org][import-js layer]] documentation.
Install =ImportJS= on your system:
#+BEGIN_SRC sh
$ npm install -g import-js
#+END_SRC
To enable it, set the layer variable =javascript-import-tool=:
#+BEGIN_SRC elisp
(javascript :variables javascript-import-tool 'import-js)
#+END_SRC
** Choosing a backend
To choose a default backend set the layer variable =javascript-backend=:
#+BEGIN_SRC elisp
(javascript :variables javascript-backend 'tern)
#+END_SRC
Alternatively the =lsp= backend will be automatically chosen if the layer =lsp=
is used and you did not specify any value for =javascript-backend=.
Backend can be chosen on a per project basis using directory local variables
(files named =.dir-locals.el= at the root of a project), an example to use the
=lsp= backend:
#+BEGIN_SRC elisp
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
((js2-mode (javascript-backend . lsp)))
#+END_SRC
When =lsp= is set as the backend, but you don't want to use lsp as the linter,
set the variable =javascript-lsp-linter= to =nil=.
#+BEGIN_SRC elisp
(javascript :variables
javascript-backend 'lsp
javascript-lsp-linter nil)
#+END_SRC
** Choosing a formatter
To choose a formatter, set the layer variable =javascript-fmt-tool=:
#+BEGIN_SRC elisp
(javascript :variables javascript-fmt-tool 'web-beautify)
#+END_SRC
The formatter can be chosen on a per project basis using directory local
variables (files named =.dir-locals.el= at the root of a project). For example
to use the =prettier= formatter:
#+BEGIN_SRC elisp
;;; Directory Local Variables
;;; For more information see (info "(emacs) Directory Variables")
((js2-mode (javascript-fmt-tool . prettier)))
#+END_SRC
*Note:* you can easily add a directory local variable with ~SPC f v d~.
You can choose formatting tool:
#+BEGIN_SRC elisp
(setq-default dotspacemacs-configuration-layers '(
(javascript :variables
javascript-fmt-tool 'prettier)))
#+END_SRC
Default is =web-beautify=.
** Format buffer before saving
#+BEGIN_SRC elisp
(javascript :variables javascript-fmt-on-save t)
#+END_SRC
* Backends
** Tern
See [[file:../../+tools/tern/README.org][tern layer]] documentation.
** Tide
See [[file:../../+tools/tide/README.org][tide layer]] documentation.
** Language Server Protocol
To use an LSP server with JavaScript, add it as a =javascript-backend= to your
=~/.spacemacs=.
#+BEGIN_SRC emacs-lisp
(setq-default dotspacemacs-configuration-layers
'((javascript :variables
javascript-backend 'lsp)))
#+END_SRC
*** TypeScript
You have to install =typescript-language-server= (recommended) or
=javascript-typescript-langserver= language server packages via
#+BEGIN_SRC sh
npm i -g typescript typescript-language-server
#+END_SRC
or
#+BEGIN_SRC sh
npm i -g typescript javascript-typescript-langserver
#+END_SRC
*** Flow
You have to install =flow-bin=.
#+BEGIN_SRC sh
npm i -g flow-bin
#+END_SRC
Or, if you'd rather use a locally-installed =flow-bin= from your project's
node_modules directory, see the [[#node-modules][node-add-modules-path setting]].
*** Debugger (dap integration)
To install the debug adapter you may run =M-x dap-firefox-setup= or
=M-x dap-chrome-setup= if you are using Linux or download it manually from
[[https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-firefox-debug][Firefox Debug Adapter]] or [[https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome][Chrome Debug Adapter]] and adjust
=dap-firefox-debug-path= or =dap-chrome-debug-path=. For usage instructions
refer to [[https://github.com/emacs-lsp/dap-mode][dap-mode]] readme.
* Configuration
** Indentation
To change how js2-mode indents code, set the variable =js2-basic-offset=, as
such:
#+BEGIN_SRC emacs-lisp
(setq-default js2-basic-offset 2)
#+END_SRC
or when adding the =javascript= configuration layer:
#+BEGIN_SRC emacs-lisp
(javascript :variables js2-basic-offset 2)
#+END_SRC
Similarly, to change how js-mode indents JSON files, set the variable
=js-indent-level=, as such:
#+BEGIN_SRC emacs-lisp
(setq-default js-indent-level 2)
#+END_SRC
or when adding the =javascript= configuration layer:
#+BEGIN_SRC emacs-lisp
(javascript :variables js-indent-level 2)
#+END_SRC
** REPL
*** Browser based REPL
To use the browser based REPL set the =javascript-repl= variable as shown below:
#+BEGIN_SRC elisp
(setq-default dotspacemacs-configuration-layers
'((javascript :variables javascript-repl `skewer)))
#+END_SRC
In addition you need a running httpd server and a page loaded
with skewer. If a blank page serves your needs, just use the run-skewer command
in your javascript buffer. If you want to inject it in your own page, follow
[[https://github.com/skeeto/skewer-mode#skewering-with-cors][these instructions]] (install the Greasemonkey script and then click the triangle
in the top-right corner - if it turns green, you're good to go).
*** Server based REPL
To use the server based REPL set the =javascript-repl= variable as shown below:
#+BEGIN_SRC elisp
(setq-default dotspacemacs-configuration-layers
'((javascript :variables javascript-repl `nodejs)))
#+END_SRC
In addition install nodejs and make sure that =node= is in the path.
** Node
*** Node Modules
If you would like =node_modules/.bin= to be automatically added to the buffer
local =exec_path=, e.g. to support project local eslint installations, set the
=node-add-modules-path= variable in the =javascript= config section. Note that
doing this [[https://stackoverflow.com/questions/9679932#comment33532258_9683472][introduces a security risk]]:
#+BEGIN_SRC elisp
(setq-default dotspacemacs-configuration-layers
'((javascript :variables node-add-modules-path t)))
#+END_SRC
*** Node Externs
If you want =js2-mode= to presume =node= variables are defined by the host
system (for completion purposes /i.a./) set the =js2-include-node-exters=
variable to =t= in the =javascript= config section:
#+BEGIN_SRC elisp
(setq-default dotspacemacs-configuration-layers
'((javascript :variables js2-include-node-externs t)))
#+END_SRC
** Flow/Typescript
Enable the [[#language-server-protocol][lsp]] backend to view type information, jump to declarations, and more.
js2-mode is sometimes confused by the type syntax, so you may wish to disable their
parse warnings:
#+BEGIN_SRC emacs-lisp
(javascript :variables javascript-backend 'lsp
js2-mode-show-strict-warnings nil
js2-mode-show-parse-errors nil)
#+END_SRC
* Key bindings
** js2-mode
| Key binding | Description |
|-------------+--------------------------------------|
| ~SPC m w~ | toggle js2-mode warnings and errors |
| ~%~ | jump between blockswith [[https://github.com/redguardtoo/evil-matchit][evil-matchit]] |
** Folding (js2-mode)
| Key binding | Description |
|-------------+--------------------------|
| ~SPC m z c~ | hide element |
| ~SPC m z o~ | show element |
| ~SPC m z r~ | show all element |
| ~SPC m z e~ | toggle hide/show element |
| ~SPC m z F~ | toggle hide functions |
| ~SPC m z C~ | toggle hide comments |
** Running NPM (npm-mode)
| Key binding | Description |
|-------------+---------------------------------------------------------------------------------|
| ~SPC m n i~ | Run the =npm install= command in the project root |
| ~SPC m n r~ | Show a list of available npm scripts, and execute the selected one |
| ~SPC m n c~ | Run the =npm clean= command in the project root |
| ~SPC m n s~ | Prompt for the name of an npm package, install it and save to =dependencies= |
| ~SPC m n d~ | Prompt for the name of an npm package, install it and save to =devDependencies= |
| ~SPC m n n~ | Initialize new project |
| ~SPC m n u~ | Remove project dependency |
| ~SPC m n l~ | List installed project dependencies |
| ~SPC m n p~ | Visit project =package.json= file |
** Importing (import-js)
| Key binding | Description |
|-------------+---------------------------------------------------------------------|
| ~SPC m i i~ | Import the module for the variable under the cursor |
| ~SPC m i f~ | Import any missing modules and remove any modules that are not used |
| ~SPC m g i~ | Go to the module of the variable under cursor |
** Refactoring (js2-refactor)
Bindings should match the plain emacs assignments.
| Key binding | Description |
|---------------+----------------------------------------------------------------------------------------------------------------|
| ~SPC m k~ | deletes to the end of the line, but does not cross semantic boundaries |
| ~SPC m r 3 i~ | converts ternary operator to if-statement |
| ~SPC m r a g~ | creates a =/* global */= annotation if it is missing, and adds var to point to it |
| ~SPC m r a o~ | replaces arguments to a function call with an object literal of named arguments |
| ~SPC m r b a~ | moves the last child out of current function, if-statement, for-loop or while-loop |
| ~SPC m r c a~ | converts a multiline array to one line |
| ~SPC m r c o~ | converts a multiline object literal to one line |
| ~SPC m r c u~ | converts a multiline function to one line (expecting semicolons as statement delimiters) |
| ~SPC m r e a~ | converts a one line array to multiline |
| ~SPC m r e f~ | extracts the marked expressions into a new named function |
| ~SPC m r e m~ | extracts the marked expressions out into a new method in an object literal |
| ~SPC m r e o~ | converts a one line object literal to multiline |
| ~SPC m r e u~ | converts a one line function to multiline (expecting semicolons as statement delimiters) |
| ~SPC m r e v~ | takes a marked expression and replaces it with a var |
| ~SPC m r i g~ | creates a shortcut for a marked global by injecting it in the wrapping immediately invoked function expression |
| ~SPC m r i p~ | changes the marked expression to a parameter in a local function |
| ~SPC m r i v~ | replaces all instances of a variable with its initial value |
| ~SPC m r l p~ | changes a parameter to a local var in a local function |
| ~SPC m r l t~ | adds a console.log statement for what is at point (or region) |
| ~SPC m r r v~ | renames the variable on point and all occurrences in its lexical scope |
| ~SPC m r s l~ | moves the next statement into current function, if-statement, for-loop, while-loop |
| ~SPC m r s s~ | splits a =String= |
| ~SPC m r s v~ | splits a =var= with multiple vars declared into several =var= statements |
| ~SPC m r t f~ | toggle between function declaration and function expression |
| ~SPC m r u w~ | replaces the parent statement with the selected region |
| ~SPC m r v t~ | changes local =var a= to be =this.a= instead |
| ~SPC m r w i~ | wraps the entire buffer in an immediately invoked function expression |
| ~SPC m r w l~ | wraps the region in a for-loop |
| ~SPC m x m j~ | move line down, while keeping commas correctly placed |
| ~SPC m x m k~ | move line up, while keeping commas correctly placed |
*** Documentation (js-doc)
You can check more [[https://github.com/mooz/js-doc/][here]]
| Key binding | Description |
|---------------+---------------------------------------|
| ~SPC m r d b~ | insert JSDoc comment for current file |
| ~SPC m r d f~ | insert JSDoc comment for function |
| ~SPC m r d t~ | insert tag to comment |
| ~SPC m r d h~ | show list of available jsdoc tags |
** Browser based REPL (skewer-mode)
| Key binding | Description |
|-------------+------------------------------------------------------------------|
| ~SPC m e e~ | evaluates the last expression |
| ~SPC m e E~ | evaluates and inserts the result of the last expression at point |
| Key binding | Description |
|-------------+------------------------------------------------------------------------------------|
| ~SPC m T l~ | Toggle live evaluation of whole buffer in REPL on buffer changes |
| ~SPC m s b~ | send current buffer contents to the skewer REPL |
| ~SPC m s B~ | send current buffer contents to the skewer REPL and switch to it in insert state |
| ~SPC m s f~ | send current function at point to the skewer REPL |
| ~SPC m s F~ | send current function at point to the skewer REPL and switch to it in insert state |
| ~SPC m s i~ | starts/switch to the skewer REPL |
| ~SPC m s r~ | send current region to the skewer REPL |
| ~SPC m s R~ | send current region to the skewer REPL and switch to it in insert state |
| ~SPC m s s~ | switch to REPL |
** Server based REPL (nodejs-repl)
| Key binding | Description |
|-------------+--------------------------------------------------------------------|
| ~SPC m s i~ | Switch to NodeJS REPL if one has been started, otherwise start one |
| ~SPC m s e~ | Send last expression to NodeJS REPL |
| ~SPC m s E~ | Send last expression to NodeJS REPL and switch to REPL |
| ~SPC m s b~ | Send current buffer to NodeJS REPL |
| ~SPC m s B~ | Send current buffer to NodeJS REPL and switch to REPL |
| ~SPC m s l~ | Send current line to NodeJS REPL |
| ~SPC m s L~ | Send current line to NodeJS REPL and switch to REPL |
| ~SPC m s r~ | Send active region to NodeJS REPL |
| ~SPC m s R~ | Send active region to NodeJS REPL and switch to REPL |
| ~SPC m s s~ | switch to REPL |
** debugger (dap mode)
Using the =dap= layer you'll get access to all the DAP key bindings, see the
complete list of key bindings on the [[https://github.com/syl20bnr/spacemacs/tree/develop/layers/%2Btools/dap#key-bindings][dap layer description]].