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

Module not found: Error: Can't resolve 'nodent' when used in Angular 2 project (browser) #325

Closed
mmc41 opened this issue Oct 18, 2016 · 23 comments

Comments

@mmc41
Copy link

mmc41 commented Oct 18, 2016

What version of Ajv are you using? Does the issue happen if you use the latest version?
4.8.0

Your code (please use options, schema and data as variables):

import * as Ajv from 'ajv';

... ...  ...

@Injectable()
export class ValidationService {
  ajv: Ajv.Ajv;

  constructor() {
      this.ajv = Ajv({ allErrors: true, verbose: false });
  }

  public validateSettings(settingsSchema: JsonSchema, settings: SettingsData): ValidationResult {
    let valid = this.ajv.validate(settingsSchema, settings);
    return {
        valid: valid,
        errors: this.ajv.errors
    };
  }
}

If I run this in chrome I get:

Module not found: Error: Can't resolve 'nodent' in '/MyProject/projects/client/node_modules/ajv/lib'
resolve 'nodent' in '/MyProject/projects/client/node_modules/ajv/lib'
Parsed request is a module
using description file: /MyProject/projects/client/node_modules/ajv/package.json (relative path: ./lib)
Field 'browser' doesn't contain a valid alias configuration
after using description file: /MyProject/projects/client/node_modules/ajv/package.json (relative path: ./lib)
resolve as module
/MyProject/projects/client/node_modules/ajv/lib/node_modules doesn't exist or is not a directory
/MyProject/projects/client/node_modules/ajv/node_modules doesn't exist or is not a directory
/MyProject/projects/client/node_modules/node_modules doesn't exist or is not a directory
/MyProject/projects/node_modules doesn't exist or is not a directory
/MyProject/node_modules doesn't exist or is not a directory
/Users/mmc/repos/node_modules doesn't exist or is not a directory
/Users/mmc/node_modules doesn't exist or is not a directory
/Users/node_modules doesn't exist or is not a directory
/node_modules doesn't exist or is not a directory
looking for modules in /MyProject/projects/client/node_modules
using description file: /MyProject/projects/client/package.json (relative path: ./node_modules)
Field 'browser' doesn't contain a valid alias configuration
after using description file: /MyProject/projects/client/package.json (relative path: ./node_modules)
using description file: /MyProject/projects/client/package.json (relative path: ./node_modules/nodent)
as directory
/MyProject/projects/client/node_modules/nodent doesn't exist
no extension
Field 'browser' doesn't contain a valid alias configuration
/MyProject/projects/client/node_modules/nodent doesn't exist
Field 'browser' doesn't contain a valid alias configuration
/MyProject/projects/client/node_modules/nodent doesn't exist
.ts
Field 'browser' doesn't contain a valid alias configuration
/MyProject/projects/client/node_modules/nodent.ts doesn't exist
.js
Field 'browser' doesn't contain a valid alias configuration
/MyProject/projects/client/node_modules/nodent.js doesn't exist
[/MyProject/projects/client/node_modules/ajv/lib/node_modules]
[/MyProject/projects/client/node_modules/ajv/node_modules]
[/MyProject/projects/client/node_modules/node_modules]
[/MyProject/projects/node_modules]
[/MyProject/node_modules]
[/node_modules]
[/MyProject/projects/client/node_modules/nodent]
[/MyProject/projects/client/node_modules/nodent]
[/MyProject/projects/client/node_modules/nodent]
[/MyProject/projects/client/node_modules/nodent.ts]
[/MyProject/projects/client/node_modules/nodent.js]
@ .//ajv/lib/async.js 116:26-48
@ ./
/ajv/lib/ajv.js
@ ./src/app/shared/services/validation-service.ts
@ ./src/app/app.module.ts
@ ./src/app/index.ts
@ ./src/main.ts
@ multi main

What results did you expect?

Are you going to resolve the issue?

@mmc41
Copy link
Author

mmc41 commented Oct 18, 2016

Nb. it does work when running from a unit test in the browser using jasmine - but not in the application itself.

@epoberezkin
Copy link
Member

