Webpack compiler inside Meteor (ES6 modules, hot reload and code splitting!)

Hi,

I’m trying to convert a moderately complex app from using universe:modules and browserify to using this. This also involved an upgrade to React and ReactRouter, so things are kind of broken, but it’s starting to render.

I’m seeing two errors in the console that mystify me, though. I’m wondering if they mean something to you:

Warning: React can't find the root component node for data-reactid value `.0.0.0.0.1:$=11:$1.$=11:$1.$=11:$1.$=11:0`. If you're seeing this message, it probably means that you've loaded two copies of React on the page. At this time, only a single copy of React can be loaded at a time.

plus this warning:

Warning: <App /> is being rendered by both MyApp and RoutingContext using the same key (null) in the same place. Currently, this means that they don't preserve state. This behavior should be very rare so we're considering deprecating it. Please contact the React team and explain your use case so that we can take that into consideration.

and:

Uncaught Error: Invariant Violation: unmountComponentAtNode(...): Target container is not a DOM element.

I am thinking this has something to do with how the router is working. I’m a bit confused about how the ReactSSR stuff actually works in the kickstart-example (I have basically the same entry as that, and then my own app under modules as per the example).

Any hints on what may be causing this?

Hi again.
One small question: how to add Material-UI to kickstart? )-:

It would be hard without looking at your code. What your webpack.conf.js looks like and your entry.js files?

You can add material-ui with webpack.packages.json. Make sure to use ~0.12.5 because the next versions require React 0.14 (which is not available yet on the Meteor package).

I want to run formsy-mui-demo inside kickstart-flowrouter…
I tried to add packages: npm install material-ui@0.12.5, npm install formsy-react@0.14.1 and npm install formsy-material-ui

Today I tried add to webpack.packages.json:
“material-ui”: “0.12.3”,
“formsy-react”: “0.14.1”,
“formsy-material-ui”: “0.2.2”

In both cases, the following errors in the chrome console:

  1. Uncaught TypeError: Cannot read property ‘firstChild’ of undefined
  2. Uncaught Error: Invariant Violation: addComponentAsRefTo(…): Only a ReactOwner can have refs. This usually means that you’re trying to add a ref to a component that doesn’t have an owner (that is, was not created inside of another component’s render method). Try rendering this component inside of a new top-level component which will hold the ref.
  3. Uncaught Error: Invariant Violation: removeComponentAsRefFrom(…): Only a ReactOwner can have refs. This usually means that you’re trying to remove a ref to a component that doesn’t have an owner (that is, was not created inside of another component’s render method). Try rendering this component inside of a new top-level component which will hold the ref.

Hi,

Some relevant bits of code: https://gist.github.com/optilude/ba5892244f7d1ef0997a

That includes the webpack configs, the entries and the routing config.

Martin

been struggling with this one:
I’d like to use css-modules, which basically takes icss, maps it, inlines it, and then extracts the text back into a pure css file. It does this by using the package extract-text-webpack-plugin. If i disable the extraction piece, the css stays inline & it works (which is fine for development). My solution would be a build step where it creates the css file & then meteor can pick it up & send it through the build process, but I’m guessing you’ve discovered something more eloquent to obviate the need for a build folder?

config file as follows (comment out the highlighted line to use inline styles): https://github.com/gajus/react-css-modules-examples/blob/master/webpack.config.js#L35

2 Likes

Here are some research notes on building Webpack into Meteor from @dgreensp: Sharing some research into Webpack and the build tool ecosystem

6 Likes

This is truly an excellent edition to Meteor and I thank everyone involved for their determined efforts.
I have one question regarding the flow-router example (mainly due to my novice level with webpack and flow router).

Has anyone managed to get code splitting working like in the huge-app example but with the flow-router example.

I really like the feel of flow-router and am looking to migrate an existing meteor/react app across to webpack and flow-router and am just stuck at how to “on demand load” modules with flow-router.

I think this may be my final stumbling block and I thank you in advance for any assistance that can be offered :smile:

1 Like

If you read the Webpack doc and look at the kickstart-hugeapp example, I think you can figure it out. require.ensure is the key to all of this.

I was able to get this worked out, @benoitt. I forgot to require('path') in the conf.js. Thanks!

1 Like

By chance I read your post, and then something that identified a possible cause within an hour of each other:

“Cannot read property ‘firstChild’ of undefined” error message on the JS console, which occurs when there are two React libraries in the same namespace).

https://www.npmjs.com/package/x-react-d3

