A resolução exige caminhos com o webpack

164

Ainda estou confuso sobre como resolver os caminhos dos módulos com o webpack. Agora eu escrevo:

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

mas eu gostaria de escrever

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

Eu estava pensando que resolve.alias pode ajudar, pois vejo um exemplo semelhante usando { xyz: "/some/dir" }como alias, então eu posso require("xyz/file.js").

Mas se eu definir meu alias { mydir: '/absolute/path/mydir' }, require('mydir/myfile.js') não funcionará.

Me sinto burra porque li o documento várias vezes e sinto falta de alguma coisa. Qual é o caminho certo para evitar escrever todo o parente exige com ../../etc?

gpbl
fonte
resolve.aliasfunciona exatamente da maneira que você sugeriu. Gostaria de saber se estava falhando por causa de outra coisa na sua resolveconfiguração. Eu uso alias{ mydir: path.resolve( __dirname, 'path', 'to', 'mydir' )e require( 'mydir/myfile.js' )funciona muito bem.
Sethro

Respostas:

142

Webpack> 2.0

Veja a resposta de wtk .

Webpack 1.0

Uma maneira mais direta de fazer isso seria usar o resolve.root.

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

resolve.root

O diretório (caminho absoluto) que contém seus módulos. Também pode ser uma matriz de diretórios. Essa configuração deve ser usada para adicionar diretórios individuais ao caminho de pesquisa.

No seu caso:

configuração do webpack

var path = require('path');

// ...

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

módulo consumidor

require('myfile')

ou

require('myfile.js')

consulte também: http://webpack.github.io/docs/configuration.html#resolve-modulesdirectories

AndyCunningham
fonte
1
Obrigado, eu tentei root, modulesDirectoriese uma mistura de ambos, mas não funcionou. Parece que os submódulos (por exemplo require("mydir/file")) não são aceitos.
Gpbl
Eles deveriam ser - podemos ver a sua configuração do webpack?
Jeff Ling
1
Se estou entendendo isso corretamente, o uso dessa configuração exigiria que os nomes de arquivos fossem exclusivos?
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 - Restabelecer Monica
1
"Webpack 2 tudo removido, mas módulos como uma forma de caminhos resolver esse raiz meios não vai funcionar." stackoverflow.com/a/36574982/588759
rofrol
72

Para referência futura, o webpack 2 removeu tudo, mas modulescomo uma maneira de resolver caminhos. Isso significa rootque não vai funcionar.

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

A configuração de exemplo começa com:

{
  modules: [path.resolve(__dirname, "app"), "node_modules"]
  // (was split into `root`, `modulesDirectories` and `fallback` in the old options)
wtk
fonte
4
Obrigado, isso é realmente útil. modulesDirectoriesainda é usado pelo webpack-dev-server, mesmo com o webpack 2, o que torna isso muito confuso.
Evan
63

resolve.alias deve funcionar exatamente da maneira que você descreveu, por isso estou fornecendo isso como uma resposta para ajudar a atenuar qualquer confusão que possa resultar da sugestão na pergunta original de que ela não funciona.

uma configuração de resolução como a abaixo fornecerá os resultados desejados:

// 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' )funcionará como esperado. Caso contrário, deve haver outro problema.

Se você possui vários módulos que deseja adicionar ao caminho de pesquisa, resolve.rootfaz sentido, mas se você apenas deseja referenciar componentes no código do aplicativo sem caminhos relativos, aliasparece ser o mais direto e explícito.

Uma vantagem importante aliasé que ela oferece a oportunidade de nomear seus requires, o que pode adicionar clareza ao seu código; assim como é fácil ver de outras requires quais módulos estão sendo referenciados, aliaspermite que você escreva requires descritivas que tornam óbvio que você está exigindo módulos internos, por exemplo require( 'my-project/component' ). resolve.rootbasta colocá-lo no diretório desejado sem dar a você a oportunidade de colocá-lo ainda mais em namespace.

sethro
fonte
46
Eu gosto de alias til:alias: {'~': path.resolve(__dirname)},
Daniel Buckmaster
alguma dica de como ajustar esta solução para suportar importações de subdiretórios sem extensões de arquivo? @sethro
Dima Feldman
@DimaFeldman, você quer dizer que não há extensões no argumento de exigência ( require('mydir/myfile'))? Isso deve realmente funcionar. Você pode ter várias entradas alias; Eu uso isso para importar do meu srcdiretório para módulos JavaScript e outro para importar do meu stylesdiretório para css. Deixe-me saber se eu entendi completamente sua pergunta.
sethro
@ thethro você está certo, deixe-me reformular minha pergunta - o que eu quis dizer é: eu tenho um diretório, digamos Component1, e dentro desse diretório eu tenho um arquivo chamado Component1.js. antes de usar o alias, eu poderia importar o arquivo apenas chamando import './path/to/Component1';- simplesmente sem o nome e a extensão do arquivo interno no caminho. De alguma forma, o webpack conseguiu detectar que o arquivo Inner tem o nome do diretório e apenas o importou. agora o que eu quero fazer é importá-lo assim: import 'shared\Component1';quando 'shared' é o alias. mas não funciona sem especificar o nome do arquivo interno. Obrigado!
Dima Feldman
1
@ DimaFeldman Desculpe, não estou familiarizado com o comportamento que você está descrevendo; então você terá que me perdoar se eu ignorar algum recurso conhecido (não consigo encontrar documentação para ele). Gostaria de saber se você tem algum carregador em sua configuração que está fornecendo a capacidade de importar um módulo especificando apenas sua localização (mas não o nome do arquivo)? Desculpe, não tenho ajuda ... Talvez seja melhor fazer uma nova pergunta com seu arquivo de configuração incluído.
sethro
13

Caso alguém encontre esse problema, eu consegui fazê-lo funcionar assim:

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

onde minha estrutura de diretórios é:

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

Então, de qualquer lugar do srcdiretório que eu possa chamar:

import MyComponent from 'components/MyComponent';
Alex Klibisz
fonte
2
Não é bom resolver node_modules usando path.resolve. Isso pode causar problemas com subdependências. Use a string em seu 'node_modules'lugar. [ path.resolve(__dirname, 'src'), 'node_modules' ],
Spencer.sm
@ spencer.sm, e se eu quiser apenas resolver os módulos do projeto atual? Eu tenho alguns projetos que são importados um do outro. Se o projeto A importa o arquivo A do projeto B e o arquivo A importa lodash, quero lodashser resolvido SOMENTE a partir de projectA/node_modules. É para isso que resolve.modules: [path.resolve(__dirname, 'node_modules')]é útil. No entanto, estou tendo problemas com subdependências, como você disse. Existe uma maneira de dizer ao webpack para também encontrar subdependências, além de restringir a resolução de node_modules projectA/node_modules?
Eric Guan
@ spencer.sm obrigado! depois de muita luta, finalmente sua solução resolveu meus problemas de subdependência: D
Saad Abdullah
5

Minha maior dor de cabeça estava trabalhando sem um caminho com espaço para nome. Algo assim:

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

Antes de definir meu ambiente para fazer isso:

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

Achei muito mais conveniente evitar um srccaminho implícito , que oculta informações importantes do contexto.

Meu objetivo é exigir assim:

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

Como você vê, todo o código do meu aplicativo reside em um espaço de nome de caminho obrigatório. Isso deixa bem claro que chamada requer uma biblioteca, código de aplicativo ou arquivo de teste.

Para isso, certifique-se de que meus caminhos de resolução sejam justos node_modulese a pasta atual do aplicativo, a menos que você coloque o nome do aplicativo dentro da pasta de origem, comosrc/my_app

Esse é o meu padrão com o webpack

resolve: {
  extensions: ['', '.jsx', '.js', '.json'],
  root: path.resolve(__dirname),
  modulesDirectories: ['node_modules']
}

Seria ainda melhor se você definir o ambiente var NODE_PATHpara o seu arquivo de projeto atual. Esta é uma solução mais universal e ajudará se você quiser usar outras ferramentas sem o webpack: teste, limpeza ...

SystematicFrank
fonte
3

Eu resolvi isso com o Webpack 2 assim:

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

Você pode adicionar mais diretórios à matriz ...

Damjan Pavlica
fonte
Tenha cuidado, caminhos absolutos e relativos não são processados ​​igualmente! Pode afetar o tempo de compilação webpack.js.org/configuration/resolve/#resolve-modules
TeChn4K
1
Funcionará nos dois casos, mas as compilações (podem) demoram mais tempo com caminhos relativos.
TeChn4K 25/01
3

Resolvi isso usando o Webpack 2:

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

Este tópico é antigo, mas como ninguém postou sobre require.context, vou mencioná-lo:

Você pode usar o require.context para definir a pasta a ser visualizada da seguinte maneira:

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

return req('./myfile.js')
altShiftDev
fonte
0

Não entendi por que alguém sugeriu incluir o diretório pai do myDir nos modulesDirectories no webpack, o que deve facilitar o truque:

resolve: {
    modulesDirectories: [
      'parentDir',
      'node_modules',
    ],
    extensions: ['', '.js', '.jsx']
  },
daniele bertella
fonte
0

Simplesmente use babel-plugin-module-resolver :

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

Em seguida, crie um .babelrcarquivo na raiz, se você ainda não tiver um:

{
    "plugins": [
        [
            "module-resolver",
            {
                "root": ["./"]
            }
        ]
    ]
}

E tudo na raiz será tratado como uma importação absoluta:

import { Layout } from 'components'

Para suporte ao VSCode / Eslint, consulte aqui .

Lucia
fonte