gaearon / react-transform-hmr

A React Transform that enables hot reloading React classes using Hot Module Replacement API
772 stars 57 forks source link

locals[0] does not appear to be a `module` object with Hot Module replacement API enabled #5

Closed bkniffler closed 9 years ago

bkniffler commented 9 years ago

Hi, I've installed 1.0.0, I've copy&pasted .babelrc from the examples and I'm using babel-loader with webpack as adviced, all in my dev environment, but I'm getting said error as soon as I'm running the whole thing. Whereas, the previous version worked.

Is there anything not yet documented I'm missing?

bkniffler commented 9 years ago

I just discovered the bootstrap you provided https://github.com/gaearon/react-transform-boilerplate and it seems to work. I'll check whats different on my end.

bkniffler commented 9 years ago

Seems like my https://github.com/reactjs/express-react-views templates are causing these errors with react-transform-hmr.

gaearon commented 9 years ago

Please provide a project reproducing the problem. Otherwise it's hard to guess why module.hot isn't available.

gaearon commented 9 years ago

One thing to look out for is that you shouldn't transform node_modules with babel-loader. Transform just your code with include option on the loader.

catamphetamine commented 9 years ago

I'm having this too. "react-transform-webpack-hmr" doesn't have it though.

bkniffler commented 9 years ago

Its because of the recent changes in version 1.0.0. And for me it seems like the problem appears since, as @gaearon supposed, I got files in custom modules that are transformed by babel-loader.

MrEfrem commented 9 years ago

@gaeron i have same error but completed your recommendations.

MrEfrem commented 9 years ago

Repo:

https://github.com/MrEfrem/react-redux-starter-kit

Execute app:

npm run compile && npm run server:start

Out in console:

...
[2] /home/user/react-redux-starter-kit/dist/server/index.js:1269
[2] k like React.');}if(!hot || typeof hot.accept !== 'function'){throw new Error(
[2]                                                                     ^
[2] Error: locals[0] does not appear to be a `module` object with Hot Module replacement API enabled. You should disable react-transform-hmr in production by using `env` section in Babel configuration. See the example in README: https://github.com/gaearon/react-transform-hmr
[2]     at proxyReactComponents (/home/user/react-redux-starter-kit/dist/server/index.js:4574:12)
[2]     at Object.<anonymous> (/home/user/react-redux-starter-kit/dist/server/index.js:14774:65)
[2]     at Object.module.exports.Object.defineProperty.value (/home/user/react-redux-starter-kit/dist/server/index.js:14827:31)
[2]     at __webpack_require__ (/home/user/react-redux-starter-kit/dist/server/index.js:21:30)
[2]     at Object.module.exports.Object.defineProperty.value (/home/user/react-redux-starter-kit/dist/server/index.js:14918:27)
[2]     at __webpack_require__ (/home/user/react-redux-starter-kit/dist/server/index.js:21:30)
[2]     at Object.<anonymous> (/home/user/react-redux-starter-kit/dist/server/index.js:14685:16)
[2]     at __webpack_require__ (/home/user/react-redux-starter-kit/dist/server/index.js:21:30)
[2]     at Object.<anonymous> (/home/user/react-redux-starter-kit/dist/server/index.js:71:19)
[2]     at __webpack_require__ (/home/user/react-redux-starter-kit/dist/server/index.js:21:30)
[2] npm
[2]  
[2] ERR! Linux 3.16.7-24-desktop
[2] npm
[2]  ERR! 
[2] argv "/usr/bin/node" "/usr/bin/npm" "run" "server:start" "--" "--nw"
[2] npm ERR!
[2]  node v0.12.7
[2] npm ERR! npm  v2.11.3
[2] npm ERR! code ELIFECYCLE
[2] npm ERR!
[2]  bankdocs-js@0.13.0 server:start: `node --harmony bin/server "--nw"`
[2] npm
[2]  ERR! Exit status 1
[2] npm ERR!
...
gaearon commented 9 years ago

Don't enable the transform in the Node server build. Most other React Transforms don't expect to be invoked on server either so it's good to fail early.

