Skip to content

Running local 'tsc' from node #6387

Closed
Closed

Description

@arfmann

I have a fairly complex build process which I've written using Node scripts, and somewhere in there I need to run the TypeScript compiler. Almost all of my build tools have a JS API which mean I can run them easily, e.g:

var uglify = require("uglify-js");
uglify.minify(...);

But I'm struggling to do the same for TypeScript. Is there a way to do this? I'm using tsconfig.json files so I only want to do the equivalent of (ran from the command line):

tsc -p my-project

I did have some luck with getting this working with child_process.spawn but this seems to rely on me having a global install of TypeScript, and I'd rather not to make that assumption...

Activity

  1. davidreher commented on Jan 7, 2016

    @davidreher

    What we are doing in our project is simply calling the tsc from node_modules/.bin folder or create an npm script (which implicitly works inside the node_modules/.bin folder) and call that

  2. mhegazy commented on Jan 7, 2016

    @mhegazy
    Contributor

    you can use the typescript compiler api, just like you use uglify today. var ts = require("typescript");. here is more information on the API https://github.com/Microsoft/TypeScript/wiki/Using-the-Compiler-API

  3. arfmann commented on Jan 7, 2016

    @arfmann
    Author

    Mohamed Hegazy (@mhegazy) - Thanks, but I'm strugging to see how to run this and have it act in the same way as the tsconfig.json-driven tsc tool. I'm hoping to just do the equivalent of giving it the '-p' argument - i.e. the directory with my tsconfig.json file, and then just have the compiler do it's thing. Is that possible?

  4. mhegazy commented on Jan 7, 2016

    @mhegazy
    Contributor

    here you go:

    /// <reference path="typings/node/node.d.ts" />
    
    import * as ts from "typescript";
    import * as fs from "fs";
    import * as path from "path";
    
    function reportDiagnostics(diagnostics: ts.Diagnostic[]): void { 
        diagnostics.forEach(diagnostic => {
            let message = "Error";
            if (diagnostic.file) {
                let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
                message += ` ${diagnostic.file.fileName} (${line + 1},${character + 1})`;
            }
            message += ": " + ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
            console.log(message);
        });
    }
    
    function readConfigFile(configFileName: string) { 
        // Read config file
        const configFileText = fs.readFileSync(configFileName).toString();  
    
        // Parse JSON, after removing comments. Just fancier JSON.parse
        const result = ts.parseConfigFileTextToJson(configFileName, configFileText);
        const configObject = result.config;
        if (!configObject) {
            reportDiagnostics([result.error]);
            process.exit(1);;
        }
    
        // Extract config infromation
        const configParseResult = ts.parseJsonConfigFileContent(configObject, ts.sys, path.dirname(configFileName));
        if (configParseResult.errors.length > 0) {
            reportDiagnostics(configParseResult.errors);
            process.exit(1);
        }
        return configParseResult;
    }
    
    
    function compile(configFileName: string): void {
        // Extract configuration from config file
        let config = readConfigFile(configFileName);
    
        // Compile
        let program = ts.createProgram(config.fileNames, config.options);
        let emitResult = program.emit();
    
        // Report errors
        reportDiagnostics(ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics));
    
        // Return code
        let exitCode = emitResult.emitSkipped ? 1 : 0;
        process.exit(exitCode);
    }
    
    compile(process.argv[2]);

    to run this:

    tsc compile.ts --m commonjs
    node compile.js c:\test\tsconfig.json
  5. arfmann commented on Jan 7, 2016

    @arfmann
    Author

    This is incredibly useful! Thanks very much.

    I'm stuck using plain [node-friendly] JavaScript for this, so I've converted it in case anyone else happens to be in the same boat.

    "use strict";
    
    const ts = require("typescript");
    const fs = require("fs");
    const path = require("path");
    const process = require("process");
    
    function reportDiagnostics(diagnostics) { 
        diagnostics.forEach(diagnostic => {
            let message = "Error";
            if (diagnostic.file) {
                const where = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
                message += ' ' + diagnostic.file.fileName + ' ' + where.line + ', ' + where.character + 1;
            }
            message += ": " + ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
            console.log(message);
        });
    }
    
    function readConfigFile(configFileName) { 
        // Read config file
        const configFileText = fs.readFileSync(configFileName).toString();  
    
        // Parse JSON, after removing comments. Just fancier JSON.parse
        const result = ts.parseConfigFileTextToJson(configFileName, configFileText);
        const configObject = result.config;
        if (!configObject) {
            reportDiagnostics([result.error]);
            process.exit(1);
        }
    
        // Extract config infromation
        const configParseResult = ts.parseJsonConfigFileContent(configObject, ts.sys, path.dirname(configFileName));
        if (configParseResult.errors.length > 0) {
            reportDiagnostics(configParseResult.errors);
            process.exit(1);
        }
        return configParseResult;
    }
    
    
    function compile(configFileName) {
        // Extract configuration from config file
        const config = readConfigFile(configFileName);
    
        // Compile
        const program = ts.createProgram(config.fileNames, config.options);
        const emitResult = program.emit();
    
        // Report errors
        reportDiagnostics(ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics));
    
        // Return code
        const exitCode = emitResult.emitSkipped ? 1 : 0;
        process.exit(exitCode);
    }
    
    compile('tsconfig.json');
  6. leftyftw commented on Feb 10, 2017

    @leftyftw

    arfmann Did you adapt this yourself for free use by others? I'd like to use it in a project, but have to ensure copyright compliance.

  7. jamiewinder commented on Feb 10, 2017

    @jamiewinder

    Jaime Torres (@leftyftw) - yes, it's a straight adaptation of what mhegazy posted, and I don't claim any rights to it. :)

  8. locked and limited conversation to collaborators on Jun 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions