Skip to content

--outFile is broken when module import is used #8634

Closed

Description

@XorgonTheTypesafe

TypeScript Version:
1.8.10

Node version :v4.2.2
OS: OSX

Code

Main.ts

/// <reference path="./typings/node/node.d.ts"/>

import * as http from 'http';

namespace Scratch
{
    export class ServerWrapper {

        public constructor() {
            this.server = http.createServer();
        }

        public Start(handler :(request :http.ClientRequest, response :http.ClientResponse)=>void) :void {
            this.server.listen(handler);
        }

        private server : http.Server;
    }
    var s = new Scratch.ServerWrapper();
    s.Start((req,res)=>{});
}

Compile with

tsc ./Main.ts --outFile /dev/stdout

Expected behavior: (what is emitted as Main.js when --outFile is not specified)

"use strict";
var http = require('http');
var Scratch;
(function (Scratch) {
    var ServerWrapper = (function () {
        function ServerWrapper() {
            this.server = http.createServer();
        }
        ServerWrapper.prototype.Start = function (handler) {
            this.server.listen(handler);
        };
        return ServerWrapper;
    }());
    Scratch.ServerWrapper = ServerWrapper;
    var s = new Scratch.ServerWrapper();
    s.Start(function (req, res) { });
})(Scratch || (Scratch = {}));

Actual behavior:

/// <reference path="./typings/node/node.d.ts"/>

