Webpack 2 won't compile a single typescript file - node.js

I'm on a project where I have multiple SPA on Angular JS, all written in typescript. I have the following directory structure:
src/
├── app
│ ├── frontend
│ │ ├── ...
│ │ └── frontend.module.ts
│ ├── backend
│ │ ├── ...
│ │ └── backend.module.ts
├── app.frontend.module.ts
├── app.backend.module.ts
Files at the root of src/ are the entry point for each app, they contain the following code (here for the frontend):
import * as angular from "angular";
import { FrontendModuleName } from './app/frontend/frontend.module';
angular.module('app', [FrontendModuleName]);
angular.bootstrap(document, ['app'], {
strictDi: true
});
So I should be able to tell Webpack to compile "src/app.frontend.module.ts", the compiler then follows the imports and everything gets merged nicely.
It works fine, but even if I explicitly tell Webpack to compile a single file, all of them are always compiled.
To give you an example, let's take this very basic configuration:
const path = require('path');
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: {
frontend: './app.frontend.module.ts',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].bundle.js',
},
module: {
loaders: [
{
test: /\.ts(x?)$/,
loaders: ['ts-loader']
}
]
}
};
Executing this will compile app.frontend.module.ts as requested BUT also app.backend.module.ts !
After some time I found out that it's not Webpack but the Typescript compiler who seems at fault, so I changed my .tsconfig to try to exclude the root files, like so :
{
"compilerOptions": {
...
},
"exclude": [
"node_modules",
"dist",
"dev",
"reports",
"./src/app.*.module.ts"
]
}
In a sense it works because it now ignores app.backend.module.ts, but it still tries to compile every .ts file in the src/app/backend/ directory!
That's where I am right now.. I've searched in the compiler options reference but didn't found any option to prevent the compiler to recursively compile everything.
In fact..
..I've found a very very ugly workaround that I don't find satisfying at all. There is the files options that can be used to specify what files should be compiled, but I cannot give it an empty array or an exception is thrown.
So I created an empty dummy.ts file in the src/ folder and it seems to work as expected:
{
"compilerOptions": {
...
},
"files": ["src/dummy.ts"],
"exclude": [
"node_modules",
"dist",
"dev",
"reports",
"./src/app.*.module.ts"
]
}
But I can't imagine there is no better way to handle this.
Any idea would be much appreciated.
Thanks for your help.

Related

paths in tsconfig cannot import the type

I'm working on server side project using TypeScript.
And I defined some types in ooo.d.ts. And I set paths in tsconfig.json.
But When I try to import the type I defined, It shows the error, Module '"../../#types/express-custom-types"' has no exported member 'CustomError'.
The project structure is like the below.
├── src
│   └── routes
│   └── errorHandlers.ts
├── tsconfig.json
└── #types
└── express-custom-types
└── index.d.ts
I define the types in index.d.ts like the below.
declare module "express-custom-types" {
export type ErrorBody = { type: string; status: number; message: string };
}
And I defined alias in tsconfig.json
"compilerOptions": {
...(omit)...
"baseUrl": "./",
"paths": {
"*": ["*"],
"#custom-types/*": ["#types/*"],
},
And import the type in errorHandlers.ts like this.
import { ErrorBody } from "#custom-types/express-custom-types";
But it shows error Module '"../../#types/express-custom-types"' has no exported member 'ErrorBody'.
I don't know what to do..
declare module ... can be used to add or augment declarations of some external module (usually installed through package.json or generated during the "build").
But this is not the case here, the file/module is part of the project and you can just remove declare module "express-custom-types" wrapper.
You want to make sure that the module you're declaring has the same full name as the one you're trying to import. This should work:
declare module "#custom-types/express-custom-types" {
export type ErrorBody = { type: string; status: number; message: string };
}

Error: Cannot find module 'build/addon.node'

I am trying to import a module using a non-relative import but it's not working:
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false,
"suppressImplicitAnyIndexErrors": true,
"rootDir": ".",
"outDir": "build/js",
"baseUrl": "."
// "paths": {
// "#build/*": ["./build/*"]
// }
},
"exclude": ["node_modules", "build-releases", "addons"]
}
Code:
// const addon = require('../../../build/addon.node');
const addon = require('build/addon.node');
const debug = true;
export { addon, debug };
The commented code works but the non-commented require does not.
This error outputs:
App threw an error during load
Error: Cannot find module 'build/addon.node'
Require stack:
- /Users/name/Desktop/workspace/proj/build/js/vapp/globals.js
Dir structure:
tree build/
build/
├── addon.node
└── js
└── vapp
├── client.js
├── client.js.map
├── globals.js
├── globals.js.map
├── index.js
├── index.js.map
├── utils.js
└── utils.js.map
(build is in CWD)
TypeScript docs say:
A relative import is one that starts with /, ./ or ../.
Any other import is considered non-relative.
Setting baseUrl informs the compiler where to find modules. All module imports with non-relative names are assumed to be relative to the baseUrl.
Question: Is this because TypeScript is not responsible for module resolution with a require? As in, it's a node related things vs. a TypeScript thing?
Edit
I tried running tsc --traceResolution and found no information about my require trying to import addon.node. That made me realize: TypeScript is likely not responsible for module resolution here, NodeJS is. It doesn't look like you can easily change the baseURL dir for NodeJS and I'd have to use something like Webpack if I wanted to transpile with different, aliased paths.

Warning: error TS18002: The 'files' list in config file is empty

