Symlinks in project – loader not working when using include?

Can webpack read through symlinks? I have a simple symlink under /src with .jsx files. I have { test: /\.jsx?$/, loader: 'babel-loader?...', include: path.resolve(__dirname, 'src') } but it won’t load files with babel-loader, I get ES5 compilation error.

If I replace the symlink with the actual folder and files – it works.
If I replace the include with exclude: /node_modules/ it also works.

Bug, or am I doing it wrong?

Author: Fantashit

14 thoughts on “Symlinks in project – loader not working when using include?

  1. Having a similar issue with symlinks… I have all my modules under a /src folder in the root. Inside that /src folder I created a symlink to a directory /globals which is outside the root. Importing modules through the symlink works fine, however the loaders (in this case babel) don’t transform these modules properly which causes:

    1:61 error Parsing error: Illegal export declaration
    ...
    You may need an appropriate loader to handle this file type.

    Tried a few things in the config such adding the actual path of the directory I symlinked to in resolveLoader.modulesDirectories and in loader.include.

    This issue seems similar but none of the solutions there solved the issue. Feel like I’m missing something obvious…

  2. +1, I have this exact problem, the loader (babel) does not seem to be getting applied to files under a symlink. Replacing the symlink with an actual directory works.

  3. I think that the main issue here is that webpack resolves symlinks and it actually ‘sees’ this files by their absolute path. And this absolute path doesn’t match your include directive or test regexp.

    Could you please check this?

  4. I was able to fix this by doing the following in webpack.config.js (this is for importing our components library using the jsx files rather than the compiled umd):

    var includePaths = [
      fs.realpathSync(__dirname + '/app'),
      fs.realpathSync(__dirname + '/node_modules/my-repo/lib'),
    ];

    And then later:

    module: {
        loaders: [{
          test: /\.js?$/,
          include: includePaths,
          loader: 'babel'
        }, {
          test: /\.jsx?$/,
          include: includePaths,
          loader: 'babel'
        },{
          test: /\.json?$/,
          loader: 'json'
        }, {
          test: /\.css$/,
          loader: 'style!css?modules&localIdentName=[name]---[local]---[hash:base64:5]'
        }]
      },
  5. I got this to work by setting the includePaths but also by setting both resolve.root and resolveLoader.root to path.resolve(__dirname, 'node_modules') (or wherever you want those external sources to be able to resolve modules). @jraede I think that worked for you only because your include paths both had node_modules in an ancestor directory. You need to set both so files external to your project that you want to import can themselves (a) import other modules from your project’s node_modules, and (b) so your loaders can be resolved (otherwise you get cannot resolve module ‘babel’, etc).

    
      resolve: {
        alias: { src: srcPath, common: commonPath },
        extensions: ['', '.js', '.scss', '.json'],
        root: [path.resolve(__dirname, 'node_modules')]
      },
    
      resolveLoader: {
        root: [path.resolve(__dirname, 'node_modules')]
      },
    
    
  6. Trying to remove the emotion here, but this really needs to be fixed: Ticket still unresolved for 68 weeks…

  7. Updating followers of this ticket:

    I ditched the symlink approach; instead, I created another node module which compiles on its own with babel that is locally linked. That package has this in package.json:

    "name": "awesome-module",
    "main": "lib/index.js",
    "scripts": {
      "build:clean": "rimraf dist lib",
      "build:ensure": "mkdir -p lib",
      "build:js": "npm run build:ensure && babel -d lib/ src/ -s inline",
      "build": "npm run build:clean && npm run build:ensure && npm run build:js",
      "watch:js": "npm run build:js -- -w",
      "watch": "npm run build && npm run watch:js",
      "postinstall": "npm run build",
      // ...
    }

    And src/index.js etc.

    Then execute npm link in that dir, which registers the module globally on my machine, and npm link awesome-module in my initial module. That way, webpack isn’t responsible for that module.

    Also running npm run watch to have files updated on save.

  8. @Undistraction correct, but the idea is to have webpack only include the other module without transpiling it with babel-loader. It’s already compiled by babel on its own, and looks like any other ES5 module.

  9. I am on the latest webpack 2.11.1 and latest wds. These lines allow me to use my file:.. linked packages in package.json for local dev symlinked and have them update when I change it. The key is the path.resolve you want to make sure you point it to the TOP and only the top node_modules.

               modules: [
                    path.resolve(path.join(__dirname, 'node_modules'))
                ],
                symlinks: true
    
  10. I figured out that babel-loader can not resolve modules outside of the project. For example I am using lerna@3 and webpack@4.41.2. After debugging I ended up that @babel/parser is responsible for the “issue” (I do not think it’s an issue, more a CWD problem) because the plugins and loaders could not be resolved to node_modules. There is also an interesting article about that in the babel configuration: https://babeljs.io/docs/en/config-files#monorepos

    However, after moving all my babel configs (originally from package.json#babel) to my webpack.config.js it works without any problems:

    // [...]
    {
        test: /\.tsx$/,
        exclude: /(disposables)/,
        use: {
            loader: "babel-loader?cacheDirectory",
            options: require("./package.json")).babel
        }
    }
    // [...]

    References:

Comments are closed.