Nodent is used only in asynchronous validation, if you are using it you have to also load nodent bundle as well.

If not:
Are you using supplied Ajv bundle or you build yourself? If so what do you use to build?
Does something overrides require?

The root of the problem is that nodent is required using require('' + 'nodent') that correctly works if you bundle with browserify.

Also you write, "if I run this in chrome" but your code sample is different from what is loaded to chrome - there is some build process. Are you getting the error during build or in chrome console?

@epoberezkin
Copy link
Member

Please also include answers to questions here: http://epoberezkin.github.io/ajv/contribute.html#compatibility (there is another issue template for compatibility issues)

@mmc41
Copy link
Author

mmc41 commented Oct 18, 2016

Thank you very much for your quick response.

I am not using synchronous validation as far as I know - at least not on purpose. I have attached a small reproducible angular 2 project for node v6 (where you can see how I use it fully). To reproduce, you can unzip, cd into the dir, type "npm install" followed by "npm start" + open chrome at localhost:4200. The ajv code I am using is in the file src/app/validation.service.ts. Be sure to notice the ajv related error output in the developer tools in the browser and on the console where "npm start" is issued.

Angular 2 uses webpack rather than browserify (webpack is apparently the new "black" while browserify is on the way out). I have no idea if webpack may need some configuration to work with ajv. I am fairly new to JS tooling and things quickly gets complicated here.

Answers to compatibility questions:
The version of Ajv you are using = 4.8.0
The environment you have the problem with: MacOS 10.12, Chrome 54, Node v6.7.0, npm 3.10.3
See source for all other packages - have no idea about what order webpack/angular loads stuff.
Results in node.js v4 - using Node v6.7.0 not v4.

The reproducible example actually produce two errors compared to my original. In addition to "Module not found: Error: Can't resolve 'nodent" it also reports "Module not found: Error: Can't resolve 'js-beautify'".

Not sure why there are now two errors related to ajv in this new example?

ajv-angular2-bugdemo.zip

@epoberezkin
Copy link
Member

I think it is related to #82 and #117 (probably duplicate). I wouldn't discard browserify yet, given that webpack doesn't support dynamic requires.

I suspect the issue may be that Angular 2 requires Ajv not from the bundle but from main. Not sure. Some PR / suggestions that would fix it are welcome, as long as it continues to work in node.js and in browserify...

I think you should be able to work around the issue by including Ajv as a separate bundle (either from npm package dist folder or from cdnjs) and using global Ajv from your code.

@epoberezkin
Copy link
Member

I have no idea if webpack may need some configuration to work with ajv.

I meant in which order script tags are loaded, assuming different JS files loaded to the browser. I understand that you are trying to bundle Ajv together with your app using webpack. Maybe some suggestions from the issues I linked could be helpful.

@mmc41
Copy link
Author

mmc41 commented Oct 19, 2016

FYI: I got Ajv working - barely - in my angular 2 - angular-cli project by adding "ajv.min.js" min to angular-cli.json ("scripts": ["../node_modules/ajv/dist/ajv.min.js"]) and to karma.conf.js (files: [
"./node_modules/ajv/dist/ajv.min.js" ... ]) + a "declare var Ajv: any;" in my typescript code + removed import statements for Ajv.

Unfortunately, I than lose all type safety. I was unable to import Ajv's typescript file from node_modules (got internal errors if I tried). So it works but only barely so.

Sorry, I don't have enough grasp of how typescript, angular2, angular2-cli, webpack, module loaders, npm etc. works together in order to do a PR for a better fix. Quite a lot of complicated technologies in play here.

@epoberezkin
Copy link
Member

That's exactly what I suggested for a workaround.

@mmc41
Copy link
Author

mmc41 commented Oct 19, 2016

Yes, sounds like the same workaround. I hope my more detailed outline of a solution can help other people though. On the long run it would be wonderful if Ajv works as is (with typescript) with angular 2 and other new web frameworks.

But thanks for your support in fixing this - it is nice to experience an OS project with such an impressive responsiveness on issues. Thanks.

