38

I'm trying to migrate my Angular Universal project from Angular v5 to v6

I've got a service where I use fs to load the translation on the server side. Everything works well with Angular v5.

With Angular v6, when I run npm run start aka ng serve --proxy-config proxy.conf.json I face the following error

ERROR in ./src/providers/core/translate/translate-universal-loader.service.ts Module not found: Error: Can't resolve 'fs' in '/Users/me/Documents/projects/myproject/src/providers/core/translate'

In my service I declare fs like the following:

declare var require: any;
const fs = require('fs');

I also tried to declare it like following, but didn't help

import * as fs from 'fs';

To tell webpack to ignore fs I tried to add the following in my webpack.server.config.js without success

node: {
    fs: 'empty'
}

also tried with a webpack plugin, wasn't successful neither

new webpack.IgnorePlugin(/fs/)

but actually it's maybe not the config use by ng serve but I don't know if I could still eject the configuration with v6?

anyone has got an idea?

UPDATE

If I declare fs as any it solves the problem for ng serve but unfortunately it will not work on the server side after npm run build:ssr and run npm run serve. On the server side I will then face the following error

ERROR ReferenceError: fs is not defined

p.s.: my project follows https://github.com/angular/universal-starter structure, config and dependencies

David Dal Busco
  • 7,975
  • 15
  • 55
  • 96

12 Answers12

57

Since previous answers are quite old, it might help to highlight here that a workaround for Angular9 is just to add the following in your package.json:

"browser": {
    "fs": false,
    "os": false,
    "path": false
  }

This works very well for me. For reference, I found this solution on the official tensorflow/tfjs Github page here.