I'm using TypeScript 2.1.5.0. I've configured the grunt-typescript-using-tsconfig plugin as shown below but I get the error in the subject line when I execute the task.
The problem is the tsconfig.json property "files":[]. I didn't encounter this error when using gulp-typescript. Do you recommend that I configure something differently? Either my gruntfile.js for this plugin or tsconfig.json? Or can you recommend a different grunt plugin that will successfully hook into tsconfig.json and process the typescript task as expected?
typescriptUsingTsConfig: {
basic: {
options: {
rootDir: "./tsScripts"
}
}
}
Or can you recommend a different grunt plugin that will successfully hook into tsconfig.json and process the typescript task as expected?
gulp typescript supports tsconfig : https://github.com/ivogabe/gulp-typescript/#using-tsconfigjson
var tsProject = ts.createProject('tsconfig.json');
gulp.task('scripts', function() {
var tsResult = gulp.src(tsProject.src())
.pipe(tsProject());
return tsResult.js.pipe(gulp.dest('release'));
});
Try setting your Gruntfile.js configuration as shown in the following gist :
Gruntfile.js
module.exports = function(grunt) {
grunt.initConfig({
typescriptUsingTsConfig: {
basic: {
options: {
rootDir: './'
}
}
}
});
grunt.loadNpmTasks('grunt-typescript-using-tsconfig');
grunt.registerTask('default', [
'typescriptUsingTsConfig'
]);
};
Note the value for rootDir is set to ./ (i.e. The same folder as the Gruntfile.js).
tsconfig.json
Then ensure you have your tsconfig.json configured to include a list of all .ts files to be compiled to .js. For example:
{
"compilerOptions": {
"outDir": "./dist"
},
"files": [
"./tsScripts/a.ts",
"./tsScripts/b.ts",
"./tsScripts/c.ts"
]
}
There are of course other compiler options you can set in tsconfig.json
Directory structure
The configurations above assumes a directory structured as follows, however you can just adapt the code examples as required:
foo
├── Gruntfile.js
├── tsconfig.json
├── tsScripts
│ ├── a.ts
│ ├── b.ts
│ └── c.ts
└── node_modules
└── ...
Running grunt
cd to the project folder, (in these examples the one named foo), and run:
$ grunt
Output
Running grunt will create a folder named dist and output all .js files to it. For example:
foo
├── dist
│ ├── a.js
│ ├── b.js
│ └── c.js
└── ...
If you want the resultant .js files to be output to the same folder as the source .ts file, (i.e. not to the 'dist' folder), just exclude the "outDir": "./dist" part from your ts.config.json.

Aliasing modules using NodeJS

Some context here: It's not that I cannot use Webpack, it's that I do not want to use Webpack. I would like to keep everything as "vanilla" as possible.
Currently when creating modules in a project you have to require them using either a relative or absolute path, for example in the following directory..
project/
├── index.js
├── lib/
│ ├── network/
│ │ request.js
│ │ response.js
├── pages/
│ ├── foo.js
Considering we're in index.js we would import request via
var networkRequest = require('./lib/network/request.js')
and if we're in foo.js we would import request via
var networkRequest = require('../lib/network/request.js')
What I'm wondering is that if there's any way to perhaps, set a local alias in Package.json or anywhere else like so:
localPackages = [
{ name: 'network-request', path: './lib/network/request.js' }
];
In which you could just do
var networkRequest = require('network-request')
From any file and it will provide the correct path.
Yep, that's what npm link is for. Native and out of the box.
You can also set local paths in package.json
{
"name": "baz",
"dependencies": {
"bar": "file:../foo/bar"
}
}

How do I compile my TypeScript code for Node.js to one file?

I want to compile TypeScript to one file when using with Node.js.
I have tried configuring "tsconfig.json" like this:
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"noImplicitAny": false,
"sourceMap": false,
"outFile": "./app/index.js",
"pretty": true,
"types": [
"node"
]
}",
...but when I try with module set to "commonjs", I get the error:
error TS6082: Only 'amd' and 'system' modules are supported alongside --outFile.
If I change it to "module": "system", I get this error when running the file in node:
ReferenceError: System is not defined
If I change module to "amd", I get this error when running the file in node:
ReferenceError: define is not defined
It is not possible to bundle Node.js modules into a single file with the TypeScript compiler alone: each file in the CommonJS module system (used by Node.js) is treated as a single module, and cannot be joined together without proper module bundling techniques found in the many JavaScript code bundlers out there (such as Browserify, Webpack, Rollup, Parceljs, ...).
Other module systems such as SystemJS do not have this limitation, and module definitions can be concatenated into a single file using just the TypeScript compiler: tsc ... --outfile bundle.js -module system. However, they are not supported by Node.js on the fly.
For the actual solution, there are two reasonable choices: either configure your project to bundle the solution using a separate tool (Browserify, Webpack, ...), or include an implementation of SystemJS into your Node.js application (instructions here).
I will also end with a side note: consider evaluating whether you really need to bundle your server-sided code. Bundling is typically performed in frontend projects to reduce the size of client-sided resources, although it can be done as well for server applications in resource-efficient scenarios.
#E_net4 is right. Currently, it is not possible to build modules into a single file with the TypeScript compiler alone. This article describes how to do so with webpack where the file structure is:
├── index.js
├── package.json
├── src
│ ├── add-message
│ │ └── index.ts
│ ├── index.ts
│ └── upcase-messages
│ └── index.ts
├── tsconfig.json
└── webpack.config.js
webpack.config.js
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: './src/index.ts',
output: {
filename: 'index.js', // <-- Important
libraryTarget: 'this' // <-- Important
},
target: 'node', // <-- Important
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
]
},
resolve: {
extensions: [ '.ts', '.tsx', '.js' ]
},
externals: [nodeExternals()] // <-- Important
};
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./",
"noImplicitAny": true,
"strictNullChecks": true
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules"
]
}

Resources