Discover millions of audiobooks, ebooks, and so much more with a free trial

From $11.99/month after trial. Cancel anytime.

Mastering Node.js Web Development: Go on a comprehensive journey from the fundamentals to advanced web development with Node.js
Mastering Node.js Web Development: Go on a comprehensive journey from the fundamentals to advanced web development with Node.js
Mastering Node.js Web Development: Go on a comprehensive journey from the fundamentals to advanced web development with Node.js
Ebook1,379 pages9 hours

Mastering Node.js Web Development: Go on a comprehensive journey from the fundamentals to advanced web development with Node.js

Rating: 0 out of 5 stars

()

Read preview
LanguageEnglish
Release dateJun 24, 2024
ISBN9781837637355
Mastering Node.js Web Development: Go on a comprehensive journey from the fundamentals to advanced web development with Node.js
Author

Adam Freeman

Adam Freeman is an experienced IT professional who started his career as a programmer. He has held senior positions in a range of companies, most recently serving as Chief Technology Officer and Chief Operating Officer of a global bank. He has written 50 programming books, focusing mostly on web application development.

Read more from Adam Freeman

Related to Mastering Node.js Web Development

Related ebooks

Internet & Web For You

View More

Reviews for Mastering Node.js Web Development

Rating: 0 out of 5 stars
0 ratings

0 ratings0 reviews

What did you think?

Tap to rate

