44

I'm writing a node app with es6 using babel transpiler.

I have 2 files index.js & my-module.js on my root directory

- index.js
- my-module.js

my-module.js

export let myFunc = () => {
  console.log('myFunc was called!!!');
}

index.js

import {myFunc} from './my-module';
myFunc();

if I run the following line from the command line everything works as expected.

$ babel-node index.js >> myFunc was called!!!

but if I remove the dot when importing my-module:

import {myFunc} from '/my-module';
myFunc();

I'm getting an error:

Error: Cannot find module '/my-module'

Any reason why I can't import modules using an absolute path? anyway to change .babelrc config to support it?

Thanks

gtournie
  • 4,143
  • 1
  • 21
  • 22
Gavriguy
  • 3,068
  • 3
  • 19
  • 23

3 Answers3

56

Like (almost) any tool '/x' means 'x' in the root of your filesystem. Babel doesn't actually look at the paths, it just compiles

import {myFunc} from '/my-module';

into

var _myModule = require('/my-module');

And node actually looks up the module.


If you really want to import relative to the root of the project, you could use a plugin. I recommend using something that isn't very ambiguous, and make sure you document this for the next person reading your code!

Here's an example where we use a leading ~ to mean project relative. You could use anything you like e.g. ^ would also be good.

Example Input:

import {a} from '~my-module';
import {b} from '/my-module';
import {c} from './my-module';

scripts/babel-plugin-project-relative-require.js

module.exports = function (babel) {
  // get the working directory
  var cwd = process.cwd();

  return new babel.Transformer("babel-plugin-project-relative-require", {
    ImportDeclaration: function(node, parent) {
      // probably always true, but let's be safe
      if (!babel.types.isLiteral(node.source)) {
        return node;
      }

      var ref = node.source.value;

      // ensure a value, make sure it's not home relative e.g. ~/foo
      if (!ref || ref[0] !== '~' || ref[1] === '/') {
        return node;
      }

      node.source.value = cwd + '/' + node.source.value.slice(1);

      return node;
    }
  });
};

.babelrc

{
    "plugins": [
        "./scripts/babel-plugin-project-relative-require.js"
    ]
}

Output (if run in /tmp):

'use strict';

var _tmpMyModule = require('/tmp/my-module');

var _myModule = require('/my-module');

var _myModule2 = require('./my-module');
Brigand
  • 84,529
  • 20
  • 165
  • 173
  • btw when running your attached plugin I get the following: TypeError: The plugin "./scripts/babel-plugin-project-relative-require.js" didn't export a Plugin instance – Gavriguy Jun 26 '15 at 11:10
  • 1
    @Gavriguy update babel? Make sure the local and global versions are up to date, `npm i -g babel@latest; npm i -D babel-core@latest` – Brigand Jun 26 '15 at 13:03
  • Once I packaged the plugin as a node module ( ` npm install https://github.com/gavriguy/babel-plugin-project-relative-require.git --save` ) it works like a charm. much appreciated @FakeRainBrigand – Gavriguy Jun 26 '15 at 13:45
41

The solution from FakeRainBrigand/Gavriguy is good and works well. So i decided to develop a plugin which you can easily install with npm in and use a simple Babel-Plugin.

https://github.com/michaelzoidl/babel-root-import

Hope this helps...

Michael J. Zoidl
  • 1,708
  • 16
  • 13
7

First of all, Babel is just a transpiler from ES2015 to ES5 syntax. Its job is to transpile this:

import {myFunc} from '/my-module'

into this:

var _myModule = require('/my-module');

Actual module requiring performed by Node, and how Node does it you can read in details here: https://nodejs.org/api/modules.html#modules_file_modules

To summary, ./module means path to module relative to local directory, /module is an absolute path to module, module triggers Node to look for module in local node_modules directory and all ascending.

vtambourine
  • 2,109
  • 3
  • 18
  • 27