14

I have a multi-package project set up, where I have one JavaScript package that relies on a TypeScript library. Initially I installed Sinopia and was reinstalling the library every time I made changes to it. Then I saw npm link and thought that it would be easier for development. Unfortunately, when I linked the library (using npm link ../typescript-package) and built, it gives an error:

ERROR in ../typescript-package/dist/index.js
Module build failed: Error: No ESLint configuration found.

Since they are separate packages, I'm not quite sure why Webpack is trying to apply eslint to this package. Here is my webpack.common.js file (using merge and the dev vs prod configs shouldn't matter):

// webpack.common.js
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const babelOptions = {
  presets: ['react', 'es2015', 'stage-0'],
  sourceMaps: true,
  retainLines: true,
};

module.exports = {
  entry: {
    solver: './source/index.jsx',
  },
  output: {
    path: `${__dirname}/dist`,
    filename: '[name].js',
    publicPath: '/dist/',
  },
  resolve: {
    modules: ['source', 'node_modules/'],
    extensions: ['.js', '.jsx', '/index.jsx', '.json', '.ts', '/index.ts', '.scss', '/index.scss', '.css'],
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: [
          {
            loader: 'babel-loader',
            options: babelOptions,
          },
          {
            loader: 'eslint-loader',

            options: {
              emitWarnings: true,
            },
          },
        ],
        exclude: /node_modules/,
      }, {
        test: /\.js$/,
        loader: 'source-map-loader',
        enforce: 'pre',
        exclude: /node_modules/,
      }, {
        test: /\.scss$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: [{
            loader: 'css-loader',
            options: {
              minimize: true,
              localIdentName: '[local]_[hash:base64:5]',
            },
          }, {
            loader: 'sass-loader',
            options: {
              includePaths: ['source/design'],
            },
          }],
        }),
      },
    ],
  },
  plugins: [
    new ExtractTextPlugin({
      filename: '[name].css',
      allChunks: true,
    }),
  ],
  node: {
    global: true,
  },
};

I can also provide other config or package.json files if need be.

iHowell
  • 2,263
  • 1
  • 25
  • 49

3 Answers3

5

Way 1 - Webpack recommendation

According to webpack doc : https://webpack.js.org/configuration/module/#rule-conditions

Be careful! The resource is the resolved path of the file, which means symlinked resources are the real path not the symlink location. This is good to remember when using tools that symlink packages (like npm link), common conditions like /node_modules/ may inadvertently miss symlinked files. Note that you can turn off symlink resolving (so that resources are resolved to the symlink path) via resolve.symlinks.

So according to it you can disable symlink : https://webpack.js.org/configuration/resolve/#resolvesymlinks

Way 2 - Fancy hack

But maybe you need symlinks for your project. So, I use my eslint rule like this :

{
  test: /\.js$/,
  enforce: 'pre',
  use: 'eslint-loader',
  include: path.resolve(__dirname), // <-- This tell to eslint to look only in your project folder
  exclude: /node_modules/
}

Plus obviously your own config of this loader.

Matthias
  • 13,607
  • 9
  • 44
  • 60
HollyPony
  • 817
  • 9
  • 15
1

I was dealing with this, as well. I'm not exactly sure why ESLint is looking for the config file in the external package (I would expect the local rc file to be adequate) but the symlink created by npm link takes the external package out of ./node_modules/, which otherwise would have been excluded by the loader.

The fix I've come up with is to copy the package into ./node_modules/. It then gets filtered out through the excludes rule in your Webpack config.

I know this is incredibly inelegant, and shouldn't be "good enough", but I've spent some time trying to get around this issue, and this is the best I was able to come up with. Until something better comes along, you can at least get moving on more pressing issues.

  • Maybe this should be filed under an issue for webpack. Not sure at the moment. I will mark this as correct though, since it does 'solve' the issue. Currently, my solution is to use the packag `install-local`, which helps with installing local packages as if they were published. – iHowell Jan 31 '18 at 02:48
  • I haven't dug into anything, so this isn't going to be _super_ helpful, but... is it web pack, the eslint-loader plugin, npm, or node itself? Is Webpack parsing the `excludes` option? Is the plugin parsing out the path of the module so that it follows the symlink? Does node's `fs` module allow for such control? Should npm's `link` work differently? Etc. etc. – John Arthur Feb 02 '18 at 18:08
  • I'm pretty sure that it is resolving the excludes correctly, but it deals with the absolute path. The current work around I'm doing is using the `install-local` package to locally install packages instead of `npm link` or `npm install`. – iHowell Feb 05 '18 at 17:50
  • Thanks @iHowell, using `npx install-local ../upstream/electron-debug` allowed me to install my locally checked out (and modified) version of a package without running into the eslint issue. – Motin Jul 20 '18 at 21:19
  • 1
    Disabling `resolve.symlinks` in WebPack may help. There's related discussion here: https://github.com/webpack/webpack/issues/943 – fefrei Nov 02 '18 at 13:49
0

You can also add a .eslintignore file and add the real path to the linked module

// Content of .eslintignore
C:/path/to/your/linked/module

This is needed, because webpack resolves the module by its real path and not by the path in the node_modules folder (see webpack docs). Usually eslint ignores node_modules by default, but because of that it does not work here.

Beat
  • 4,386
  • 2
  • 35
  • 52