Review must be at least 10 words

    Book preview

    Mastering Node.js Web Development - Adam Freeman

    Cover of Mastering Node.js Web Development by Adam Freeman

    Mastering Node.js Web Development

    Go on a comprehensive journey from the fundamentals to advanced web development with Node.js

    Adam Freeman

    Mastering Node.js Web Development

    Copyright © 2024 Packt Publishing

    All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.

    Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.

    Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.

    Senior Publishing Product Manager: Suman Sen

    Acquisition Editor – Peer Reviews: Jane Dsouza

    Project Editor: Parvathy Nair

    Content Development Editor: Shazeen Iqbal

    Copy Editor: Safis Editing

    Technical Editors: Kushal Sharma and Anirudh Singh

    Proofreader: Safis Editing

    Indexer: Hemangini Bari

    Presentation Designer: Ganesh Bhadwalkar

    Developer Relations Marketing Executive: Priyadarshini Sharma

    First published: June 2024

    Production reference: 1100624

    Published by Packt Publishing Ltd.

    Grosvenor House

    11 St Paul’s Square

    Birmingham

    B3 1RB, UK.

    ISBN 978-1-80461-507-2

    www.packt.com

    Dedicated to my lovely wife, Jacqui Griffyth.

    (And also to Peanut.)

    Contributors

    About the author

    Adam Freeman is an experienced IT professional who started his career as a programmer. He held senior positions in a range of companies, where he was most recently serving as Chief Technology Officer and Chief Operating Officer of a global bank. He has written 53 programming books, focusing mostly on web application development. Now retired, he spends his time writing and trying to make furniture.

    About the reviewer

    Fabio Claudio Ferracchiati is a senior consultant and a senior analyst/developer using Microsoft technologies. He works for TIM (an Italian telecommunications company). He is a Microsoft Certified Solution Developer for .NET, a Microsoft Certified Application Developer for .NET, a Microsoft Certified Professional, and a prolific author and technical reviewer. Over the past ten years, he’s written articles for Italian and international magazines and co-authored a number of books on a variety of computer topics.

    I would like to thank Adam, who has always wanted me by his side in his works, which are of a quality superior to the norm. I would like to thank my wife for giving me two wonderful daughters who are my whole life, currently nicknamed Peguin and Rani. I love you.

    Part I

    Putting Node.js in Context

    Start your Node.js development journey by learning the essential tools, exploring fundamental JavaScript features, and understanding core Node.js support for web applications.

    This part comprises the following chapters:

    Chapter 1, Getting Ready

    Chapter 2, Working with the Node.js Tools

    Chapter 3, JavaScript and TypeScript Primer

    Chapter 4, Understanding Node.js Concurrency

    Chapter 5, Handling HTTP Requests

    Chapter 6, Using Node.js Streams

    Chapter 7, Using Bundles and Content Security

    Chapter 8, Unit Testing and Debugging

    1

    Getting Ready

    Node.js is a server-side JavaScript runtime that has become one of the most popular platforms for creating web applications. Node.js benefits from a vast library of packages and frameworks, providing every kind of feature and function imaginable, built on a rich API that Node.js provides for handling low-level tasks.

    This book is different from most other Node.js books because it explains the relationship between the Node.js API and popular web application packages. Each chapter explains how a core feature required for web development can be implemented using the Node.js API, before replacing the custom implementation with a popular and well-tested open-source package.

    Understanding the Node.js API gives you a solid understanding of how web application features really work, and using popular packages lets you build those features without having to write custom code. When problems arise, as they will in any project, your knowledge of the Node.js API will give you a solid foundation to demystify the way that specific packages work and to figure out what’s going wrong.

    The first part of this book provides an overview of the tools used in Node.js development and provides a primer for the most important language and platform features, including how concurrency is implemented by JavaScript, and how this relates to handling HTTP requests using Node.js.

    The second part of this book focuses on the key building blocks for web applications: generating HTML content, processing forms, using databases, and authenticating users.

    The third and final part of this book demonstrates how the features described in earlier chapters can be combined to create a simple but realistic web store application.

    This is the SportsStore example that I have used in many of my books, and which includes common features such as a product catalog, a shopping cart, a checkout process, and administration features.

    What do you need to know?

    To follow the examples in this book, you should be familiar with HTML and CSS and understand the basics of JavaScript development. I provide a primer for the JavaScript features that are useful for this book, but this isn’t a complete language tutorial.

    How do you set up your development environment?

    The tools needed for Node.js development are set up in Chapter 2. Later chapters require additional tools and packages, with full instructions provided for each.

    Are there lots of examples?

    There are loads of examples. The best way to learn is by example, and I have packed as many of them into this book as I can. To maximize the number of examples in this book, I have adopted a simple convention to avoid listing the same code or content repeatedly. When I create a file, I will show its full contents, just as I have in Listing 1.1. I include the name of the file and its folder in the listing’s header, and I show the changes that I have made in bold.

    Listing 1.1: Asserting an unknown value in the index.ts file in the primer folder

    function getUKCapital() : string { return London; } function writeCity(f: () => string) { console.log(`City: ${f()}`) } writeCity(getUKCapital); writeCity(() => Paris);

    let myCity = Rome;

    writeCity(() => myCity);

    This is a listing from Chapter 3, which shows the contents of a file called

    index.ts

    that can be found in the

    primer

    folder. Don’t worry about the content of the listing or the purpose of the file; just be aware that this type of listing contains the complete contents of a file and that the changes you need to make to follow the example are shown in bold.

    Some code files become long, and the feature I will describe will require only a small change. Rather than list the complete file, I use an ellipsis (three periods in succession) to indicate a partial listing, which shows just a portion of the file, as shown in Listing 1.2.

    Listing 1.2. Including user input in the sql_repository.Ts file in the src/server/data folder

    ... getResultsByName($name: string, $limit: number): Promise {

    return this.executeQuery

    (`

    SELECT Results.*, name, age, years, nextage FROM Results

    INNER JOIN People ON personId = People.id

    INNER JOIN Calculations ON calculationId = Calculations.id

    WHERE name = ${$name}`, {});

    } ...

    This is a listing from Chapter 12, and it shows a set of changes applied to one part of a larger file. When you see a partial listing, you will know that the rest of the file does not have to change and that only the sections marked in bold are different.

    In some cases, changes are required in different parts of a file, which makes it difficult to show as a partial listing. In this situation, I omit part of the file’s contents, as shown in Listing 1.3.

    Listing 1.3. Defining model relationships in the orm_helpers.ts file in the src/server/data folder

    import { DataTypes, Sequelize } from sequelize; import { Calculation, Person, ResultModel } from ./orm_models; const primaryKey = { id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true } }; export const initializeModels = (sequelize: Sequelize) => { // ...statements omitted for brevity... }

    export const defineRelationships = () => {

    ResultModel.belongsTo(Person, { foreignKey: personId });

    ResultModel.belongsTo(Calculation, { foreignKey: calculationId});

    }

    In this listing, the changes are still marked in bold, and the parts of the file that are omitted from the listing are not affected by this example.

    Where can you get the example code?

    You can download the example projects for all the chapters in this book from https://github.com/PacktPublishing/Mastering-Node.js-Web-Development. We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!

    What if you have problems following the examples?

    The first thing to do is to go back to the start of the chapter and start over. Most problems are caused by skipping a step or not fully applying the changes shown in a listing. Pay close attention to the bold emphasis in code listings, which highlights the changes that are required.

    Then, check the errata/corrections list, which is included in the book’s GitHub repository. Technical books are complex, and mistakes are inevitable, despite my best efforts and those of my editors. Check the errata list for the list of known errors and instructions to resolve them.

    If you still have problems, then download the project for the chapter you are reading from the book’s GitHub repository (https://github.com/PacktPublishing/Mastering-Node.js-Web-Development) and compare it to your project. I created the code for the GitHub repository by working through each chapter, so you should have the same files with the same contents in your project.

    If you still can’t get the examples working, then you can contact me at [email protected] for help. Please make it clear in your email which book you are reading, and which chapter/example is causing the problem. A page number or code listing is always helpful. Please remember that I get a lot of emails and that I may not respond immediately.

    What if you find an error in the book?

    You can report errors to me by email at [email protected] or visit http://www.packtpub.com/submit-errata, click Submit Errata, and fill in the form, although I ask that you first check the errata/corrections list for this book, which you can find in the book’s GitHub repository at https://github.com/PacktPublishing/Mastering-Node.js-Web-Development, just in case it has already been reported.

    I add errors that are likely to confuse readers, especially problems with example code, to the errata/corrections file on the GitHub repository, with a grateful acknowledgment to the first reader who reported it. I also publish a list of less serious issues, which usually means errors in the text surrounding the code that are less likely to confuse.

    How do you contact the author?

    You can email me at [email protected]. It has been a few years since I started publishing an email address in my books. I wasn’t entirely sure that it was a good idea, but I am glad that I did it. I have received emails from around the world, from readers working or studying in every industry, and – for the most part, anyway – the emails are positive, polite, and a pleasure to receive.

    I try to reply promptly, but I get many emails, and sometimes I get a backlog, especially when I have my head down trying to finish writing a book. I always try to help readers who are stuck with an example in the book, although I ask that you follow the steps described earlier in this chapter before contacting me.

    While I welcome reader emails, there are some common questions for which the answers will always be no. I am afraid that I won’t write the code for your new start-up, help you with your college assignment, get involved in your development team’s design dispute, or teach you how to program.

    What if you really enjoyed this book?

    Please email at [email protected] and let me know. It is always a delight to hear from a happy reader, and I appreciate the time it takes to send those emails. Writing these books can be difficult, and those emails provide essential motivation to persist in an activity that can sometimes feel impossible. Alternatively, you can also send feedback to [email protected].

    What if this book has made you angry?

    You can still email at [email protected], and I will still try to help you. Bear in mind that I can help only if you explain what the problem is and what you would like me to do about it. You should understand that, sometimes, the only outcome is to accept I am not the writer for you and that we will have closure only when you return this book and select another. I’ll give careful thought to whatever has upset you, but after 25 years of writing books, I have come to accept that not everyone enjoys reading the books I like to write. Alternatively, you can also send feedback to [email protected].

    Now that you understand the structure of the book, the next chapter explores the tools used for Node.js development.

    Download a free PDF copy of this book

    Thanks for purchasing this book!

    Do you like to read on the go but are unable to carry your print books everywhere?

    Is your eBook purchase not compatible with the device of your choice?

    Don’t worry, now with every Packt book you get a DRM-free PDF version of that book at no cost.

    Read anywhere, any place, on any device. Search, copy, and paste code from your favorite technical books directly into your application.

    The perks don’t stop there, you can get exclusive access to discounts, newsletters, and great free content in your inbox daily.

    Follow these simple steps to get the benefits:

    Scan the QR code or visit the link below:

    https://packt.link/free-ebook/9781804615072

    Submit your proof of purchase.

    That’s it! We’ll send your free PDF and other benefits to your email directly.

    Share your thoughts

    Once you’ve read Mastering Node.js Web Development, we’d love to hear your thoughts! Please click here to go straight to the Amazon review page for this book and share your feedback.

    Your review is important to us and the tech community and will help us make sure we’re delivering excellent quality content.

    2

    Working with the Node.js Tools

    In this chapter, I explain the simple process of getting started with Node.js, beginning with the simple steps that are required to prepare for development. I explain how to execute JavaScript code using Node.js and then I introduce the real power in Node.js development: the Node Package Manager (npm).

    npm

    is the tool that does most of the work during development, taking responsibility for everything from downloading and installing JavaScript packages, reporting on security vulnerabilities, and running development commands. Table 2.1 summarizes the chapter.

    Table 2.1: Chapter summary

    Getting ready

    The key step to prepare for Node.js development is, as you would expect, to install Node.js and its supporting tools. The version of Node.js I have used in this book is 20.9.0, which is the Long-Term Support (LTS) version at the time of writing. There may be later versions available by the time you read this, but you should stick to this release for the examples in this book.

    A complete set of installers for Node.js version 20.10.0 is available at https://nodejs.org/download/release/v20.10.0. Download and run the installer for your platform and ensure the npm package manager and the Add to PATH options are checked, as shown in Figure 2.1:

    A screenshot of a computer setup Description automatically generated

    Figure 2.1: Installing Node.js

    When the installation is complete, open a new command prompt and run the command shown in Listing 2.1:

    Listing 2.1: Running Node.js

    node -v

    If the installation has been successful, you will see the following version number displayed:

    v20.10.0

    The installer should have set up the package manager, which plays a key role in Node.js development. Run the command shown in Listing 2.2 to ensure the package manager is working:

    Listing 2.2: Running the package manager

    npm -v

    If the installation was successful, you will see the following version number:

    10.1.0

    Installing Git

    Some packages depend on Git, which is a popular version control system. Download the installer for your platform from https://git-scm.com/downloads and follow the installation instructions.

    Once you have completed the installation, use a command prompt to run the command shown in Listing 2.3 to check that Git is working. You may have to manually configure the executable paths:

    Listing 2.3: Checking Git

    git --version

    At the time of writing, the latest version of Git for Windows and Linux is 2.42.0.

    Selecting a code editor

    An editor is required to write the code that will be executed by Node.js, and any editor that supports JavaScript and TypeScript can be used to follow the examples in this book. If you don’t already have a preferred editor, then Visual Studio Code (https://code.visualstudio.com) has become the most popular editor because it is good (and free), and it is the editor that I used while writing this book.

    If you are using Visual Studio Code, run the command code to start the editor or use the program icon created during installation, and you will see the welcome screen shown in Figure 2.2. (You may need to add Visual Studio Code to your command prompt path before using the command code.)

    Figure 2.2: The Visual Studio Code Welcome screen

    Using Node.js

    The entire purpose of Node.js is to execute JavaScript code. Open a command prompt, navigate to a convenient location, and create a folder named

    tools

    . Add a file named

    hello.js

    to the

    tools

    folder, with the content shown in Listing 2.4:

    Listing 2.4: The Contents of the hello.js File in the tools Folder

    console.log(Hello, World);

    The Node.js API has some features that are also provided by modern JavaScript browsers, including the

    console.log

    method, which writes a message to the console. Run the command shown in Listing 2.5 in the

    tools

    folder to execute the JavaScript code:

    Listing 2.5: Executing the JavaScript Code

    node hello.js

    The

    node

    command starts the Node.js runtime and executes the specified JavaScript file, producing the following output:

    Hello, World

    That’s all there is to know about executing JavaScript code. The rest of the functionality that Node.js provides is delivered through an API, which is described in the rest of this book, starting with Chapter 4.

    Understanding the npm tool

    The

    node

    command isn’t often used directly, and most development activities rely on the

    npm

    tool, which is installed alongside Node.js. The headline

    npm

    feature is that it provides access to the

    npm

    repository (npmjs.com), which contains an incredible collection of open-source JavaScript packages that can be added to projects.

    npm

    has grown from its original purpose to add related features and has become an integral part of working with Node.js, as I describe in the following sections. For quick reference, Table 2.2 lists the most useful commands supported by

    npm

    , which is the package manager command.

    Table 2.2: Useful

    npm

    commands

    Initializing a project

    npm

    relies on a configuration file named

    package.json

    , which describes the development project, keeps track of the packages on which it depends, and stores configuration settings related to packages. Run the command shown in Listing 2.6 in the

    tools

    folder to create the

    package.json

    file for the example project:

    Listing 2.6: Initializing the project

    npm init -y

    The

    init

    command prompts the user for the values to put in the

    package.json

    file, but the

    -y

    argument selects the default values, which are suitable for most projects, including the example for the chapter. The

    init

    command creates a

    package.json

    file with the following contents:

    { name: tools, version: 1.0.0, description: , main: hello.js, scripts: { test: echo \"Error: no test specified\" && exit 1 }, keywords: [], author: , license: ISC }

    Most of the initial contents of the

    package.json

    file describe the project so that it can be published to a package registry, which is why there are settings for version numbers and licenses. Additional settings will be added to the file in later sections, and you can see the complete list of supported settings at https://docs.npmjs.com/cli/v10/configuring-npm/package-json.

    Managing packages

    The headline

    npm

    feature is the management of the packages used in a project. This may not seem like a big deal, but one compelling aspect of Node.js development is the immense library of open-source packages, which are available in a public registry (npmjs.com).

    npm

    provides access to the registry, takes care of downloading and installing packages, and manages dependencies between packages to avoid conflicts.

    Packages are added to the project with the

    npm install

    command. Run the command shown in Listing 2.7 in the

    tools

    folder to add a package to the example project:

    Listing 2.7: Adding a package

    npm install [email protected]

    The

    npm install

    command adds a package to the project and the argument specifies the name of the package (

    bootstrap

    , in this case), followed by the

    @

    character, followed by a version number. You can omit the

    @

    character and the version number, in which case, the latest version will be installed, but it is good practice to be specific when installing a package.

    The command in Listing 2.7 adds the excellent Bootstrap CSS/JavaScript package to the project. As part of this process,

    npm

    looks at the packages that Bootstrap depends on and installs them, too. Once the command has completed, you will see a new section in the

    package.json

    file:

    { name: tools, version: 1.0.0, description: , main: hello.js, scripts: { test: echo \"Error: no test specified\" && exit 1 }, keywords: [], author: , license: ISC,

    dependencies: {

    bootstrap: ^5.3.0

    }

    }

    The

    dependencies

    section is used to keep track of the packages used in the project. The version number in the

    packages.json

    file is prefixed with a caret (the

    ^

    character), which is part of the

    npm

    system for specifying ranges of version numbers, as described in Table 2.3:

    Table 2.3:

    npm

    version numbers

    Using exact version numbers

    When I specified

    [email protected]

    in Listing 2.7,

    npm

    gave itself some wiggle room by interpreting the version as

    ^5.3.0

    . The process of resolving dependencies and conflicts between packages is a complex process, which is made easier by broadening the range of acceptable versions. This approach relies on the idea that version

    5.4.0

    , say, will be compatible with version

    5.3.0

    and won’t contain breaking changes.

    If you can’t rely on packages to maintain compatibility, then you can configure

    npm

    to use exact version numbers by running this command:

    npm config set save-exact false

    npm

    will only use the versions that you specify, but the trade-off is that resolving dependencies and version conflicts between packages may be more difficult.

    Packages are stored in the

    node_modules

    folder, which is created automatically.

    npm

    creates a folder for each package that it downloads, and there can be a large number of folders as packages and their dependencies are resolved.

    To ensure that dependencies are resolved consistently,

    npm

    creates the

    package-lock.json

    file, which contains a complete list of the packages that have been installed, along with specific version numbers.

    Installing development packages

    The

    dependencies

    section of the

    package.json

    file is for the packages that the application needs to run. The

    npm

    command can also be used to add packages that are only required during development, such as compilers and debuggers. Run the command shown in Listing 2.8 in the

    tools

    folder to add development packages to the project:

    Listing 2.8: Adding a development package to the example project

    npm install --save-dev [email protected] [email protected]

    The

    --save-dev

    argument specifies a development package, and this command installs two packages that are required only during development. The

    typescript

    package includes the TypeScript compiler, which is used to compile TypeScript code into JavaScript that can be executed by Node.js. The

    tsc-watch

    package is a useful add-on that monitors TypeScript files for changes and automatically compiles and executes them.

    Examine the

    package.json

    file and you will see a new configuration section:

    { name: tools, version: 1.0.0, description: , main: hello.js, scripts: { test: echo \"Error: no test specified\" && exit 1, start: tsc message.ts }, keywords: [], author: , license: ISC, dependencies: { bootstrap: ^5.3.0 },

    devDependencies: {

    tsc-watch: "

    ^6.0.4",

    typescript: ^5.2.2

    }

    }

    The

    devDependencies

    section keeps track of the development packages, which don’t need to be included when the application is prepared for deployment. The new section contains entries for the packages specified by the command in Listing 2.8.

    Choosing packages and tools

    JavaScript benefits from a broad and dynamic ecosystem of open-source packages that solve just about any problem you might encounter. There is so much choice that it can be difficult to decide which packages to use, especially since there is a constant flow of online articles claiming that a particular new package is a hot way to build applications.

    The sad fact is most projects die from a lack of support. Someone, somewhere, becomes frustrated with the way that a particular package works and decides to write their own replacement. They realize that other people may benefit and altruistically decide to publish their code for anyone to use. Most of the time, that’s the end of the story, either because not many other people encounter the same frustrations or because the new package solves the problem in a way that doesn’t suit other projects.

    In many ways, that’s the best outcome – at least for the original developer – because as soon as a package starts to get users, the developer will start to get demands for fixes, features, and general support. The idea of open-source packages is that everyone pitches in, but that often doesn’t happen. The burdens on the package developer can be substantial, user demands can be endless and aggressive, and the amount of – unpaid – work can get out of hand. Many packages that start to become popular are abandoned at this point because the original developer can’t cope with the maintenance and no one pitches in to help.

    A small number of packages make it past this point. The original developer successfully enlists help in fixing problems and writing new features and puts the package onto a project-like footing. The original developer may move on to other projects, but the package becomes important enough that someone else is willing to take on the task and the project continues. At this point, the package matures, can be widely used, and almost always becomes the unfashionable approach that attracts the ire of all those online articles.

    My advice is to choose packages that suit the type of project you are working on. For mainstream commercial development, I recommend using packages that have made it past these hurdles and become well-established and well-maintained. These are the packages that have high weekly download numbers (which you can see on

    npm.js

    ), which are updated regularly, and have an engaged team that responds to issues and queries. These are the packages that will continue to be supported throughout the life of your project, allowing you to deliver your features on a solid platform. It is this type of package that I have used throughout this book.

    For hobby and experimental projects, I recommend using the less well-established packages. These won’t be as well-supported and you will encounter more problems and do more work to get everything working, but you will learn more, and you may have more fun.

    Regardless of how you choose packages, remember that you are benefiting from the altruism of others. If you can, then contribute to the packages you use. Just about every package has a list of bugs waiting to be fixed, which is a good way to get involved. If you don’t feel confident contributing code, then consider making a financial contribution. Many projects accept donations, and even the largest and most widely used packages are managed by foundations that welcome individual and corporate supporters.

    Listing packages

    You may only rely on a small number of packages in a project but each of those packages has dependencies and it is easy to end up with hundreds of small packages in a project, each of which contributes a small amount of functionality. To see the set of packages that have been added to the project, run the command shown in Listing 2.9 in the

    tools

    folder:

    Listing 2.9: Listing the installed packages

    npm list

    The output corresponds to the

    npm install

    commands used in earlier sections of this chapter, although you may see slightly different version numbers:

    +-- [email protected] +-- [email protected] `-- [email protected]

    Behind the scenes,

    npm

    has inspected these packages to discover their dependencies and installed those packages as well, which can be seen by running the command shown in Listing 2.10 in the

    tools

    folder:

    Listing 2.10: Listing packages and dependencies

    npm list --all

    The

    --all

    argument tells

    npm

    to list dependencies as well and produces output similar to the following, although you may see different details:

    +-- [email protected] +-- [email protected] | +-- [email protected] | | +-- [email protected] | | +-- [email protected] | | | `-- [email protected] | | `-- [email protected] | | `-- [email protected] | +-- [email protected] | +-- [email protected] | | `-- [email protected] | | +-- [email protected] | | +-- [email protected] | | +-- [email protected] | | +-- [email protected] | | | `-- [email protected] deduped | | +-- [email protected] | | | `-- [email protected] deduped | | +-- [email protected] | | | `-- [email protected] deduped | | `-- [email protected] | +-- [email protected] | `-- [email protected] deduped `-- [email protected]

    You may see small differences when you run this command. Most projects rely on a deep tree of packages, and

    npm

    takes care of resolving the dependencies for each of them and automatically downloading all the packages that are required.

    Checking for package security vulnerabilities

    The large number of JavaScript packages in a project makes it difficult to know exactly which packages you are using and whether those packages may have reported security vulnerabilities.

    To address this issue, package repositories maintain a list of known problems. As

    npm

    resolves package dependencies, it checks all of the packages that it is installing against the vulnerabilities list and emits a warning if it finds any problems. As an example, here is a command that installs a package whose dependencies contain a vulnerability:

    npm install --save-dev [email protected]

    This command may not have the same effect by the time this book is published because of the dynamic nature of JavaScript package dependencies, but when I ran this command, I received the following response:

    added 32 packages, and audited 54 packages in 3s 5 packages are looking for funding run `npm fund` for details

    3 moderate severity vulnerabilities

    npm

    has identified three security issues in the packages that have been installed. For more details, I ran this command:

    npm audit

    The

    npm audit

    command reports on potential problems. In this case, there is an issue with versions 7.0.0 to 7.5.1 with a package named

    semver

    :

    # npm audit report semver 7.0.0 - 7.5.1 Severity: moderate semver vulnerable to Regular Expression Denial of Service - https://github.com/advisories/GHSA-c2qf-rxjj-qqgw fix available via `npm audit fix --force` Will install [email protected], which is a breaking change node_modules/simple-update-notifier/node_modules/semver simple-update-notifier 1.0.7 - 1.1.0 Depends on vulnerable versions of semver node_modules/simple-update-notifier nodemon 2.0.19 - 2.0.22 Depends on vulnerable versions of simple-update-notifier node_modules/nodemon 3 moderate severity vulnerabilities

    The output provides a URL where details can be found and the suggestion that installing a later version of the top-level package – the one added by the

    npm install

    command – would fix the problem, albeit by introducing a breaking change that may stop existing code from working.

    There is an

    npm audit fix

    command that attempts to move to fixed versions of packages but that can cause problems with deeply nested dependencies and should be used with caution.

    For the packages used in this book, you should use the versions I have specified, even if there are warnings about security vulnerabilities, to ensure the examples work as expected. For real projects, you should assess each reported vulnerability and figure out whether moving to a patched package is possible without breaking code. It won’t always be possible to move away from all vulnerable packages without making corresponding changes in the project, and only you can decide what is sensible for your projects.

    To be clear, I am not advising you to ignore security warnings. I am saying that not all warnings are for problems that are likely to occur in all projects and there will be times when you might decide to stick with a vulnerable package because the risk to your project is low and the amount of work required to upgrade a package is substantial. You might also form the view that problems with developer packages are less of a risk because those packages are not included when the project is deployed.

    Executing packages

    Some packages include shell scripts that can be used to execute the package features, and these are installed in the

    node_modules/.bin

    folder. The package added in Listing 2.10, for example, includes a

    tsc

    script, which starts the TypeScript compiler. Add a file named

    message.ts

    to the

    tools

    folder, with the content shown in Listing 2.11. (The

    ts

    file extension denotes a TypeScript file.)

    Listing 2.11: The contents of the message.ts file in the tools folder

    function writeMessage(msg: string) { console.log(`Message: ${msg}`); } writeMessage(This is the message);

    TypeScript code has to be compiled into pure JavaScript before it can be executed by Node.js. I describe this process in more detail in Chapter 3, but for this chapter, it is enough to know that I need to use the

    tsc

    command provided by the package added to the project in Listing 2.8.

    The first step is to add the folder that contains the scripts to the path used to search for commands. Execute the command shown in Listing 2.12 if you are using PowerShell, which is what I use for development on Windows machines:

    Listing 2.12: Setting the path in powershell

    $env:path += ';.\node_modules\.bin'

    Listing 2.13 shows the equivalent command for the Bourne shell, which is commonly encountered on Linux machines:

    Listing 2.13: Setting the path in the bourne shell

    PATH=$PATH:./node_modules/.bin/

    Packages that provide shell scripts generally support a range of command shells. For its compiler, the

    typescript

    package adds three files to the

    node_modules/.bin

    folder:

    tsc

    (which supports the Bourne shell),

    tsc.ps1

    (which supports PowerShell), and

    tsc.cmd

    (which supports the older Windows Command Prompt).

    These are not the only script files added to the

    .bin

    folder. The

    typescript

    package also adds scripts for the

    tsserver

    command, which is used to integrate TypeScript into development tools, such as editors, but which is not required for this book. Entries are added by other packages as

    npm

    installs packages and resolves dependencies.

    Run the command shown in Listing 2.14 in the

    tools

    folder to run the compiler:

    Listing 2.14: Running a package command

    tsc message.ts

    The command won’t produce any messages but it does create a file named

    message.js

    in the

    tools

    folder, with the following content:

    ... function writeMessage(msg) { console.log(Message: .concat(msg)); } writeMessage(This is the message); ...

    Run the command shown in Listing 2.15 in the

    tools

    folder to execute the compiled JavaScript code using Node.js:

    Listing 2.15: Executing JavaScript code

    node message.js

    The Node.js runtime executes the code in the file created by the TypeScript compiler, producing the following output:

    Message: This is the message

    Using the npx command

    Not all packages install scripts, and another way to execute package features is to use the

    npx

    command. Each package added to the

    node_modules

    folder has its own

    package.json

    file. In addition to keeping track of the package’s dependencies, the

    package.json

    file defines a

    bin

    section that defines the commands that

    npx

    can execute. For the package added in Listing 2.8, the

    package.json

    file can be found in the

    node_modules/typescript

    folder and it contains this

    bin

    section:

    ... bin: { tsc: ./bin/tsc, tsserver: ./bin/tsserver }, ...

    The entries in the

    bin

    section define a command and a JavaScript file that will be executed by that command. The

    typescript

    package defines

    bin

    entries for

    tsc

    and

    tsserver

    commands, which correspond to the shell scripts used in the previous section. Run the command shown in Listing 2.16 in the

    tools

    folder to execute the TypeScript compiler using

    npx

    :

    Listing 2.16: Executing the TypeScript compiler

    npx tsc message.ts

    This command has the same effect as the one in Listing 2.14. When multiple packages define commands with the same name, the

    --package

    argument can be used, as shown in Listing 2.17:

    Listing 2.17: Specifying a package

    npx --package=typescript tsc message.ts

    If the package that contains the command isn’t installed, then the

    npx

    command will download the package into a cache folder and then execute the command.

    Using script commands

    npm

    supports a set of commands that are customized by adding entries to the

    scripts

    section of the

    package.json

    file. This can feel a little odd at first, but it is a powerful way to use the features provided by JavaScript packages concisely and consistently.

    npm

    supports the following basic commands:

    start

    stop

    restart

    test

    Projects won’t always need every command, and there are no firm rules for how these commands can be used, but the convention is to use the

    start

    command to start the development tools and use the

    test

    command to run unit tests, which I describe in Chapter 8.

    Listing 2.18 adds an entry to the

    scripts

    section:

    Listing 2.18: Configuring a command in the package.Json file in the tools folder

    { name: tools, version: 1.0.0, description: , main: hello.js, scripts: { test: echo \"Error: no test specified\" && exit 1,

    start

    : tsc-watch message.ts --onSuccess \"node message.js\"

    }, keywords: [], author: , license: ISC, dependencies: { bootstrap: ^5.3.0 }, devDependencies: { tsc-watch: ^6.0.4, typescript: ^5.2.2 } }

    Each entry in the

    scripts

    section consists of a command name and an associated action. The action associated with the

    start

    command in Listing 2.18 runs the

    tsc-watch

    command, which is a wrapper around the TypeScript compiler that watches TypeScript files for changes and can be configured to execute a command when compilation is successful. (The

    test

    command was added automatically when the

    package.json

    file was created and just prints out an error message.)

    I could run the

    tsc-watch

    command directly from the command line, either using the shell scripts the package added to the

    node_modules/.bin

    folder or with the

    npx

    command, but as commands get more complex, it becomes more difficult to remember the syntax and enter them correctly. The new entry in the

    package.json

    file lets me define the command once and then always invoke it consistently. Run the command shown in Listing 2.19 in the

    tools

    folder:

    Listing 2.19: Running a script command

    npm start

    The

    npm start

    command tells

    npm

    to perform the

    start

    action defined in the

    package.json

    file, producing the following output:

    09:19:15 - Starting compilation in watch mode... 09:19:16 - Found 0 errors. Watching for file changes. Message: This is the message

    Listing 2.20 makes a small change to the TypeScript file:

    Listing 2.20: Making a change in the message.ts file in the tools folder

    function writeMessage(msg: string) { console.log(`Message: ${msg}`); }

    writeMessage(This is the new message);

    When you save the altered file, the change is detected, the TypeScript file is compiled, and Node.js is used to execute the JavaScript, producing the following output:

    ... Message: This is the new message ...

    Most web application project development depends on tools that run continuously, monitoring files for changes, and this is a pattern that I will follow throughout this book. Use Control+C to stop the command once you have seen the output.

    Defining custom commands

    In addition to the built-in commands,

    npm

    supports custom commands as well, as shown in Listing 2.21:

    Listing 2.21: Defining a custom script command in the package.json file in the tools folder

    ... scripts: { test: echo \"Error: no test specified\" && exit 1, start: tsc-watch message.ts --onSuccess \"node message.js\",

    go: tsc message.ts && node message.js

    }, ...

    The name of the new command is

    go

    and it compiles the

    message.ts

    TypeScript file and then uses Node.js to execute the compiled JavaScript.

    Tip

    Commands separated by

    &&

    are executed sequentially. Commands separated by a single

    &

    are executed in parallel.

    Custom commands are executed with

    npm run

    , as shown in Listing 2.22:

    Listing 2.22: Executing a custom script command

    npm run go

    The name of the custom command follows

    npm run

    , so that

    npm run go

    executes the custom

    go

    command, producing the following output:

    Message: This is the new message

    Summary

    In this chapter, I explained the simple setup process to prepare for this book and introduced the core Node.js tools:

    Node.js development requires the Node.js installer, the Git version control system, and a JavaScript/TypeScript code editor, such as Visual Studio Code.

    JavaScript files are executed with the

    node

    command.

    Much of the functionality provided by Node.js is presented through the API it provides, which is the topic of this book.

    The node package manager (npm) is used to download JavaScript packages, execute commands, run development tools, and start unit tests.

    In the next chapter, I will provide a primer that describes the essential JavaScript and TypeScript features that are required to follow the examples in this book.

    3

    JavaScript and TypeScript Primer

    Developers come to the world of web app development via many paths and are not always grounded in the basic technologies that web apps rely on. In this chapter, I introduce the basic features of JavaScript and TypeScript. This is not a comprehensive guide to either language, but it addresses the essentials, and it will give you the knowledge you need to get started.

    Preparing for this chapter

    To prepare for this chapter, create a folder named

    primer

    in a convenient location. Navigate to the

    primer

    folder and run the command shown in Listing 3.1.

    Listing 3.1: Preparing the project folder

    npm init --yes

    Run the command shown in Listing 3.2 in the

    primer

    folder to install the development packages that are used in this chapter.

    Listing 3.2: Installing the development package

    npm install [email protected] npm install [email protected] npm install [email protected] npm install @tsconfig/[email protected] npm install @types/[email protected]

    The

    nodemon

    package will be used at the start of the chapter to monitor and execute JavaScript files. The

    tsc-watc1h

    package does the same thing for TypeScript files, and the

    typescript

    package contains the TypeScript compiler. The

    @tsconfig/node20

    package contains configuration settings for the TypeScript compiler for use in Node.js projects.

    Replace the

    scripts

    section in the

    package.json

    file as shown in Listing 3.3, which will make it easier to use the development packages.

    Listing 3.3: Replacing the scripts section in the package.json file in the primer folder

    { name: primer, version: 1.0.0, description: , main: index.js, scripts: {

    use_js: nodemon,

    "

    use_ts: tsc-watch --onSuccess \node index.js\"

    }, keywords: [], author: , license: ISC, dependencies: { @tsconfig/node20: ^20.1.4, @types/node: ^20.6.1, nodemon: ^2.0.20, tsc-watch: ^6.0.4, typescript: ^5.2.2 } }

    Add a file named

    tsconfig.json

    to the

    primer

    folder with the content shown in Listing 3.4, which creates a basic configuration for the TypeScript compiler suitable for a Node.js project.

    Listing 3.4: The contents of the tsconfig.json file in the primer folder

    { extends: @tsconfig/node20/tsconfig.json }

    Add a file named

    index.js

    to the

    primer

    folder with the content shown in Listing 3.5.

    Listing 3.5: The contents of the index.js file in the primer folder

    console.log(Hello, World);

    Run the command shown in Listing 3.6 in the

    primer

    folder to start monitoring and executing JavaScript

    Enjoying the preview?
    Page 1 of 1