Support for output of declaration file?
joewood opened this issue · 13 comments
I'm trying to use tsify to generate a declaration file. Given the documentation at ts-compiler, I would expect this to work in the gruntfile:
options: {
preBundleCB: function (bundle) {
bundle.plugin('tsify', { target: 'ES5', module: 'commonjs', declaration:true });
},
Compilation works fine, but the declaration file is never produced.
That feature is presently not supported by tsify
; only the options listed in the README are passed through to ts-compiler
. Can you explain what sort of output you would expect if declaration files were supported? The *.d.ts files that the TypeScript compiler would produce would not really represent the bundle that Browserify generates. The compiler would generate a *.d.ts file for each input file, which seems kind of useless as soon as Browserify concatenates everything together. What are you trying to use the declaration files for?
Yes, I admit - it is a niche usecase. The bundler was being used with some private packages installed locally. A consumer of this package/bundle wouldn't be able to install the dependent packages in traditionally npm style. The declaration file would be just the top-level file.
Not a problem, I can see why this isn't straightforward and I can work around it.
I see! Yeah, my recommendation for now would be to compile your TS using the regular compiler, and then invoke Browserify on the generated JS files. I'll close this for now, but if more people want declaration file generation support and I can get a feel for what the output should look like, then I will consider adding support to tsify
. Thanks for the info!
So i've been revisiting using tsify with my browserify setup. Good to see the problem with not having a single entry point has been fixed further up the stream but I'm still stumbling over replicating my current use case, which create declaration files.
I can see from this thread declaration files have been discussed before, so let me take you though my setup to show you a possible use case. Yes i agree that creating individual declaration files is pretty useless, but I do feel that creating a single declaration file (say, for use in another typescript module) has a lot of benefits.
My current setup complies using typescript, then packages using browserify. The main issue with this is that I am locked out of being able to incrementally compile using watchify, something that would vastly reduce my current compile times.
As to what the declarations look like, I take my typescript output and concatenate all files by wrapping them in ambient declarations (the ts equivalent of external module definitions). This gives me the interface i need to compile other modules down the chain that depend on the compiled module, and creates an easily distributed build file.
You can see an example of my declaration file generated here: https://github.com/awayjs/awayjs-core/blob/5102af04f2f1660593ec9d59592f9416b8c92a5d/build/awayjs-core.d.ts, and the gulp code used to build them here: https://github.com/awayjs/awayjs-core/blob/5102af04f2f1660593ec9d59592f9416b8c92a5d/gulpfile.js#L26.
If it were possible to add such an output to tsify, i could finally achieve my goal of having watchers on my module files to incrementally build module updates when debugging in a project. It would be infinitely more preferable than the setup i have now, which requires manual triggering of gulp files at the relevant module project to recompile and repackage the entire module codebase. With an output declaration from tsify, I could use watchify for incremental compilation and not ever have to worry about recompiling module code again
Cool, thanks for the extra info. That project setup looks pretty reasonable.
I can definitely see the value here. I think making it work in the general case is a nontrivial but doable task. The real key to how this setup works is here: https://github.com/awayjs/awayjs-core/blob/5102af04f2f1660593ec9d59592f9416b8c92a5d/gulpfile.js#L62
That sets up Browserify to expose files for use elsewhere. Any module that's exposed should be reflected in the resultant declaration file, under the name under which it is exposed. Other modules are inaccessible and should therefore not be included. (TBD: does this get more complicated if an exposed module references a non-exposed module? I'm not sure that type of setup is legal in straight TypeScript, but Browserify adds an extra level of module hiding that potentially complicates things...) Your setup is a relatively trivial special case in that every module is exposed, which means that every generated declaration file should be reflected in the output.
A valid declaration file feature would have to reference the list of exposed modules, and generate a declaration file based on that. It would also add an additional file output from Browserify. (TBD: how does that work with Gulp? Have to look into how e.g. factor-bundle
deals with it)
I don't know if and when I'll get to this feature -- PRs are certainly welcome.
Yes, i think you're right about the exposed path in browserify - this is the same as the one required in the declaration file and would be considered the general case, so in theory this information could be used by the plugin to build the same d.ts file that I am currently building manually
To answer your question, I don't think an exposed module referencing a non-exposed module is a problem for browserify or typescript, but it does then follow that a non-exposed module shouldn't be included in the declaration file as it would be similarly inaccessible to any typescript code implementing the module.
I'm not an expert in browserify internals so i wouldn't be able to tell you how this would work with the plugin, but you say you are already handling multiple .js file outputs from the typescript compiler so I would hope a similar process could be executed in parallel to output the declaration file as a concatenated result of the multiple .t.ds files from the compiler. The code i currently use to concatenate results can be seen here: https://github.com/awayjs/awayjs-core/blob/5102af04f2f1660593ec9d59592f9416b8c92a5d/gulpfile.js#L28
I'd be happy to discuss a contractual arrangement if you were interested in working on this feature, as my developers are losing days with slow compile times atm, as am I. Please PM me at rob@infiniteturtles.co.uk if you'd like to discuss further.
Hi, we also have the same core need of producing a declaration file to be used in 'downstream' typescript projects, but the specifics and transformations applied to the individual d.ts files as spit out by tsc are very different.
Could we just have second stream (like gulp-typescript does) which would contain the original d.ts files, and then leave transformation / concat / output stage to the user. That stage differs anyway between users and projects, and could be very challenging to implement in general way that works with all build styles and projects, and takes care of all corner cases in each.
I came back to see how the PR on this is progressing, but seems that the PR has been deleted? Or do I remember completely wrong?
Is anybody working on this?
The PR (#32) had several issues and seemed to be abandoned by the author, so I closed it last month while tidying up issues. I haven't personally put any more time into the feature, although I do potentially see the value. I think there are a lot of edge cases to consider, though, and I would be uncomfortable shipping the feature without a pretty broad suite of test cases to hit some of those edges.
Thanks for the reply. The current work-around / workflow of running regular compiler separately to generate definitions is perfectly adequate for us. I also appreciate your policy of not adding half-baked features with potential/unresolved edge cases.
👍
Is this one still on schedule?
Why do I need the bundled .d.ts?
I have one bundle named "core", which is reliable available and no one needs to import things from this bundle. To make this behavior work, I thought, it would be nice to have the core.d.ts generated from all the bundled .ts-files. Currently the only one knowing, what is bundled is browserify, which afterwards streams to tsify.
Does someone know an workaround for this scenario to work?
I'm interesting too... tsify makes a library from many files, but any library needs the dts file.