Skip to content

fix: resolve a cylcic-dependency problem#482

Merged
ariporad merged 1 commit intomasterfrom
fix-plugin-import-issue
Jul 25, 2016
Merged

fix: resolve a cylcic-dependency problem#482
ariporad merged 1 commit intomasterfrom
fix-plugin-import-issue

Conversation

@nfischer
Copy link
Copy Markdown
Member

If a plugin was imported before the ShellJS instance was created, the user's script would crash (common.register wouldn't be instantiated yet). Now plugins can be imported either before or after the ShellJS instance is created.

One really cool consequence of this fix is that now plugins are compatible with the shelljs/global script:

require('shelljs-plugin-open');
require('shelljs/global');

open('file.txt'); // it works!

Another cool consequence is that this would allow me to rewrite shelljs-exec-proxy as a ShellJS plugin, which would let it play nicely with other plugins (such as shelljs-plugin-open).

If a plugin was imported before the ShellJS instance was created, the program
would crash (common.register wouldn't be instantiated yet). Now plugins can be
imported either before or after the ShellJS instance is created.
@nfischer nfischer added fix Bug/defect, or a fix for such a problem refactor labels Jul 24, 2016
@nfischer
Copy link
Copy Markdown
Member Author

Also, this should have no influence whatsoever on ShellJS when used normally, but would only help make plugins a bit easier 😄

@ariporad
Copy link
Copy Markdown
Contributor

I'm not really sure I understand how this helps... Could you explain it?

Other than that, LGTM.

@nfischer
Copy link
Copy Markdown
Member Author

@ariporad A plugin would require('src/common') (or whatever file we eventually move the plugin utils into) in order to register its own commands (using common.register()).

If the plugin is included before the ShellJS instance is created (require('shelljs-plugin-open') precedes require('shelljs')), then src/common.js is require()ed before shell.js. This is where the problems arise. src/common.js includes shell.js, so if shell.js hasn't yet been require()ed, Node goes and loads in shell.js. This tries to load src/common.js, but since we were in the middle of loading src/common.js, this returns common = {} (the empty object). Then, when shell.js loads in the built-in commands, it tries to common.register() them, but fails. This is because common is still {}, and doesn't have the .register attribute yet (and it won't until the initial require() completes). In essence, common.register() is used before it gets defined.

The problem didn't arise for normal ShellJS use because shell.js is require()ed first, so it is able to load in src/common.js completely before continuing to load each command (so common.register() is defined before it is used).

The solution here is to check if common.register() is defined as soon as shell.js is loaded for the first time. If common.register is not yet defined, invalidating the require-cache will force Node to load all of src/common.js (making sure that common.register() gets defined before it's used).

Hopefully that's a good explanation. I had to draw out dependency graphs to discover what the problem was and how to solve it. From what I've seen, however, it seems to work. I'll update the plugin after this is merged as a proof of concept.

@ariporad
Copy link
Copy Markdown
Contributor

Ahh... That makes sense. Thanks!

@ariporad ariporad merged commit 880d732 into master Jul 25, 2016
@ariporad ariporad deleted the fix-plugin-import-issue branch July 25, 2016 00:52
@nfischer
Copy link
Copy Markdown
Member Author

Yeah, it's a bit non-intuitive, but hopefully that was a clear enough explanation for all looking into the matter in the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix Bug/defect, or a fix for such a problem refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants