我希望我的文件始终位于项目的根目录中,而不是相对于当前模块。
例如,如果您查看https://github.com/visionmedia/express/blob/2820f2227de0229c5d7f28009aa432f9f3a7b5f9/examples/downloads/app.js第6行,您会看到
express = require('../../')
那是非常糟糕的IMO。想象一下,我想把我的所有例子都放在根目录上,只有一个级别。这是不可能的,因为我必须在每个示例中更新超过30个示例和多次。对此:
express = require('../')
我的解决方案是基于root有一个特例:如果一个字符串以$开头,那么它相对于项目的根文件夹。
感谢任何帮助,谢谢
现在我正在使用require.js,它允许您以一种方式编写,并在客户端和服务器上运行。 Require.js还允许您创建自定义路径.-«
现在我转到webpack + gulp并使用enhanced-require来处理服务器端的模块。请参阅此处的基本原理:http://hackhat.com/p/110/module-loader-webpack-vs-requirejs-vs-browserify/
答案 0 :(得分:149)
那怎么样:
var myModule = require.main.require('./path/to/module');
它要求文件好像是从主js文件中需要的,所以只要你的主要js文件位于项目的根目录下它就能很好地工作......而且这是我所欣赏的东西。
答案 1 :(得分:120)
Browserify Handbook中有一个非常有趣的部分:
避免../../../../../../..
并非应用程序中的所有内容都属于公共npm 设置私人npm或git repo的开销仍然是 在许多情况下相当大。以下是一些避免使用的方法
../../../../../../../
相对路径问题。node_modules
人们有时反对将特定于应用程序的模块放入其中 node_modules因为不清楚如何检查你的内部 没有从npm检查第三方模块的模块。
答案很简单!如果您有
.gitignore
个文件 忽略node_modules
:node_modules
您可以为每个内部添加
!
的例外 应用模块:node_modules/* !node_modules/foo !node_modules/bar
请注意,如果是父目录,则不能 unignore 子目录 已经被忽略了因此,您必须不要忽略
node_modules
忽略node_modules
内的每个目录node_modules/*
技巧,然后您可以添加例外。现在您的应用程序中的任何位置都可以
require('foo')
或require('bar')
没有一个非常大而脆弱的亲戚 路径。如果你有很多模块,并希望让它们更加独立 由npm安装的第三方模块,您可以将它们全部放入 在
node_modules
目录下,例如node_modules/app
:node_modules/app/foo node_modules/app/bar
现在您可以
require('app/foo')
或require('app/bar')
来自您申请中的任何地方。在
.gitignore
中,只需为node_modules/app
添加例外:node_modules/* !node_modules/app
如果您的应用程序在package.json中配置了转换,那么您将会这样做 需要创建一个单独的package.json,其中包含自己的转换字段 您的
node_modules/foo
或node_modules/app/foo
组件目录 因为变换不适用于模块边界。这将 使您的模块更强大,以防止您的配置更改 应用程序,它将更容易独立重用包 在您的申请之外。符号链接
如果您正在使用应用程序,那么另一个方便的技巧 制作符号链接,不需要支持窗口是符号链接
lib/
或app/
文件夹到node_modules
。从项目根目录执行:ln -s ../lib node_modules/app
现在,您可以从项目的任何位置获取文件 在
lib/
中require('app/foo.js')
获取lib/foo.js
。自定义路径
您可能会看到一些地方谈论使用
$NODE_PATH
环境变量或opts.paths
添加节点和目录的目录 浏览以查找模块。与大多数其他平台不同,使用shell样式的路径数组 与
$NODE_PATH
相比,node_modules
的目录在节点上并不那么有利 有效利用$NODE_PATH
目录。这是因为您的应用程序与运行时紧密耦合 环境配置,所以有更多的移动部件和你的 应用程序仅在您的环境设置正确时才有效。
节点和浏览器都支持但不鼓励使用 {{1}}。
答案 2 :(得分:60)
我喜欢为共享代码创建一个新的node_modules
文件夹,然后让node和require做它最擅长的事情。
例如:
- node_modules // => these are loaded from your package.json
- app
- node_modules // => add node-style modules
- helper.js
- models
- user
- car
- package.json
- .gitignore
例如,如果您在car/index.js
,require('helper')
可以require('./foo.js')
,节点会找到它!
节点有一个聪明的算法来解析竞争对手中独有的模块 平台。
如果/beep/boop/bar.js
来自./foo.js
,则节点会在/beep/boop/foo.js
中查找./
。以../
或require()
开头的路径始终是调用require('xyz')
的文件的本地路径。
如果您需要来自/beep/boop/foo.js
的非相对名称,例如/beep/boop/node_modules/xyz
/beep/node_modules/xyz
/node_modules/xyz
,则节点按顺序搜索这些路径,在第一个匹配时停止并在未找到任何内容时引发错误:
xyz
对于存在的每个xyz/package.json
目录,节点将首先查找"main"
以查看是否存在"main"
字段。如果您require()
目录路径,/beep/node_modules/xyz
字段定义应该负责哪个文件。
例如,如果/beep/node_modules/xyz/package.json
是第一个匹配且{
"name": "xyz",
"version": "1.2.3",
"main": "lib/abc.js"
}
具有:
/beep/node_modules/xyz/lib/abc.js
然后将返回require('xyz')
的导出
package.json
。
如果没有"main"
或没有index.js
字段,则会假定/beep/node_modules/xyz/index.js
:
{{1}}
答案 3 :(得分:37)
看起来“非常糟糕”,但要给它时间。事实上,它确实很好。明确的require()
给出了完全的透明度和易于理解,就像在项目生命周期中呼吸新鲜空气一样。
以这种方式思考:你正在阅读一个例子,将你的脚趾浸入Node.js并且你已经确定它是“非常糟糕的IMO”。你是Node.js社区的第二猜测领导者,他们编写和维护Node.js应用程序的时间比任何人都多。作者犯这样一个菜鸟错误的可能性有多大? (我同意,从我的Ruby和Python背景来看,它最初看起来像是一场灾难。)
围绕Node.js有很多炒作和反炒作。但当尘埃落定时,我们将承认明确的模块和“本地第一”包是采用的主要动力。
当然,从当前目录中node_modules
,然后搜索父母,祖父母,曾祖父母等。所以你安装的软件包已经以这种方式工作了。通常,您可以在项目的任何位置require("express")
,它可以正常工作。
如果您发现自己从项目的根目录加载公共文件(可能是因为它们是常用的实用程序功能),那么这是一个很大的线索,是时候制作一个包。包非常简单:将文件移至node_modules/
并放置package.json
那里。 Voila!该命名空间中的所有内容都可以从整个项目中访问。包是将代码放入全局命名空间的正确方法。
我个人不使用这些技巧,但他们确实回答了你的问题,当然你比我更了解你自己的情况。
您可以将$NODE_PATH
设置为项目根目录。当您require()
时,将搜索该目录。
接下来,您可以妥协并要求所有示例中的公共本地文件。该公共文件只是重新导出祖父目录中的真实文件。
examples / downloads / app.js (和许多其他人一样)
var express = require('./express')
实例/下载/ express.js
module.exports = require('../../')
现在,当您重新定位这些文件时,最糟糕的情况是修复一个 shim 模块。
答案 4 :(得分:17)
答案 5 :(得分:12)
恕我直言,最简单的方法是将自己的函数定义为GLOBAL
对象的一部分。
使用以下内容在项目的根目录中创建projRequire.js
:
var projectDir = __dirname;
module.exports = GLOBAL.projRequire = function(module) {
return require(projectDir + module);
}
在require
任何项目特定模块之前的主文件中:
// init projRequire
require('./projRequire');
以下内容对我有用:
// main file
projRequire('/lib/lol');
// index.js at projectDir/lib/lol/index.js
console.log('Ok');
<小时/> @Totty,我已经解决了另一个解决方案,这可能适用于您在评论中描述的案例。说明将为
tl;dr
,因此我最好使用structure of my test project显示图片。
答案 6 :(得分:11)
我在我的项目中使用process.cwd()
。例如:
var Foo = require(process.cwd() + '/common/foo.js');
值得注意的是,这会导致require
绝对路径,但我还没有遇到问题。
答案 7 :(得分:8)
如果您使用的是 yarn 而不是 npm ,则可以使用workspaces。
假设我有一个文件夹services
,我希望更轻松地进行访问:
.
├── app.js
├── node_modules
├── test
├── services
│ ├── foo
│ └── bar
└── package.json
要创建Yarn工作区,请在package.json
内创建一个services folder
文件:
{
"name": "myservices",
"version": "1.0.0"
}
在您的主package.json中添加:
"private": true,
"workspaces": ["myservices"]
从项目的根目录运行yarn install
。
然后,您可以在代码中的任何地方执行以下操作:
const { myFunc } = require('myservices/foo')
而不是类似的东西:
const { myFunc } = require('../../../../../../services/foo')
答案 8 :(得分:8)
对此问题进行了很好的讨论here。
我遇到了同样的架构问题:想要一种给我的应用程序提供更多组织和内部命名空间的方法,而不需要:
最后,我决定使用文件命名约定而不是目录来组织我的代码。结构看起来像:
然后在代码中:
var app_config = require('./app.config');
var app_models_foo = require('./app.models.foo');
或只是
var config = require('./app.config');
var foo = require('./app.models.foo');
像往常一样,和node_modules可以使用外部依赖项:
var express = require('express');
通过这种方式,所有应用程序代码都按层次结构组织成模块,并且可用于相对于应用程序根目录的所有其他代码。
主要缺点当然是在文件浏览器中,您无法展开/折叠树,就好像它实际上已组织到目录中一样。但我喜欢它非常清楚所有代码的来源,并且它不使用任何“魔法”。
答案 9 :(得分:8)
假设您的项目root是当前工作目录,这应该有效:
// require built-in path module
path = require('path');
// require file relative to current working directory
config = require( path.resolve('.','config.js') );
答案 10 :(得分:7)
一些答案是说最好的方法是将代码作为一个包添加到node_module中,我同意并且它可能是丢失../../../
中的最佳方法,但它们中没有一个实际给出了这样做的方法。
2.0.0
您可以从本地文件安装软件包,这意味着您可以在根目录中创建包含所需软件包的文件夹,
-modules
--foo
--bar
-app.js
-package.json
所以在package.json中你可以将modules
(或foo
和bar
)作为包添加,而无需发布或使用这样的外部服务器:
{
"name": "baz",
"dependencies": {
"bar": "file: ./modules/bar",
"foo": "file: ./modules/foo"
}
}
之后,您执行npm install
,您可以使用var foo = require("foo")
访问代码,就像使用所有其他软件包一样。
可在此处找到更多信息:
https://docs.npmjs.com/files/package.json#local-paths
以及如何创建包:
https://docs.npmjs.com/getting-started/creating-node-modules
答案 11 :(得分:6)
您可以在app.js中定义类似的内容:
requireFromRoot = (function(root) {
return function(resource) {
return require(root+"/"+resource);
}
})(__dirname);
然后只要你想要从root用户那里获得一些东西,无论你身在何处,你只需要使用requireFromRoot而不是vanilla require。到目前为止对我来说效果很好。
答案 12 :(得分:6)
这是我超过6个月的实际行动方式。我在项目中使用名为node_modules的文件夹作为我的根文件夹,这样它总是会从我称之为绝对需求的地方查找该文件夹:
当您嵌套到文件夹中时,这更有用,如果以绝对方式设置,更改文件位置的工作要少得多。我只在whole app中使用2相对要求。
答案 13 :(得分:6)
您可以使用我制作的模块Undot。它没什么先进的,只是一个帮手,所以你可以简单地避免那些点地狱。
示例:
var undot = require('undot');
var User = undot('models/user');
var config = undot('config');
var test = undot('test/api/user/auth');
答案 14 :(得分:4)
Imho实现这一目标的最简单方法是在node_modules/app
(或任何你称之为)的应用启动时创建一个指向../app
的符号链接。然后你可以打电话给require("app/my/module")
。所有主要平台都提供符号链接。
但是,您仍然应该将您的东西拆分为通过npm安装的较小的可维护模块。您也可以通过git-url安装私有模块,因此没有理由拥有一个单一的app-directory。
答案 15 :(得分:4)
在您自己的项目中,您可以修改根目录中使用的任何.js文件,并将其路径添加到def UuserEmailAgentIdD(self, CemailToIdD, MUuserWithAgentD):
"""return a dict of user_email:agent:id - only users with agents
Argumetns:
CemailToIdD: dict of all user emails : ids
MUuserWithAgentD: dict of pure user ID:agent_id"""
return_dict = {}
user_ids = MUuserWithAgentD.keys()
for user_email in CemailToIdD:
if CemailToIdD[user_email] in user_ids:
return_dict[user_email] = MUuserWithAgentD[CemailToIdD[user_email]]
return return_dict
变量的属性中。例如:
process.env
之后您可以随处访问该物业:
// in index.js
process.env.root = __dirname;
答案 16 :(得分:3)
另一个答案:
想象一下这个文件夹结构:
<强>测试强>
然后在 test.js 中,你需要这样的文件:
const foo = require("../src/subdir/foo");
const bar = require("../src/subdir/bar");
const main = require("../src/main");
const _ = require("lodash");
并在 main.js :
const foo = require("./subdir/foo");
const bar = require("./subdir/bar");
const _ = require("lodash");
现在,您可以使用babel和babel-plugin-module-resolver与此。 babelrc 文件配置2个根文件夹:
{
"plugins": [
["module-resolver", {
"root": ["./src", "./src/subdir"]
}]
]
}
现在您可以在测试和 src 中以相同的方式要求文件:
const foo = require("foo");
const bar = require("bar");
const main = require("main");
const _ = require("lodash");
如果您想使用 es6模块语法:
{
"plugins": [
["module-resolver", {
"root": ["./src", "./src/subdir"]
}],
"transform-es2015-modules-commonjs"
]
}
然后您导入测试和 src 中的文件,如下所示:
import foo from "foo"
import bar from "bar"
import _ from "lodash"
答案 17 :(得分:3)
我喜欢做的是利用节点从node_module目录加载的方式。
如果有人试图加载模块&#34;事情&#34;,可以做类似
的事情require('thing');
然后,节点会查找&#39;&#39; “node_module”中的目录&#39; 。目录
由于node_module通常位于项目的根目录,因此我们可以利用此一致性。 (如果node_module不在根目录,那么你还有其他自我引发的问题需要处理。)
如果我们进入目录然后退出目录,我们就可以获得到节点项目根目录的一致路径。
require('thing/../../');
然后,如果我们想访问/ happy目录,我们就会这样做。
require('thing/../../happy');
虽然它有点hacky,但我觉得如果node_modules加载方式的功能发生变化,那么处理的问题会更大。此行为应保持一致。
为了清楚起见,我这样做,因为模块的名称并不重要。
require('root/../../happy');
我最近用它来做角度2。我想从根目录加载服务。
import {MyService} from 'root/../../app/services/http/my.service';
答案 18 :(得分:2)
我编写了这个小包,它允许你从项目根目录的相对路径需要包,而不引入任何全局变量或覆盖节点默认值
https://github.com/Gaafar/pkg-require
它像这样工作
// create an instance that will find the nearest parent dir containing package.json from your __dirname
const pkgRequire = require('pkg-require')(__dirname);
// require a file relative to the your package.json directory
const foo = pkgRequire('foo/foo')
// get the absolute path for a file
const absolutePathToFoo = pkgRequire.resolve('foo/foo')
// get the absolute path to your root directory
const packageRootPath = pkgRequire.root()
答案 19 :(得分:2)
examples
目录无法包含node_modules
,其中包含指向项目根project -> ../../
的符号链接,因此允许示例使用require('project')
,尽管这不是不删除映射,它允许源使用require('project')
而不是require('../../')
。
我已经测试了这个,它确实适用于v0.6.18。
project
目录的列表:
$ ls -lR project
project:
drwxr-xr-x 3 user user 4096 2012-06-02 03:51 examples
-rw-r--r-- 1 user user 49 2012-06-02 03:51 index.js
project/examples:
drwxr-xr-x 2 user user 4096 2012-06-02 03:50 node_modules
-rw-r--r-- 1 user user 20 2012-06-02 03:51 test.js
project/examples/node_modules:
lrwxrwxrwx 1 user user 6 2012-06-02 03:50 project -> ../../
index.js
的内容为exports
对象的属性赋值,并调用console.log
并显示一条消息,指出它是必需的。 test.js
的内容为require('project')
。
答案 20 :(得分:2)
如果有人正在寻找另一种解决这个问题的方法,那么这就是我自己对这项工作的贡献:
基本思路:在项目的根目录中创建一个JSON文件,将文件路径映射到速记名称(或让use-automapper为您完成)。然后,您可以使用这些名称请求您的文件/模块。像这样:
var use = require('use-import');
var MyClass = use('MyClass');
那就是那个。
答案 21 :(得分:1)
如果你的app的入口点js文件(即你实际运行的那个&#34; node&#34; on)在你的项目根目录中,你可以使用{{3}轻松地完成这项工作}。只需通过
安装即可npm install --save rootpath
...然后在入口点js文件的最顶部,添加:
require('rootpath')();
从那时起,所有需要调用现在都相对于项目根目录 - 例如require('../../../config/debugging/log');
变为require('config/debugging/log');
(配置文件夹位于项目根目录中)。
答案 22 :(得分:1)
简单来说,你可以将自己的文件夹称为模块:
为此我们需要:全局和app-module-path模块
这里“App-module-path”是模块,它允许您向Node.js模块搜索路径添加其他目录 并且“全局”是,您附加到此对象的任何内容都将在您的应用中随处可用。
现在看看这个片段:
global.appBasePath = __dirname;
require('app-module-path').addPath(appBasePath);
__ dirname是node的当前运行目录。您可以在此处提供自己的路径来搜索模块的路径。
答案 23 :(得分:1)
我遇到同样的问题,所以我写了一个名为include的软件包。
Include通过查找package.json文件来处理项目的根文件夹,然后将您提供给它的路径参数传递给本机require(),而不会出现所有相对路径混乱。我想这不是require()的替代品,而是需要处理非打包/非第三方文件或库的工具。像
这样的东西var async = require('async'),
foo = include('lib/path/to/foo')
我希望这可能有用。
答案 24 :(得分:1)
我们即将尝试一种新方法来解决这个问题。
从spring和guice等其他已知项目中获取示例,我们将定义一个“context”对象,该对象将包含所有“require”语句。
然后,此对象将传递给所有其他模块以供使用。
例如
var context = {}
context.module1 = require("./module1")( { "context" : context } )
context.module2 = require("./module2")( { "context" : context } )
这要求我们将每个模块编写为接收opts的函数,无论如何我们认为这是最佳实践..
module.exports = function(context){ ... }
然后你会引用上下文而不是需要东西。
var module1Ref = context.moduel1;
如果您愿意,可以轻松编写循环来执行require语句
var context = {};
var beans = {"module1" : "./module1","module2" : "./module2" };
for ( var i in beans ){
if ( beans.hasOwnProperty(i)){
context[i] = require(beans[i])(context);
}
};
当您想要模拟(测试)时,这应该会让生活变得更轻松,并且在将代码作为包重用时可以解决您的问题。
您还可以通过将bean声明与其分离来重用上下文初始化代码。
例如,您的main.js
文件可能如此
var beans = { ... }; // like before
var context = require("context")(beans); // this example assumes context is a node_module since it is reused..
此方法也适用于外部库,无需在每次需要时对其名称进行硬编码 - 但是它需要特殊处理,因为它们的导出不是期望上下文的函数。
稍后我们也可以将bean定义为函数 - 这将允许我们根据环境require
不同的模块 - 但它超出了这个线程的范围。
答案 25 :(得分:1)
只想跟进来自 Paolo Moretti 的great answer和Browserify。如果您使用的是转换器(例如,babel,typescript),并且您有源代码和转换代码的单独文件夹,例如src/
和dist/
,则可以使用解决方案的变体
使用以下目录结构:
app
node_modules
... // normal npm dependencies for app
src
node_modules
app
... // source code
dist
node_modules
app
... // transpiled code
然后你可以让babel等将src
目录转换为dist
目录。
使用符号链接我们可以摆脱某些级别的嵌套:
app
node_modules
... // normal npm dependencies for app
src
node_modules
app // symlinks to '..'
... // source code
dist
node_modules
app // symlinks to '..'
... // transpiled code
有关babel的警告--copy-files --copy-files
的{{1}}标志不能很好地处理符号链接。它可能会继续导航到babel
符号链接并重复看到无穷无尽的文件。解决方法是使用以下目录结构:
..
通过这种方式,app
node_modules
app // symlink to '../src'
... // normal npm dependencies for app
src
... // source code
dist
node_modules
app // symlinks to '..'
... // transpiled code
下的代码仍会src
解析为app
,而babel则不会再看到符号链接。
答案 26 :(得分:1)
答案 27 :(得分:1)
刚遇到提及this article。它允许您配置这样的基础:
require('app-module-path').addPath(baseDir);
答案 28 :(得分:1)
我一直在寻找完全相同的简单性以要求任何级别的文件,但我发现module-alias。
只需安装:
Sueldos <- Sueldos %>% rename(Sueldo = Monto.bruto.enpesos.chilenos) %>% dplyr::select(Desde, Sueldo) %>% mutate(Desde = lubridate::dmy(Desde), Sueldo = str_remove_all(Sueldo, pattern = intToUtf8(160)))
打开您的package.json文件,您可以在此处添加路径的别名,例如
npm i --save module-alias
并通过以下简单方式使用您的别名:
"_moduleAliases": {
"@root" : ".", // Application's root
"@deep" : "src/some/very/deep/directory/or/file",
"@my_module" : "lib/some-file.js",
"something" : "src/foo", // Or without @. Actually, it could be any string
}
答案 29 :(得分:1)
我有多次相同的问题。这可以通过使用basetag
npm软件包来解决。它本身并不需要,仅需安装即可,因为它会在node_modules
内部创建指向您的基本路径的符号链接。
const localFile = require('$/local/file')
// instead of
const localFile = require('../../local/file')
使用$/...
前缀将始终引用相对于应用程序根目录的文件。
答案 30 :(得分:0)
前段时间我创建了相对于预定义路径加载模块的模块。
您可以使用它代替require。
irequire.prefix('controllers',join.path(__dirname,'app/master'));
var adminUsersCtrl = irequire("controllers:admin/users");
var net = irequire('net');
也许它会对某人有用..
答案 31 :(得分:0)
虽然这些答案有效但它们并未解决npm test
的问题例如,如果我在server.js中创建一个全局变量,则不会为我的测试套件执行设置它。
要设置一个全局appRoot变量,该变量将避免../../../问题,并且将在npm start和npm test中都可用,请参阅:
Mocha tests with extra options or parameters
请注意,这是新的官方摩卡解决方案。
答案 32 :(得分:0)
尝试使用asapp:
npm install --save asapp
https://www.npmjs.com/package/asapp
var { controller, helper, middleware, route, schema, model, APP, ROOT } = require('asapp')
controller('home')
代替require('../../controllers/home)
答案 33 :(得分:0)
如果您使用的是ES5语法,则可以使用asapp。对于ES6,您可以使用babel-plugin-module-resolver并使用如下配置文件:
.babelrc
{
"plugins": [
["module-resolver", {
"root": ["./"],
"alias": {
"app": "./app",
"config": "./app/config",
"schema": "./app/db/schemas",
"model": "./app/db/models",
"controller": "./app/http/controllers",
"middleware": "./app/http/middleware",
"route": "./app/http/routes",
"locale": "./app/locales",
"log": "./app/logs",
"library": "./app/utilities/libraries",
"helper": "./app/utilities/helpers",
"view": "./app/views"
}
}]
]
}
答案 34 :(得分:-1)
我认为你不需要以你描述的方式解决这个问题。如果你想在大量文件中更改相同的字符串,请选择sed。在您的示例中,
find . -name "*.js" -exec sed -i 's/\.\.\/\.\.\//\.\.\//g' {} +
会将../../更改为../
或者,您可以要求配置文件存储包含库路径的变量。如果将以下内容存储为示例目录中的config.js
var config = {};
config.path = '../../';
并在您的示例文件中
myConfiguration = require('./config');
express = require(config.path);
您将能够从一个文件中控制每个示例的配置。
这只是个人偏好。
答案 35 :(得分:-2)
这里已经有很多好的答案了。这只是表明这是一个没有明确最佳解决方案的常见问题。最好的当然是 Node.js 的原生支持。这是我目前使用的:
const r = p => require (process.cwd() + p);
let see = r ('/Subs/SubA/someFile.js' );
let see2 = r ('/Subs/SubB/someFile2.js');
...
我喜欢这个解决方案,因为 requires 部分变得更短,不需要多次输入“require”。绝对路径的主要好处是您可以将它们从一个文件复制到另一个文件,而无需像使用相对路径那样调整它们。因此,复制额外的单行箭头函数 'r()' 也不是太多的额外工作。并且不需要为了完成这个非常简单的任务而导入额外的 npm 依赖项。