tsickle breaks module names when outDir specified
See original GitHub issueI 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).
Issue Analytics
- State:
- Created 6 years ago
- Comments:39 (20 by maintainers)
Top Results From Across the Web
bazelbuild/rules_nodejs - aspect build
a string specifying a subdirectory under the bazel-out folder where outputs are written. Equivalent to the TypeScript --outDir option. Note that Bazel always ......
Read more >TSConfig Reference - Docs on every TSConfig option
Lets you set a base directory to resolve non-absolute module names. You can define a root folder where you can do absolute file...
Read more >@bazel/typescript - npm
We control the output format and module syntax so that downstream rules can rely on them. They are also fast and optimized: We...
Read more >H2 - Groups and Classes
Unless otherwise specified by contractual agreement with the Federal Government, ... Cataloging Handbook H6, the alphabetic index of item names, includes a ...
Read more >tsickle@0.46.3 - jsDocs.io
Documentation for npm package tsickle@0.46.3 - jsDocs.io. ... an ES6 import and generates a googmodule module name for the imported module.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
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?