Don’t know if that helps? Might be unrelated.

I’m having an issue with the React Router SSR and Sass. In production mode I noticed that I was getting FOUC on load. When I pull in .css in componentWillMount() it renders just fine on the server. If I pull in .scss then it doesn’t load at all. Everything works perfectly on the client side. I’m sure it’s some issue on my side but I don’t know what to do. Any help? Relevant code below.

Server webpack.conf.js loaders:

loaders: [
      { test: /\.jsx?$/, loader: 'babel', query: { stage: 0 }, exclude: /node_modules/ },
      { test: /\.css$/, loader: 'style-collector!css' },
      { test: /\.scss$/, loader: 'style-collector!css!sass' },
      { test: /\.(png|jpe?g)(\?.*)?$/, loader: 'url?limit=8182' },
      { test: /\.(svg|ttf|woff|woff2|eot)(\?.*)?$/, loader: 'file' }
    ]

componentWillMount() example:

componentWillMount() {
    require('./css/bootstrap.css'); // Works on the server
    require('./css/app.import.scss'); // Does not work on the server
}

Thanks so much @benoitt, I will have another read.
You have re-energized my enthusiasm knowing I can do it, as I was starting to move on, maybe I just wasn’t getting it.

I think I am overthinking it by looking at the ReactRoute stuff vs the FlowRouter stuff too much between the two examples, more reading into how to properly use require.ensure in this scenario is needed I think. :persevere:

Is anyone else having issues with some modules hot reloading and some requiring a manual refresh? I can’t make out any rhyme or reason why some are and some are not.

@zaklampert
I am having the same issue where modules aren’t reflecting the changes in the browser yet the hot code refresh has happened. I’d love to see peoples ideas on this as well.
I’m having to kill the meteor process and re-run meteor to pick up the changes. (this is in dev mode)

@benoitt
Thank you so much for the advice on how to solve my flow-router and hugeapp integration confusion.
I have it working perfectly now, it is the selfless efforts of people like yourself that helps people get over that wall we sometimes hit when starting out with unfamiliar tech.

I just needed a “point in the right direction”, thanks so much :smile:

1 Like

@jasonweise can you share a basic boilerplate to demonstrate how you have done this for future reference

@garrilla
I am at home now but the way I managed to get it to work was as follows (this isn’t direct code copy but should give you an idea)

In the Modules/AdminApp/client/routes.js file

FlowRouter.route(’/admin’, {
action() {
require.ensure([], () => {
let AdminApp = require(’./AdminApp’);
let Dashboard = require(’./Dashboard’);
ReactLayout.render(AdminApp, { content: <Dashboard/> });
});

}
});

In the Modules/AdminApp/client/AdminApp.jsx use the following as an example

import { Component, PropTypes } from ‘react’;

export default class AdminApp extends Component {
static propTypes = {}

componentWillMount() {
}
render() {
    return (
        <div>
             {this.props.content}
        </div>
    );
}

}

In the Modules/AdminApp/client/Dashboard.jsx use the following as an example

import { Component, PropTypes } from ‘react’;

export default class Dashboard extends Component {
static propTypes = {}

componentWillMount() {
}
render() {
    return (
        <div>
            <h2>THIS IS MY DASHBOARD!!!</h2>
        </div>
    );
}

}

In the entry\client\routes.jsx file make sure you add the AdminApp\client\routers file to your imports (you need to add all your module routes here as far as I can tell)

import ‘AdminApp/client/routes’;

Result:
Now when \admin url is browsed to, the AdminApp module will load and dynamically include the Dashboard due to the rules in the routes file. This dashboard is then inserted into the AdminApp module render() function through the props (content).

I hope this makes sense as it is off the top of my head from today at work. @benoitt was 100% right, the magic lays in the require.ensure.

If you have any other questions, please don’t hesitate to ask and I will help where I can (I am still learning React, Flow-Router and WebPack LOL).

Please keep in mind this my examples above won’t run “as is”, it’s just supposed to provide a guide on how I figured it out.
If I am completely off the mark and this is a terrible interpretation, please tell me, we are all here to get better ideas :slight_smile:

This is awesome. One little mistake though:

Should be:

require.ensure([], require => {
1 Like

I am trying to get the Autoform to work under this setup:

let rQuickForm = BlazeToReact('quickForm');
<rQuickForm collection= "TBooks" id="insertBookForm" type="insert" />

but with no results, the form does not show up. Can anyone confirm this should or shoult not work?

1 Like