tsickle: tsickle breaks module names when outDir specified
I have an extremely simple TypeScript project, in total it is:
// classB.ts:
export class ClassB {
constructor() { }
toString(): string {
return "this is a class B instance";
}
}
// index.ts:
import { ClassB } from "./classB";
export let myLib: any = {}
// very semantic version
myLib.version = "lalala";
// runtime API
myLib.ClassB = ClassB;
// tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "./tsout",
"rootDir": "./src",
"noEmitHelpers": true, // needed for tsickle
"strict": true
}
}
Running tsickle
produces almost valid output, except index.js
looks like this:
goog.module('tsout.index'); exports = {}; var module = {id: 'tsout/index.js'};
Object.defineProperty(exports, "__esModule", { value: true });
var classB_1 = goog.require('tsout_classB');
exports.myLib = {};
// very semantic version
exports.myLib.version = "lalala";
// runtime API
exports.myLib.ClassB = classB_1.ClassB;
goog.require('tsout_classB');
is causing the closure compiler to fail. Shouldn’t tsickle produce 'tsout.classB'
instead? If I change that line by hand so that the underscore is a period, it works.
PS C:\VerySimpleTSProject> java -jar .\closure-compiler.jar --js_output_file=myLib.js './tsout/*.js' --jscomp_off=deprecatedAnnotations --compilation_level ADVANCED_OPTIMIZATIONS --formatting=pretty_print
tsout/index.js:3: ERROR - Required namespace "tsout_classB" never defined.
var classB_1 = goog.require('tsout_classB');
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
What explains this error? Running tsc with the above, there are no similar require
errors.
(Unrelated to the bug, I’m trying to write TS to produce a browser library called myLib. If I’m doing anything obviously wrong on that front please let me know).
About this issue
- Original URL
- State: open
- Created 7 years ago
- Comments: 39 (20 by maintainers)
I’m going to try and be concise so let me know if you need more information. What’s passed to
pathToModuleName
oremitGoogRequire
are strings which are sometimes relative paths, and other times full paths. Why? Well, it looks like TypeScript is doing this, not your code. When TS is taking the input, remember I’m only passing tsc/tsickle one file right now:the typescript code (
node_modules/typescript/lib/typescript.js
) goes through the passed-in code and gathers lists of relevant files. Typically they are stored in arrays ofSourceFileObject
s, and if you look at the arrays and theSourceFileObject.fileName
in each you find:In other words, sometimes
fileName
is the relative path and other times it resolved to a full path. So this is what TypeScript gathers, and its what you’re using asES5Processor.file.fileName
.So in
typescript.js
, (Line 9047 of this file in the TypeScript project)host.writeFile(fileName
- That fileName will be sometimes relative, and sometimes absolute.Your code,
processES5
callsts.createSourceFile
which ultimately uses that code.So either we must ask the TypeScript project to change how they’re doing this, or the tsickle project must find a way to accomodate both absolute and relative file paths.
Annoyingly, the TypeScript project returns a mixture of absolute and relative file paths even if you pass in all the files! This is because if you have:
TypeScript starts by looking inside of the first file, and looks at all the files it references to build its list of fileNames, so it ends up with:
Presumably, “src/classA.ts” isn’t here because by the time it was ready to process the second relative file, it already found it (as an absolute reference) by searching through index.ts.
I hope this has been helpful. Unfortunately being myself a simple JavaScript farmer, I am not the right person to determine where and how tsickle may need to change to accommodate both relative and absolute file paths.
I am seeing the same problems in one of my projects using master branch of tsickle, both with Typescript 2.4.2 and 2.5.3 on Ubuntu 14.04. (Not using angular.)
Got no combination working by playing with different combinations of outDir, baseUrl, etc.
After some debugging I found that toClosureJS() (main.ts:124) recevied a list of relative file paths. Independent of the outDir/baseUrl settings in tsconfig.json, they were always relative to CWD. However, shouldSkipTsickleProcessing() (main.ts:130) received a mixed list of absolute and relative paths, so I tried to always work with relative paths by changing the implementation to:
And now all files were processed by tsickle, still with broken module names.
For the broken module names, I looked at pathToModuleName() in cli_support.ts. I found that “context” that is used to resolve the relative “fileName” sent to this function are one of these:
Just before generating the moduleName in cli_support.ts I added
Now all module names are correct and it generated 100% closure typed output while all bazel tests still passes. As the same method pathToModuleName() is used to resolve source TS files and built JS files, I am not sure how this can work at all when configuring “outDir” to point to anything else than the src directory.
If pathToModuleName() could also get the values of outDir and baseUrl, etc. it could use those to map to the correct module id. I don’t have time to play with that though.
I am not that familiar with the code base yest, so not sure if this is the way to go, or if there are better places of handling paths. Not sure yet if relative paths are always relative current working directory or if we can get this from tsc somehow?
I’m also experiencing problems with absolute paths, however for me it’s the goog.forwardDeclare() rather than the goog.require(), I’m utterly unable to avoid it no matter what options or setup I use. I’m on Windows 10 too. And I’m also using the --typed argument for tsickle.
src/main.ts
src/foo.ts
Output (main.js):
But the Closure Compiler refuses to so swallow it, reporting on the forwardDeclare “Required namespace (path) never defined.”
As you can see, I have no file named index.ts, I can’t switch between absolute or relative paths by using “outDir” like b-strauss is reporting, it doesn’t matter if I feed in foo.ts in before main.ts like simonsarris is reporting, I tried compiling tsickle from Github rather than running the NPM verison like orenmizr suggested but there was no difference.
Interestingly enough if I just manually delete the offending line and feed both .js files to the Closure Compiler it compiles it just fine.
There was an upgrade to TypeScript 2.3.1 recently. Maybe the TS paths are always relative now.
@simonsarris could you wait until I’m done testing before you close this?
Pardon my ignorance, but how can I install it from GitHub?
npm install angular/tsickle
andnpm install https://github.com/angular/tsickle.git
seem to fail.
Is there a guide for building tsickle from source?