catamphetamine commented 9 years ago

@gaearon Why can't one use babel in webpack configuration? Is it prohibited somewhere?

gaearon commented 9 years ago

I'm not sure I understand the question.

You can configure Babel plugin either in .babelrc with env option (corresponds to BABEL_ENV or NODE_ENV, whichever is set), or in your build tool setup (for example babel-loader for Webpack lets you pass configuration as an object to "query" field).

catamphetamine commented 9 years ago

my locals array looks like this:

@@@@@@@@@@@@ [ { id: 'G:\\work\\cinema\\code\\client\\html.js',
    exports: { __esModule: true },
    parent:
     { id: 'G:\\work\\cinema\\code\\server\\webpage rendering.js',
       exports: [Object],
       parent: [Object],
       filename: 'G:\\work\\cinema\\code\\server\\webpage rendering.js',
       loaded: false,
       children: [Object],
       paths: [Object] },
    filename: 'G:\\work\\cinema\\code\\client\\html.js',
    loaded: false,
    children: [ [Object], [Object], [Object], [Object] ],
    paths:
     [ 'G:\\work\\cinema\\code\\client\\node_modules',
       'G:\\work\\cinema\\code\\node_modules',
       'G:\\work\\cinema\\node_modules',
       'G:\\work\\node_modules',
       'G:\\node_modules' ] } ]

Is it good?

catamphetamine commented 9 years ago

It's the error i get when running the server. I guess hot module replacement is not intended for use on the server. But .babelrc should be uniform therefore it's a single file. You should fix this plugin to not run on the server while there is NODE_ENV = development

catamphetamine commented 9 years ago

My solution is as follows:

