Good day, friends!
I continue to post a translation of this Node.js tutorial .
Other parts:
Part 1
Part 2
Part 3
Part 4
Getting user entered data in Node.js
How do I make a Node.js program interactive?
To do this, version 7 of Node.js introduces the readline module : it is used to get data from a stream for reading, such as
process.stdin
- the command line during the execution of a Node.js program.
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
})
readline.question(`What is your name?`, name => {
console.log(`Hi ${name}!`)
readline.close()
})
This code asks for the username, after the user has typed and clicked
enter
, a greeting is displayed.
The method
question()
prints the first parameter (question) to the console and waits for the user's response. When pressed enter
, the callback function is executed.
In this callback, we close the interface
readline
.
readline
contains other methods, which you can read about in the documentation.
If you need to prompt for a password, it is best not to return it explicitly, but rather use symbols
*
.
One way to do this is to use the readline-sync package , which is simple to understand and easy to configure.
A more complete and abstract solution is provided by the Inquirer.js package .
We install it with the help
npm install inquirer
and use it as follows:
const inquirer = require('inquirer')
const questions = [
{
type: 'input',
name: 'name',
message: `What's your name?`
}
]
inquirer.prompt(questions).then(answers => {
console.log(`Hi ${answers['name']}!`)
})
Inquirer.js allows you to do a lot of cool things, like suggesting multiple choices, providing radio buttons, asking for confirmation, etc.
It is better known as an alternative to built-in solutions, but if you plan to take user experience to the next level, Inquirer.js is the best solution.
Extending Node.js File Functionality Using Export
Node.js has a built-in modular system.
The Node.js file can import functionality from other Node.js files.
When you want to import something you use
const library = require('./library')
to import functionality exported in a file
library.js
located in the current directory.
In this file, functionality must be exported before it can be imported in another file.
Any other object or variable defined in a file is by default private (private) and cannot be used in other files.
This is what the interface
module.exports
provided by the modular system allows us to do .
When you assign an object or function as a new property of the object
exports
, you export them, and then they can be imported elsewhere in the application or in another application.
This can be done in two ways.
The first way is to assign a value
module.exports
, which is the default object provided by the modular system. This method allows you to export only this object:
const car = {
brand: 'Ford',
model: 'Fiesta'
}
module.exports = car
//
const car = require('./car')
The second way is to add the exported object as a property of the object
exports
. This method allows you to export many objects, functions or data:
const car = {
brand: 'Ford',
model: 'Fiesta'
}
exports.car = car
or so
exports.car = {
brand: 'Ford',
model: 'Fiesta'
}
To use this object in another file, you must make a link to the import:
const items = require('./items')
items.car
or
const car = require('./items').car
What is the difference between
module.exports
and exports
?
The first one exports the referenced object, the second one a property of the object.
An introduction to the npm package manager
Introduction to npm
npm
Is the default Node.js package manager.
As of January 2017, npm had over 350,000 packages, making it the largest repository of code in a single programming language on Earth, and you can rest assured that there are packages to do just about anything.
It all started with downloading and managing dependencies in Node.js, but soon this tool began to be actively used in the development of the client side of applications.
npm
does several things.
An alternative to npm is yarn .
Loading
npm
manages the loading of project dependencies.
If a file exists in the project,
package.json
launching npm install
will install everything that the project requires into the directory node_modules
that is created if it does not exist.
A specific package can be installed using
npm install <package-name>
.
Often the installation of a package is accompanied by flags:
- --save - install the package and add an entry about it to the dependencies section of the file
package.json
- --save-dev - install the package and add an entry about it to the devDependencies section of the file
package.json
The main difference is that devDependencies is used for development purposes, for example, for testing, and dependencies are used in production (when building a project).
Updating packages
Updating is easy with
npm update
.
npm
will check all packages for new versions that meet the established restrictions.
You can also update a specific package:
npm update <package-name>
.
Versioning
In addition to standard downloads, npm supports versioning, so you can specify any specific version of a package, or request a newer or older version.
You will often find that one library is only compatible with a certain (major) version of another library.
And also with the bugs of the latest releases that have not been fixed for a long time.
Versioning also aids team development because each team member knows which version to use before updating the file
package.json
.
In all these cases, versioning helps; in this regard,
npm
it follows accepted standards.
Executing tasks
package.json
supports a format for specifying commands to be executed in the terminal with npm run <task-name>
.
For example:
{
"scripts": {
"start-dev": "node lib/server-development",
"start": "node lib/server-production"
},
}
It is common practice to use this capability to run Webpack:
{
"scripts": {
"watch": "webpack --watch --progress --colors --config webpack.conf.js",
"dev": "webpack --progress --colors --config webpack.conf.js",
"prod": "NODE_ENV=production webpack -p --config webpack.conf.js"
},
}
This allows, instead of a set of long commands that are easy to forget or which are easy to make mistakes, to do this:
npm run watch
npm run dev
npm run prod
Where does npm install packages?
When installing packages using,
npm
you can choose between two types of installation:
- local
- global
By default, when you enter
npm install
for example:
npm install lodash
the package is installed to a folder
node_modules
in the current directory.
After installation
npm
adds an o record lodash
to the dependencies
file section package.json
in the current directory.
For a global installation, use the flag
-g
:
npm install -g lodash
In a global installation, the package is installed not in the current directory, but in the global one.
But where exactly?
To determine this, you need to run the command
npm root -g
.
On macOS or Linux, this directory can be
/usr/local/lib/node_modules
. On Windows - C:\Users\YOU\AppData\Roaming\npm\node_modules
. This directory may be different
when used
nvm
for Node.js versioning.
How do I use installed packages?
How to use a
node_modules
package installed in a folder or globally.
Let's say you installed a
lodash
popular JavaScript helper library with npm install lodash
.
This command will install
lodash
to a local directory node_modules
.
To use the program, you need to import the package using
require
:
const _ = require('lodash')
What if the package is executable (file)?
In this case, the executable file will be placed in the directory
node_modules/.bin/
.
This can be easily demonstrated using the cowsay library .
This package provides a command line program, when executed, the cow (and other animals) "speaks" something.
When installing a package via
npm install cowsay
, the package itself and several of its dependencies will be installed:
The folder
.bin
is hidden and contains symbolic links to the binary data cowsay:
How to execute them?
You can of course type
./node_modules/.bin/cowsay
and it should work, but npx included with npm (since 5.2) is the best option. You just donpx cowsay
and npx will locate the file automatically: The
cow says "take me out of here."
Package.json manual
When working with JavaScript, when interacting with a JavaScript project, Node.js, or the front-end of an application, you will likely come across a
package.json
.
What it is? What should you know about him? And what can you do with it?
package.json
Is a kind of project manifesto. He can do many things that are completely unrelated to each other. For example, it can be the main file for the settings of the tools used. It also stores the names and versions of all installed packages (this information is used npm
and yarn
).
File structure
Here's an example
package.json
:
{}
As you can see, it is empty. There
package.json
are no requirements for the content . The only requirement is its format (JSON), otherwise programs will not be able to access it.
If you're creating a Node.js package that you plan to distribute through
npm
, the situation changes dramatically and you need to add properties to help other people use the package. We'll look at this later.
Here's another example
package.json
:
"name": "test-project"
Here we have defined the name of the package or application located in the same directory as
package.json
.
Here's an example of a more complex
package.json
one borrowed from a Vue.js application:
{
"name": "test-project",
"version": "1.0.0",
"description": "A Vue.js project",
"main": "src/main.js",
"private": true,
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit",
"build": "node build/build.js"
},
"dependencies": {
"vue": "^2.5.2"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1",
"babel-eslint": "^8.2.1",
"babel-helper-vue-jsx-merge-props": "^2.0.3",
"babel-jest": "^21.0.2",
"babel-loader": "^7.1.1",
"babel-plugin-dynamic-import-node": "^1.2.0",
"babel-plugin-syntax-jsx": "^6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
"babel-plugin-transform-runtime": "^6.22.0",
"babel-plugin-transform-vue-jsx": "^3.5.0",
"babel-preset-env": "^1.3.2",
"babel-preset-stage-2": "^6.22.0",
"chalk": "^2.0.1",
"copy-webpack-plugin": "^4.0.1",
"css-loader": "^0.28.0",
"eslint": "^4.15.0",
"eslint-config-airbnb-base": "^11.3.0",
"eslint-friendly-formatter": "^3.0.0",
"eslint-import-resolver-webpack": "^0.8.3",
"eslint-loader": "^1.7.1",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-vue": "^4.0.0",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^1.1.4",
"friendly-errors-webpack-plugin": "^1.6.1",
"html-webpack-plugin": "^2.30.1",
"jest": "^22.0.4",
"jest-serializer-vue": "^0.3.0",
"node-notifier": "^5.1.2",
"optimize-css-assets-webpack-plugin": "^3.2.0",
"ora": "^1.2.0",
"portfinder": "^1.0.13",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"postcss-url": "^7.2.1",
"rimraf": "^2.6.0",
"semver": "^5.3.0",
"shelljs": "^0.7.6",
"uglifyjs-webpack-plugin": "^1.1.1",
"url-loader": "^0.5.8",
"vue-jest": "^1.0.2",
"vue-loader": "^13.3.0",
"vue-style-loader": "^3.0.1",
"vue-template-compiler": "^2.5.2",
"webpack": "^3.6.0",
"webpack-bundle-analyzer": "^2.9.0",
"webpack-dev-server": "^2.9.1",
"webpack-merge": "^4.1.0"
},
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
},
"browserslist": ["> 1%", "last 2 versions", "not ie <= 8"]
}
There's a lot here:
name
- application / package nameversion
- application / package versiondescription
- a short description of the application / packagemain
- main file (entry point) of the applicationprivate
- the valuetrue
prevents accidental publication of the application tonpm
scripts
- a set of scripts (commands) that can be run (executed)dependencies
- project dependenciesdevDependencies
- project dependencies used only during developmentengines
- versions the application / package is running onbrowserlist
- supported browsers (and their versions)
All of these properties are used
npm
.
Properties
In this section, we will talk about some of the properties you can use. We'll use the term "package", but most of what has been said is also true for applications.
Most of the properties are needed to publish the package to
npm
, some to interact with the package.
Name (name)
Specifies the name of the package.
For example:
"name": "test-project"
The name should not exceed 214 characters, should not contain spaces, and may only consist of lowercase letters (lowercase), hyphens (-), and underscore (_).
This is because a
npm
URL is assigned to the package when it is published based on its name.
If the package is published on GitHub, it is good practice to link to the repository.
Author
Identifies the author of the package.
For example:
{
"author": "Joe <joe@whatever.com> (https://whatever.com)"
}
or like this:
{
"author": {
"name": "Joe",
"email": "joe@whatever.com",
"url": "https://whatever.com"
}
}
Collaborators
Specifies one or more contributors to the package. This property is an array of strings.
For example:
{
"contributors": ["Joe <joe@whatever.com> (https://whatever.com)"]
}
or like this:
{
"contributors": [
{
"name": "Joe",
"email": "joe@whatever.com",
"url": "https://whatever.com"
}
]
}
Mistakes
Defines a link to an issue tracker, usually an issue tracker on GitHub.
For example:
{
"bugs": "https://github.com/whatever/package/issues"
}
Homepage
Defines the address of the home page.
For example:
{
"homepage": "https://whatever.com/package"
}
Version
Determines the current version of the package.
For example:
"version": "1.0.0"
This property follows the semantic versioning standard. This means that it must always consist of three numbers separated by dots
x.x.x
.
The first number is the major version, the second is the minor version, the third is the patch.
Each number has a specific meaning: an update to fix bugs is a patch, a release of backward compatible changes is a minor release, and a major release may mean changes that are incompatible with the previous version.
License
Specifies the license for the package.
For example:
"license": "MIT"
Keywords
This property is an array of keywords associated with the package.
For example:
"keywords": [
"email",
"machine learning",
"ai"
]
They help people find packages.
Description
Defines a short description for the package.
For example:
"description": "A package to work with strings"
When publishing a package to a
npm
given property, it helps people understand what it is for.
Repository
Determines where the source code for the package is located.
For example:
"repository": "github:whatever/testing",
Pay attention to the prefix
github
. There are other similar services:
"repository": "gitlab:whatever/testing",
"repository": "bitbucket:whatever/testing",
You can also define a version control system:
"repository": {
"type": "git",
"url": "https://github.com/whatever/testing.git"
}
You can specify multiple version control systems:
"repository": {
"type": "svn",
"url": "..."
}
main
Defines the main file (entry point) for the package.
When importing a package into an application, it is in this file that the application will look for exported modules.
For example:
"main": "src/main.js"
private
Setting this property to a value
true
prevents the package from being accidentally published to npm
.
For example:
"private": true
scripts
Defines a list of commands (scripts) that can be executed (run).
For example:
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"start": "npm run dev",
"unit": "jest --config test/unit/jest.conf.js --coverage",
"test": "npm run unit",
"lint": "eslint --ext .js,.vue src test/unit",
"build": "node build/build.js"
}
These scripts are command line applications. You can run them with
npm run XXXX
or yarn run XXXX
, where XXXX
is the command name. For example: npm run dev
.
You can use any name as the command name, the script will do whatever you specify in it.
Dependencies
Defines a list of package dependencies.
When installing a package using npm or yarn:
npm install <PACKAGENAME>
yarn add <PACKAGENAME>
the record for this package will be automatically added to the property in question.
For example:
"dependencies": {
"vue": "^2.5.2"
}
devDependencies
Defines a list of dependencies for development purposes.
They differ from
dependencies
, since they are installed only on the developer's computer and do not go into production.
When installing a package using npm or yarn:
npm install --save-dev <PACKAGENAME>
yarn add --save-dev <PACKAGENAME>
the record about it is automatically added to the considered property.
For example:
"devDependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.22.1"
}
engines
Determines which versions of Node.js or other tools the package / application is running on.
For example:
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0",
"yarn": "^0.13.0"
}
browserlist
Defines a list of supported browsers (and their versions). This information is used by Babel, Autoprefixer and other tools to create polyfills and ensure compatibility with specified browsers.
For example:
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
This setting means that you want to support the two latest versions of all browsers that more than 1% of people use according to CanIUse statistics , with the exception of IE8 and older versions.
Special properties
package.json
can contain special properties for tools like Babel, ESLint, etc.
Each of these tools has its own properties, for example
eslintConfig
, babel
and so on. For details on special properties, see the corresponding documentation.
Package versions
In the examples above, you've probably noticed entries like this:
~3.0.0
, ^0.13.0
. What do they mean? And what other version specifiers can I use?
These specifiers are used to define update conditions.
The rules are as follows:
~
- write~0.13.0
means that only patch updates are allowed, i.e. release is0.13.1
valid, but release is0.14.0
not^
- write^0.13.0
means patch and minor updates are allowed*
- record*
means that any updates are allowed>
- any new versions are allowed>=
- similar or newer versions are allowed<=
- similar or older versions are acceptable<
- any old versions are allowed
Here are a couple more rules:
- no leading character - only the specified version is allowed
latest
- only the latest version is allowed
These characters can be combined in various ways, for example:
1.0.0 || >=1.1.0 <1.2.0
.
Thank you for attention.
To be continued…