Activity

  1. aluanhaddad commented on May 17, 2016

    @aluanhaddad
    Contributor

    Main.ts describes an external module with no exports. I'm not sure if that's what's causing your issue but you may want to look into that as you seem to be trying to export classes from it.

  2. XorgonTheTypesafe commented on May 17, 2016

    @XorgonTheTypesafe
    Author

    Why an external module when it is defined via 'namespace' and no --module flag is used ?
    And why with no exports when there is an export keyword before 'class ServerWrapper' ?
    The behavior is the same with or without the export keyword btw, and I don't actually want to export anything from the Scratch namesapce - the generated Main.js without --outFile is what I'm expecting.

    My original requirement is to have ServerWrapper in a separate .ts file, referenced via /// <reference in Main.ts and combined into a single js artifact that would define and invoke it (as opposed to require()-ing it at runtime) but it looks like it cannot be done even with a single .ts file with --outFile ?

  3. mhegazy commented on May 17, 2016

    @mhegazy
    Contributor

    A module, as defined by the ES 2015 spec, is a file with a top level import or export. you do have one of these: import * as http from 'http'; this causes the compiler to treat it as an external module. please see http://www.typescriptlang.org/docs/handbook/modules.html for more details.

    by default the module system is commonjs. if you want to enforce that you do not use modules in inadvertently, use --module none, and you should see errors whenever you use a module syntax.

    As for the types issue, you will need to extract the types you are using from the module "http" and define them in an interface in the global namespace, this way you can use them without importing.

    Hope that helps.

  4. XorgonTheTypesafe commented on May 17, 2016

    @XorgonTheTypesafe
    Author

    Thanks for the explanation, this is somewhat unintuitive since |'m targeting es5 rather then es2015 (I believe that's the default but even when I specify it explicitly the behaviour is still the same)
    and expected the import to be treated as a typescript construct rather than a javascript construct
    How does that explain tsc ./Main.ts creating a valid (commonjs es5) output vs. tsc ./Main.ts --outFile app.js creating an empty one though ?

  5. mhegazy commented on May 17, 2016

    @mhegazy
    Contributor

    commonjs modules can not be concatenated. they do have different scopes, and that is enforced by the engine at runtime. the compiler will give you an error for using --outFile with --module commonjs as well.

  6. XorgonTheTypesafe commented on May 17, 2016

    @XorgonTheTypesafe
    Author

    so it does:
    error TS6082: Only 'amd' and 'system' modules are supported alongside --outFile.
    but if we say that commonjs is the default when no --module is specified then shouldn't it give the same error, rather then emitting an empty file ?

  7. mhegazy commented on May 17, 2016

    @mhegazy
    Contributor

    well.. i was a bit fuzzy when i said "commonjs" was the default. the system detects that the module is unspecified which is commonJS if you have one file that is a module, and none if you do not. and looks like you did not have any imports in the past, then added one and the behavior changed on you. I would recommend using --module none to avoid such implicit behavior changes in the future.

  8. XorgonTheTypesafe commented on May 17, 2016

    @XorgonTheTypesafe
    Author

    the system detects that the module is unspecified which is commonJS if you have one file that is a module, and none if you do not.

    If each possibility (commonjs,none) when specified explicitly along with --outFile, results in an error message I don't see how it can be considered correct behavior not to do so when it is deduced implicitly, at the very least it would have made it clear to me that tsc considers my code an external module.

  9. mhegazy commented on May 17, 2016

    @mhegazy
    Contributor

    the reason is for backward compatibility. in the past the default was none. switching to commonjs all the time would have broken users not using modules.

  10. XorgonTheTypesafe commented on May 17, 2016

    @XorgonTheTypesafe
    Author

    You mean there was a time when --outFile was legal for 'none'/'commonjs' ? Didn't that use to be '--out' ?
    That still doesn't explain why giving an error message for --outFile when 'commonjs' is deduced implicitly shouldn't be the expected behavior, emitting an empty file also breaks backward compatibility in such a case if I understand correctly.

  11. mhegazy commented on May 17, 2016

    @mhegazy
    Contributor

    the original behavior was a bit wacky :).

    so the original behavior is in the presence of --module commonjs and --outFile, module code will go to its own file, and non-module code will go to the outFile. do not think any one expected that or expected it to continue working this way though.

  12. XorgonTheTypesafe commented on May 17, 2016

    @XorgonTheTypesafe
    Author

    So the empty js artifact is where the non-module code was supposed to be and since tsc implicitly decided to treat Main.ts as a commonjs module based on the presence of import there was no non-module code ?

  13. mhegazy commented on May 17, 2016

    @mhegazy
    Contributor

    correct.

  14. XorgonTheTypesafe commented on May 17, 2016

    @XorgonTheTypesafe
    Author

    Riiiight.
    Ok, I think you will agree that this is very non-intuitive to the point of frustration for people not deeply familiar with the ancient (read: ~2 y.o.) lore.
    Between browser/node, different versions of javascript, modules vs. namespaces the typescript modularity story is already very hairy, add to that obsolete examples for previous versions of the language that can be found online.
    So can this condition be at least made to emit a warning ?
    Specifically: when --outFile is used and a .ts file causes no code to be generated despite defining types and no --module flag is specified.

  15. mhegazy commented on May 17, 2016

    @mhegazy
    Contributor

    i agree.

  16. added
    BugA bug in TypeScript
    and removed
    QuestionAn issue which isn't directly actionable in code
    on May 17, 2016
  17. aluanhaddad commented on May 18, 2016

    @aluanhaddad
    Contributor

    the system detects that the module is unspecified which is commonJS if you have one file that is a module, and none if you do not.

    I had no idea that was the case. It does seem quite confusing perhaps a compiler warning would help.

  18. XorgonTheTypesafe commented on May 18, 2016

    @XorgonTheTypesafe
    Author

    Thanks!
    So it looks like you've decided to make it an error in 2.0 ?

  19. amcdnl commented on Jul 19, 2016

    @amcdnl

    Mohamed Hegazy (@mhegazy) So just to be clear, in 2.0 only System and AMD modules are supported for outFile? Is there any plans to expand this?

    My use case is I'd like be able to use TypeScript outFile to package my opensource project for others to import.

  20. weswigham commented on Jul 19, 2016

    @weswigham
    Member

    Austin (@amcdnl): If you need a concatenated outfile with other module kinds (which is really just commonjs), I'd reccomend using browserify or webpack to do the job (we use browserify for the compiler itself at present). We prototyped an implementation of a commonjs bundler, but the maintanence burden was too high for something a bunch of other well-know tools already do really well.

  21. amcdnl commented on Jul 19, 2016

    @amcdnl

    Wesley Wigham (@weswigham) understood, I ended up going with Rollup. Example: https://github.com/swimlane/angular2-data-table/blob/master/package.json#L34

    Its probably worth just removing the option all together if thats the overall plan to reduce questions like these ;)

  22. 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

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions