gulp-typescript
gulp-typescript copied to clipboard
JSON files are not emitted with "resolveJsonModule" enabled
Hello!
Thank you for this great plugin!
However, it's not emitting the json files to the destination directory.
I'm using tsconfig.json with resolveJsonModule option enabled. And I'm adding json files to the build in the include section of the config.
When I compile it using tsc everything is generated correctly, but if I run the same config through gulp-typescript only JavaScript files are emitted, but not the JSON ones.
What could be the reason for this?
Thanks!
I'm using a very simple gulpfile taken from the documentation to test this:
var gulp = require('gulp');
var ts = require('gulp-typescript');
var tsProject = ts.createProject('tsconfig.json');
gulp.task('default', function () {
var tsResult = tsProject.src()
.pipe(tsProject());
return tsResult.js.pipe(gulp.dest('.build'));
});
Hi there,
gulp-typescript needs to split the generated files into different categories, namely JavaScript files, declaration files and source maps. The reason is that we need to pass the source maps to gulp-sourcemaps and pipe the javascript files and declaration files to different streams. That currently causes that files with other extensions are ignored. I think it's a simple and good idea to just treat those as JavaScript files. That should happen in ProjectCompiler#attachContentToFile.
It probably (hopefully) suffices to replace case 'js': case 'jsx': with a default clause at the end of the switch statement in ProjectCompiler#attachContentToFile.
@ivogabe thanks, I will try to do that. However, when I tried to build and test the source code in master yesterday it was failing with errors.
What errors did you get? And did you install the git submodules (git submodule update --init)?
On the other hand, the errors were due to the fact that I've installed this repository as a submodule to my project. When deployed separately it works correctly.
Could you please explain or document how does the tests infrastructure works? What steps are required to add another test?
How do you select what versions of TypeScript should be used for a specific test? For example, the resolveJsonModule option is only available starting from version 2.9 of TypeScript. It doesn't make sense to run this test for previous versions, because it will always fail for them.
Is there a way to run only specific test? I don't want to run all tests every time (it's just takes too long).
You can create a new test by creating a new folder in /test. A simple approach is to just copy another test, like basic. You can then adjust the gulpfile and tsconfig for your test and add a JSON file. After creating the test you run gulp test. This will fail, as the new tests gives a different output then the baseline. The baseline contains the 'expected' / 'correct' output. You can update the baselines for your test with gulp test-baselines-accept. I usually look at the gulp diff to check whether the new baseline is correct.
You don't have to specify the version of TypeScript for the test. It will also be executed on older versions of TypeScript, but it will just add the errors to the baseline and not crash the test suite.
I see, thanks. Please look at my working branch: https://github.com/ivogabe/gulp-typescript/compare/master...slavafomin:feat-resolve-json-module?expand=1
I've added changes to the code as you suggested and I've added a test suite.
However, I see the following issues:
-
For some reason I'm getting an error:
Unknown compiler option 'resolveJsonModule'.for all TypeScript versions besides a"dev"one. However, it should work with TypeScript 2.9. See here. -
Even for
"dev"library version it's not emitting the JSON-files. However, I can see thatattachContentToFile()is not even called for JSON files right now. I've tried to trace where the issue arises, but I've lost track at a call tothis.emit(). Looks like theWriteFileCallbackis not executed for JSON files. But I can see thatProject.src()returns all files, even the JSON one. And result of the manual call to thethis.program.getSourceFiles()shows all files.
Strange points, let's ignore the first issue for now, I think most people are on 3.0+ and I have no idea why that's happening. For the second issue, it appears that this.program.emit(..) does not emit the JSON files. The TypeScript api apparently does not emit JSON files. That may be intentional, as these files are not compiled by TypeScript, they are just passed through. But to be sure about that, we'll probably need to look how tsc handles those files or ask them whether this is correct.
I'm trying to understand how tsc utility is calling the TypeScript API and maybe create an isolated minimal example, but it doesn't look like an easy thing to do. I can't even figure out how to read config file with their API right now :)
I've managed to create a minimal example based on TypeScript 2.9.2 and in my case the WriteFileCallback is executed with both index.ts and data.json. It looks like issue is somewhere else. Do you have any ideas what could prevent the TypeScript from emitting this JSON file?
Great debugging, so the TS api does emit JSON files. They are thus lost elsewhere, I'll try to debug that tomorrow.
It might be caused by some code in lib/index.ts. That code distinguishes source files from config files (with FileKind). A .json file is treated as a config file and thus not passed to the TypeScript compiler. Maybe we can just treat all files as source files when resolveJsonModule is enabled. Could you try that?
And tsProject.src() might need to be changed, to also load the JSON files.
I just ran into this issue too. Took me a while to understand that the problem was actually in gulp-typescript and not in my tsconfig. Any updates on this?
Seeing this too
Another discrepancy is that tsc automatically picks up all off the JSONs even if they are not mentioned in the include section when using multiple rootDirs, while gulp-typescript throws something like this:
error TS6059: File '/assets/geo/cities.rbush.json' is not under 'rootDir' '/src'. 'rootDir' is expected to contain all source files.
I was just bit by this as well. I created a little task to work around the issue by simply copying the JSON files to the output (in their respectivte sub-directories):
/**
* This is a workaround! Currently, typescript-gulp doesn't include .json files, even if "resolveJsonModules" is
* enabled in .tsconfig Copy them manually for the time being...
* @see https://github.com/ivogabe/gulp-typescript/issues/609
*/
function copyJson() {
return gulp.src('src/**/*.json').pipe(gulp.dest("dist"));
}
I do agree though that typescript-gulp should handle this correctly.
Seeing this too
I just edited the workaround (in typescript) from @LukasKnuthImagineOn to use the tsconfig.json values if given, and only if resolveJsonModule is set , but yes, seeing gulp-typescript handling JSON files would be a must (maybe a json property in ICompileStream interface?)
const buildTypescript = async (tsConfig: string, clean?: boolean): Promise<any[]> => {
console.log('Build typescript from', tsConfig);
const tsProject = ts.createProject(tsConfig);
const srcDir = path.resolve(tsProject.projectDirectory, tsProject.options.rootDir || '.');
const outDir = path.resolve(tsProject.projectDirectory, tsProject.options.outDir || '.');
const tsResult = tsProject.src().pipe(tsProject());
if (clean) await del(outDir, { force: true });
return Promise.all([
streamToPromise(tsResult.js.pipe(dest(outDir))),
streamToPromise(tsResult.dts.pipe(dest(outDir))),
/**
* This is a workaround! Currently, typescript-gulp doesn't include .json files, even if "resolveJsonModules" is
* enabled in .tsconfig Copy them manually for the time being...
* @see https://github.com/ivogabe/gulp-typescript/issues/609
*/
tsProject.options.resolveJsonModule
? streamToPromise(src([`${srcDir}/**/*.json`]).pipe(dest(outDir)))
: Promise.resolve(),
]);
};