Why ngc partially ignore compileroptions.outDir? Does a workaround exist? - javascript

I have a tsconfig.json which specifies an outDir. The reason is that I want to separate the generated JavaScript output from the TypeScript sources.
So:
"compilerOptions": {
...
"outDir": "target/",
...
}
This works very well, until I compile the project with the typescript compiler only. All generated javascript output is created in the target/ directory.
But, if I call it with the angular compiler (ngc, it is essentially a wrapper around the tsc typescript compiler), we have an additional build step. It compiles the template files and components into typescript, which will be compiled further to javascript by the tsc.
These intermediary typescript files have the *.ngfactory.ts or *.ngsummary.json extension.
Now my problem is, that the ngc command generates these files still in my src/ directory, totally ignoring my outDir setting in my tsconfig.json.
What is the cause of this problem? Does any useful workaround exist?
Extension: regarding comments, ng from the angular-cli can do this. This leads to a side-question, how does it do with the ngc?

The cause of the problem was that ngc has some additional options in tsconfig.json what I didn't add.
The following settings in tsconfig.json do what I want.
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit" : true
}

Related

How do I convert TSX to JSX

I have a project where I wrote some new code in Expo with TypeScript (since I am more used to having a type safe language). However, I want to port what I wrote to something that was written with Expo with JavaScript.
I can manually just strip off the types as I go along to solve the problem, but I was wondering if there's a more automatic way of doing it. I know typescript eventually compiles down to JavaScript but I want to keep the HTML embedded code the same when I do the conversion. Is it possible?
The answer provided by #Jason is close to what I needed.
In the end I ran this command
npx tsc --jsx preserve -t es2020 --outDir js --noEmit false
This generated the .js and .jsx files in the js folder which can be copied over to non-typescript systems.
--noEmit false is needed for the Expo generated tsconfig.js which is noEmit: true
The -t es2020 generates output using ES2020 standards so you can get import and export along with the async await intact.
In the tsconfig.json file change "jsx": "react" to "jsx": "preserve" and then run tsc.
https://www.typescriptlang.org/docs/handbook/jsx.html

Webpack using Typescript: Common settings in both configs, so which take precedence?