{
    "stage"    : 0,
    "optional" : "runtime",
    "loose"    : "all",
    "plugins":
    [
        "typecheck"
    ],
    "env":
    {
        "development/client":
        {
            "plugins":
            [
                "typecheck",
                "react-transform"
            ],
            "extra":
            {
                "react-transform":
                [{
                    "target"  : "react-transform-hmr",
                    "imports" : ["react"],
                    "locals"  : ["module"]
                }]
            }
        }
    }
}
configuration.plugins = configuration.plugins.concat
(
    // environment variables
    new webpack.DefinePlugin
    ({
        'process.env':
        {
            NODE_ENV: JSON.stringify('development'),
            BABEL_ENV: JSON.stringify('development/client')
        },
...

With this configuration it works, but they've made a mistake by using JSON instead of Javascript in their .babelrc file.

gaearon commented 9 years ago

With this configuration it works, but they've made a mistake by using JSON instead of Javascript in their .babelrc file.

Maybe, but that would be up to Babel. Maybe you can file an issue there (unless one already exists).

catamphetamine commented 9 years ago

@gaearon Nah, they obviously won't listen to a stranger with no history of commits. The thing is Babel requires Node.js so why not make the configuration non-declarative like they did in Webpack.

By the way, I didn't find a way to stop Babel from loading the default .babelrc, so my approach with custom .babelrc.server didn't work. The custom BABEL_ENV is the only one that worked.

gaearon commented 9 years ago

If you use Webpack on client, you can put React Transform configuration there. For example see this React Native example using babel-loader's configuration query field. This way you can share .babelrc between client and server.

catamphetamine commented 9 years ago

@gaearon hmmm, actually, that would be a better solution. I'll use it.

aulizko commented 9 years ago

That's really strange. After running some test cases it looks like this error appears wherever I use any babel-related stuff on the server, like require('babel/register'). I didn't even start nor webpack-dev-server nor webpack-dev-middleware + webpack-hot-middleware, just bare express instance that is intended to run React on the server-side. It's really confusing that example at Readme recommends not-the-best(bulletproof?) way. Anyway, @halt-hammerzeit, @gaearon, thanks for discussion, I have everything up and running now. I suggest to add some clarification about how to use this plugin with projects that heavily rely on server-side (I mean universal apps here too).

catamphetamine commented 9 years ago

@aulizko yes, that's a new feature of babel so I recommend removing .babelrc way from the README http://babeljs.io/blog/2015/03/31/5.0.0/#babelrc

gaearon commented 9 years ago

It's really confusing that example at Readme recommends not-the-best(bulletproof?) way.

You can always make a PR to recommend the right way. :wink: Open source projects need help, especially in documentation.

catamphetamine commented 9 years ago

@gaearon but there's always the project owner factor where the project owner should say "yes, do it" otherwise noone's gonna merge your PR. so I woudn't submit such a PR blindly. if the project owner says "aaah, that's actually a good idea, username!" only then a stranger should start thinking about contributing.

catamphetamine commented 9 years ago

@gaearon by the way you've got a bunch of cool projects here. not Holowaychuk level of course but still a lot of development efforts. so that you know we appreciate your contribution to the progression of society.

ferdinandsalis commented 9 years ago

@gaearon I think you are awesome. Whatever level that is.

gaearon commented 9 years ago

I believe the change itself is for the better so that's why I released it. However configuring Babel is something you know better than me: you have real apps with different requirements and you are a better judge of how to make this change work in your project and what best practices are. That's what I'm trying to say: I can't document the best approach because I don't know it. If you know a better approach than the docs say, submit a PR and let's discuss it.

catamphetamine commented 9 years ago

okay, I propose some kind of this textual addition to the readme:

## React

If you're rendering React both on client and server then you should add `react-transform` plugin to your `babel-loader` configuration
...
  module: {
    loaders: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel',
      query: {
        stage: 0,
        plugins: []
      }
    },
    ...]
  },
...

// enable React Hot loader
if (process.env.HOT) {
  config.module.loaders[0].query.plugins.push('react-transform');
  config.module.loaders[0].query.extra = {
    'react-transform': [{
      target: 'react-transform-hmr',
      imports: ['react'],
      locals: ['module']
    }]
  };
}

Otherwise, if you're not using React on server side, you can just edit your .babelrc to include extra.babel-plugin-react-transform.
...

That's my idea of updating the Readme but most likely you'll want to change this somehow.

eriknyk commented 9 years ago

that's not working for me, I have a webpack config especial for HMR

 {
  devtool: 'eval',
  entry: [
    'webpack-hot-middleware/client',
    './client.js'
  ],
  output: {
    path: path.join(__dirname, 'public/js/'),
    filename: 'bundle.js',
    publicPath: '/js/'
  },
  module: {
    loaders: [{
      test: /\.(js|jsx)$/,
      exclude: /node_modules/,
      loader: 'babel',
      query: {
        stage: 0,
        plugins: [
          'react-transform'
        ],
        extra: {
          'react-transform': [{
            target: 'react-transform-hmr',
            imports: ['react'],
            locals: ['module']
          }]
        }
      }
    }]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin()
  ],
  progress: true,
  resolve: {
    extensions: ['', '.js', '.jsx']
  }
}

and my .babelrc

{
  "stage": 0,
  "loose": [
    "es6.modules",
    "es6.classes",
    "es7.classProperties"
  ],
  "optional": [ "es7.classProperties", "es7.exportExtensions" ],
  "env": {
    "development": {
      "plugins": ["react-transform"],
      "extra": {
        "react-transform": [{
          "target": "react-transform-hmr",
          "imports": ["react"],
          "locals": ["module"]
        }, {
          "target": "react-transform-catch-errors",
          "imports": ["react", "redbox-react"]
        }]
      }
    }
  }
}

still getting

/Users/erik/towbook/isomorphic-app-hmr/node_modules/react-transform-hmr/lib/index.js:51
    throw new Error('locals[0] does not appear to be a `module` object with Hot Module ' + 'replacement API enabled. You should disable react-transform-hmr in ' + 'production by using `env` section in Babel configuration. See the ' + 'example in README: https://github.com/gaearon/react-transform-hmr');
    ^

Error: locals[0] does not appear to be a `module` object with Hot Module replacement API enabled. You should disable react-transform-hmr in production by using `env` section in Babel configuration. See the example in README: https://github.com/gaearon/react-transform-hmr
    at Object.proxyReactComponents [as default] (/Users/erik/towbook/isomorphic-app-hmr/node_modules/react-transform-hmr/lib/index.js:51:11)
    at Object.<anonymous> (/Users/erik/towbook/isomorphic-app-hmr/components/Nav.jsx:4:36)
    at Module._compile (module.js:434:26)
    at normalLoader (/Users/erik/towbook/isomorphic-app-hmr/node_modules/babel/node_modules/babel-core/lib/api/register/node.js:199:5)
    at Object.require.extensions.(anonymous function) [as .jsx] (/Users/erik/towbook/isomorphic-app-hmr/node_modules/babel/node_modules/babel-core/lib/api/register/node.js:216:7)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Module.require (module.js:365:17)
    at require (module.js:384:17)
    at Object.<anonymous> (/Users/erik/towbook/isomorphic-app-hmr/components/Application.jsx:23:1
catamphetamine commented 9 years ago

@eriknyk so you don't have .babelrc file in your project?

eriknyk commented 9 years ago

I have it, that why it is confusing me, I need setup both or just one?

my .babelrc

{
  "stage": 0,
  "loose": [
    "es6.modules",
    "es6.classes",
    "es7.classProperties"
  ],
  "optional": [ "es7.classProperties", "es7.exportExtensions" ],
  "env": {
    "development": {
      "plugins": ["react-transform"],
      "extra": {
        "react-transform": [{
          "target": "react-transform-hmr",
          "imports": ["react"],
          "locals": ["module"]
        }, {
          "target": "react-transform-catch-errors",
          "imports": ["react", "redbox-react"]
        }]
      }
    }
  }
}
catamphetamine commented 9 years ago

@eriknyk yep what? do you have .babelrc in your project or you don't?

eriknyk commented 9 years ago

I have a .babelrc file on my project

catamphetamine commented 9 years ago

@eriknyk delete it and try to run your project again. then tell me that it works now.

eriknyk commented 9 years ago

this is my example proj.

https://github.com/eriknyk/isomorphic-app-hmr

catamphetamine commented 9 years ago

@eriknyk see my comment above ^^^

eriknyk commented 9 years ago

@halt-hammerzeit it worked, thanks you!

delete it and try to run your project again. then tell me that it works now.

but it means that now we can't use .babelrc? ... I was using it and everything was working fine before,.. after I updated the reference when react-transform-webpack-hmr was renamed to react-transform-hmr, it stops working.

Best regards.

catamphetamine commented 9 years ago

@eriknyk you can still use .babelrc as long as you don't enable react-transform-hmr plugin there. the root cause is that when you do require('babel/register') in your server-side code it loads .babelrc and if react-transform-hmr is enabled there then it enables react-transform-hmr on the server where there's no "hot reload" hence the error.

eriknyk commented 9 years ago

ok, thank you for your answers @halt-hammerzeit

aulizko commented 9 years ago

@eriknyk, @halt-hammerzeit, @gaearon I spent a day thinking about this problem with .babelrc and now I think that it's actually good that we can't store hmr plugin config inside of .babelrc. Think yourself: it actually make sence to store your configuration inside your webpack/browserify config so that it explicitely tells you what is going on with your development/production build in one place. And it was by far not so good when we have to store half of the configuration inside of webpack.config.js and other half inside the different file like .babelrc. I mean it should be really confusing for a new member of the team when he would try to grok project structure. Like webpack.config.js contains webpack-hot-middleware/client, but other half of the hot-reload contains in the .babelrc. Not-intuitive, error-prone solution, I think.

But now it is good.

You should store everything about your development configuration inside of webpack.config.js. And .babelrc would keep only all-project-related configuration for babel. Like, I dunno, stage: 0.

It is always good to have one and only one file that contains all configuration details for one domain-specific problem. IMO.

catamphetamine commented 9 years ago

what he said ^^^^^

bkniffler commented 9 years ago

Great input, thanks for the suggestion concerning the webpack.config.js and deleting .babelrc, it works perfectly for my dev environment.

module: {
    loaders: [
        {
            test: /\.js$|\.jsx$|\.es6$|\.babel$/,
            loader: 'babel',
            query: {
                stage: 0,
                plugins: ['react-transform'],
                extra: {
                "react-transform": [{
                    "target": "react-transform-hmr",
                    "imports": ["react"],
                    "locals": ["module"]
                }, {
                    "target": "react-transform-catch-errors",
                    "imports": ["react", "redbox-react"]
                }]
            }
        }
    }]
}
greypants commented 8 years ago

Confirming that killing the .babelrc file in favor of configuring in the webpack babel loader fixes the issue. The config format changed a little bit since @bkniffler posted above, so here's what a working setup currently looks like:

module: {
  loaders: [
    {
      test: /\.jsx?$/,
      loader: 'babel',
      include: path.join(process.cwd(), config.root.src, config.tasks.js.src), // wherever your source js lives
      exclude: /node_modules/,
      query: {
        "stage": 0,
        "plugins": ["react-transform:after"],
        "extra": {
          "react-transform": {
            "transforms": [{
              "transform": "react-transform-hmr",
              "imports": ["react"],
              "locals": ["module"]
            }, {
              "transform": "react-transform-catch-errors",
              "imports": ["react", "redbox-react"]
            }]
          }
        }
      }
    }
  ]
}

UPDATE: Added :after to "plugins": ["react-transform:after"] See https://github.com/gaearon/babel-plugin-react-transform/issues/19#issuecomment-147755452 for details.

luandro commented 8 years ago

thanks @greypants

svnm commented 8 years ago

Sorry @greypants your webconfig did not work for me, but @bkniffler's did work fine. Why was your config using react-transform:after instead of react-transform?

My example of using react-transform based on @gaearon's example. This works well in prod and dev, with different webconfig and a different express server for dev and prod.

Thanks for your help @halt-hammerzeit, I also agree that this better alternative version of running react-transform-hmr should be updated in the README, I am happy to add a PR.

greypants commented 8 years ago

@StevenIseki without :after, class names are lost in the debug output, and instead you'll see ProxyClass everywhere (detailed in the issue I referenced in my comment). The config I posted is for the latest versions. Syntax changed a bit. Also be sure to replace include and exclude with your own paths (or remove them altogether—they're optional). The ones in that config are specific to my setup.

svnm commented 8 years ago

Thanks for the tip on the classes @greypants that makes sense now. It was more likely the include, exclude which caused the error.

creeperyang commented 8 years ago

Things changed with babel6. I still have this problem with babel@6.4, babel-plugin-react-transform@2.0 and react-transform-hmr@1.0.1.

gaearon commented 8 years ago

Things changed with babel6. I still have this problem with babel@6.4, babel-plugin-react-transform@2.0 and react-transform-hmr@1.0.1.

What exactly changed? The problem is that you're either enabling the transform in environments other than development, or you are compiling for production with a dev/empty environment. This was the cause of the problem before, and it is the cause of the problem now. How did this change?

creeperyang commented 8 years ago

@gaearon wow, I have this problem because I comment // new webpack.HotModuleReplacementPlugin() :joy: So it's all right besides query: {stage:0, xxx} is not valid setting with babel6.

However, I found my app wont update even there is log:

[WDS] Hot Module Replacement enabled.
[WDS] App updated. Recompiling...
[WDS] App hot update...
[WDS] App updated. Recompiling...
[WDS] App hot update...
hiddaorear commented 8 years ago

Hi, try this: webpack.config.js: devServer: { historyApiFallback: true, inline: true, hot: true, progress: true } and package.json: "scripts": { "dev": "webpack-dev-server --progress --hot --profile --colors" }

hot is the key.

gaearon commented 8 years ago

None of this should matter in React Hot Loader 3. I know React Transform has been a configuration hell; hopefully, this should be solved. See https://github.com/gaearon/react-hot-boilerplate/pull/61 if you’d like to try it!