Chapter 1. Setting Up a Development Environment
You may have heard it said that the âtools make the developer.â While thatâs something of an exaggeration, no one wants to be left in front of a wall of JavaScript code without their favorite tools to edit, analyze, and debug it.
When youâre setting up your own development environment, the first tool youâll consider is a code editor. Even the most basic editor adds essentials like autocompletion and syntax highlightingâtwo simple features that prevent piles of potential mistakes. Modern code editors add many more features, such as integration with a source control service like GitHub, line-by-line debugging, and smart refactoring. Sometimes these features will snap into your editor with a plug-in. Sometimes youâll run them from the terminal or as part of a build process. But no matter how you use your tools, assembling the right combination to suit your coding style, development environment, and project types is part of the fun. Itâs like a home improvement pro collecting tools, or an aspiring chef investing in just the right cooking gear.
Tool choices arenât static. As a developer, your preferences may shift. Youâll grow your kit as you evolve and as new tools prove themselves useful. This chapter explores the minimum toolset that every JavaScript developer should consider before they tackle a project. But thereâs plenty of room to choose between different, broadly equivalent options. And, as many a wise person has remarked, thereâs no accounting for taste!
Note
In this chapter, weâre putting on our advocacy hat. Youâll see some of our favorite tools, and references to other, equally good options. But we donât attempt to cover every tool, just some excellent default choices you can start with.
Choosing a Code Editor
Solution
If youâre in a hurry, you wonât go wrong with our favorite choice, Visual Studio Code (often shortened to just VS Code). You can download this free, open source editor for Windows, Macintosh, or Linux.
If you have time to research, there are a number of other editors you might consider. The list in Table 1-1 is far from complete, but shows some of the most consistently popular editors.
Editor | Supported platforms | Open source | Cost | Notes |
---|---|---|---|---|
Windows, Macintosh, Linux |
Yes |
Free |
A great choice for any language, and our first choice for JavaScript development |
|
Windows, Macintosh, Linux |
Yes |
Free |
Most of the chapters in this book were written using Atom with plug-ins for AsciiDoc support |
|
Windows, Macintosh, Linux |
No |
Free for open source developers and educational users, otherwise roughly $60 per year for an individual |
A heavier-weight environment thatâs closer to a traditional IDE than a code editor |
|
Windows, Macintosh, Linux |
No |
A one-time payment of $80 for an individual, although there is no license enforcement or time limit |
A popular editor with a reputation for fast performance with massive text files |
|
Windows, Macintosh |
Yes |
Free |
An Adobe-sponsored project thatâs focused on web development |
No matter what code editor you choose, youâll follow a similar process to start a new project. Begin by creating a new folder for your project (like test-site). Then, in your code editor, look for a command like File > Open Folder, and choose the project folder you created. Most code editors will immediately show the contents of the project folder in a handy list or tree panel, so you can quickly jump between files.
Having a project folder also gives you a place to put the packages you use (âDownloading a Package with npmâ) and store application-specific configuration files and linting rules (âEnforcing Code Standards with a Linterâ). And if your editor has a built-in terminal (âExtra: Using a Terminal and Shellâ), it always starts in the current project folder.
Discussion
Recommending a best editor is a little like me choosing your dessert. Personal taste is definitely a factor, and there are at least a dozen reasonable choices. Most of the suggestions listed in Table 1-1 tick off all the important boxes, meaning theyâre:
-
Cross-platform, so it doesnât matter what operating system youâre using.
-
Plug-in-based, so you can snap in whatever features you need. Many of the tools mentioned in this book (like the Prettier code formatter described in âEnforcing Code Standards with a Linterâ) have plug-ins that integrate with different editors.
-
Multilanguage, allowing you to go beyond HTML, CSS, and JavaScript to write code in other programming languages (with the right plug-in).
-
Community-driven, which gives you confidence that theyâll be maintained and improved long into the future.
-
Free, or available for a modest cost.
Our top choice, VS Code, is a Microsoft-built code editor with native JavaScript support. In fact, the editor itself is written in JavaScript, and hosted in Electron. (More precisely, itâs written in TypeScript, a stricter superset of JavaScript thatâs transpiled into JavaScript before itâs distributed or executed.)
In many ways, VS Code is the younger, trendier sibling to Microsoftâs sprawling Visual Studio IDE, which is also available in a free Community edition, and also supports JavaScript coding. But VS Code strikes a better balance for developers that arenât already working with the Microsoft .NET stack. Thatâs because it starts out lightweight, but is endlessly customizable through its library with thousands of community plug-ins. In Stack Overflowâs developer survey, VS Code regularly ranks as the most popular code editor across as languages.
See Also
For an introduction to VS Codeâs basic features and overall organization, thereâs an excellent set of introductory videos. In this chapter, youâll also learn how to use Emmet shortcuts in VS Code (âFilling in HTML Boilerplate with Emmet Shortcutsâ), and how to add the ESLint (âEnforcing Code Standards with a Linterâ) and Prettier (âStyling Code Consistently with a Formatterâ) plug-ins.
Using the Developer Console in Your Browser
Solution
Use the developer console in your browser. Table 1-2 shows how to load the developer tools in every modern desktop browser.
Browser | Operating system | Shortcut |
---|---|---|
Chrome |
Windows or Linux |
F12 or Ctrl+Shift+J |
Chrome |
Macintosh |
Cmd-Option-J |
Edge |
Windows or Linux |
F12 or Ctrl+Shift+J |
Firefox |
Windows or Linux |
F12 or Ctrl+Shift+J |
Firefox |
Macintosh |
Cmd-Shift-J |
Safaria |
Macintosh |
Cmd-Option-C |
Opera |
Windows |
Ctrl+Shift+J |
Opera |
Macintosh |
Cmd-Option-J |
a Before you can use the developer console in Safari, you must enable it. To do so, choose Safari Menu > Preferences from the menu, click the Advanced tab, and check Show Develop menu in the menu bar. |
The developer tools are usually presented as a tabbed group of panes at the right or bottom of the web browser window. The Console panel is the one that shows the messages you output with console.log()
and any unhandled errors.
Hereâs the full code for a page that writes to the console and then fails with an error:
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
/>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
/>
<meta
http-equiv=
"X-UA-Compatible"
content=
"ie=edge"
/>
<title>
Log and Error Test</title>
</head>
<body>
<h1>
Log and Error Test</h1>
<script>
console
.
log
(
'This appears in the developer console'
);
</script>
<script>
// This will cause an error that appears in the console
const
myNumber
=
</script>
</body>
</html>
Figure 1-1 shows the output in the developer console. The logged message appears first, followed by the error (a SyntaxError
for âUnexpected end of inputâ). Errors are displayed in red lettering, and Chrome helpfully adds links next to each message, so you can quickly view the source code that caused the message. Lines in your web pages and script files are numbered automatically. In this example, that makes it easy to distinguish between the source of the message (line 13) and the source of the error (the closing </script>
tag on line 19).
Discussion
We use console.log()
throughout this book, often to write quick testing messages. However, there are other console
methods you can use. Table 1-3 lists some of the most useful.
Method | Description |
---|---|
|
Similar to |
|
Similar to |
|
If the expression is |
|
Displays a stack trace. |
|
Displays the number of times youâve called this method with this label. |
|
Displays all the properties of an object in an expandable, tree-like list. |
|
Starts a new group with the title you supply. The following console messages are indented underneath this heading, so they appear to be part of one logically related section. You use |
|
Starts a timer with a label you use to identify it. |
|
Stops the timer associated with the label and displays the elapsed time. |
Note
The consoles in modern browsers sometimes use lazy evaluation with objects and arrays. This issue may appear if you output an object with console.log()
, then change it, and then output the same object a second time. If you do this from the script code in a web page, youâll often find that both calls to console.log()
emit the same changed object, even though the first call preceded the actual change!
To avoid this quirk, you can explicitly convert your object to a string before you log it. This trick works because the console doesnât use lazy evaluation with strings. This technique isnât always convenient (for example, it doesnât help if you want to log a complete array that contains objects), but it does let you work around most cases.
Of course, the console is only one panel (or tab) in the developer tools. Look around, and youâll find quite a bit of useful functionality packed into the other panels. The exact arrangement and naming depends on your browser, but here are some highlights in Chrome:
- Elements
-
Use this panel to view the HTML markup for specific parts of your page, and inspect the CSS rules that apply to individual elements. You can even change markup and styles (temporarily) to quickly test potential edits.
- Sources
-
Use this panel to browse all the files the current page is using, including JavaScript libraries, images, and style sheets.
- Network
-
Use the panel tab to watch the size and download time of your page and its resources, and to view the asynchronous messages being sent over the wire (for example, as part of a
fetch
request). - Performance
-
Use this panel to start tracking the time your code takes to execute (see âAnalyzing Runtime Performanceâ).
- Application
-
Use this panel to review all the data the current site is storing with cookies, in local storage or with the IndexedDB API.
You can play around with most of these panels to get an idea about how they work, or you can review Googleâs documentation.
See Also
âRunning Blocks of Code in the Developer Consoleâ explains how to run ad hoc bits of code in the developer console.
Running Blocks of Code in the Developer Console
Solution
Use the developer console in your browser. First, open the developer tools (as explained in âUsing the Developer Console in Your Browserâ). Make sure the Console panel is selected. Then, paste or type your JavaScript.
Press Enter to run your code immediately. If you need to type multiple lines of code, press Shift+Enter at the end of each line to insert a soft return. Only press Enter when youâre finished and you want to run your full block of code.
Often, youâll want to modify the same piece of code and rerun it. In all modern browsers, the developer console has a history feature that makes this easy. To use it, press the up arrow key to show the previously executed code block. If you want to see the code you ran before that, press the up arrow multiple times.
Figure 1-2 shows an example with a code block that didnât run successfully the first time because of a syntax error. The code was then called up in the history, edited, and executed, with the output (15) appearing underneath.
The history feature only works if you donât start typing in any new code. If the console command line isnât empty, the up arrow key will just move through the current code block rather than stepping back through the history.
Discussion
In the developer console, you can enter JavaScript code exactly as you would in a script block. In other words, you can add functions and call them, or define a class and then instantiate it. You can also access the document
object, interact with HTML elements in the current page, show alerts, and write to the console. (The messages will appear directly below.)
Thereâs one potential stumbling block when using the console for longer code examples. You may run into a naming clash, because JavaScript wonât allow you to define the same variables or function names in the same scope more than once. For example, consider a simple block of code like this:
const
testValue
=
40
+
12
;
console
.
log
(
testValue
);
This works fine if you run it once. But if you call it back up in the history to make a modification (by pressing the up arrow), and you try to run it again, youâll get an error informing you that testValue
is already declared. You could rename your variable, but if youâre trying to perfect a snippet of code with multiple values and functions, this renaming gets awkward fast. Alternatively, you could execute the command location.reload()
to refresh the page, but that can be slow for complex pages, and you might lose some page state youâre trying to keep.
Fortunately, thereâs a simpler solution. Simply enclose your entire block of code in an extra set of braces to create a new naming scope. You can then safely run the code multiple times, because each time a new context is created (and then discarded).
{
const
testValue
=
40
+
12
;
console
.
log
(
testValue
);
}
See Also
âDebugging JavaScriptâ explores the art of debugging in the developer console. âAnalyzing Runtime Performanceâ shows how to use the developer console for performance analysis.
Using Strict Mode to Catch Common Mistakes
Solution
Add the use strict
directive at the top of your JavaScript code file, like this:
'use strict'
;
Alternatively, consider writing your JavaScript in a module, which is always loaded in strict mode (âOrganizing Your JavaScript Classes with Modulesâ).
Discussion
JavaScript has a (somewhat deserved) reputation for tolerating sloppy code practices. The problem is that languages that ignore minor rule breaking put developers at a disadvantage. After all, you canât fix a problem that you never notice.
The following example demonstrates an example of JavaScript gone bad. Can you find the mistake?
// This function adds a list of consecutive numbers
function
addRange
(
start
,
end
)
{
let
sum
=
0
;
for
(
let
i
=
start
;
i
<
end
+
1
;
i
++
)
{
sum
+=
i
;
}
return
sum
;
}
// Add numbers from 10 to 15
let
startNumber
=
10
;
let
endNumber
=
15
;
console
.
log
(
addRange
(
startNumber
,
endNumber
));
// Displays 75
// Now add numbers from 1 to 5
startnumber
=
1
;
endNumber
=
5
;
console
.
log
(
addRange
(
startNumber
,
endNumber
));
// Displays 0, but we expect 15
Although the code runs without an error, the results arenât what we expect. The problem occurs in this line:
startnumber
=
1
;
The issue here is that JavaScript creates variables whenever you assign a value, even if you donât explicitly define the variable. So if you assign to startnumber
when you really want startNumber
, JavaScript quietly creates a new startnumber
variable. The end result is that the value you intended to assign to startNumber
vanishes into another variable, never to be seen or used again.
To catch this problem, add the strict mode directive to the top of the file, before the function code:
'use strict'
;
Now a ReferenceError
occurs when JavaScript reaches the startnumber
assignment. This interrupts your code, ending the script. However, the error appears in red lettering in the developer console, explaining the problem and the line number where it happened. Now, a fix is trivially easy.
Strict mode catches a number of small but pernicious errors. Some examples include:
-
Assignments to undeclared variables
-
Duplicate parameter names (like
function(a, b, a)
) or object literal property names (as in{a: 5, a: 0}
) -
Attempts to assign values to special keywords like
Infinity
orundefined
-
Attempts to set read-only properties (âCustomizing the Way a Property Is Definedâ) or change frozen objects (âPreventing Any Changes to an Objectâ)
Many of these actions would fail without strict mode. However, they would fail silently, potentially leading to a maddening situation where your code doesnât work the way you expect it to, and you have no idea why.
Tip
You may be able to configure your editor to insert the use strict
directive to every new code file. For example, Visual Studio Code has at least three small extensions that offer to perform this task.
Strict mode catches a relatively small set of errors. Most developers also use a linting tool (âEnforcing Code Standards with a Linterâ) to catch a much broader range of bugs and potentially risky actions. In fact, developers rely on linters to such an extent that they sometimes donât bother to apply strict mode at all. However, itâs always recommended to have strict mode as a basic level of protection against shooting yourself in the foot.
See Also
For the full details on what strict mode wonât accept, see the strict mode documentation. To see how to use modules, which always execute in strict mode, see âOrganizing Your JavaScript Classes with Modulesâ.
Filling in HTML Boilerplate with Emmet Shortcuts
Solution
Emmet is an editor feature that automatically changes predefined text abbreviations into standard blocks of HTML. Some code editors, like Visual Studio and WebStorm, support Emmet natively. Other editors, like Atom and Sublime Text, require the use of an editor plug-in. You can usually find the right plug-in by searching the plug-in library for âEmmet,â but if youâre in doubt, thereâs a master list of Emmet-supporting plug-ins.
To use Emmet, create a new file and save it with a .html or .htm extension, so your code editor recognizes it as an HTML document. Then, type one of Emmetâs abbreviations, followed by the Tab key. (In some editors, you might use a different shortcut, like Enter or Ctrl+E, but the Tab key is most common.) Your text will be automatically expanded into the corresponding block of markup.
For example, the Emmet abbreviation input:time
expands into this markup:
<input
type=
"time"
name=
""
id=
""
/>
Figure 1-3 shows how VS Code recognizes an Emmet abbreviation as you type it. VS Code provides autocomplete support for Emmet, so you can see possible choices, and it adds the note âEmmet Abbreviationâ to the autocomplete menu to signal that you arenât writing HTML, but an Emmet shortcut that will be translated into HTML.
Discussion
Emmet provides a straightforward syntax, but itâs surprisingly flexible. You can write more complicated expressions that create nested combinations of elements, set attributes, and incorporate sequential numbers into names. For example, to create a bulleted list with five items, you use the abbreviation ul>li*5
, which adds the following block of markup:
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Or, you can create the starting skeleton for an HTML5 web page (the modern standard) with the shortcut html:5
.
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"UTF-8"
/>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1.0"
>
<title>
Document</title>
</head>
<body>
</body>
</html>
All of these features are described in the Emmet documentation. If youâre in a hurry, start with the patterns in the useful cheatsheet.
Installing the npm Package Manager (with Node.js)
Solution
The Node Package Manager (npm) hosts the largest (and currently most popular) software registry in the world. The easiest way to get software from the npm registry is using npm, which is bundled with Node.js. To install Node, download an installer for your operating system (Windows, MacOS, or Linux) from the Node website.
Once you finish installing Node, you can test that itâs available using the command line. Open a terminal window and type the command node -v
. To check if npm is installed, type npm -v
. Youâll see the version number of both packages:
$ node -v v14.15.4 $ npm -v 6.14.10
Discussion
npm is included with Node.js, a JavaScript runtime environment and web server. You might use Node to run a server-side JavaScript framework like Express, or to build a JavaScript desktop application with Electron. But even if you donât plan to use Node, youâll almost certainly still install it just to get access to the npm package manager.
The Node Package Manager is a tool that can download packages from the npm registry, a free catalog that tracks tens of thousands of JavaScript libraries. In fact, youâll be hard-pressed to find a computer thatâs used for JavaScript development that doesnât have an installation of Node and npm.
The work of a package manager goes beyond simply downloading useful libraries. The package manager also has the responsibility of tracking what libraries your project is using (called dependencies), downloading the packages they depend on (sometimes called subdependencies), storing versioning information, and distinguishing between test and production builds. Thanks to npm, you can take a completed application to another computer and install all the dependencies it needs with a single command, as explained in âDownloading a Package with npmâ.
Although npm is currently the most popular package manager for JavaScript, itâs not the only one you might encounter. Yarn is favored by some developers who find it offers faster package installation. Pnpm is another option that aims to be command-line compatible with npm, while requiring less diskspace and offering better installation performance.
See Also
To install a package with npm, see âDownloading a Package with npmâ.
If youâre using Node for development (not just npm), you should consider installing it with nvm, the Node version manager. That way you can easily switch between different Node versions and quickly update your installation when new releases are available (which is often). For more information, see âManaging Node Versions with Node Version Managerâ. And if you need help to get started running code in the Node environment, Chapter 17 has many more examples.
Extra: Using a Terminal and Shell
To run Node or npm, you use the terminal. Technically, a terminal is a text-based interface that communicates with a shell to execute commands. Many different terminal programs exist, along with many different shells. The terminal and shell program that you use depends on your operating system (and your personal preference, because there are plenty of third-party alternatives).
Here are some of the most common terminal and shell combinations youâll encounter:
-
On a Macintosh computer, go to Applications, open the Utilities folder, and choose Terminal. This launches the default terminal program, which uses
bash
as its shell. -
On a Linux computer, the terminal program depends on the distro. Thereâs often a shortcut named Terminal, and it almost always uses the
bash
shell. -
On Windows, you can launch PowerShell from the Start menu. Technically, PowerShell is the shell and itâs wrapped in a terminal process called
conhost
. Microsoft is developing a modernconhost
replacement called Windows Terminal, which early adopters can install from the Windows Store (or download from GitHub). Microsoft also includes thebash
shell as part of its Windows Subsystem for Linux, although thatâs a relatively recent addition to the operating system. -
Code editors sometimes include their own terminals. For example, if you open the terminal window in VS Code (use the Ctrl + ` shortcut [thatâs a backtick, not a single quote] or choose View > Terminal from the menu) you get VS Codeâs integrated terminal window. By default, it communicates with PowerShell on Windows and
bash
on other systems, although you can configure its settings.
When we direct you to use a terminal command, you can use the terminal window in your code editor, the terminal program thatâs specific to your computer, or one of the many third-party terminal and shell applications. They all get the same environment variables (which means they have access to Node and npm once theyâre installed), and they all have the ability to run programs in the current path. You can also use your terminal for the usual filesystem maintenance tasks, like creating folders and files.
Note
In this book, when we show the commands you should type in a terminal (as in âInstalling the npm Package Manager (with Node.js)â), we preceded them with the $
character. This is the traditional prompt for bash
. However, different shells have different conventions. If youâre using PowerShell youâll see a folder name followed by the >
character instead (as in C:\Projects\Sites\WebTest>
). Either way, the commands you use to run utilities (like npm) donât change.
Downloading a Package with npm
Solution
First, you must have npm on your computer (see âInstalling the npm Package Manager (with Node.js)â for instructions). Assuming you do, open a terminal window (âExtra: Using a Terminal and Shellâ), and go to the project directory for your website.
Next, you should create a package.json file, if your application doesnât already have one. You donât actually need this file to install packages, but it does become important for some other tasks (like restoring your packages to another development computer). The easiest way to create a package.json file is with npmâs init
command:
$ npm init -y
The -y
parameter (for yes) means that npm will simply choose default values rather than prompt you for specific information about your application. If you donât include the -y
parameter, youâll be asked a variety of questions about your application (its package name, description, version, license, and so on). However, you donât need to fill in any of these details at first (or at all), so itâs perfectly acceptable to press Enter to leave each field blank and create the basic package.json boilerplate. For more information about the descriptive information inside package.json, see âExtra: Understanding package.jsonâ.
Once youâve initialized your application, youâre ready to install a package. You must know the exact name of the package you want to install. By convention, npm names are made up of dash-separated lowercase words, like fs-extra
or react-dom
. To install your package of choice, run the npm install
command with the package name. For example, hereâs how you would install the popular Lodash library:
$ npm install lodash
npm adds the packages you install to the package.json file. It also records more detailed versioning information about each package in a file named package-lock.json.
When you install a package, npm downloads its files and places them in a folder named node_modules. For example, if you install Lodash in a project folder named test-site, the Lodash script files will be placed in the folder test-site/node_modules/lodash.
You can remove a package by name using npm uninstall
:
$ npm uninstall lodash
Discussion
The genius of npm (or any package manager) becomes apparent when you have a typical web project with half a dozen or more packages, each of which depends on additional packages. Because all these dependencies are tracked in the package-lock.json file, itâs easy to figure out what a web application needs. You can see a full report by executing this command from your project folder:
$ npm list
Itâs also easy to re-download these packages on a new computer. For example, if you copy your website to another computer with the package.json and package-lock.json files, but without the node_modules folder, you can install all the dependent packages like this:
$ npm install
So far, youâve seen how to install packages locally (as part of the current web application). npm also allows packages to be installed globally (in a system-specific folder, so the same version is available to all the web applications on your computer). For most software packages, local installation is best. It gives you the flexibility to control the exact version of a package that you use, and it lets you use different versions of the same package with different applications, so you never break compatibility. (This potential problem becomes magnified when one package depends on the specific version of another package.) However, global installation is useful for certain types of packages, particularly development tools that have command-line utilities. Some examples of packages that are sometimes installed globally include create-react-app
(used to create a new React project), http-server
(used to run a test web server), typescript
(used to compile TypeScript code into JavaScript), and jest
(used to run automated tests on your code).
To see all the global npm packages installed on your computer, run this command:
`npm list -g --depth 0`
Here, the --depth
parameter makes sure that you only see the top layer of global packages, not the other packages that these global packages use. npm has additional features that we wonât cover here, including the ability to:
-
Designate some dependencies as developer dependencies, meaning theyâre required for development but not deployment (like a unit testing tool). Youâll see this technique in Recipes and .
-
Audit your dependencies by searching the npm registry for reports of known vulnerabilities, which it may be able to fix by installing new versions.
-
Run command-line tasks through a bundled utility called npx. You can even launch tasks automatically by adding them to package.json, like prepping your site for production deployment or starting a web server during development testing. Youâll see this technique with the test server in âSetting Up a Local Test Serverâ.
npm isnât the only package manager that JavaScript developers use. Yarn is a similar package manager that was initially developed by Facebook. It has a performance edge in some scenarios, due to the way that it downloads packages in parallel and uses caching. Historically, itâs also enforced stricter security checks. Thereâs no reason not to use Yarn, but npm remains significantly more popular in the JavaScript community.
To learn everything there is to know about npm, you can spend some quality time with the npm developer docs. You can also take a peek at Yarn.
Extra: Understanding package.json
The package.json file is an application configuration file that was introduced with Node, but is now used for a variety of purposes. It stores descriptive information about your project, its creator, and its license, which becomes important if you ever decide to publish your project as a package on npm (a topic covered in âConverting Your Library into a Node Moduleâ). The package.json file also tracks your dependencies (the packages your application uses) and can store extra configuration steps for debugging and deployment.
Itâs a good practice to begin by creating a package.json file whenever you start a new project. You can create the file by hand, or using the npm init -y
command, which is what we use in the examples in this chapter. Your newly generated file will look something like this (assuming your project folder is named test_site):
{
"name"
:
"test_site"
,
"version"
:
"1.0.0"
,
"description"
:
""
,
"main"
:
"index.js"
,
"scripts"
:
{
"test"
:
"echo \"Error: no test specified\" && exit 1"
},
"keywords"
:
[],
"author"
:
""
,
"license"
:
"ISC"
}
As you may notice, the package.json file uses the JSON (JavaScript Object Notation) format. It holds a comma-separated list of property settings, all wrapped inside {}
braces. You can edit package.json in your code editor at any time.
When you install a package with npm, that dependency is recorded in package.json using a property named dependencies
. For example, if you install Lodash, the package.json file will look like this:
{
"name"
:
"test_site"
,
"version"
:
"1.0.0"
,
"description"
:
""
,
"main"
:
"index.js"
,
"scripts"
:
{
"test"
:
"echo \"Error: no test specified\" && exit 1"
},
"keywords"
:
[],
"author"
:
""
,
"license"
:
"ISC"
,
"dependencies"
:
{
"lodash"
:
"^4.17.20"
}
}
Donât confuse package.json with package-lock.json. The package.json file stores basic project settings and lists all the packages you use. The package-lock.json file specifies the exact version and checksum of every package you use (and the version and checksum of each package those packages use). For example, hereâs the automatically created package-lock.json file after you install Lodash:
{
"name"
:
"test-site"
,
"version"
:
"1.0.0"
,
"lockfileVersion"
:
1
,
"requires"
:
true
,
"dependencies"
:
{
"lodash"
:
{
"version"
:
"4.17.20"
,
"resolved"
:
"https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz"
,
"integrity"
:
"sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5h
agpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA=="
}
}
}
In other words, package-lock.json âlocksâ your packages to a specific version. This is useful if youâre deploying your project to another computer, and you want to install exactly the same versions of every package that you used during development.
There are two common reasons you might edit your applicationâs package.json file. First, you might want to add more descriptive details for completeness before you share the project with anyone else. Youâll definitely want to make sure this information is correct if youâre planning to share your package in the npm registry (âConverting Your Library into a Node Moduleâ). Second, you might decide to configure command-line tasks for debugging, like starting a test server (âSetting Up a Local Test Serverâ). For a complete, property-by-property description of what you can put in package.json, refer to the npm documentation.
Updating a Package with npm
Problem
You want to update an npm package to a newer version.
Solution
For minor updates, use npm update
. You can name the specific package you want to update, or ask npm to check for new versions of every package your site uses, and update them all in one fell swoop:
$ npm update
npm will examine the package.json file and update every dependency and subdependency. It will also download any missing packages. Finally, it will update the package-lock.json file to match the new versions.
Discussion
Itâs a good practice to regularly update the packages you use. However, not all updates can happen automatically. npm updates follow the rules of semver (semantic versioning). npm will install updates that have greater patch numbers (for example, updating 2.1.2
to 2.1.3
) or minor version numbers (2.1.2
to 2.2.0
), but it wonât upgrade a dependency if the new release changes the major version number (2.1.2
to 3.0.0
). This behavior guards against breaking changes when you update or deploy your application.
You can review what updates are available for all of your dependencies using the npm outdated
command:
$ npm outdated
This produces output like this:
Package Current Wanted Latest Location ------- ------- ------ ------ -------- eslint 7.18.0 7.25.0 7.25.0 my-site eslint-plugin-promise 4.2.1 4.3.1 5.1.0 my-site lodash 4.17.20 4.17.21 4.17.21 npm-test
The Wanted
column shows available updates that will be installed the next time you run npm update
. The Latest
column shows the most recent version of the package. In the example above, both lodash
and eslint
can be updated to the latest package version. But the eslint-plugin-promise
package will only be updated to version 4.3.1. The latest version, 5.1.0, changes the major version number, which means that according to the rules of semver it canât be applied automatically.
Note
This is a slight simplification, because npm gives you the ability to specify versioning policies more specifically in the package.json file. But in practice, this is the way that almost all npm updates will work. For more information about npm versioning, see the npm documentation.
If you want to update a dependency to use a new major version, you need to do it deliberately. Options include editing the package.json file by hand (slightly painful) or using a tool that can do it for you, like npm-check-updates
. The npm-check-updates
tool allows you to review your dependencies, see what updates are available, and choose to update the package.json file to allow a new major version update. Once youâve done that, call npm update
to download the new version.
Setting Up a Local Test Server
Solution
Install a local test server on your computer. The test server will handle requests and send web pages to your browser, just like a real web server. The only difference is that the test server wonât accept remote connections from other computers.
There are many choices for a test server (see the Discussion section). However, two simple, reliable choices are the http-server
and lite-server
packages that you can install through npm. We use lite-server
here, because it adds a live update feature that automatically refreshes the page in the browser when you save changed code in your editor.
Before you install lite-server
, it helps to have a sample web page to request. If you havenât already done so, make a project folder and configure it with the npm init -y
command (âDownloading a Package with npmâ). Then, add a file named index.html with a basic content. If youâre in a hurry, hereâs a minimal but valid HTML document you can use to test where your code is running:
<!DOCTYPE html>
<html
lang=
"en"
>
<head>
<meta
charset=
"utf-8"
>
<title>
Test Page</title>
</head>
<body>
<p>
This is the index page</p>
<script>
if
(
window
.
location
.
protocol
===
'file:'
)
{
console
.
log
(
'Running as local file!'
);
}
else
if
(
window
.
location
.
host
.
startsWith
(
'localhost'
))
{
console
.
log
(
'Running on a local server'
);
}
else
{
console
.
log
(
'Running on a remote web server'
);
}
</script>
</body>
</html>
Now youâre ready to make this document accessible to your browser through a test server.
To install lite-server
, use npm with the --save-dev
option. That way itâs marked as a developer dependency that wonât be deployed in a production build.
npm install lite-server --save-dev
Now you can run lite-server
directly from a terminal window using npmâs package runner, npx
:
npx lite-server
This launches lite-server
, opens a new browser tab, and requests http://localhost:3000 (where 3000
is whatever port lite-server
acquires dynamically). The lite-server
attempts to return index.html, or just displays âCannot GET /â if you donât have a file with that name. If you used the sample page from this section, youâll see the âThis is the index pageâ message on the page and âRunning on a local serverâ in the developer console. If you donât have an index.html page in your test site, you can load up a different page by editing the URL in the address bar (for example, http://localhost:3000/someOtherPage.html).
Now try making some changes. The lite-server
instance watches your project folder. Whenever you change a file, it automatically forces the browser to refresh the page. In the terminal, youâll see a âReloading Browsersâ message whenever this happens.
To end the server, press Ctrl+C at the terminal (Command-C on a Macintosh) and answer Y
. Or, close the terminal window (or use the Kill Terminal trashcan icon in VS Code).
Note
Behind the scenes, lite-server
uses a popular browser automation tool called BrowserSync to implement its live reloading. The only requirement is that your web page must have a <body>
section. (Create a super-simple test page without that detail, and you wonât see the automatic refreshing behavior.)
Discussion
You can save a web page on your local computer, open it in a web browser, and run its code. However, web browsers greatly restrict pages that are opened from the local filesystem. Entire features are unavailable and will fail quietly (like web workers, ES modules, and certain Canvas operations). To avoid hitting these security barriers orâeven worseâbeing confused at why code isnât working the way you expect, itâs always better to run your web pages from a test web server.
While testing, itâs common to use a development server. There are many options, and your decision will depend somewhat on the other server-side technologies that you plan to use. For example, if you want to run PHP code in your web pages, youâll need a web server that supports it. If you plan to build part of the backend of your application using JavaScript or a JavaScript-powered server-side framework like Express, youâll need to use Node.js. But if youâre running web pages with traditional client-side JavaScript, a simple server that sends static files is enough, like http-server
or lite-server
. There are many more and code editors often have their own plug-in-based test server. For example, if youâre using Visual Studio Code you can search the extension library for the popular Live Server plug-in.
In the Solution section, you saw how to run lite-server
with npx
. However, a more convenient setup is to make a development run task that automatically starts the server. You can do that by editing the package.json file and adding the following instruction to the scripts
section:
{
...
"scripts"
:
{
"dev"
:
"lite-server"
}
}
The scripts
section holds executable tasks that you want to run regularly. These might include verifying your code with a linter, checking it into source control, packaging your files for deployment, or running a unit test. You can add as many scripts as you needâfor example, itâs common to use one task to run your application, another to test it with an automated testing tool (âWriting Unit Tests for Your Codeâ), another to prepare it for distribution, and so on. In this example, the script is named dev
, which is a convention that identifies a task you plan to use while developing your application.
Once youâve defined a script in package.json, you can run it with the npm run
command at the terminal:
npm run dev
This launches lite-server
with npx
.
Some code editors have additional support for this configuration detail. For example, if you open the package.json file in VS Code youâll see that a âDebugâ link is added just above the dev
setting. Click this link and VS Code opens a new terminal and launches lite-server
automatically.
See Also
To learn more about using Node as a test server, see the recipes in Chapter 17. For more information about running tasks with npm, you can read this good overview.
Enforcing Code Standards with a Linter
Solution
Check your code with a linter, which warns you when you deviate from the rules youâve chosen to follow. The most popular JavaScript linter is ESLint.
To use ESLint, you first need npm (see âInstalling the npm Package Manager (with Node.js)â). Open a terminal window in your project folder. If you havenât already created the package.json file, get npm to create it now:
$ npm init -y
Next, install the eslint
package using the --save-dev
option, because you want ESLint to be a developer dependency thatâs installed on developer computers, but not deployed to a production server:
$ npm install eslint --save-dev
If you donât already have an ESLint configuration file, you need to create one now. Use npx to run the ESLint setup:
$ npx eslint --init
ESLint will ask you a series of questions to assess the type of rules it should enforce. Often, it presents a small menu of choices, and you must use the arrow keys to pick the option you want.
The first question is âHow would you like to use ESLint?â Here you have three options, arranged from least strict to most strict:
- Check syntax only
-
Uses ESLint to catch errors. Itâs not any stricter than the error-highlighting feature in most code editors.
- Check syntax and find problems
-
Enforces ESLintâs recommended practices (the ones marked with a checkmark). This is an excellent starting point, and you can override individual rules to your preference later on.
- Check syntax, find problems, and enforce code style
-
Is a good choice if you want to use a specific JavaScript style guide, like Airbnb, to enforce a broader set of style conventions. If you choose this option, youâll be asked to pick the style guide later in the process.
Next, youâll be asked a series of technical questions: are you using modules, the React or Vue framework, or the TypeScript language? Choose JavaScript modules to get support for the ES6 modules standard described in âOrganizing Your JavaScript Classes with Modulesâ, and choose No for other questions unless youâre using the technology in question.
Next, youâll be asked âWhere does your code run?â Choose Browser for a traditional website with client-side JavaScript code (the usual), or Node if youâre building a server-side application that runs in the Node.js server.
If youâve chosen to use a style guide, JavaScript will now prompt you to pick one from a small list of choices. It then installs these rules automatically using one or more separate packages, provided you allow it.
Finally, ESLint asks âWhat format do you want your config file to be in?â All the format choices work equally well. We prefer to use JSON for symmetry with the package.json file, in which case ESList stores its configuration in a file named .eslintrc.json. If you use a JavaScript configuration file, the extension is .js, and if you choose a YAML configuration file, the extension is .yaml.
Hereâs what youâll see in the .eslintrc.json file if youâve asked ESLint to âcheck syntax and find problemsâ without the addition of a separate style guide:
{
"env"
:
{
"browser"
:
true
,
"es2021"
:
true
},
"extends"
:
"eslint:recommended"
,
"parserOptions"
:
{
"ecmaVersion"
:
12
,
"sourceType"
:
"module"
},
"rules"
:
{
}
}
Now you can ESLint to check your files in the terminal:
npx eslint my-script.js
But a far more practical option is to use a plug-in that integrates ESLint with your code editor. All the code editors introduced in âChoosing a Code Editorâ support ESLint, and you can browse the full list of ESLint-supporting plug-ins.
To add ESLint to your code editor, go to its plug-in library. For example, in Visual Studio Code you begin by clicking Extensions in the left panel, and then searching the library for âeslint,â then clicking Install. Once youâve installed ESLint, you will need to officially allow it through the plug-inâs settings page (or by clicking the lightbulb icon that appears when you open a code file in the editor, and then choosing Allow). You may also need to install ESLint globally across your entire computer so the plug-in can find it:
$ npm install -g eslint
Once ESLint is enabled, youâll see the squiggly underlines that denote ESLint errors and warnings. Figure 1-4 shows an example where ESLint detects a case
in a switch
statement that falls through to the next case
, which isnât allowed in ESLintâs standard settings. The âeslintâ label in the pop-up identifies that this message is from the ESLint plug-in, not VS Codeâs standard error checking.
Note
If ESLint isnât catching the issues that you expect it to catch, it could be due to another error in your file, possibly even one in a different section of code. Try resolving any outstanding issues, and then recheck your file.
Click Quick Fix (or the lightbulb icon in the margin) to learn more about the problem or attempt a fix (if possible). You can also disable checking for this issue in the current line or file, in which case your override is recorded in a special comment. For example, this disables the rule against declaring variables that you donât use:
/* eslint-disable no-unused-vars */
If you must override ESLint with comments, itâs probably best to be as targeted and judicious as possible. Instead of disabling checking for an entire file, override it for a single, specific line, like this:
// eslint-disable-next-line no-unused-vars
let
futureUseVariable
;
or this (replacing eslint-disable-next-line
with eslint-disable-line
):
let
futureUseVariable
;
// eslint-disable-line no-unused-vars
If you want to resume checking for the issue, just remove the comment.
Discussion
JavaScript is a permissive language that gives developers a great deal of flexibility. Sometimes this flexibility can lead to problems. For example, it can hide errors or cause ambiguity that makes the code harder to understand. A linter works to prevent these problems by enforcing a range of standards, even if they donât correspond to outright errors. It flags potential issues in the making, and suspicious practices that donât trigger your code editorâs error checker but may eventually come back to haunt you.
ESLint is an opinionated linter, which means it flags issues that you may not consider problems, like variables you declare but donât use, parameter values you change in a function, empty conditional blocks, and regular expressions that include literal spaces (to name just a few). If you want to allow some of these, you have the power to override any of these settings in the ESLint configuration file (or on a file-by-file or line-by-line basis with a comment). But usually youâll just decide to change your ways to get along, knowing that ESLintâs choices will eventually avoid a future headache.
ESLint also has the ability to correct certain types of errors automatically, and enforce style conventions (like tabs versus spaces, single quotes versus double quotes, brace and indent styles, and so on). Using the ESLint plug-in for an editor like VS Code, you can configure it to perform these corrections automatically when you save your file. Or, you can use ESLint to flag potential problems only, and use a formatter (âStyling Code Consistently with a Formatterâ) to enforce code style conventions.
If you work in a team, you may simply receive a preordained ESLint configuration file to use. If not, you need to decide which set of ESLint defaults to follow. You can lean more about ESLint recommended set (used in this recipe), which provides examples of nonconforming code for every issue the ESLint can check. If you want to use a more thorough JavaScript style guide, we recommend the popular Airbnb JavaScript Style Guide, which can be installed automatically with eslint -init
.
Styling Code Consistently with a Formatter
Solution
Use the Prettier code formatter to automatically format your code according to the rules youâve established. Prettier enforces consistency on style details like indentation, use of single and double quotes, spacing inside brackets, spacing for function parameter lists, and the wrapping of long code lines. But unlike a linter (âEnforcing Code Standards with a Linterâ), Prettier doesnât flag these issues for you to fix them. Instead, it applies its formatting automatically every time you save your JavaScript code, HTML markup, or CSS style rules.
Although Prettier exists as a package you can install with npm and use at the command line, itâs much more useful to use a plug-in for your code editor. All the code editors introduced in âChoosing a Code Editorâ have a Prettier plug-in. Most of them are listed at the Prettier website.
To add Prettier to your code editor, go to its plug-in library. For example, in Visual Studio Code you click Extensions in the left panel, search the library for âprettier,â and then click Install.
Once youâve installed Prettier, youâll be able to use it when youâre editing a code file. Right-click next to your code in the editor and choose Format Document. You can configure the plug-in settings to change a small set of options (like the maximum allowed width before code lines are split, and whether you prefer spaces to tabs).
Tip
In VS Code, you can also configure Prettier to run automatically every time you save a file. To activate this behavior, choose File > Preferences > Settings, go to the Text Editor > Formatting section, and choose Format On Save.
Discussion
Although many code editors have their own automatic formatting features, a code formatter goes beyond these. For example, the Prettier formatter strips away any custom formatting. It parses all the code and reformats it according to the conventions youâve set, with almost no consideration to how it was originally written. (Blank lines and object literals are the only two exceptions.) This approach guarantees that the same code is always presented in the same way, and that code from different developers is completely consistent. And like a linter, the rules for a code formatter are defined in a configuration file, which means you can easily distribute them to different members of a team, even if theyâre using different code editors.
The Prettier formatter takes particular care with line breaks. By default, the maximum line length is set to 80, but Prettier will allows some lines to stretch a bit longer if it avoids a confusing line break. And if a line break is required, Prettier does it intelligently. For example, it would prefer to fit a function call into one line:
myFunction
(
argA
(),
argB
(),
argC
());
But if that isnât practical, it doesnât just wrap the code however it fits. It chooses the most pleasing arrangement it understands:
myFunction
(
reallyLongArg
(),
omgSoManyParameters
(),
IShouldRefactorThis
(),
isThereSeriouslyAnotherOne
()
);
Of course, no matter how intelligent a formatter like Prettier is, you may prefer your own idiosyncratic code arrangements. Itâs sometimes said that âNobody loves what Prettier does to their syntax. Everyone loves what Prettier does to their coworkersâ syntax.â In other words, the value of an aggressive, opinionated formatter like Prettier is the way it unifies different developers, cleans up legacy code, and irons out bizarre habits. And if you decide to use Prettier, youâll have the unchecked freedom to write your code without thinking about spacing, line breaks, or presentation. In the end, your code will still be converted to the same canonical form.
Tip
If youâre not entirely certain that you want to use a code formatter, or youâre not sure how to configure its settings, spend some time in the Prettier playground to explore how it works.
A linter like ESLint and a formatter like Prettier have some overlap. However, their goals are different and their use is complementary. If youâre using both ESLint and Prettier, you should keep the ESLint rules that catch suspicious coding practices, but disable the ones that enforce formatting conventions about indents, quotes, and spacing. Fortunately, this is easy to do by adding an extra ESLint configuration rule that turns off potential settings that could conflict with Prettier. And the easiest way to do that is by adding the eslint-config-prettier
package to your project:
$ npm install --save-dev eslint-config-prettier
Lastly, you need to add prettier
to the extends
section in your .eslintrc.json file. The extends
section will hold a list wrapped in square brackets, and prettier
should be at the very end. Hereâs an example:
{
"env"
:
{
"browser"
:
true
,
"es2021"
:
true
}
,
"extends"
:
[
"eslint:recommended"
,
"prettier"
]
,
"parserOptions"
:
{
"ecmaVersion"
:
12
,
"sourceType"
:
"module"
}
,
"rules"
:
{
}
}
To review the most recent installation instructions, check out the documentation for the eslint-config-prettier
package.
Experimenting in a JavaScript Playground
Solution
Use a JavaScript playground, which is a website where you can edit and run JavaScript code. There are well over a dozen JavaScript playgrounds, but Table 1-4 lists five of the most popular.
Website | Notes |
---|---|
Arguably the first JavaScript playground, JSFiddle is still at the forefront with features for simulating asynchronous calls and GitHub integration. |
|
A classic playground with a simple tab-based interface that lets you pop different sections (JavaScript, HTML, CSS) into view one at a time. The code for JS Bin is also available as an open source project. |
|
One of the more attractively designed playgrounds, with an emphasis on the social (popular examples are promoted in the CodePen community). Its polished interface is particularly suitable for novice users. |
|
One of the newer playgrounds, it uses an IDE-like layout that feels a lot like a web-hosted version of Visual Studio Code. |
|
Another IDE-in-a-browser, Glitch is notable for its VS Code plug-in, which lets you switch between editing in a browser playground or using your desktop editor on the same project. |
All these JavaScript playgrounds are powerful, practical choices. They all work similarly, although they can look strikingly different. For example, compare the dense developer cockpit of JSFiddle (Figure 1-5) to the more spaced-out editor in CodePen (Figure 1-6).
Hereâs how you use a JavaScript playground. When you visit the site, you can start coding immediately at a blank page. Even though your JavaScript, HTML, and CSS are presented separately, you donât need to explicitly add a <script>
element to connect your JavaScript or a <link>
element for your style sheet. These details are already filled into the markup of your page or, more commonly, are an implicit part of boilerplate thatâs hidden behind the scenes.
All JavaScript playgrounds let you see the page youâre working on beside your code window. In some (like CodePen), the preview is refreshed automatically as you make changes. In others (like JSFiddle), you need to explicitly click a Play or Run button to reload your page. If you write messages with console.log()
, some JavaScript playgrounds send that directly to the browser console (like CodePen), while others can also show it in a dedicated panel thatâs visible on the page (like JSFiddle).
When youâre finished you can save your work, at which point you receive a newly generated, shareable link. However, itâs a better idea to sign up for an account first, so youâre able to return to the JavaScript playground, find all the examples youâve created, and edit them. (If you save an example anonymously, you canât edit it, although you can use it as a starting point to build another example.) All the playgrounds listed in Table 1-4 let you create an account and save your work for free.
Note
The exact terminology for the kind of example you create in a JavaScript playground varies based on the site. It might be called a fiddle, a pen, a snippet, or something else.
Discussion
JavaScript playgrounds are a useful idea thatâs been picked up by more than a dozen websites. Almost all of them share some important characteristics:
-
Theyâre free to use. However, many have a subscription option for premium features, like being able to save your work and keep it private.
-
You can save your work indefinitely. This is particularly handy if you want to share a quick mock-up or collaborate on a new experiment with others.
-
They support a wide range of popular JavaScript libraries and frameworks. For example, you can quickly add Lodash, React, or jQuery to your example, just by picking it from a list.
-
You can edit HTML, JavaScript, and CSS all in one window. Depending on the playground, it may be divided into panels that are all visible at once (like JSFiddle) or tabs that you switch between (like JS Bin). Or, it may be customizable (like CodePen).
-
They provide some level of autocompletion, error checking, and syntax highlighting (colorizing different code ingredients), although itâs not as complete as what youâll get in a desktop code editor.
-
They provide a preview of your page so you can jump easily between coding and testing.
JavaScript playgrounds also have limits. For example, you may not be able to host other resources like images, interact with backend services like databases, or use asynchronous requests with fetch
.
JavaScript playgrounds should also be distinguished from full cloud-based programming environments. For example, you can use VS Code online in a completely hosted environment called GitHub Codespaces, or AWS Cloud9 from Amazon, or Google Cloud. None of these products are free, but all are appealing if you want to set up a specific development environment that you can use in your browser, on different devices, and with no setup or performance concerns.
Get JavaScript Cookbook, 3rd Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.