Solid: Comp is not a function

Created on 2 Nov 2019  路  15Comments  路  Source: ryansolid/solid

I created this repo: https://github.com/Seanmclem/solidjs-router

It's a simple SPA router implementation for solid-js. It works well locally in my solid-js boilerplate, but when I try to build it and distribute/consume it as an npm module, and use it in my boilerplate project as an npm module - I get this error.

Comp is not a function

The error is triggered here, in core solid-js code

function createComponent(Comp, props, dynamicKeys) {
  if (dynamicKeys) {
    for (let i = 0; i < dynamicKeys.length; i++) dynamicProp(props, dynamicKeys[i]);
  }

  return Comp(props);
}

I'm using rollup to try and do the transpilation -seen in another repo here. It seemed to come out correctly, but something is not working. I'd appreciate any help or fixes you can offer.

Most helpful comment

You might want to look at something like solid-element. The .gitignore is configured to not commit build files (under ./dist or ./lib) and only the source. The .npmignore doesn't include /src or /test. Notice the entry points in the package.json, with main being a commonjs build and module being a es6 build. You have some options there, might not need commonjs. I was doing to support some non-build node environments, but with the JSX it is probably unlikely to be necessary.

For your library I'd set solid-js in peerDependencies not a dependencies and put the rest of your deps under devDependencies. From there you just have to tell npm to build on publish. I use the prepublishOnly under scripts. This will automatically create your build as part of your submission to npm.. ie. it runs when you run npm publish.

I mean there are a lot of details like that. I hope some of that helps.

All 15 comments

Alright cool. It's awesome to see people starting to try to make libraries to extend Solid's capability. I was looking at the codebase to understand what was going on. I guess my first question is why not make "solid-js" an external in the rollup build since any consuming app I imagine would be bringing their own version since Solid's context tracking needs to be a singleton (ie.. only one version of Solid in the application). That alone would cause some issues if you tried to use it in another project.

The error you are seeing is saying that the Component isn't a function. Most likely, it means somewhere there is a tag like <MyComponent /> where MyComponent isn't a function. This being a runtime bug it is pretty hard to see just from the code. Your code only creates the Context Provider component with this method, so unless its there this is most likely in the code that is using your library.

Creating a reproduction case would be the best way for me to help you debug. Something like codesandbox.io is an easy way to share it. Another Github repo would be ok. On the surface other than Solid being bundled in there I don't see any issues.

I've updated the rollup config, latest in the repo
I added the config to include externals and globals but it's not quite right. I don't think I'm identifying the globals properly. I still get an error when using the library, seemingly because of the hyphen in solid-js but definitely I missed a step.

I created a repo for an example of a project I'm using it in, here
With a code-sandbox of it here, but it doesn't quite work. For a different reason

So at this point my rollup looks like this, No matter how I format the globals -it can't seem to resolve anything
````
import resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';
import { terser } from 'rollup-plugin-terser';

const plugins = [
babel({
exclude: 'node_modules/**',
presets: ["solid"]
}),
resolve({ extensions: ['.js', '.jsx'] })
];

if (process.env.production) {
plugins.push(terser());
}

export default {
external: ['solid-js'],
input: 'src/index.jsx',
output: {
globals: {
'solid-js': 'solid-js'
},
file: 'dist/index.js',
format: 'iife',
name: 'solidjsrouter'
},
plugins
};
````
Does solid-js have a default export? Currently my library is targeting { useContext, createState, createContext } ... Rollup's output seems to get all of these off a solidJS variable that is never defined. Their documentation is a bit sparse on how this all fits together.

I've updated the rollup config, latest in the repo
I created a repo for an example of a project I'm using it in, here

ok, I got it to mostly work by updating my rollup config to the proper module/library setup. The routing doesn't seem to fully work yet, but now importing it into my solid-js-boilerplate runs without errors, except for some 'computations created without a root or parent will never be disposed' warning.

using

`export default {
    external: ['solid-js'],
    input: 'src/index.jsx',
    output: {
        file: 'dist/index.js',
        format: 'es'
    },
    plugins
};`

Yeah that looks right on the rollup config side. Solid's libraries work the same way(like solid-element etc). Sorry didn't pay attention to the iife output which was probably messing everything up. I can review your boilerplate this evening.

Thanks, I really do appreciate any amount of time you can spend looking at it. I really like solidjs so far. Thanks for all your work

You need to make "solid-js/dom" external as well. Right now parts of a second version of solid are being included. The JSX compilation auto adds "solid-js/dom" references.

If it is not iife you shouldnt need to set globals.

Well, everything works now. Thanks for your help! I'll close this issue. I look forward to using your libraries more, and writing some articles about solid

That's awesome. I look forward to seeing how it goes.

Sorry one last thing. On aside any reason to package the build and the release repo separately? I figure with a good .gitignore and .npmignore setup and setting the right entry in the package.json you could easily manage it under a single repo. Easier for contributors etc..

@ryansolid maybe I misunderstood. You're right, the build and release repo should _not_ be separate. Could you please elaborate a bit more about how to effectively combine them for effective contributions and distribution on npm?

You might want to look at something like solid-element. The .gitignore is configured to not commit build files (under ./dist or ./lib) and only the source. The .npmignore doesn't include /src or /test. Notice the entry points in the package.json, with main being a commonjs build and module being a es6 build. You have some options there, might not need commonjs. I was doing to support some non-build node environments, but with the JSX it is probably unlikely to be necessary.

For your library I'd set solid-js in peerDependencies not a dependencies and put the rest of your deps under devDependencies. From there you just have to tell npm to build on publish. I use the prepublishOnly under scripts. This will automatically create your build as part of your submission to npm.. ie. it runs when you run npm publish.

I mean there are a lot of details like that. I hope some of that helps.

Thanks for the tips and info. I've refactored my npm repo to also include the source and scripts. All seems to work well. Thanks again

Yeah looks good. I think your build(index.js) snuck into git before the .gitignore applied. I've had this happen before. There might be an easier way to fix it. In the past I temporarily removed the line from the ..gitignore and delete the file and commit. Once it is checked in even in .gitignore it will still be in the repo.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shybyte picture shybyte  路  4Comments

ajihyf picture ajihyf  路  6Comments

samadadi picture samadadi  路  7Comments

aguilera51284 picture aguilera51284  路  7Comments

kavsingh picture kavsingh  路  4Comments