Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

importing .jsx module from Engine, Webpacker 3, Rails 5.1.4 #786

Closed
1 of 4 tasks
tomasc opened this issue Sep 20, 2017 · 11 comments
Closed
1 of 4 tasks

importing .jsx module from Engine, Webpacker 3, Rails 5.1.4 #786

tomasc opened this issue Sep 20, 2017 · 11 comments

Comments

@tomasc
Copy link

tomasc commented Sep 20, 2017

Help us help you! Please choose one:

  • My app crashes with react-rails, so I've included the stack trace and the exact steps which make it crash.
  • My app doesn't crash, but I'm getting unexpected behavior. So, I've described the unexpected behavior and suggested a new behavior.
  • I'm trying to use react-rails with another library, but I'm having trouble. I've described my JavaScript management setup (eg, Sprockets, Webpack...), how I'm trying to use this other library, and why it's not working.
  • I have another issue to discuss.

I am trying to import .jsx components from Rails engine.

Engine

In the engine I have added simple HelloWorld.jsx under app/javascript/components:

import React from 'react'

class HelloWorld extends React.Component {
  render() {
    return <div>HELLO WORLD</div>;
  }
}

export default HelloWorld;

App

And in the main app (Webpacker 3, Rails 5.1.4, unreleased react-rails coming from master branch):

  • updated resolved_paths: ['engine/app/javascript'] in webpacker.yml
  • added Engine.jsx under javascript/component that contains:
import HelloWorld from 'components/HelloWorld'

Then in my application.html.erb, I added the javascript_pack_tag 'application' and tried to load the react component:

<%= react_component 'Engine.HelloWorld' %>

It seems the component is being found, but the .jsx preprocessor is not being recognised/applied, as I am getting the following error:

fromRequireContextWithGlobalFallback.js?7c97:19 Error: Module build failed: SyntaxError: Unexpected token (5:11)

  3 | class HelloWorld extends React.Component {
  4 |   render() {
> 5 |     return <div>HELLO WORLD</div>;
    |            ^
  6 |   }
  7 | }
  8 | 


    at eval (107:1)
    at Object.<anonymous> (application-a71cca030c96f6cdcea4.js:1376)
    at __webpack_require__ (application-a71cca030c96f6cdcea4.js:20)
    at eval (Engine.jsx?76a9:1)
    at Object.<anonymous> (application-a71cca030c96f6cdcea4.js:783)
    at __webpack_require__ (application-a71cca030c96f6cdcea4.js:20)
    at webpackContext (application-a71cca030c96f6cdcea4.js:1173)
    at eval (fromRequireContext.js?f05c:13)
    at Object.eval [as getConstructor] (fromRequireContextWithGlobalFallback.js?7c97:13)
    at Object.mountComponents (index.js?0542:82)

Am I doing something wrong, or is this a bug?

@rmosolgo
Copy link
Member

When using Webpacker, react-rails does not automatically convert JSX. Instead, it leaves this repsonsiblity to babel & your webpack config. So, you should convert JS as part of your webpack setup, for example, with webpackers React integration: https://github.com/rails/webpacker#react

Did you add any JSX converter to your webpack setup?

@tomasc
Copy link
Author

tomasc commented Sep 20, 2017

@rmosolgo yes, I have a default webpacker react config (after running rails generate react:install). .jsx files that are not coming from the additional directory (ie 'engine/app/javascript') are transformed without any issues.

@BookOfGreg BookOfGreg changed the title importing .jsx module, Webpacker 3, Rails 5.1.4 importing .jsx module from Engine, Webpacker 3, Rails 5.1.4 Oct 11, 2017
@BookOfGreg
Copy link
Member

rails/webpacker#21

This seems a pretty relevant PR on Webpacker.
I can't see any linked PR from that or linked discussions that solved it for Webpacker (maybe I haven't followed it deep enough though)
Once there is a way to do it in Webpacker, that can be rolled into (or documented for) this gem.

@tomasc
Copy link
Author

tomasc commented Oct 25, 2017