I am in the initial stages of converting a javascript (with webpack) project into a typescript project and one of the many confusions I have is that their appears to be some configuration settings that can appear in webpack and typescript, so which takes precedence?
(I'm currently working on a node cli application).
Eg, the primary example is which files are included in compilation.
In webpack config, you can specify which input files are selected with rules:
module: {
rules: [
{
test: /index.ts/,
use: 'shebang-loader'
},
{
test: /\.ts(x?)$/,
use: 'ts-loader'
},
{
test: /\.json$/,
use: 'json-loader'
}
]
},
As you can see from above, I'm using various loaders for different file types.
Then my initial tsconfig.json is as follows:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"noImplicitAny": true,
"lib": [
"es5", "es2015", "es6", "dom"
]
},
"include": [
"lib/**/*"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
So what is the true nature of the interaction between webpack and typescript? I have not been able to discern this from typescript or webpack documentation. Both appear to be able to specify the input files that are included in compilation.
Another (probably better example) is the output file. In webpack config I have the following:
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, 'dist'),
filename: 'application-bundle.js'
}
which defines 'application-bundle.js' is the output file inside the 'dist' folder.
In the tsconfig, you can have something like the following:
"outFile": "./dist/application-bundle.js",
(I currently do not define an outFile property, but I know you can do so, but in being able to do so, brings up ambiguities and hence confusion). So in this scenario, does webpack override typescript or vice-versa? What is the recommended strategy?
There are probably more typescript/webpack crossovers that are going to cause confusion, but the 2 that I have described so far are the most upfront and pressing issues I need to understand, thanks.
EDIT: Having thought about it, I also need another clarification. I am guessing when you build a TS/WP project, the TS compiler runs first creates all the .js files (let's say in the .dist folder). Then webpack bundles all the generated .js files. So assuming this is correct, do I then need to configure webpack to use as its input the .js files in the dist folder instead of the .js files inside the project source (ie everything under ./lib which is where my source js files are)?
I was hoping to convert my project in an incremental manner so what I have just said does not really fit my needs. Webpack would need to pick up some .js files from ./dist and some files from ./lib which have not yet been converted to typescript. I don't know how to modify the project for incremental upgrade.
[...] there appears to be some configuration settings that can appear in webpack and typescript, so which takes precedence?
You are right on the point that there is some natural redundancy in the configuration when Webpack is combined with TypeScript. Lets pick up your first question:
which files are included in compilation? [...] Another example is the output file. [...] So in this scenario, does webpack override typescript or vice-versa? What is the recommended strategy?
Simply spoken, both TypeScript and Webpack process/transform input files and emit the output in a target directory structure or file bundle(s) - both need some input/output configuration info. TypeScript compiler can run on its own, and also be integrated as file processor as part of a bigger Webpack build. With outFile option TypeScript can even be seen as a mini-bundler on its own, as it bundles all .ts-files to a single target file.
To answer the question, if TypeScript or Webpack configuration takes precedence, it is important to understand, how Webpack works. I'll quote one of your assumptions here:
I am guessing when you build a TS/WP project, the TS compiler runs first creates all the .js files (let's say in the .dist folder). Then webpack bundles all the generated .js files.
That is not quite correct. But good you said that, as it sheds more light on your core understanding problem. Everything in Webpack starts with the entry point you specify in the config - if you will, that's the input. From this entry module, webpack considers all other transitively imported modules (e.g. via import or require) and creates a dependency tree.
Every file in the dependency tree can optionally be transformed by Loaders, which can also be chained like a file processing pipeline. So ts-loader and the underlying TypeScript compiler apply transformations for .ts/.tsx files with test: /\.ts(x?)$/ predicate.
All in all you see, that Webpack considers your entry file, which leads to a bunch of further imported .ts/.tsx files (amongst your other file types, we neglect them here). And for each single file, the TypeScript loader will be invoked in the course of the loader processing pipeline. Therefore, it is inherent that TypeScript I/O config will be ignored and Webpack's entry/output configuration takes precedence in the build. All other TypeScript related settings are taken from tsconfig.json, as described in the ts-loader docs: "The tsconfig.json file controls TypeScript-related options so that your IDE, the tsc command, and this loader all share the same options."
I was hoping to convert my project in an incremental manner
It is perfectly fine to migrate from JavaScript to TypeScript in a stepwise manner!
Hope, that helps.

How to generate d.ts and d.ts.map files using webpack?

I can't find a way to generate d.ts and d.ts.map files using webpack. babel-loader only generates js and js.map files. I also need d.ts and d.ts.map files (which I was able to generate using tsc command) as shown in this picture:
Here is a minimal repo that contains all the settings: https://github.com/stavalfi/lerna-yarn-workspaces-example
More Details
I moved to Lerna + yarn. One of my packages is core (will be used in other packages) which is written in TS and JS.
I'm using webpack 4,babel-loader 8 for ts-to-js.
The other packages are trying to find type definitions and implementation of my core package but I was only able to generate index.js and index.js.map with webpack:
output: {
path: distPath,
filename: 'index.js',
},
{
"extends": "../tsconfig.settings.json",
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"declarationDir": "dist",
"rootDir": "src",
"outDir": "dist"
}
}
When I compile with tsc (without webpack), everything is working great as I showed in the picture above.
Does my strategy is wrong? what should I do?
I have tried a lot of plugins that generate d.ts files but they don't work and doesn't create d.ts.map files.
I already tried: typescript-declaration-webpack-plugin, npm-dts-webpack-plugin, dts-bundle-webpack, #ahrakio/witty-webpack-declaration-files. (They are listed in the package.json of core so you can clone and play with it).
Running ts-loader before babel-loader will do the trick.
Specifying that you want declaration files in config is all you need.
If you are using an absolute path, the output d.ts files will also contain absolute paths which are useless and will result in typescript compilation errors.
To fix that, I wrote a plugin to convert an absolute path to a relative path:
https://github.com/stavalfi/babel-plugin-module-resolver-loader
You can call the Typescript compiler tsc directly to do that.
Use tsc --declaration to output a .d.ts file and tsc --declarationMap to generate the corresponding map file.
You can find more documentation here:
https://www.typescriptlang.org/docs/handbook/compiler-options.html

Compiler option for specifying the name of the tsconfig.json file?

I need to have two tsconfig.json files. One for testing and one for publishing. Reading through a number of Typescript repository issues it seems like the flag for specifying the tsconfig file to use is tsc --project tsconfig-test.json, however when using this I get the following error:
return path.replace(backslashRegExp, ts.directorySeparator);
^
Thoughts?

Do I have to reference TypeScript definition in every file?

Is there a way to tell TypeScript to use a certain file (or set of files) as a definition for everything compiled?
My only alternative currently is to add something like this in every single TypeScript file (which seems clunky):
/// <reference path="DefinitelyTyped/requirejs/require.d.ts" />
When using TypeScript's internal module system, you can avoid having any <reference> tags at all in the code. I personally do this because I don't want to encode paths (realtive or absolute) within the code as I constantly move stuff around.
One way to do this is by making sure all required declaration files and TypeScript source files are passed to the compiler as arguments during compile time.
Using gulp together with gulp-typescript simplifies this task. You can set noExternalResolve in gulp-typescript to true, and create gulp tasks that take all your .d.ts files along with your sources and pipe it down to the compiler. When you pull in tsd into your stack, you only need to pass the tsd.d.tsfile that contains references to all other definition files installed via tsd.
UPDATE for TypeScript >= v1.5: you can use a tsconfig.json file, and the compiler will get the ordering of the classes right. This removes the need to use gulp-typescript alltogether. You can either chose to have all files explicitly listed in the tsconfig.json file, or completely leave out the files property to include all *.ts/*.tsx files within the directory the tsconfig.json resides (including all subfolders).
A sample tsconfig.jsonmay look like:
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"lib": [ "es5", "es2015.promise", "dom" ]
},
"include": [
"src/**/*.ts"
]
}
What I've learned so far is that /// < reference >-ing a module with reference comments is not a good method.
For example: in case you have a file Foo and a file Bar. Both files use jquery, but only file Foo has a reference comment to jquery. If file Foo is deleted for some reason, your file Bar is broken, because the reference is missing.
If you are using TypeScript >= 2.0 It is better to define the TypeScript definition files (.d.ts) in your tsconfig.json under the "files" section.
This could look like this:
{
"compileOnSave": true,
"compilerOptions": {
"noImplicitAny": true,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "es5",
"outDir": "./Scripts/"
},
"files": [
"./src/foo.ts",
"./src/bar.ts",
"./Scripts/typings/jquery/jquery.d.ts",
"./Scripts/typings/jqueryui/jqueryui.d.ts",
"./Scripts/MicrosoftMaps/Microsoft.Maps.d.ts"
]
}
Using the /// directive (reference comments) is often used in examples to get you started quickly, but it is not a best practice. Also many examples come from a version < TypeScript 2.0.
Some IDEs auto-detect all the files in a project (Visual Studio).
For everything else, you can create a _references.ts file and put all of your reference comments in there - then you only ever need to add:
/// <reference path="_references.ts" />
...to each file (instead of possibly many).
Your IDE may also support tsconfig files.
This question is a duplicate of Reference typescript definitions in one file, instead of all JS files?
The answer is, for now, add each file you want to reference to your tsconfig.json file's "files" section. It's still many lines, but all in one file.
In future when Typescript 2 is released you can then use the "filesGlob" section and solve the problem in two lines.
I've started recently with TypeScript and as I've understood the internal modules resolution is that yes, you can compile all .ts files from the tsconfig.json's directory and all its subdirectories, provided that you don't have set .ts files in it without /// <references path="" />.
But the order in which the .ts files are compiled into resulting .js files is not determined by the dependencies the files (or classes they contain) have. So it is possible to have a situation where the child class is compiled before the parent one (child inherits from parent relation). Then the code won't run, even though it is compiled successfully. It will complain that it couldn't understand the parent class within the child class. Therefore you need to add a /// <references path="" /> as a hint to the compiler to resolve the dependencies between .ts files.
This is want the Typescript documentation says:
The /// directive is the most common of this group. It serves as a declaration of dependency between files.
Triple-slash references instruct the compiler to include additional files in the compilation process.
They also serve as a method to order the output when using --out or --outFile. Files are emitted to the output file location in the same order as the input after preprocessing pass.

Categories

Resources