作为 Write for DOnations 计划的一部分,作者选择了 Open Internet/Free Speech Fund 来接受捐赠。
介绍
在 Node.js 中,module 是可供外部应用程序使用的 JavaScript 函数和对象的集合。 将一段代码描述为一个模块,与其说是代码是什么,不如说是它的作用——任何 Node.js 文件或文件集合都可以被视为一个模块,如果它的功能和数据可供外部程序使用。
因为模块提供了可以在许多大型程序中重用的功能单元,它们使您能够创建松散耦合的应用程序,这些应用程序随复杂性而扩展,并为您与其他开发人员共享代码打开了大门。 能够编写导出有用函数和数据的模块将使您能够为更广泛的 Node.js 社区做出贡献——事实上,您在 npm 上使用的所有包都被捆绑并作为模块共享。 这使得创建模块成为 Node.js 开发人员的基本技能。
在本教程中,您将创建一个 Node.js 模块,该模块建议 Web 开发人员在他们的设计中应该使用什么颜色。 您将通过将颜色存储为数组并提供随机检索颜色的函数来开发模块。 之后,您将通过各种方式将模块导入 Node.js 应用程序。
先决条件
- 您需要在开发环境中安装 Node.js 和 npm。 本教程使用版本 10.17.0。 要在 macOS 或 Ubuntu 18.04 上安装它,请按照 如何在 macOS 上安装 Node.js 和创建本地开发环境中的步骤或 的 使用 PPA 部分安装如何在 Ubuntu 18.04 上安装 Node.js。 通过安装 Node.js,您还将安装 npm; 本教程使用版本 6.11.3。
- 您还应该熟悉
package.json
文件,并且使用 npm 命令的经验也会很有用。 要获得这种经验,请遵循 如何使用带有 npm 和 package.json 的 Node.js 模块,尤其是 步骤 1 — 创建 package.json 文件。 - 它还有助于熟悉 Node.js REPL(读取-评估-打印-循环)。 您将使用它来测试您的模块。 如果您需要这方面的更多信息,请阅读我们关于 如何使用 Node.js REPL 的指南。
第 1 步 — 创建模块
此步骤将指导您创建第一个 Node.js 模块。 您的模块将在一个数组中包含一组颜色,并提供一个随机获取颜色的函数。 您将使用 Node.js 内置的 exports
属性使函数和数组可用于外部程序。
首先,您将首先决定将在模块中存储哪些颜色数据。 每种颜色都是一个对象,其中包含一个人类可以轻松识别的 name
属性,以及一个包含 HTML 颜色代码的字符串的 code
属性。 HTML 颜色代码是六位十六进制数字,可让您更改网页上元素的颜色。 您可以通过阅读这篇 HTML 颜色代码和名称 文章了解有关 HTML 颜色代码的更多信息。
然后,您将决定要在模块中支持哪些颜色。 您的模块将包含一个名为 allColors
的数组,其中包含六种颜色。 您的模块还将包含一个名为 getRandomColor()
的函数,该函数将从您的数组中随机选择一种颜色并返回它。
在您的终端中,创建一个名为 colors
的新文件夹并进入其中:
mkdir colors cd colors
初始化 npm,以便其他程序可以在教程后面导入此模块:
npm init -y
您使用 -y
标志跳过了自定义 package.json
的常用提示。 如果这是您希望发布到 npm 的模块,您将使用相关数据回答所有这些提示,如 如何使用带有 npm 和 package.json 的 Node.js 模块 中所述。
在这种情况下,您的输出将是:
Output{ "name": "colors", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
现在,打开一个命令行文本编辑器,例如 nano
并创建一个新文件作为模块的入口点:
nano index.js
你的模块会做一些事情。 首先,您将定义一个 Color
class。 您的 Color
类将使用其名称和 HTML 代码进行实例化。 添加以下行以创建类:
~/colors/index.js
class Color { constructor(name, code) { this.name = name; this.code = code; } }
现在您已经有了 Color
的数据结构,将一些实例添加到您的模块中。 将以下突出显示的 array 写入您的文件:
~/colors/index.js
class Color { constructor(name, code) { this.name = name; this.code = code; } } const allColors = [ new Color('brightred', '#E74C3C'), new Color('soothingpurple', '#9B59B6'), new Color('skyblue', '#5DADE2'), new Color('leafygreen', '#48C9B0'), new Color('sunkissedyellow', '#F4D03F'), new Color('groovygray', '#D7DBDD'), ];
最后,输入一个 函数,它从您刚刚创建的 allColors
数组中随机选择一个项目:
~/colors/index.js
class Color { constructor(name, code) { this.name = name; this.code = code; } } const allColors = [ new Color('brightred', '#E74C3C'), new Color('soothingpurple', '#9B59B6'), new Color('skyblue', '#5DADE2'), new Color('leafygreen', '#48C9B0'), new Color('sunkissedyellow', '#F4D03F'), new Color('groovygray', '#D7DBDD'), ]; exports.getRandomColor = () => { return allColors[Math.floor(Math.random() * allColors.length)]; } exports.allColors = allColors;
exports
关键字引用了每个 Node.js 模块中可用的全局对象。 当其他 Node.js 模块导入模块时,存储在模块的 exports
对象中的所有函数和对象都会暴露出来。 例如,getRandomColor()
函数是直接在 exports
对象上创建的。 然后,您将 allColors
属性添加到 exports
对象,该对象引用之前在脚本中创建的局部常量 allColors
数组。
当其他模块导入此模块时,allColors
和 getRandomColor()
都将被暴露并可供使用。
保存并退出文件。
到目前为止,您已经创建了一个包含颜色数组和随机返回颜色的函数的模块。 您还导出了数组和函数,以便外部程序可以使用它们。 在下一步中,您将在其他应用程序中使用您的模块来演示 export
的效果。
第 2 步 — 使用 REPL 测试您的模块
在构建完整的应用程序之前,请花点时间确认您的模块正在运行。 在此步骤中,您将使用 REPL 加载 colors
模块。 在 REPL 中,您将调用 getRandomColor()
函数来查看它的行为是否符合您的预期。
在与 index.js
文件相同的文件夹中启动 Node.js REPL:
node
当 REPL 启动后,您将看到 >
提示。 这意味着您可以输入将立即评估的 JavaScript 代码。 如果您想了解更多相关信息,请按照我们的 指南使用 REPL。
首先,输入以下内容:
colors = require('./index');
在此命令中,require()
在其入口点加载 colors
模块。 当你按下 ENTER
你会得到:
Output{ getRandomColor: [Function], allColors: [ Color { name: 'brightred', code: '#E74C3C' }, Color { name: 'soothingpurple', code: '#9B59B6' }, Color { name: 'skyblue', code: '#5DADE2' }, Color { name: 'leafygreen', code: '#48C9B0' }, Color { name: 'sunkissedyellow', code: '#F4D03F' }, Color { name: 'groovygray', code: '#D7DBDD' } ] }
REPL 向我们展示了 colors
的值,它是从 index.js
文件导入的所有函数和对象。 当您使用 require
关键字时,Node.js 会返回模块的 exports
对象内的所有内容。
回想一下,您在 colors
模块中将 getRandomColor()
和 allColors
添加到 exports
中。 因此,当它们被导入时,您会在 REPL 中看到它们。
在提示符下,测试 getRandomColor()
功能:
colors.getRandomColor();
系统会提示您使用随机颜色:
OutputColor { name: 'groovygray', code: '#D7DBDD' }
由于索引是随机的,因此您的输出可能会有所不同。 现在您确认 colors
模块正在工作,退出 Node.js REPL:
.exit
这将使您返回到终端命令行。
您刚刚确认您的模块使用 REPL 可以按预期工作。 接下来,您将应用这些相同的概念并将模块加载到应用程序中,就像您在实际项目中所做的那样。
第 3 步 — 将本地模块保存为依赖项
在 REPL 中测试您的模块时,您使用 相对路径 导入它。 这意味着您使用了 index.js
文件相对于工作目录的位置来获取其内容。 虽然这可行,但通常通过名称导入模块是一种更好的编程体验,这样在更改上下文时导入不会中断。 在这一步中,您将使用 npm 的本地模块 install
功能安装 colors
模块。
在 colors
文件夹之外设置一个新的 Node.js 模块。 首先,转到上一个目录并创建一个新文件夹:
cd .. mkdir really-large-application
现在进入你的新项目:
cd really-large-application
与 colors
模块一样,使用 npm 初始化您的文件夹:
npm init -y
将生成以下 package.json
:
Output{ "name": "really-large-application", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
现在,安装您的 colors
模块并使用 --save
标志,以便将其记录在您的 package.json
文件中:
npm install --save ../colors
您刚刚在新项目中安装了 colors
模块。 打开package.json
文件可以看到新的本地依赖:
nano package.json
您会发现添加了以下突出显示的行:
~/really-large-application/package.json
{ "name": "really-large-application", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "colors": "file:../colors" } }
退出文件。
colors
模块已复制到您的 node_modules
目录。 使用以下命令验证它是否存在:
ls node_modules
这将给出以下输出:
Outputcolors
在这个新程序中使用您安装的本地模块。 重新打开您的文本编辑器并创建另一个 JavaScript 文件:
nano index.js
您的程序将首先导入 colors
模块。 然后它将使用模块提供的getRandomColor()
功能随机选择一种颜色。 最后,它将向控制台打印一条消息,告诉用户使用什么颜色。
在index.js
中输入以下代码:
~/really-large-application/index.js
const colors = require('colors'); const chosenColor = colors.getRandomColor(); console.log(`You should use ${chosenColor.name} on your website. It's HTML code is ${chosenColor.code}`);
保存并退出此文件。
您的应用程序现在将告诉用户网站组件的随机颜色选项。
使用以下命令运行此脚本:
node index.js
您的输出将类似于:
OutputYou should use leafygreen on your website. It's HTML code is #48C9B0
您现在已经成功安装了 colors
模块,并且可以像在项目中使用的任何其他 npm 包一样管理它。 但是,如果您向本地 colors
模块添加了更多颜色和功能,则必须在应用程序中运行 npm update
才能使用新选项。 在下一步中,您将以另一种方式使用本地模块 colors
,并在模块代码更改时自动更新。
第 4 步 - 链接本地模块
如果您的本地模块正在大量开发中,那么不断更新软件包可能会很乏味。 另一种方法是 link 模块。 链接模块可确保对模块的任何更新立即反映在使用它的应用程序中。
在此步骤中,您将 colors
模块链接到您的应用程序。 您还将修改 colors
模块并确认其最新更改在应用程序中有效,而无需重新安装或升级。
首先,卸载本地模块:
npm un colors
npm 通过使用 符号链接 (或符号链接)链接模块,这些链接是指向计算机中文件或目录的引用。 链接模块分两步完成:
- 创建到模块的 全局链接 。 npm 在全局
node_modules
目录和模块目录之间创建符号链接。 全局node_modules
目录是安装所有系统范围的 npm 包的位置(使用-g
标志安装的任何包)。 - 创建一个 本地链接 。 npm 在使用模块的本地项目和模块的全局链接之间创建符号链接。
首先,通过返回 colors
文件夹并使用 link
命令创建全局链接:
cd ../colors sudo npm link
完成后,您的 shell 将输出:
Output/usr/local/lib/node_modules/colors -> /home/sammy/colors
您刚刚在 node_modules
文件夹中创建了指向 colors
目录的符号链接。
返回really-large-application
文件夹并链接包:
cd ../really-large-application sudo npm link colors
您将收到类似于以下内容的输出:
Output/home/sammy/really-large-application/node_modules/colors -> /usr/local/lib/node_modules/colors -> /home/sammy/colors
注意:如果你想打字少一点,你可以用ln
代替link
。 例如,npm ln colors
的工作方式完全相同。
如输出所示,您刚刚创建了一个从 really-large-application
的本地 node_modules
目录到全局 node_modules
中的 colors
符号链接的符号链接,它指向colors
模块的实际目录。
链接过程完成。 运行您的文件以确保它仍然有效:
node index.js
您的输出将类似于:
OutputYou should use sunkissedyellow on your website. It's HTML code is #F4D03F
您的程序功能完好无损。 接下来,测试是否立即应用更新。 在您的文本编辑器中,重新打开 colors
模块中的 index.js
文件:
cd ../colors nano index.js
现在添加一个函数来选择存在的最佳蓝色阴影。 它不接受任何参数,并且总是返回 allColors
数组的第三项。 将这些行添加到文件的末尾:
~/colors/index.js
class Color { constructor(name, code) { this.name = name; this.code = code; } } const allColors = [ new Color('brightred', '#E74C3C'), new Color('soothingpurple', '#9B59B6'), new Color('skyblue', '#5DADE2'), new Color('leafygreen', '#48C9B0'), new Color('sunkissedyellow', '#F4D03F'), new Color('groovygray', '#D7DBDD'), ]; exports.getRandomColor = () => { return allColors[Math.floor(Math.random() * allColors.length)]; } exports.allColors = allColors; exports.getBlue = () => { return allColors[2]; }
保存并退出文件,然后重新打开really-large-application
文件夹下的index.js
文件:
cd ../really-large-application nano index.js
调用新创建的 getBlue()
函数,并打印带有颜色属性的句子。 将这些语句添加到文件末尾:
~/really-large-application/index.js
const colors = require('colors'); const chosenColor = colors.getRandomColor(); console.log(`You should use ${chosenColor.name} on your website. It's HTML code is ${chosenColor.code}`); const favoriteColor = colors.getBlue(); console.log(`My favorite color is ${favoriteColor.name}/${favoriteColor.code}, btw`);
保存并退出文件。
代码现在使用新创建的 getBlue()
函数。 像以前一样执行文件:
node index.js
你会得到如下输出:
OutputYou should use brightred on your website. It's HTML code is #E74C3C My favorite color is skyblue/#5DADE2, btw
您的脚本能够使用 colors
模块中的最新功能,而无需运行 npm update
。 这将使在开发中更改此应用程序变得更加容易。
当您编写更大、更复杂的应用程序时,请考虑如何将相关代码分组到模块中,以及您希望如何设置这些模块。 如果你的模块只被一个程序使用,它可以留在同一个项目中并被相对路径引用。 如果您的模块稍后将单独共享或存在于与您现在正在处理的项目非常不同的位置,则安装或链接可能更可行。 活跃开发中的模块也受益于链接的自动更新。 如果模块未在积极开发中,使用 npm install
可能是更简单的选择。
结论
在本教程中,您了解到 Node.js 模块是一个 JavaScript 文件,其中包含其他程序可以使用的函数和对象。 然后,您创建了一个模块并将您的函数和对象附加到全局 exports
对象,以使它们可用于外部程序。 最后,您将该模块导入到程序中,演示了模块如何组合成更大的应用程序。
既然您知道如何创建模块,请考虑您要编写的程序类型并将其分解为各种组件,将每组独特的活动和数据保存在它们自己的模块中。 您编写模块的练习越多,您在学习过程中编写高质量 Node.js 程序的能力就越好。 要查看使用模块的 Node.js 应用程序示例,请参阅我们的 如何在 Ubuntu 18.04 上设置用于生产的 Node.js 应用程序教程。