23

I'm working on a simple nodejs electron (formerly known as atom shell) project. I'm writing it using angular 2, using the project the same project setup as they recommend in the documentation for typescript:

tsc:

{
  "compilerOptions": {
    "target": "es5",
    "module": "system",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  },
  "exclude": [
  "node_modules",
  "typings/main",
  "typings/main.d.ts"
  ]
}

I need to run a command, I found out that I can do it with node "child_process". I couldn't find anyway for me to "import" or "require" it while having its type used from the node.d.ts file. I have found the "child_process" interface in the node.d.ts file which suits my need, this is how it looking in the node.d.ts file:

    declare module "child_process" {
    import * as events from "events";
    import * as stream from "stream";

    export interface ChildProcess extends events.EventEmitter {
        stdin:  stream.Writable;
        stdout: stream.Readable;
        stderr: stream.Readable;
        pid: number;
        kill(signal?: string): void;
        send(message: any, sendHandle?: any): void;
        disconnect(): void;
        unref(): void;
    }

    export function spawn(command: string, args?: string[], options?: {
        cwd?: string;
        stdio?: any;
        custom?: any;
        env?: any;
        detached?: boolean;
    }): ChildProcess;
    export function exec(command: string, options: {
        cwd?: string;
        stdio?: any;
        customFds?: any;
        env?: any;
        encoding?: string;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
    }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function exec(command: string, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function execFile(file: string,
        callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function execFile(file: string, args?: string[],
        callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function execFile(file: string, args?: string[], options?: {
        cwd?: string;
        stdio?: any;
        customFds?: any;
        env?: any;
        encoding?: string;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
    }, callback?: (error: Error, stdout: Buffer, stderr: Buffer) =>void ): ChildProcess;
    export function fork(modulePath: string, args?: string[], options?: {
        cwd?: string;
        env?: any;
        execPath?: string;
        execArgv?: string[];
        silent?: boolean;
        uid?: number;
        gid?: number;
    }): ChildProcess;
    export function spawnSync(command: string, args?: string[], options?: {
        cwd?: string;
        input?: string | Buffer;
        stdio?: any;
        env?: any;
        uid?: number;
        gid?: number;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
        encoding?: string;
    }): {
        pid: number;
        output: string[];
        stdout: string | Buffer;
        stderr: string | Buffer;
        status: number;
        signal: string;
        error: Error;
    };
    export function execSync(command: string, options?: {
        cwd?: string;
        input?: string|Buffer;
        stdio?: any;
        env?: any;
        uid?: number;
        gid?: number;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
        encoding?: string;
    }): string | Buffer;
    export function execFileSync(command: string, args?: string[], options?: {
        cwd?: string;
        input?: string|Buffer;
        stdio?: any;
        env?: any;
        uid?: number;
        gid?: number;
        timeout?: number;
        maxBuffer?: number;
        killSignal?: string;
        encoding?: string;
    }): string | Buffer;
}

but I can only (as I know of) get this type only by using import:

import * as child_process from 'child_process'; 

Only problem is that when I do this, my app cant load and I get the following error in the console:

GET file:///C:/angular2Samples/NGW-electron-VS%20-%20TEMP/child_process net::ERR_FILE_NOT_FOUND

For now, im getting my way around by using:

var child_process = require('child_process');

but I couldn't find anyway to add the type information to this var:

var child_process : I_CANT_PUT_ANY_CHILD_PROCESS_TYPE_HERE = require('child_process');

Any ideas on how I can get the child_process (or any other declared node modules that arent public interface that I can state after ":" operator) with type information?

Thanks alot in advance for any help and explanations :)

UPDATE ------------------------------------------------------------------

As tenbits suggested I have added the reference as follows to the top of the file: ///

and used the import statment you said, but didnt chage my module loader. it still didnt work with the same error as expected. Im not feeling very comfortable about changing the module system, as my project uses angular 2 and their docs and some of their guides said that new projects that has no former prefernce to this matter (I am very new to the module loaders scene and im not fully understanding how it works yet). When I tried to change it I got some errors regarding angular 2 stuffs which I dont have enough time to get into at the moment. Shouldn't there be a way to this without changing the module loader? by glancing at the systemjs site it says at the start that it supports commonjs modules: Systemjs doc

I would really appriciate a solution that doesn't change the module system, or maybe a more depth explanition about what's going on and which approaches to these kind of module loading problems exists out there

tenbits
  • 7,568
  • 5
  • 34
  • 53
Ziv Glazer
  • 786
  • 2
  • 8
  • 24

4 Answers4

46

Ok, after some research #L138 I have found the solution

You can use import as before

import * as child from 'child_process';

var foo: child.ChildProcess = child.exec('foo.sh');
console.log(typeof foo.on);

But you should configure SystemJS to map the module to NodeJS.

System.config({
  map: {
    'child_process': '@node/child_process'
  }
});

That's it!

Rich
  • 5,603
  • 9
  • 39
  • 61
tenbits
  • 7,568
  • 5
  • 34
  • 53
  • Thanks alot for your comment ! I have tried it, please look at my update to the questetion regarding your answer :) – Ziv Glazer Apr 11 '16 at 14:42
  • I'm not quite got it: Have you tried `import child = require('child_process');` instead of `var child = require('child_process');`? Do you have the same result as with `var`? – tenbits Apr 11 '16 at 15:26
  • Yes, exactly the same (notice that I didnt change the module to commonjs as you suggested, the reason for that is noted in my update above) – Ziv Glazer Apr 12 '16 at 16:03
  • Thanks again for your new suggestion. Im afraid it didn't work. I copied your last version of the System.config and changed my code to use the import statement with require as you suggested in the first version of your andwer and still got the same xhr error. I also tried: import * as child from "child_process"; That didn't work either with same error. I also tried doing it with the /// reference at the top to the node.d.ts but as I expected it didn't change anything – Ziv Glazer Apr 14 '16 at 07:44
  • Maybe also rename the title of the question to "Require nodejs “child_process” with typescript, systemjs and electron". – tenbits Apr 14 '16 at 09:10
  • @user1245668, have you checked this solution? – tenbits Apr 15 '16 at 12:06
  • Not yet, I will check and edit the questetion first thing tomorrow :) – Ziv Glazer Apr 16 '16 at 13:10
  • It worked ! Thanks alot for the help its much appreciated :) I looked at the source code of systemjs that you linked and I understood how this works, but im still feeling as if you found it by chance and im wondering how this sort of stuffs regarding systemjs aren't documented anywhere – Ziv Glazer Apr 17 '16 at 09:56
  • 2
    Glad it was helpful, actually I was not familiar with `SystemJS`, only the TypeScript and Electron, but I supposed the problem was, that `SystemJS` was loading nodejs module as regular browser dependency. So at first I suggested to map it somehow to CommonJS module name pattern. When that no helped I just looked into the source code to understand how actually the mapping works, and saw that it was this `@node` prefix required. Yes, It should be documented, but you can always take a look into the source codes, so you can understand how the library was "designed"). Cheers – tenbits Apr 18 '16 at 08:14
  • How to achieve this with commonJs module? – AishApp Apr 28 '16 at 12:22
  • @Aish123, with `@node/` you can only load the core node modules, see the [line](https://github.com/systemjs/systemjs/blob/8703bf0f93c20a6e6a7ad976a5a49a0c4cedc2ec/lib/core.js#L138) and notice the `nodeCoreModules` array. What definitely works: `import * as baz from 'node_modules/foo/x.js';` And for TypeScript you have to create empty module definition to get this compiled. – tenbits Apr 28 '16 at 13:03
  • @tenbits, sorry i unable to understand what you mean as empty module definition. I have .d.ts library file which calls the child_process. I am getting error as the "cannot find module 'child_process '". Could you please elaborate what you mean so that i can try. – AishApp Apr 28 '16 at 13:29
  • @Aish123, ah, you get the Typescript error at compile time. You have to install Node Typings `node.d.ts`. You do this with `tsd`. Install it first: `npm install tsd -g`. Then in your project directory run the command `tsd install node`. This will install `node.d.ts` in `typings` directory. And will create `tsconfig.json`. – tenbits Apr 28 '16 at 14:38
  • well i have done that as well. Included the ref and added import {exec} from 'child_process';. Still getting the error Cannot resolve module 'child_process' – AishApp Apr 28 '16 at 14:44
  • @Aish123, make in `tsconfig.json` you have the property `"moduleResolution": "node",`. Maybe also try to install node typings with save falg `tds install node --save`. Please, give also the feedback) – tenbits Apr 28 '16 at 14:46
  • sorry for the delayed response. i am still getting error and the reason in "child_process" module is checked in node_modules folder rather than the reference node.d.ts file. I am unsure how to import it in my file – AishApp Apr 29 '16 at 04:38
  • Hm, actually "child_process" is the core module of nodejs. How it can be in "node_modules" folder? And there is no 3rd party [`child_process`](https://www.npmjs.com/package/child_process) modules: May be you should start the new question and explain your problem in details, so that we move the discussion in there? – tenbits Apr 29 '16 at 08:35
  • i have modified my query in the link http://stackoverflow.com/questions/36913677/cannot-find-module-shelljs-on-including-the-lib-in-angular-2-typescript – AishApp Apr 29 '16 at 13:06
  • i dont have system.config.js can you help me out how to solve this problem? – Shreenil Patel Dec 28 '17 at 10:27
8

If the error message is 'Cannot find module 'child_process' or its corresponding type declarations' the answer is 'npm install @types/watch'

5

For me it worked with the callback to display the results.

import * as child from 'child_process';

 var foo: child.ChildProcess = child.exec('dir', (error: string, stdout: string, stderr: string) => {
            console.log(stdout);      
        });

I didn't add any mappings in SystemJS as I dont have any such configuration in the node application

rinoy
  • 471
  • 4
  • 10
2

Me & Bing chat:

import { exec } from "child_process";

function openBrowser(url) {
  // Get the operating system
  const os = process.platform;

  // Choose the command based on the operating system
  let cmd;
  if (os === "win32") {
    // Windows
    cmd = `start ${url}`;
  } else if (os === "darwin") {
    // Mac OS
    cmd = `open ${url}`;
  } else if (os === "linux") {
    // Linux
    cmd = `xdg-open ${url}`;
  } else {
    // Unsupported OS
    throw new Error("Unsupported operating system");
  }

  // Execute the command
  exec(cmd, (error, stdout, stderr) => {
    if (error) {
      console.error(`Failed to open browser: ${error.message}`);
      return;
    }
    if (stderr) {
      console.error(`Error: ${stderr}`);
      return;
    }
    console.log(`Opened browser: ${stdout}`);
  });
}

// Example usage
openBrowser("https://www.google.com");
Casper
  • 166
  • 9