La resolución requiere rutas con webpack

164

Todavía estoy confundido sobre cómo resolver las rutas del módulo con webpack. Ahora escribo:

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

pero me gustaria escribir

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

Estaba pensando que resolve.alias puede ayudar ya que veo un ejemplo similar usando{ xyz: "/some/dir" } como alias, entonces puedo require("xyz/file.js").

Pero si configuro mi alias a { mydir: '/absolute/path/mydir' } , require('mydir/myfile.js') no funcionará.

Me siento tonto porque he leído el documento muchas veces y siento que me falta algo. ¿Cuál es la forma correcta de evitar escribir todo lo que el pariente requiere con ../../etc.?

gpbl
fuente
resolve.aliasfunciona exactamente de la manera que sugirió. Me pregunto si estaba fallando debido a algo más en su resolveconfiguración. Yo uso alias{ mydir: path.resolve( __dirname, 'path', 'to', 'mydir' )y require( 'mydir/myfile.js' )funciona bien.
Sethro

Respuestas:

142

Paquete web> 2.0

Ver la respuesta de wtk .

Webpack 1.0

Una forma más directa de hacerlo sería utilizar resolve.root.

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

resolver.root

El directorio (ruta absoluta) que contiene sus módulos. También puede ser una matriz de directorios. Esta configuración debe usarse para agregar directorios individuales a la ruta de búsqueda.

En tu caso:

configuración del paquete web

var path = require('path');

// ...

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

módulo de consumo

require('myfile')

o

require('myfile.js')

ver también: http://webpack.github.io/docs/configuration.html#resolve-modulesdirectories

AndyCunningham
fuente
1
Gracias, lo intenté root, modulesDirectoriesy una combinación de ambos, pero no funcionó. Parece que require("mydir/file")no se aceptan submódulos (p . Ej. ).
gpbl
Deberían ser: ¿podemos ver la configuración de su paquete web?
Jeff Ling
1
Si entiendo esto correctamente, ¿usar esta configuración requeriría que los nombres de los archivos sean únicos?
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 - Restablece a Monica el
1
"webpack 2 eliminó todo menos los módulos como una forma de resolver rutas. Esto significa que la raíz no funcionará" stackoverflow.com/a/36574982/588759
rofrol
72

Para referencia futura, webpack 2 eliminó todo, pero modulescomo una forma de resolver rutas. Esto significa rootque no funcionará.

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

La configuración de ejemplo comienza con:

{
  modules: [path.resolve(__dirname, "app"), "node_modules"]
  // (was split into `root`, `modulesDirectories` and `fallback` in the old options)
wtk
fuente
44
Gracias, esto es realmente útil. modulesDirectorieswebpack-dev-server todavía lo utiliza, incluso con webpack 2, lo que hace que esto sea muy confuso.
Evan
63

resolve.alias debería funcionar exactamente de la manera que usted describió, por lo que proporciono esto como una respuesta para ayudar a mitigar cualquier confusión que pueda resultar de la sugerencia en la pregunta original de que no funciona.

Una configuración de resolución como la siguiente le dará los resultados deseados:

// 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 se esperaba. Si no es así, debe haber algún otro problema.

Si tiene varios módulos que desea agregar a la ruta de búsqueda, resolve.roottiene sentido, pero si solo desea poder hacer referencia a componentes dentro del código de su aplicación sin rutas relativas,alias parece ser el más directo y explícito.

Una ventaja importante aliases que le brinda la oportunidad de asignar un espacio de nombre a su correo requireelectrónico, lo que puede agregar claridad a su código; al igual que es fácil ver desde otro requires a qué módulo se hace referencia, le aliaspermite escribir descriptivos requireque hacen obvio que necesita módulos internos, por ejemplo require( 'my-project/component' ).resolve.rootsimplemente lo coloca en el directorio deseado sin darle la oportunidad de espaciarlo más.

sethro
fuente
46
Me gusta alias the tilde:alias: {'~': path.resolve(__dirname)},
Daniel Buckmaster
¿Alguna sugerencia de cómo ajustar esta solución para admitir importaciones de subdirectorios sin extensiones de archivo? @sethro
Dima Feldman
@DimaFeldman, ¿quiere decir que no hay extensiones en el argumento require ( require('mydir/myfile'))? Eso debería funcionar realmente. Puede tener múltiples entradas en alias; Lo uso para importar desde mi srcdirectorio para módulos JavaScript y otro para importar desde mi stylesdirectorio para css. Avísame si he entendido mal tu pregunta.
sethro
@sethro tienes razón, déjame reformular mi pregunta, lo que quise decir es: tengo un directorio, digamos Component1, y dentro de este directorio tengo un archivo llamado Component1.js. antes de usar el alias, podría importar el archivo simplemente llamando import './path/to/Component1';, simplemente sin el nombre de archivo interno y la extensión en la ruta. webpack de alguna manera logró detectar que el archivo interno tiene el nombre del directorio, y simplemente lo importó. ahora lo que quiero hacer es importarlo así: import 'shared\Component1';cuando 'compartido' es el alias. pero no funciona sin especificar el nombre del archivo interno. ¡Gracias!
Dima Feldman
1
@DimaFeldman Lo siento, no estoy familiarizado con el comportamiento que está describiendo; así que tendrás que perdonarme si solo ignoro alguna característica conocida (no puedo encontrar documentación para ello). Me pregunto si tiene algún cargador en su configuración que le brinde la capacidad de importar un módulo al especificar solo su ubicación (pero no su nombre de archivo). Lo siento, no soy de ayuda ... Puede ser mejor hacer una nueva pregunta con su archivo de configuración incluido.
sethro
13

En caso de que alguien más se encuentre con este problema, pude hacer que funcione así:

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

donde mi estructura de directorios es:

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

Luego, desde cualquier lugar del srcdirectorio, puedo llamar:

import MyComponent from 'components/MyComponent';
Alex Klibisz
fuente
2
No es bueno resolver node_modules usando path.resolve. Esto puede causar problemas con subdependencias. Usa la cuerda en su 'node_modules'lugar. [ path.resolve(__dirname, 'src'), 'node_modules' ],
spencer.sm
@ spencer.sm ¿y si solo quiero que los módulos se resuelvan desde el proyecto actual? Tengo algunos proyectos que se importan unos de otros. Si el proyecto A importa el archivo A desde el proyecto B, y el archivo A importa lodash, quiero lodashque se resuelva SOLO desde projectA/node_modules. Para esto es resolve.modules: [path.resolve(__dirname, 'node_modules')]útil. Sin embargo, me encuentro con problemas con subdependencias como dijiste. ¿Hay alguna manera de decirle a webpack que también encuentre subdependencias además de restringir la resolución de node_modules projectA/node_modules?
Eric Guan
@ spencer.sm gracias! después de mucha lucha, finalmente su solución resolvió mis problemas de subdependencia: D
Saad Abdullah
5

Mi mayor dolor de cabeza era trabajar sin una ruta de espacio de nombres. Algo como esto:

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

Antes solía configurar mi entorno para hacer esto:

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

Encontré mucho más conveniente evitar una srcruta implícita , que oculta información de contexto importante.

Mi objetivo es exigir así:

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

Como puede ver, todo el código de mi aplicación se encuentra dentro de un espacio de nombre de ruta obligatorio. Esto deja bastante claro qué llamada requerida requiere una biblioteca, un código de aplicación o un archivo de prueba.

Para esto, me aseguro de que mis rutas de resolución sean justas node_modulesy la carpeta de la aplicación actual, a menos que el espacio de nombres de su aplicación dentro de su carpeta de origen comosrc/my_app

Este es mi valor predeterminado con webpack

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

Sería aún mejor si configura el entorno var NODE_PATHa su archivo de proyecto actual. Esta es una solución más universal y ayudará si desea utilizar otras herramientas sin paquete web: pruebas, linting ...

Frank sistemático
fuente
3

Lo resolví con Webpack 2 así:

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

Puede agregar más directorios a la matriz ...

Damjan Pavlica
fuente
¡Cuidado, los caminos absolutos y relativos no se procesan por igual! Puede afectar el tiempo de compilación webpack.js.org/configuration/resolve/#resolve-modules
TeChn4K
1
Funcionará en ambos casos, pero las compilaciones (pueden) llevar más tiempo con rutas relativas.
TeChn4K
3

Lo resolví usando Webpack 2:

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

Este hilo es antiguo pero como nadie publicó sobre require.context lo voy a mencionar:

Puede usar require.context para configurar la carpeta para que se vea así:

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
fuente
0

No entendí por qué alguien sugirió incluir el directorio principal de myDir en modulesDirectories en webpack, eso debería hacer el truco fácilmente:

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

Simplemente use babel-plugin-module-resolver :

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

Luego crea un .babelrcarchivo bajo root si aún no tienes uno:

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

Y todo bajo root será tratado como una importación absoluta:

import { Layout } from 'components'

Para obtener soporte de VSCode / Eslint, consulte aquí .

Lucia
fuente