@ValeryVS
Copy link

ValeryVS commented Dec 5, 2016

It is not webpack or angular 2, it is typescript.
https://www.typescriptlang.org/docs/handbook/module-resolution.html
see node section

When you import

import * as Ajv from 'ajv';

typescript get script from package.json's "main" with typings from package.json's "typings".

When you import

import * as Ajv from 'ajv/lib/ajv.js';

you get ajv/lib/ajv.jswith ajv/lib/ajv.d.ts typings.

You cant import ajv/dist/ajv.bundle.js because there is no ajv/dist/ajv.bundle.d.ts typings.

You can still require() it, but without typings.


Summary.

If we copy typings file into dist/ajv.bundle.d.ts we can import /dist/ajv.bundle.js.

And if we change package.json's "main" to dist/ajv.bundle.js, or make separate distributable package we import just ajv.

@mmc41
Copy link
Author

mmc41 commented Dec 5, 2016

@ValeryVS Great with a more detailed analysis of the problem. I have tried many things but so far been unable to get typescript working when using my ajv hack inside Angular 2.

@epoberezkin Can ajv be updated in line with one of ValeryVS's suggestions above. Maybe copying the ajv.bundle.d.ts to dist is the easiest solution for now?

@epoberezkin
Copy link
Member

@ValeryVS I am not sure I understand why do you want to require the bundle and not the main file. Ajv is used by with Typescript without any problem.

@ValeryVS
Copy link

ValeryVS commented Dec 5, 2016

@epoberezkin Because I use it in angular 2 app, that builded with angular-cli. Which use webpack and print warnings with huge stacktrace in console.

@ValeryVS
Copy link

ValeryVS commented Dec 5, 2016

Or may be we can ask angular-cli team how to make it realy optional. Without warnings.

@epoberezkin
Copy link
Member

So it is a webpack issue essentially? Same as #117 ?

@ValeryVS
Copy link

ValeryVS commented Dec 6, 2016

@epoberezkin The example provided by @mmc41 also use angular-cli. So, yes, this is webpack issue.
It will be good to fix it some way, without warning suppression.
I use ajv in validation library and suppress warning in all my projects, looks weird.

@ValeryVS
Copy link

ValeryVS commented Dec 6, 2016

@epoberezkin
I discover something interesting.
There is no warnings, if I type require path as variable instead of string.

There is strings from async.js and compile/index.js

      var regeneratorPath = 'regenerator';
      regenerator = require(regeneratorPath);


    var nodentPath = 'nodent';
    if (!nodent) nodent = require(nodentPath)({ log: false, dontInstallRequireHook: true });


    var jsBeautifyPath = 'js-beautify';
    try { beautify = require(jsBeautifyPath).js_beautify; }

@epoberezkin
Copy link
Member

@ValeryVS cool. So we've found a way to trick webpack finally, not only browserify! Do you want to make a PR?

@ValeryVS
Copy link

ValeryVS commented Dec 6, 2016

@epoberezkin
Working on it.

I'm still get warning while test.

WARNING in ./~/ajv/lib/compile/index.js
13:21 Critical dependency: the request of a dependency is an expression

but, at least, there no warnings in browser console.

@andrewsuzuki
Copy link

Not sure this is a great solution, I'm getting the same warning as above. A bit annoying as they're the only warnings in my build using webpack 2.1.0-beta.27.

WARNING in ./~/validators/~/ajv/lib/async.js
96:20 Critical dependency: the request of a dependency is an expression

WARNING in ./~/validators/~/ajv/lib/async.js
119:15 Critical dependency: the request of a dependency is an expression

WARNING in ./~/validators/~/ajv/lib/compile/index.js
13:21 Critical dependency: the request of a dependency is an expression

@epoberezkin
Copy link
Member

It will be resolved by #382 and #383

@epoberezkin
Copy link
Member

Resolved in 5.0.1-beta.0
To use: npm install ajv@^5.0.1-beta

@epoberezkin
Copy link
Member

5.0.1-beta.3 should resolve it, finally

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

No branches or pull requests

4 participants