Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symlinking react modules with npm link for local development gives error

During development of my React npm module, I symlinked it with npm link. After doing this, the package gets linked correctly and also appears in the consumers app node_modules.

The module exposes an interface to create a React component. Because I'm using React, jsx and es2015, I'm using babel to transpile my module code in the pre publishing stage, using the npm prepublish hook.

However, when I try to build my consumer app with webpack (i.e. after linking it) an error occurs in my package stating:

Module build failed: Error: Couldn't find preset "es2015"

Now the funny part is that if I publish the package on npm, then npm install from the registry in my consumer app, build it, everything works fine.

I tried installing the babel-preset-es2015 in my consumer app, but then it starts complaining about not finding babel:

Module not found: Error: Cannot resolve module 'babel'

Again, if I install it from the npm registry everything works fine, no errors are thrown during build.

I also tried installing babel-core, babel-cli and babel-polyfill, all to no avail.

I'm using babel v6.1.x everywhere and aware of all the recent changes, however I guess I'm missing something obvious and would really appreciate it if someone can help me out, because continuously publishing the module in order to test if stuff works is just bad practice.

For completeness sake here is the code:

  • module
  • consumer app

These are the steps I follow to link the module:

  1. cd ~/Sites/me/react-leafbox
  2. npm link
  3. cd ~/Sites/me/mapp
  4. npm link react-leafbox
  5. npm start

Stack trace after building:

ERROR in ../react-leafbox/lib/index.js
Module build failed: Error: Couldn't find preset "es2015"
    at OptionManager.mergePresets (/Users/daniel/Sites/me/mapp/node_modules/babel-core/lib/transformation/file/options/option-manager.js:329:17)
    at OptionManager.mergeOptions (/Users/daniel/Sites/me/mapp/node_modules/babel-core/lib/transformation/file/options/option-manager.js:289:12)
    at OptionManager.addConfig (/Users/daniel/Sites/me/mapp/node_modules/babel-core/lib/transformation/file/options/option-manager.js:223:10)
    at OptionManager.findConfigs (/Users/daniel/Sites/me/mapp/node_modules/babel-core/lib/transformation/file/options/option-manager.js:366:16)
    at OptionManager.init (/Users/daniel/Sites/me/mapp/node_modules/babel-core/lib/transformation/file/options/option-manager.js:410:12)
    at File.initOptions (/Users/daniel/Sites/me/mapp/node_modules/babel-core/lib/transformation/file/index.js:191:75)
    at new File (/Users/daniel/Sites/me/mapp/node_modules/babel-core/lib/transformation/file/index.js:122:22)
    at Pipeline.transform (/Users/daniel/Sites/me/mapp/node_modules/babel-core/lib/transformation/pipeline.js:42:16)
    at transpile (/Users/daniel/Sites/me/mapp/node_modules/babel-loader/index.js:14:22)
    at Object.module.exports (/Users/daniel/Sites/me/mapp/node_modules/babel-loader/index.js:83:14)
 @ ./src/js/components/App.jsx 2:10-34

Stack trace after adding extra babel related dependencies (which I believe should't be necessary, because they're available in the react-leafbox module):

ERROR in ../react-leafbox/lib/index.js
Module not found: Error: Cannot resolve module 'babel' in /Users/daniel/Sites/me/react-leafbox/lib
 @ ../react-leafbox/lib/index.js 8:11-39

I'm using node v5.0.0 with npm v3.3.6 on MAC OSX El Capitan v10.11.1. I also tried using node v4.2.1 with npm 2.14.7, which gives me the same errors.

like image 938
danillouz Avatar asked Nov 14 '15 17:11

danillouz


1 Answers

I found a solution to my problem. I discovered this in the webpack docs:

IMPORTANT: The loaders here are resolved relative to the resource which they are applied to. This means they are not resolved relative the the configuration file. If you have loaders installed from npm and your node_modules folder is not in a parent folder of all source files, webpack cannot find the loader. You need to add the node_modules folder as absolute path to the resolveLoader.root option. (resolveLoader: { root: path.join(__dirname, "node_modules") })

After adding the root option to the webpack.config.js the error about not being able to resolve babel disappeared. Instead I got a new one saying it can’t resolve react. I have it defined as a peer dependency, which made me think it needs to fallback when it can’t find it locally, then I found this in the docs:

resolve.fallback A directory (or array of directories absolute paths), in which webpack should look for modules that weren’t found in resolve.root or resolve.modulesDirectories.

I combined these two options in the webpack.config.js of my consumer app and it worked!

// webpack.config.js
var path = require('path');

module.exports = {

    entry: path.resolve(__dirname, 'src/js/index.js'),

    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: "build.js"
    },

    module: {
        loaders: [
            {
                test: /\.jsx?$/,
                exclude: /(node_modules)/,
                loader: 'babel',
                query:
                    {
                        presets:[ 'react', 'es2015' ]
                    }
            }
        ]
    },

    resolve: {
        extensions: [ '', '.js', '.jsx' ],
        fallback: path.join(__dirname, "node_modules")
    },


    resolveLoader: {
        root: path.join(__dirname, "node_modules")
    }
};

I hope this helps anyone coming across a similar issue.

Update for Webpack ^2.5.0

Remove the resolveLoader Object and replace resolve.fallback with resolve.symlinks set to false:

resolve: {
    extensions: [ '', '.js', '.jsx' ],
    symlinks: false
}
like image 156
danillouz Avatar answered Nov 01 '22 15:11

danillouz