使用Webpack解决require路径问题

184

我还不清楚如何使用webpack解决模块路径的问题。现在我的写法是:

myfile = require('../../mydir/myfile.js') 

但我想写作

myfile = require('mydir/myfile.js') 

我曾考虑使用resolve.alias来帮助解决问题,因为我看到一个类似的例子,使用{ xyz: "/some/dir" }作为别名,这样我就可以用require("xyz/file.js")来引入文件。

但如果我把别名设置为{ mydir: '/absolute/path/mydir' }require('mydir/myfile.js') 就行不通了。

我感觉有点蠢,因为我已经多次阅读文档,但感觉自己缺少某些东西。 避免写所有相对路径的../../等内容的正确方法是什么?


resolve.alias 正是您所建议的方式。我想知道它是否因为您的 resolve 配置中的其他原因而失败。我使用 alias{ mydir: path.resolve( __dirname, 'path', 'to', 'mydir' ),并且 require( 'mydir/myfile.js' ) 运行得非常好。 - sethro
11个回答

148

Webpack >2.0

请参阅wtk的答案

Webpack 1.0

更直接的方法是使用resolve.root。

http://webpack.github.io/docs/configuration.html#resolve-root

resolve.root

包含模块的目录(绝对路径)。也可以是目录数组。应将此设置用于向搜索路径添加单个目录。

在你的情况下:

webpack 配置

var path = require('path');

// ...

  resolve: {
    root: path.resolve('./mydir'),
    extensions: ['', '.js']
  }

消费模块

require('myfile')
或者
require('myfile.js')

参见:http://webpack.github.io/docs/configuration.html#resolve-modulesdirectories


1
谢谢,我尝试了 rootmodulesDirectories 和两者混合的方式,但没有成功。似乎不接受子模块(例如 require("mydir/file"))。 - gpbl
我有些困惑,因为该应用程序还通过node.js要求相同的模块,而更改“node_modules”路径并不是一个好的做法。所以最终,我只是像往常一样使用了“../”。 - gpbl
1
如果我理解正确的话,使用这个配置需要确保文件名是唯一的? - Jonny
1
`WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
  • configuration.resolve has an unknown property 'root'.`
- Tomáš Zato
1
webpack 2 移除了除模块外的所有内容作为解析路径的方式。这意味着根路径将不起作用。 - rofrol
显示剩余5条评论

90

未来参考,webpack 2 只保留了 modules 作为解析路径的方式。这意味着 root不再起作用

https://gist.github.com/sokra/27b24881210b56bbaff7#resolving-options

示例配置如下:

{
  modules: [path.resolve(__dirname, "app"), "node_modules"]
  // (was split into `root`, `modulesDirectories` and `fallback` in the old options)

4
谢谢,这真的很有帮助。即使在使用Webpack 2的情况下,webpack-dev-server仍在使用modulesDirectories,这使得事情变得非常混乱。 - Evan

69

resolve.alias应该按照你所描述的方式工作,因此我提供了这个答案来帮助缓解原问题中建议它不能正常工作所导致的任何混淆。

像下面这样的解析配置将为您提供所需的结果:

// used to resolve absolute path to project's root directory (where web pack.config.js should be located)
var path = require( 'path' );
...
{
  ...
  resolve: {
    // add alias for application code directory
    alias:{
      mydir: path.resolve( __dirname, 'path', 'to', 'mydir' )
    },
    extensions: [ '', '.js' ]
  }
}

require( 'mydir/myfile.js' )会按预期工作。如果它无法正常工作,那么必须存在其他问题。

如果您有多个模块要添加到搜索路径中,则resolve.root是有意义的,但如果您只想能够引用应用程序代码中的组件而不使用相对路径,则alias似乎是最简单和明确的方法。

alias的一个重要优点是它提供了命名空间的机会,这可以增加代码的清晰度;就像从其他require中很容易看出正在引用哪个模块一样,alias允许您编写描述性的require,使清楚地表明您正在要求内部模块,例如require('my-project/component')resolve.root仅将您放入所需的目录中,而没有进一步提供命名空间的机会。


49
我喜欢给波浪号取别名:alias: {'~': path.resolve(__dirname)}, - Daniel Buckmaster
有任何提示可以调整此解决方案以支持子目录导入且不需要文件扩展名吗?@sethro - Dima Feldman
@DimaFeldman,你的意思是在require参数中不使用扩展名(require('mydir/myfile'))?那应该是可以的。你可以在alias中有多个条目;我用它来从我的JavaScript模块的src目录导入,另一个用于从我的css的styles目录导入。如果我完全误解了你的问题,请告诉我。 - sethro
@sethro 你说得对,让我重新表述我的问题 - 我的意思是:我有一个目录,比如 Component1,这个目录里面有一个文件叫 Component1.js。在使用别名之前,我可以通过调用 import './path/to/Component1'; 来导入文件 - 简单地在路径中不包含内部文件名和扩展名。Webpack 不知何故能够检测到内部文件名与目录名相同并进行导入。现在我想做的是这样导入:import 'shared\Component1'; 其中'shared'是别名。但是如果不指定内部文件名,它无法正常工作。谢谢! - Dima Feldman
1
@DimaFeldman 很抱歉,我对你所描述的行为不熟悉,如果我对某些已知功能一无所知,请原谅我(我找不到文档)。我想知道你的配置中是否有一些加载器,可以通过指定模块位置(而不是文件名)来导入模块的能力?很抱歉,我没有帮助...最好在新问题中询问,并包含您的配置文件。 - sethro
extensions may be omited, because webpack defaults are: ['.js', '.json'] - Arsen K.

13

如果其他人遇到了这个问题,我通过以下方式解决:

var path = require('path');
// ...
resolve: {
  root: [path.resolve(__dirname, 'src'), path.resolve(__dirname, 'node_modules')],
  extensions: ['', '.js']
};

我的目录结构在哪里:

.
├── dist
├── node_modules
├── package.json
├── README.md
├── src
│   ├── components
│   ├── index.html
│   ├── main.js
│   └── styles
├── webpack.config.js

然后我可以从 src 目录中的任何地方调用:

import MyComponent from 'components/MyComponent';

2
不建议使用 path.resolve 解析 node_modules。这可能会导致子依赖项出现问题。请改用字符串 'node_modules'[ path.resolve(__dirname, 'src'), 'node_modules' ], - spencer.sm
@spencer.sm 如果我只想从当前项目中解析模块怎么办?我有几个项目相互导入。如果projectA从projectB导入fileA,而fileA导入lodash,我希望lodash仅从projectA/node_modules中解析。这就是resolve.modules: [path.resolve(__dirname, 'node_modules')]的用处。但是,像你说的那样,我遇到了一些子依赖问题。有没有办法告诉webpack除了限制projectA/node_modules的解析之外,还要找到子依赖项? - Eric Guan
@spencer.sm 謝謝你!經過很多掙扎,最終你的解決方案解決了我的子依賴問題:D - Saad Abdullah

6

我用Webpack 2解决了这个问题,方法如下:

module.exports = {
  resolve: {
    modules: ["mydir", "node_modules"]    
  }
}

你可以将更多的目录添加到数组中...

请注意,绝对路径和相对路径的处理方式不同!可能会影响构建时间。 https://webpack.js.org/configuration/resolve/#resolve-modules - TeChn4K
1
它在两种情况下都可以工作,但使用相对路径可能需要更长的构建时间。 - TeChn4K

5

我的最大烦恼是在没有命名空间路径的情况下工作。就像这样:

./src/app.js
./src/ui/menu.js
./node_modules/lodash/

以前,我会设置我的开发环境来做这件事:

require('app.js')
require('ui/menu')
require('lodash')

我发现避免使用隐式的src路径更为方便,因为这会隐藏重要的上下文信息。

我的目的是像这样要求:

require('src/app.js')
require('src/ui/menu')
require('test/helpers/auth')
require('lodash')

如您所见,所有我的应用程序代码都位于强制性路径命名空间中。这使得很清楚哪个require调用需要库、应用程序代码或测试文件。
为此,我确保我的解析路径只是 node_modules 和当前应用程序文件夹,除非您将应用程序命名空间放在源文件夹中,例如 src/my_app。
这是我的 webpack 默认设置。
resolve: {
  extensions: ['', '.jsx', '.js', '.json'],
  root: path.resolve(__dirname),
  modulesDirectories: ['node_modules']
}

如果您将环境变量NODE_PATH设置为当前项目文件,效果会更好。这是一种更通用的解决方案,如果您想使用其他工具(例如测试,代码检查等)而不是webpack,也会有帮助。


3

使用Webpack 2解决了此问题:

   resolve: {
      extensions: ['', '.js'],
        modules: [__dirname , 'node_modules']
    }

3
如果您正在使用create-react-app,您可以简单地添加一个包含以下内容的.env文件:
NODE_PATH=src/

来源:https://medium.com/@ktruong008/absolute-imports-with-create-react-app-4338fbca7e3d

本文介绍了如何在使用create-react-app创建React应用程序时使用绝对导入。 绝对导入是一种更好的组织代码的方式,可以使您的代码更加易于维护和阅读。在这篇文章中,我们将学习如何通过配置webpack来实现绝对导入。


2

这个帖子已经很老了,但由于没有人提到require.context,我要提一下:

您可以使用require.context来设置要查找的文件夹,如下所示:

var req = require.context('../../mydir/', true)
// true here is for use subdirectories, you can also specify regex as third param

return req('./myfile.js')

1

只需使用babel-plugin-module-resolver

$ npm i babel-plugin-module-resolver --save-dev

如果您还没有一个,请在根目录下创建一个.babelrc文件:
{
    "plugins": [
        [
            "module-resolver",
            {
                "root": ["./"]
            }
        ]
    ]
}

而根目录下的所有内容都将被视为绝对导入:

import { Layout } from 'components'

对于 VSCode/Eslint 支持,请访问 此处

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接