@BookOfGreg yes, although I follow the closing argument there and have solved the issue by making a a package.json in my engine for JS only and yarn add it to the main app as a package coming from private GitHub repo. You can then yarn link that package in your app for local development, and things work fine.
I guess it's just a matter of having a clear convention for dealing with JS coming from engines.

@BookOfGreg
Copy link
Member

BookOfGreg commented Oct 25, 2017

I suppose a part of the problem is Webpack won't have access to the 'invisible' gem files like Sprockets would, so it would be impossible to to compile them.

The engine could hypothetically do something like have a rake task that generates a compiled JS in the parent's JS directory when it gets installed, similar to how the Devise engine dumps it's views in the parent if needed.

I could document both solutions in the wiki once I get onto that task.

@tomasc
Copy link
Author

tomasc commented Oct 25, 2017

@BookOfGreg , though the 'dumping' sounds awful ;-).

Gem's own package.json works just fine. One just needs to add a bit of config for webpack and build the JS per release, eventually push to NPM.

In the engine, my webpack.config.js looks like this (I am using CoffeeScript 2, you might want to alter the config for .jsx etc.):

const path = require('path');
const webpack = require('webpack')

module.exports = {
  module: {
    rules: [
      {
        test: /\.coffee$/,
        use: ['babel-loader', 'coffee-loader']
      }
    ]
  },
  entry: './package/src/index.js',
  output: {
    library: '@tomasc/myengine',
    libraryTarget: 'umd',
    umdNamedDefine: true,
    filename: 'index.js',
    path: path.resolve(__dirname, 'package/dist')
  },
  resolve: {
    extensions: ['.coffee', '.js']
  }
};

So far I located all the JS under /package/src, but it might make more sense to pull the source directly from app/javascript

The package.json looks like this, basically:

{
  "name": "@tomasc/myengine",
  "version": "1.0.0",
  "description": "",
  "main": "package/dist/index.js",
  "files": [
    "package"
  ],
  "repository": {
    "type": "git",
    "url": "git+https://github.com/tomasc/myengine.git"
  },
  "author": "",
  "license": "",
  "homepage": "",
  "scripts": {
    "build": "webpack"
  },
  "dependencies": {
    "@rails/webpacker": "^3.0.1",
    "babel-preset-react": "^6.24.1",
    "coffee-loader": "^0.8.0",
    "coffeescript": "^2.0.1",
    "prop-types": "^15.5.10",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "webpacker-react": "^0.3.2"
  },
  "devDependencies": {
    "babel-preset-env": "^1.6.0",
    "babel-preset-es2015": "^6.24.1",
    "webpack-dev-server": "^2.8.2"
  }
}

You can then yarn link this package to your app, ev. run yarn build --watch in the engine to have the code re-compiled on change for development.

@BookOfGreg
Copy link
Member

That's a nice solution! Thank you for the work you put in here, this looks like it does solve the original issue. My apologies for not seeing what you meant originally, I'm much more a ruby dev than a JS dev so missed your meaning.

Could you add something to the Readme as a starter under an "Engine" header? You deserve the contributor badge with a great solution like that.

@tomasc
Copy link
Author

tomasc commented Oct 25, 2017

@BookOfGreg will do, thanks!

BTW I have another one for binding the react components to dom elements via JS MutationObserver – this solves all the module lookup (each module registers itself to be bound to a DOM element) and Turbolinks, pjax etc. issues. Will post an example later.

@tomasc
Copy link
Author

tomasc commented Oct 25, 2017

@BookOfGreg here it is:

https://github.com/reactjs/react-rails/wiki/Using-JS-components-from-Rails-engines

Please feel free to update as you see fit.

@BookOfGreg
Copy link
Member

Thanks @tomasc for your work on the wiki, I linked it from the Wiki's home.
I'm glad to see new content in there, it helps greatly with answering questions for folk.
I plan on trying to put some more time into getting docs up to scratch in general once the issue count is under control.
Could you close this for now if you're satisfied it solves your original issue?
If you have any other thoughts on this gem I'd be glad to hear them 💚

@tomasc
Copy link
Author

tomasc commented Oct 31, 2017

thanks @BookOfGreg !

@tomasc tomasc closed this as completed Oct 31, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants