[SOLVED] Impossible? Does anyone run Meteor/React client side code from a Node package?


#1

I’m trying to create a Meteor/React npm package that includes both server and client. It’s a CRUD module with authorization controls, logging and other goodies.

The server side works, and nearly all the client side but, just when I thought I was done, I hit two horrendous, impenetrable bugs. They both occur while trying instantiate interactive forms made with tcomb-form.

Ignoring the stuff below the line; my question is simple :

Are there known reasons why Meteor/React client side code cannot be run out of a Node package?

Has anyone else done this successfully? Am I the fool rushing in where angels fear to tread?


The two failures …

Exception from Tracker recompute function:
TypeError: reactiveFn is not a function
    at modules.js?hash=38eec26…:30735
    at Tracker.Computation._compute (tracker.js?hash=9f8a0ce…:339)
    at new Tracker.Computation (tracker.js?hash=9f8a0ce…:229)
    at Object.Tracker.autorun (tracker.js?hash=9f8a0ce…:604)
    at modules.js?hash=38eec26…:30734
    at Object.Tracker.nonreactive (tracker.js?hash=9f8a0ce…:631)
    at onPropsChange (modules.js?hash=38eec26…:30733)
    at Container._subscribe (modules.js?hash=38eec26…:30440)
    at new Container (modules.js?hash=38eec26…:30368)
    at modules.js?hash=38eec26…:23391
Exception from Tracker recompute function:
meteor.js?hash=e3f53db…:930 Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Check the render method of `_class`.
    at invariant (http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:11044:15)
    at instantiateReactComponent (http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:23037:134)
    at instantiateChild (http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:22850:28)
    at http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:22877:16
    at traverseAllChildrenImpl (http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:24536:5)
    at traverseAllChildren (http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:24631:10)
    at Object.instantiateChildren (http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:22876:7)
    at ReactDOMComponent._reconcilerInstantiateChildren (http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:22422:41)
    at ReactDOMComponent.mountChildren (http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:22461:27)
    at ReactDOMComponent._createInitialChildren (http://localhost:3000/packages/modules.js?hash=38eec2661c38495d18ae8ce92ab43d7c9049dd5e:19705:32)

For the suicidally curious –

I’m using the Chrome debugger to try to find where the failure occurs, but I get lost in seemingly endless messaging loops and, frankly, can’t be certain I’m not just following error paths caused by time outs introduced by the debugger.

I believe it’s failing in composeWithTracker somewhere, before it ever gets to tcomb-form.

  • the code blows up on this line here, with the reactiveFn failure when trying to Update an existing widget, and with the Invariant Violation when trying to Create a new one.
  • the Circle Ci build and test (failing of course) is here.
  • the package is incorporated with npm link in this file.
  • package dependencies (like logging and authorization) that are initialized later than the package are mocked in utils.js and then replaced by the real ones here.
  • the complete original working client side code, from before trying to move it out to an npm package, is here.

The whole project uses the Mantra spec structure and mantra-core tooling.


#2

I think it has little to do with running from a node-module.

reactiveFn is the first argument from composeWithTracker.

While the first composer singleComposer runs, the second authComposer seems to be null.
The import there seems to be wrong to me


#3

From a mile-high perspective, I’d guess the tcomb-form package is buggy (like most every other forms package out there). It could be either form logic abstraction, or the native hooks. Or both. Is the entire app React Native? Are there going to be hundreds or thousands of forms? If there aren’t hard requirements there, maybe another form library is possible?

I was also going to ask about imports. I guess you’re migrating off of Atmosphere? Otherwise I’d recommend looking at using the meteor/account:package syntax, which we’ve been having great success when when importing things onto the client. Also, there’s been some community success with nova:forms, as far as React based form libraries go.


#4

Yes. i’m homing in on that with the debugger.

Running from a Node package changes the order in which things are loaded and instantiated. I believe the Authorization component is getting instantiated too late, or I’m just not getting it when I think I am.


#5

Hi Abigail,

Thanks for the input. The code I’m moving out to a package works without problem if it’s loaded normally.

I have been maintaining a fork of Meteor Mantra Kickstarter, keeping it up to date and adding bits. Full-stack CRUD in an npm package seems like a useful goal, so I took an existing CRUD, cloned it with different names and got it to work. I then successfully moved the back-end bits to the package, and nearly all the front-end too. Adding or editing an item (“color”) fails.

To answer you:

  • no there’s no React Native.
  • There won’t be many forms. I’m not married to tcomb-form, but I have no proof that it’s the culprit here.
  • There’s very little from Atmosphere, and definitely not the bit I’m working on.
  • “… recommend looking at using the meteor/account:package syntax” Where can I find that?

Do I understand that you are in fact currently running Meteor/React client code out of an NPM package?
If you are then you’ll have confirmed for me that I’m not attempting something that’s not doable.


#6

Well, yes and no. I don’t think I’ve gotten any Meteor/React code loaded out of my own NPM package yet. But it’s a refactor goal, and we’re working towards it and have been tracking it. And we’ve gotten React code loaded out of NPM packages into our own apps. So I’ve basically been researching how to make that final step this past week.

We’ve been using a fork of Meteor Chef Base, and in the /imports directory, you can see a use of the meteor/account:package syntax, like so:

That pulls in the code from an Atmosphere package as an import module. Basically, anything in the package’s api.export() statement will behave like an module.exports or export const or export class. So, the refactor path should basically go from this in Atmosphere/Meteor/React:

//package.js
Package.describe({
  name: 'myaccount:foo',
});
Package.onUse(function (api) {
  api.export("Foo");
  api.addFiles('lib/Foo.js');
});

// lib/Foo.js
Foo = {
  bar: "123",
  baz: function(){
    return "lorem ipsum";
  }
}

// imports/ui/page/FooPage.js
import { Foo } from 'meteor/myaccount:foo';
let fooNumber = Foo.bar;  //123
let fooText = Foo.baz();  // lorem ipsum

to this with NPM/Meteor/React:

//package.json
{
  "name": "foo-on-npm",
  "main": "./lib/index.js",
}

// lib/index.js
export Foo from './Foo';

// lib/Foo.js
export default Foo {
  bar: "123",
  baz: function(){
    return "lorem ipsum";
  }
}

// imports/ui/page/FooPage.js
import { Foo } from 'foo-on-npm';
let fooNumber = Foo.bar;  //123
let fooText = Foo.baz();  // lorem ipsum

That’s basically as far as I’ve figured things out. So to answer your question very specifically, we’re loading a lot of Meteor/React functionality via the import { Foo } from 'meteor/myaccount:foo' syntax as an intermediary step. The next step is to move everything to an NPM package.

The problem, of course, is that it’s not clear how to import Meteor into an NPM package. It’s easy enough to include the React components. It’s the collections, minimongo, sessions, the Meteor object itself, and all the rest of the Meteor environment that’s missing.


#7

I’m not trying to make an NPM package that anyone can use.

I just want to use NPM packages as a way to mix’n match functionality between different projects based on the same foundation – the Meteor / Mantra Kickstarter.

Once I have that, I want to pull the guts of it and replace with Apollo. The point of getting it out to NPM was to clarify exactly what is separate code and what is integral to the base project.

I haven’t messed with the .meteor/packages in a long time; it’s all package.json for me now.


#8

@macrozone That was brilliant. You nailed it! I sure hope they’re paying you what you’re worth.


#9

:smiley:

btw. some Advertisement :wink: :

for forms in react use https://github.com/vazco/uniforms/

it has simple-schema (2) support, soon graphql-schemas, comes with bootstrap-ui and semantic and its really easy to roll your own ui and even create complex form-fields (file-uploads, nested fields or similar). And the guys maintaining it are really helpful and fast with responses.


¡Get to know Vazco / Uniforms! looɔ ʎɹǝΛ
#10

Agreed :slight_smile: Great success with Vazco Uniforms.


¡Get to know Vazco / Uniforms! looɔ ʎɹǝΛ
#11

Hmmm… interesting. This is what? A 4th or 5th generation forms library? Semi-compatible API with AutoForm. Anybody have success migrating from AutoForms to Uniforms? Anybody have experience with it compared to Nova Forms?

If only it had a uniforms-material-ui package…


¡Get to know Vazco / Uniforms! looɔ ʎɹǝΛ
#12

The guy from uniforms here. We have an internal uniforms-material package. It’s not public because it’s not complete. Why? Because there’s no universal way to render a list of fields in material ui. If you feel interested - go on, create an issue - I’ll tell you more (and of course - help with such integration, if it’s needed). I guess you are not the only one with such requirement, so a new theme package would be nice.


¡Get to know Vazco / Uniforms! looɔ ʎɹǝΛ
#13

This is worth a topic of its own, so please continue the conversation over there.