Marc
  • 2,183
  • 2
  • 11
  • 16
  • 3
    Coolio. Updated the accepted answer with a reference to yours. – David Dal Busco Aug 16 '20 at 07:48
  • 2
    The best answer for Angular 9+ – Daniel Danielecki Oct 18 '20 at 09:20
  • 2
    Wish I could upvote this answer one time for each false-positive solution I've found. In my case it solved the error `ERROR in ./node_modules/foo/foo.js Module not found: Error: Can't resolve 'path' in 'my-app/node_modules/foo`, where `foo` is a module that uses `path`. :). In my case, only `"browser": { "path": false }` was needed. – tresf Oct 22 '20 at 02:29
  • Check the spec of the "browser" field to see why it works (or doesn't): https://github.com/defunctzombie/package-browser-field-spec – j2L4e Nov 12 '20 at 12:22
  • 6
    Solves the build issue; however, my app does not properly load anymore `Uncaught ReferenceError: __dirname is not defined at Object.vbkW (index.js:4)` – d4rty Dec 17 '20 at 14:50
  • 1
    Yea 2022 with 'file-system' module and this fix makes no difference. Anyone able to make this work with Angular 14? – Jake_3H Dec 14 '22 at 10:16
34

Update 2020

See answer of Marc for Angular v9.

Update 2019

See comment, according @Tahlil it is now possible. This works for Angular v8 (Ivy compiler) see this answer. It sets specific modules to false for use in the browser in package.json.

Original answer

Ok after hours I come to the conclusion with the answers I gathered that the real answer is:

You can't use fs anymore in Angular v6

Furthermore, since it's not possible anymore to eject the webpack configuration, there is no way to tell webpack to ignore the fs require

There is an open issue about this subject: https://github.com/angular/angular-cli/issues/10681

P.S.: I was using fs to load the translations on the server side, I overcome the problem by following solution of @xuhcc, see https://github.com/ngx-translate/core/issues/754

David Dal Busco
  • 7,975
  • 15
  • 55
  • 96
14

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.

For updates, Track the issue here

https://github.com/angular/angular-cli/issues/9827

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.

Nishkal Kashyap
  • 960
  • 7
  • 17
  • I have a project with a dependency that uses `path` and `fs`. I did the above mentioned steps but can't seem to resolve the issue. – Tanzeel Nov 21 '18 at 02:49
  • Hard to tell without any info, whats the version of angular, electron, nodejs that you're using? – Nishkal Kashyap Nov 21 '18 at 03:30
  • 1
    I'm a lot closer than I was, but I'm getting an error `TypeError: window.require is not a function` when trying to use `window['require']`. Not sure how to get around this one – ntgCleaner Feb 28 '19 at 15:29
  • @ntgCleaner try this: `declare global { interface Window { require: NodeRequire; } }` Then, use window['require']. If it was a typescript compiler error, it must be solved with this. If that doesn't works, try this: `window['require']=eval('require')`. And the use window['require']. – Nishkal Kashyap Feb 28 '19 at 16:51
  • @NishkalKashyap after trying what you've mentioned and playing around with it more, I just can't seem to get it to work. I'm trying to do some simple web scraping with cheerio and request-promise, but they both need `require` to use. I'll keep trying stuff out – ntgCleaner Feb 28 '19 at 17:32
  • @ntgCleaner try adding this code in electron creation function. it worked for me. `webPreferences: { nodeIntegration: true }`. see this [answer](https://stackoverflow.com/a/56095485/2342414) – benshabatnoam Aug 19 '19 at 13:54
  • works perfectly with electron 4.1.0, Ionic 5 and angular 8 – Mr. Ratnadeep Jan 03 '20 at 12:10
  • This didn't work for me .. Marc's answer did. Thanks for sharing ! – Aymane EL Jahrani Oct 07 '22 at 14:02
5

In Angular 8, you can now use Angular Builders to specify a web.config.js which extends the virtual config produced by Angular.

This blogpost explains it quite well.

tldr:

  1. run npm i -D @angular-builders/custom-webpack
  2. edit your angular.json file architect.serve and architect.build to tell it to use the custom-webpack module to extend the virtual config with your webpack.config.js file
  3. Create your custom webpack.config.js - in this case it would look like this:
module.exports = {
    node: {
        fs: 'empty'
      }
};
bighairdave
  • 592
  • 5
  • 19
3

add below lines in your package.json

  1. "browser": { "fs": false, "os": false, "path": false }

Click here to see sample image

1

The accepted answer is correct; you can't use fs anymore in Angular v6+.

However, this alternative builder (it's an extension to the Angular CLI) allows you to target an Electron environment and have full access to Electron's features:

https://github.com/angular-guru/electron-builder

adamup
  • 1,508
  • 19
  • 29
1

I fixed this by adding

"types": [
  "node"
]

in tsconfig.app.json

Ebram
  • 1,042
  • 1
  • 13
  • 26
0

You can declare the fs also by doing this declare var fs: any;

John Velasquez
  • 3,421
  • 2
  • 18
  • 23
  • 1
    actually, unfortunately, it doesn't fully solve the problem. this solve `ng serve` but if I build my project, `npm run build:ssr` and then run it `npm run serve`, I will face the error `fs is not defined` on the serve side :( – David Dal Busco May 06 '18 at 19:28
0

Alternatively In NativeScript File is implemented as part of the file system module. To use it you have to import it in your code behind file. e.g.

import * as fs from "file-system';

var documents = fs.knownFolders.documents();
var path = fs.path.join(documents.path, "FileFromPath.txt");
var file = fs.File.fromPath(path);

// Writing text to the file.
file.writeText("Something")
    .then(function () {
        // Succeeded writing to the file.
    }, function (error) {
        // Failed to write to the file.
    });
Subrata Fouzdar
  • 724
  • 5
  • 17
0

I am running an Angular app inside an Angular CLI monorepo, set up with the help of Nx schematics. I’m sharing code from a lib directory.

When trying to use a Typescript Enum from a shared lib inside the Angular app I got:

Critical dependency: the request of a dependency is an expression

Can't resolve 'fs'

The error stack involved:

It was strange because on the face of if the inclusion of the Enum had nothing to do with type-graphql.

The issue turned out to be related to the fact that type-graphql schemas and Typescript Enums were defined in the same lib. Extracting the Enums into their own lib solved the problem. I’m not clear on why the error happened, but in any case the solution worked.

EDIT

So the problem was that per this nx issue, and this type-graphql issue, at a certain point including stuff from a lib with TypeGraphQL ends up trying to bundle whole TypeGraphQL into the browser app (the @Input() decorator seems to be another such trigger).

The solution, if you want to include TypeGraphQL classes in the frontend, is to update the webpack config. Doing this is in an AngularCLI app involves quite a few steps.

Community
  • 1
  • 1
Derek Hill
  • 5,965
  • 5
  • 55
  • 74
0

If you have imported jasmine in your spec file to avoid tslint error, you should to following:

  1. Remove import jasmine; from spec file.
  2. Add jasmine in tsconfig.json
...
...
"compilerOptions": {
  ...
  ...
  "types": [
      "webpack-env",
      "jasmine"
  ]
  ...
  ...
}
...
...

Yuvraj Patil
  • 7,944
  • 5
  • 56
  • 56
-3

Apparently advanced-json-path resolves this issue in Angular 6 onwards if anyone is using fs

So one has to do an

npm i advanced-json-path --save-dev

as it is a dev dependency (at least in my case) as of this message instance, it is version 1.0.8 Then the Module 'fs' not found doesn't occur.

package.json
{
    ....
   "advanced-json-path": "^1.0.8",
}

In our application it got rid of the Module 'fs' not found error.

Mark Ormesher
  • 2,289
  • 3
  • 27
  • 35
user428602
  • 47
  • 2
  • 11