Angular-cli: Can't resolve 'net'/'global' or other node globals

Created on 1 Mar 2018  ·  39Comments  ·  Source: angular/angular-cli

Versions

Angular CLI: 6.0.0-beta.4
Node: 8.9.3
OS: win32 x64
Angular: 6.0.0-beta.6
... animations, common, compiler, compiler-cli, core, forms
... platform-browser, platform-browser-dynamic, router

@angular/cdk: 5.2.3
@angular/cli: 6.0.0-beta.4
@angular/material: 5.2.3
@angular-devkit/build-optimizer: 0.4.3
@angular-devkit/core: 0.4.3
@angular-devkit/schematics: 0.4.3
@ngtools/json-schema: 1.2.0
@ngtools/webpack: 6.0.0-beta.4
@schematics/angular: 0.4.3
@schematics/package-update: 0.4.3
typescript: 2.6.2
webpack: 4.0.1

Repro steps

udpate from 1.7.2 to @next branch beta4

Observed problems:

1

it was working in 1.7.2 but not in @next branch I get in one module problem
image
But I fixed it after "npm i net"

2

after reinstalling 6beta4 I get:

Could not find local "typescript" package.The "@ngtools/webpack" package requires a local "typescript@^2.4.2" package to be installed.Error: Cannot find module 'typescript'
Error: Could not find local "typescript" package.The "@ngtools/webpack" package requires a local "typescript@^2.4.2" package to be installed.Error: Cannot find module 'typescript'
    at Object.<anonymous> (C:\...\i10\node_modules\@ngtools\webpack\src\index.js:18:11)
    at Module._compile (module.js:635:30)
    at Object.Module._extensions..js (module.js:646:10)
    at Module.load (module.js:554:32)
    at tryModuleLoad (module.js:497:12)
    at Function.Module._load (module.js:489:3)
    at Module.require (module.js:579:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (C:\...node_modules\@angular\cli\models\webpack-config.js:3:19)
    at Module._compile (module.js:635:30)

Fixed after "npm update --next" and "npm i"

3

Then I have an deprecation warning:
image

4

Then I have strange long chunk name
image

5

Another point is when running ng build --build-optimizer --prod
It block at step : 70% building modules without never finish .

Mention any other details that might be useful (optional)

Maybe this is due to webpack4.0 resolution, any temp idea?

faq

Most helpful comment

Heya, first of all I want to thank you all for trying the 6.x versions. They are still pretty raw and getting feedback early is super important to address problems.

The build times and chunkname bugs are unexpected, probably to do with Webpack 4 interop. We expect those to get fixed soon.

The problem with net/global is not so straightforward. We are removing it for 6.x, yes (https://github.com/angular/angular-cli/pull/9812). And we do expect this to cause problems to some projects. But we're not doing it because we want to break projects, we're doing it because leaving it in also breaks other projects, and it is incorrect.

The incorrect part is libraries that are meant to run in the browser relying on node globals being available. Browser code runs in the browser, not in node, and shouldn't expect things that are not available in a browser context to be there.

For instance, if you open up your browser and type require('fs') you will get an error saying require does not exist. require is only available in node. But if you tried to import it some other way, like import('fs') (chrome supports import at the moment), you will also get an error saying it doesn't know what fs is. fs is also available only in node.

Some libraries use those constructs because they expect to be built in node, but to run in the browser. And they also expect the tooling that builds them to either provide a browser version of those node built-ins, or to pretend it's there when it actually is not.

In Angular CLI we never provided a browser version of node built-ins. But we did:

  • provide a shim for global and process.
  • supply an empty module when fs, crypto, tls and net were requested.

This is a problematic situation because even that can break some libraries (https://github.com/angular/angular-cli/issues/5804), increase the size of others (https://github.com/angular/angular-cli/pull/8130#pullrequestreview-71174772), and just generally make for a situation where browser code that shouldn't work at all works only when built in with very specific tooling. This is not a good situation. Browser code should not rely on things that are not available in browser environments.

We investigated the topic and reached this conclusion some time ago but did not remove support for this broken behaviour in CLI 1.x to avoid a breaking change. But now with 6.x it is a good time to make needed breaking changes.

You can find some more context in https://github.com/angular/angular-cli/pull/8250, https://github.com/angular/angular-cli/pull/8130, https://github.com/angular/angular-cli/issues/8160, https://github.com/angular/angular-cli/issues/5804 and https://github.com/angular/angular-cli/issues/1548

We understand that this isn't great if your code relies, directly or indirectly, on a library that makes incorrect assumptions about browser environments. The best I can say is that you should bring this problem to their attention via an issue on their tracker. Maybe newer versions of that library don't have this behaviour anymore.

But although it is inconvenient to address these problems, I hope we can agree that the current behaviour is incorrect. Browser code should not rely on things that are not available in browser environments.

All 39 comments

Can you describe steps you used to update your project?

  1. remove nodes_modules
  2. npm uninstall @angular/cli -g && npm install @angular/cli@next -g && npm install @angular/cli@next && npm i && ng s

Have you tried to remove package-lock.json file together with node_modules?

@alexzuza already disabled generating this file , thanks

@alexzuza @istiti I fairly certain your original issue with needing net is coming from this commit:
https://github.com/angular/angular-cli/commit/e84baa1d4e65dba4c64ff4632f2e8ea1a964b1f8 (master) / https://github.com/angular/angular-cli/commit/c7a8b619fb67b42e346b98fb6e6629cf4aace850 (6.0.x)
(they're the same commit just in different branches form the release process afaik)

If you look, they've removed all of the node globals shimming. I'm currently trying to figure out how to overcome that, and put the node builtins back in the bundle.

We're having the same issue with jszip:
slack_-_yoobic

Some things I've noticed having a poke at the next CLI with Webpack 4:

  • Serve compilation times are massively off (it says 11377ms but is actually more like 377ms)
  • Building is slightly slower by about 20sec for me (64405ms vs 81253ms).. or maybe it's a false time, I guess I would need to physically time it :)
  • Chunk names seem long and duplicated:

    • 1.7.1: chunk {thing.module} thing.module.db03a5a276313f5358e2.chunk.js () 19.9 kB [rendered]

    • 6.0.0 beta 4: chunk {5} thing-thing-module-ngfactory.fa3021a44cf5d19f158e.js (thing-thing-module-ngfactory) 27.3 kB [rendered]

  • Some modules are larger (19.9kb vs 27.3kb)

Just tried to update
@jskrzypek
I run into the same problem with jszip. Installing stream package manually solves the issue but i shouldn't do so.

@intellix
I also noticed that console output shows inaccurate time.

One more thing:
If we run cli as ng serve -o then new window will be opened after each rebuild.

Heya, first of all I want to thank you all for trying the 6.x versions. They are still pretty raw and getting feedback early is super important to address problems.

The build times and chunkname bugs are unexpected, probably to do with Webpack 4 interop. We expect those to get fixed soon.

The problem with net/global is not so straightforward. We are removing it for 6.x, yes (https://github.com/angular/angular-cli/pull/9812). And we do expect this to cause problems to some projects. But we're not doing it because we want to break projects, we're doing it because leaving it in also breaks other projects, and it is incorrect.

The incorrect part is libraries that are meant to run in the browser relying on node globals being available. Browser code runs in the browser, not in node, and shouldn't expect things that are not available in a browser context to be there.

For instance, if you open up your browser and type require('fs') you will get an error saying require does not exist. require is only available in node. But if you tried to import it some other way, like import('fs') (chrome supports import at the moment), you will also get an error saying it doesn't know what fs is. fs is also available only in node.

Some libraries use those constructs because they expect to be built in node, but to run in the browser. And they also expect the tooling that builds them to either provide a browser version of those node built-ins, or to pretend it's there when it actually is not.

In Angular CLI we never provided a browser version of node built-ins. But we did:

  • provide a shim for global and process.
  • supply an empty module when fs, crypto, tls and net were requested.

This is a problematic situation because even that can break some libraries (https://github.com/angular/angular-cli/issues/5804), increase the size of others (https://github.com/angular/angular-cli/pull/8130#pullrequestreview-71174772), and just generally make for a situation where browser code that shouldn't work at all works only when built in with very specific tooling. This is not a good situation. Browser code should not rely on things that are not available in browser environments.

We investigated the topic and reached this conclusion some time ago but did not remove support for this broken behaviour in CLI 1.x to avoid a breaking change. But now with 6.x it is a good time to make needed breaking changes.

You can find some more context in https://github.com/angular/angular-cli/pull/8250, https://github.com/angular/angular-cli/pull/8130, https://github.com/angular/angular-cli/issues/8160, https://github.com/angular/angular-cli/issues/5804 and https://github.com/angular/angular-cli/issues/1548

We understand that this isn't great if your code relies, directly or indirectly, on a library that makes incorrect assumptions about browser environments. The best I can say is that you should bring this problem to their attention via an issue on their tracker. Maybe newer versions of that library don't have this behaviour anymore.

But although it is inconvenient to address these problems, I hope we can agree that the current behaviour is incorrect. Browser code should not rely on things that are not available in browser environments.

@filipesilva is there any chance we could pass in an override for the node webpack config to override the false? Since the options for the node property are all booleans or strings, it's completely encodable as json, and would be straightforward to add it to the .angular-cli.json config.

If you'll consider a PR adding support for that possibility, I'd be happy to make it.

@alexzuza I managed to fix my issue with jszip by changing the import from 'jszip' to 'jszip/dist/jszip.min', which is the more expected choice for web apps I guess...

@jskrzypek I don't import jszip directly. It's one of dependencies of my dependencies

@alexzuza A path mapping in the app's tsconfig should allow redirection of the jszip import to the jszip/dist/jszip.min.js file.

Untested example:

paths: {
      'jszip': [ '../node_modules/jszip/dist/jszip.min.js' ],
    }

Ideally, since the package appears to ship a browser bundled version it should point the package.json field browser to the file. The CLI would then pick up that file and use it directly.

@clydin Big thank's for clarification.

It would be great if it was written under

BREAKING CHANGES
@angular/cli: Libraries/Packages must contain a web version if not web specific.

Update

The paths option works

Now only one thing annoys me :)

If we run cli as ng serve -o then new window will be opened after each rebuild.

@alexzuza You're welcome. We are working on that last mentioned annoyance and should be fixed in the next release.

What I understand in this issue the asnwer to my problems:
number 1 : it's time to make breaking change in v6 and ask lib to update and make correct browser support

number 2: no reasons to solve/lost time here because magically if delete all uninstall all ts will install well

number 3: what about DeprecationWarning ?

number 4: long chunkname is webpack4 problem ?

number 5: @filipesilva you say it seems to be webpack4 problem too ? actually it block and never finish at step :
image
on my project

thanks to confirm

update to 6beta5:

   "ok": "npm run fr && npm run de",
    "fr": "node --max-old-space-size=8192 ./node_modules/@angular/cli/bin/ng build --build-optimizer --prod --app=prod --output-path dist/fr --locale fr --bh /fr/ --i18n-format xtb --i18n-file src/locale/fr.xtb",
    "de": "node --max-old-space-size=8192 ./node_modules/@angular/cli/bin/ng build --build-optimizer  --prod --app=prod --output-path dist/de --locale de --bh /de/ --i18n-format xtb --i18n-file src/locale/de.xtb",

when npm run ok i got build-optimizer can't run without --aot, then I remove --buildoptimizer and seems "ng build --prod" build with sourcemap and without aot/minify app, this is chaning ? we need yet specify that we don't want sourcemap ?and add --prod --aot to build aot+minify ? sorry i missed it in readme ? any links of changes ?

second my app is still blocking on build at 92% without moving to 100%

cc @filipesilva

@istiti we're actually in the middle of moving a lot of things around and hope to have a more stable 6.0 beta soon, so some of those problems are not going to be solved in the next beta but should all be taken care of before 6.0 final.

I am having hard time to understand this. Please correct me if I am missing anything.

"Browser code should not rely on things that are not available in browser environments." sounds perfectly correct. But the situation can be phrased in another form,

"No library should support both browser and node". This is what I am having trouble with.

As a library developer it is pretty normal to have both browser code and node code, then run according to environment.

Are we saying this is wrong? Any library in order to work with Angular has to be pure?

Sorry if I misunderstood something. Any clarification is appreciated.

This is statement is not what is implied by the first:

"No library should support both browser and node".

Rather, a library should not assume its environment if it intends to support both node and a browser. This is essentially a standard cross-platform situation. Just as a library should not assume linux system APIs are present on Windows (or the opposite), a library should not assume node APIs are present within a browser. A cross-platform library should rather test for its platform (or API) and use the functionality indicated by the outcome. NPM packages also can use the browser field to indicate an alternate browser only entry point which many utilities currently support; CLI included.

Thank you @clydin for the response. What I meant was not assuming, but detecting. Basically something like

if (is_browser) {
  // browser code
} else {
  // node code
}

So this is wrong. Instead should choose between these two options, 1) have separate packages; 2) specify browser field in package.json to indicate browser entry point.

correct?

None of those are truly wrong. They are all design decisions based on the complexity of the code, volume of platform-dependent APIs, and personal choice. The basic conditional, for instance, is quite acceptable if the API usage is minimal; or if combined with an abstraction layer that is then used throughout the package.

On version 6 of Angular CLI we are removing the shim for global and other node built-ins as I mentioned in https://github.com/angular/angular-cli/issues/9827#issuecomment-369578814.

If you are using a library that assumes these globals are present, you can try manually shimming it inside your polyfills.ts file:

// Add global to window, assigning the value of window itself.
(window as any).global = window;

I ran a quick test with socket.io-client and this seemed to allow it to run.

@filipesilva
I understand the reasoning behind this, but not providing a recommendation for dealing with it or a switch to disable it is unreasonable. The suggestion of submitting a ticket to all of the repos related to the dependencies my app has is almost laughable and unrealistic. We need a way to deal with this in the near term if anyone is going to be able to migrate their angular 5 apps to angular 6

@filipesilva :

The incorrect part is libraries that are meant to run in the browser relying on node globals being available. Browser code runs in the browser, not in node, and shouldn't expect things that are not available in a browser context to be there.

That's why some libraries have code that looks like this :

if (ENVIRONMENT_IS_NODE) {
  var fs = require("fs");
  var NODEJS_PATH = require("path");
  NODEFS.staticInit();
};

Such code used to run fine in Angular 5.

However, in Angular 6, this same code produces the following errors :

ERROR in ./lib/luciad/photon/photon_painter.js
Module not found: Error: Can't resolve 'fs' in 'D:RIA ANGULARria-angular-cli-2libluciadphoton'
ERROR in ./lib/luciad/photon/photon_painter.js
Module not found: Error: Can't resolve 'path' in 'D:RIA ANGULARria-angular-cli-2libluciadphoton'

This is simply ridiculous.


@clydin :

This is statement is not what is implied by the first:

"No library should support both browser and node".

Rather, a library should not assume its environment if it intends to support both node and a browser.

Of course. And that's why libraries have stuff like if (ENVIRONMENT_IS_NODE) { }, which now no longer seems possible with Angular 6. Thus, compatibility with Angular 6 prevents libraries from supporting both browser & Node.

None of those are truly wrong. They are all design decisions based on the complexity of the code, volume of platform-dependent APIs, and personal choice. The basic conditional, for instance, is quite acceptable if the API usage is minimal; or if combined with an abstraction layer that is then used throughout the package.

So are you saying I CAN use libraries that have stuff like if (ENVIRONMENT_IS_NODE) { } in them in Angular 6?

And if so, what would I need to do to get this to work?

well seems like someone else is even more frustrated than me ;D

Any update how to solve those issues?

How to bring access to node's process back again?
Tried something like: (window as any).process = process; or (window as any).process = window; at polyfills.ts but of course it didn't work. Doing that I have access to a process variable but it comes empty =S...
Update: rethink if you really need this, I was digging here 'cause of Ionic 4 and I ended up with the newest Ionic 4 environments no needing this access anymore.

For anyone still looking for an answer, here's how I managed to require('fs') in my angular 7 app. Or for that matter, any other node module.

Versions

Angular CLI: 7.0.4
Node: 10.13.0
OS: win32 x64
    "@angular/animations": "~7.0.0",
    "@angular/common": "~7.0.0",
    "@angular/compiler": "~7.0.0",
    "@angular/core": "~7.0.0",
    "@angular/forms": "~7.0.0",
    "@angular/http": "~7.0.0",
    "@angular/platform-browser": "~7.0.0",
    "@angular/platform-browser-dynamic": "~7.0.0",
    "@angular/router": "~7.0.0",
    "@angular-devkit/build-angular": "~0.10.0",
    "@angular/cli": "~7.0.4",
    "@angular/compiler-cli": "~7.0.0",
    "@angular/language-service": "~7.0.0",
    "electron": "^3.0.7",
    "typescript": "~3.1.1"

1. Install @types/node

npm install --save-dev @types/node

2. Modify tsconfig.json

Take note of "allowSyntheticDefaultImports" flag. It must be set to true.

{
  "compileOnSave": false,
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "module": "es2015",
    "moduleResolution": "node",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "target": "es5",
    "types": [
      "node"
    ],
    "typeRoots": [
      "node_modules/@types"
    ],
    "lib": [
      "es2018",
      "dom"
    ],
    "strict": false
  }
}

3. Require fs

import { Component } from '@angular/core';
import { } from 'electron';
import Fs from 'fs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {

  constructor() {
    //check if platform is electron
    let isElectron: boolean = window && window['process'] && window['process'].type;

    if (isElectron) {
      let fs: typeof Fs = window['require']('fs');
      let app: Electron.App = window['require']('electron').remote;
      console.log(fs, app, window['process']);
    }
  }
}

Note: The import statements at the top of the file are just to provide for type information. The variable values are set using node _require_.

4. Result

electron-angular

Edit:

Turns out, that if your project has dependencies that _require_ 'fs', 'path', 'child_process' etc. The angular compiler fails to compile the code. To get around this, as someone has already suggested, add (window as any).global = window; to your polyfills.ts.

In my case, I had chokidar, node-pty and electron as a dependency. This worker for me.

in an angular 7 app the workaround (https://github.com/angular/angular-cli/issues/9827#issuecomment-386154063) only works for me if i put

(window as any).global = window;

in a .ts file and import it in polyfill.ts , e.g. import 'cstm-polyfill.ts';

Hello, is there any lib for deflation that can be used with Angular 6 ?
Since the upgrade I am having the following issues with these zlibs:
https://github.com/devongovett/browserify-zlib/issues/36
https://github.com/imaya/zlib.js/issues/74
I've tried some workarounds, described in the issues above but to no avail.
p.s. I use pako for the deflation without any issue, however, the above is still valid for the mentioned libs.

I followed the guidance you provided here and on my StackOverflow Question but it is still failing to compile.

@filipesilva @Nishkalkashyap @vlkrrrr is there an alternative method to execute rather than using webpack? The config.js produced via ng eject is deprecated and I don't want to rely on 3rd party libraries. I can understand using electron.remote does not produce any errors with regards to a ts component but electron/index.js is having some issues and (windows as any).require('fs') code is not working. Any help will be appreciated! Is there any way where we fetch the required module from elsewhere except electron package?

While https://github.com/angular/angular-cli/issues/9827#issuecomment-369578814 is relevant to the problem. I need some form of solution in order to get my app working.

@shinde-ha using https://github.com/manfredsteyer/ngx-build-plus to alter the webpack config is the most convenient option I think.

@filipesilva @clydin i think ngx-build-plus might not be required unless necessary. I guess we can always have IPC communication and supply 'fs' and 'path' thru main process which handle node built-ins and send the contents back to renderer.

Another option for those is to use TS config path mapping to map the “fs”/“path” imports to either manually installed shims or even arbitrary application code.

@filipesilva @clydin It makes sense on the fact that chromium server architecture should have such changes. But it risks the main process in electron to be relatively busy.
Consequently, What are your thoughts about handling this issue with regards to electron being used in Angular? I won't prefer relying on any third party libraries.

Why cli shows a warning from a library which requests a stream global inside the try/catch block?
e.g. https://github.com/isaacs/sax-js/issues/237

I fixed this by adding

"types": [
  "node"
]

in tsconfig.app.json

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

IngvarKofoed picture IngvarKofoed  ·  3Comments

donaldallen picture donaldallen  ·  3Comments

brtnshrdr picture brtnshrdr  ·  3Comments

JanStureNielsen picture JanStureNielsen  ·  3Comments

naveedahmed1 picture naveedahmed1  ·  3Comments