Angular2 build under angular-cli with directive and ng build --prod - node.js

I have an angular-cli app,
npm -v 3.10.8
node -v v6.9.1
angular2 ^2.4.0
angular/cli 1.0.0-beta.32.3
when I add to package.json this
"angular2-auto-scroll": "1.0.12"
angular2-auto-scrol website
and in app.module.ts import it
import { Angular2AutoScroll } from "angular2-auto-scroll/lib/angular2-auto-scroll.directive";
and add it to declarations section ng build --prod fails with this error
ERROR in Unexpected value 'Angular2AutoScroll in C:/coding/workspace/myapp/myapp-web/node_modules/angular2-auto-scroll/lib/angular2-auto-scroll.directive.d.ts' declared by the module 'AppModule in C:/coding/workspace/myapp/myapp-web/app_code/app/app.module.ts'
ERROR in ./app_code/main.ts Module not found: Error: Can't resolve './$$_gendir/app/app.module.ngfactory' in 'C:\coding\workspace\myapp\myapp-web\app_code'
# ./app_code/main.ts 6:0-74
# multi ./app_code/main.ts
however when I build with just ng build without --prod then all build fine.
Does anyone know what could be the reason? Or any other way I can import this npm package so it does not fail PROD build?

The issue is with AOT compilation. AOT happens by default when using --prod flag.
take a look at the source code for angular2-auto-scroll That project defines one TS file in the src/angular2-auto-scroll.directive.ts
If you look at the tsconfig.js file specifically "module": "commonjs". you'll see that the module this directive transpiles to is commonjs
If you look in your project under C:/coding/workspace/myapp/myapp-web/node_modules/angular2-auto-scroll/lib/ you'll see a TS type definition .d.ts, a .js and a .map file. the js file is a commonjs module.
AOT does not like commonjs modules, you can research that on your own, it needs either an es5 or es6 module.
All that said, here are some options to fix it
Copy the directive TS file from the source github angular2-auto-scroll.directive.ts to your prject and remove the dependency.
or you can make a pull request to the repo asking to change the "module": "commonjs" to "module": "es6" note: I opened an issue for it here
or if you do not care for aot, (which is highly recommended btw), you can cancel it by running buildcommand with --aot=false read here on build options
hope this helps.
Resources on AOT:
https://angular.io/docs/ts/latest/cookbook/aot-compiler.html
https://github.com/angular/angular-cli/issues/1732

Related

Publish Typescript Interfaces with NPM

I'm working in a project that has multiple typescript projects. I'm trying to have a common package for all the interfaces, types, enums, etc.
I thought I could make it work creating a NPM package with Typescript and have an index.ts with this content:
When I'm working in the projects that depend on this package, everything seems fine, but when I want to start the development environment I'm getting this error:
I've got the suggestion of running ts-node with --skipIgnore flag, but I'm getting the same error:
Maybe I needed to compile the code and import the .js (doesn't make ANY sense, but at this point 🤷🏽‍♂️)... no luck.
Let me share both tsconfig.json:
The one from the "common" package:
The one from the project that depends on the common package:
Things suggested and tried:
Because your target is ES6, commonjs modules cannot use your package. The dependent project should change its module type to ES6 as well - #kellys
Changing project's module to ES6, brings me this error:
All right, let's add moduleResolution: "node" ... and I'm getting:
So I'm adding "type":"module" in package.json:

MODULE_NOT_FOUND trying to share code by directory between modules in Node JS / TypeScript projects

I have set up an example project to demonstrate the issue:
https://github.com/garethrbrown/node-share-code
In this example there are two projects, example-api (a mini express project) and example-shared (a class library), both using Node JS / TypeScript. I want example-api to be able to use classes from example-shared to avoid code duplication. Having followed this example, I have referenced the example-shared project from package.json in example-api.
"dependencies": {
"example-shared": "file:..\\example-shared",
"express": "^4.17.1"
}
Having done this, and following running npm install, intellisense in VSCode sees ApiClass from the example-shared project and assists with the import.
I can then run by build command tsc --build via NPM, which succeeds.
I can also see that the sym link has been created in the example-api node_modules directory.
However, when I try to run the example-api project using the npm start script from under example-api, I get an error along the lines of:
Error: Cannot find module 'example-shared/apiClass'
Require stack:
...
code: 'MODULE_NOT_FOUND',
requireStack: [
...
]
I have tried running commands from different locations such as described here, but with no luck so far.
I'm using current stable versions of Node (14+) and NPM (7+).
I don't want to share via NPM or git repositories as I feel it will slow down development.
What am I doing wrong?
Seems like this is a discussed problem, see this post Typescript: How to resolve absolute modules paths for node.js?
I did not investigate further, but in the example-shared folder you can remove "outDir" from your example-shared/tsconfig.json and then run npm run build.
Unfortunately, this will emit the javascript files next to typescript files instead of placing them in a separate directory.
Finally, in the example-api run npm i, npm run build and npm start.
Now, Express will run because Node is using the javascript file instead of typescript file.
As per #mtbno's answer, the standard behavior without "outDir" is all js and map files will just be created next to each of your TypeScript files, which is super gross.
Without using some extra npm package or webpack or any of that, you can solve this by adding that "outDir" in your tsconfig, and then making a couple of tweaks to your package.json.
For argument's sake, say your root TypeScript file is called app.ts and your outDir folder is lib.
Relevant sections in your package.json can look like this:
"scripts": {
"build": "tsc --build",
"clean": "tsc --build --clean",
"start": "npm run build && node ./lib/app"
},
and
"main": "./lib/app",
And here's an example tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"lib": ["es6"],
"sourceMap": true,
"outDir": "./lib",
},
"exclude": [
"node_modules"
]
}
After those 2 files are updated, then running npm run start should build out your lib folder with the compiled JavaScript, and your server should start up successfully. Note that if you previously did a build and you have "old" .js and .map files next to your TypeScript files, you may have to delete those manually because npm run clean won't do it for you.

VsCode clean Typescript project no auto import suggestions

When I create a new Node project using Typescript, VsCode auto import suggestions do not work at all.
Steps to reproduce:
Create a workspace directory.
Run npm init specifying main.ts as entrypoint file.
Import typescript cli npm i typescript
Create tsconfig.json .\node_modules\.bin\tsc --init
Create main.ts containing console.log('Running');
Transpile using .\node_modules\.bin\tsc -w
Run by clicking Debug in VsCode and using the default Nodejs launch config.
Import a library e.g. Rxjs Import typescript cli npm i rxjs
Result:
In main.ts attempting to use any Rxjs type Observable, BehaviourSubject, global operators from of sequenceEqual etc results in no import assistance whatsoever.
I've read the VsCode Typescript docs, there is no hint there of what is wrong. https://code.visualstudio.com/docs/languages/typescript
I've tried explicitly setting include and exclude directories in tsconfig.json which also has no effect.
Do I need to manually set some module resolution options in tsconfig or something.
I have no idea, I'm at a loss as to why this doesn't work.
UPDATE:
I managed to get VsCode auto import working by specifying
"typeRoots": [ "node_modules" ]
...in tsconfig.json
The results in a minor issue which is that tsc now reports the error
error TS2688: Cannot find type definition file for '.bin'.
It appears the tsc now tries to read the contents of node_modules.bin which is not helpful. I've tried setting
"exclude": [ "./node_modules/.bin"]
in tsconfig, but that has no effect.
Try giving main.js as your entrypoint not main.ts
Steps that I followed:
Create a workspace directory.
Run npm init specifying index.js as entry point file.
Install typescript cli: npm i typescript
Create tsconfig.json: .\node_modules\.bin\tsc --init
Create index.ts containing console.log('Running');
Transpile using .\node_modules\.bin\tsc -w
Run by clicking Debug in VSCode and using the default Nodejs launch config.
Install a library e.g. Rxjs: npm i rxjs
Now in index.ts file: import { observable, BehaviorSubject } from "rxjs";
I was able to get those IntelliSense(import assistance)

How to create a simple (Hello World) node.js TypeScript project with ES6 modules?

Imagine a very simple program with a main file and some functions in a separate file, using ES6 modules and intended to be run with node.js.
my-utils.ts:
import * as fs from "fs";
export function readSimpleFile() {
return fs.fileReadSync("hello.txt", "utf-8");
}
main.ts:
import {readSimpleFile} from "./my-utils"
console.log(readSimpleFile());
What is the minimum set of files I need to add to the project and commands I have to run to get it building, running and checking types?
If you are to run a typescript project with node you need to have at least node, npm and typescript installed on your plateform.
Using an IDE to setup the project
Using intelliJ IDEA or Webstorm (they are the ones I know the best), the compilation of typescript into javascript is done automatically; you only need to do some settings.
Let us assume you have a file called project.ts containing your hello world code; IDEA or Webstorm will compile your code to project.js. Then you will only need to do node project.js to run your project.
Doing everything from scratch
First you need to know where exactly your npm packages are installed globally. This command can help you identify the path: npm config get prefix. In this folder, you should have a nodes_modules subfolder that contains the typescript module. If there is no typescript module, that is because you did not install typescript globally (npm install -g typescript).
Then you have to add the path of the bin of typescript subfolder in your environment variable.
Now you can compile the project with typescipt: tsc project.ts and you can run it node project.js.
Since you are using node function like fs you will need to install node typings npm install #types/node --save-dev before compiling with tsc.
Compilation option
To enable or disable all strict type checking options, you might need to use compilation option. You have to create the file in which you will specify the compilation option: tsc --init will create a tsconfig.json in which you can specify what behaviour you would like to have during the compilation of your app. All options are listed here.

browserify will not compile express js

I wrote a very basic express.js app. Then tried to make it one .js file. Browserify compiled the whole thing to a one file. But browserify-compiled code didn't work. As far as I know, browserify just replaces require statements with module codes. Error is:
C:\Users\HP\n\express\app.js:27025
__proto__: http.IncomingMessage.prototype
^
TypeError: Cannot read property 'prototype' of undefined
at Object.__dirname.173.accepts (C:\Users\HP\n\express\app.js:27025:34)
at s (C:\Users\HP\n\express\app.js:1:316)
at C:\Users\HP\n\express\app.js:1:367
at Object.__dirname.170../application (C:\Users\HP\n\express\app.js:26823:11)
at s (C:\Users\HP\n\express\app.js:1:316)
at C:\Users\HP\n\express\app.js:1:367
at Object.__dirname.168../lib/express (C:\Users\HP\n\express\app.js:26154:18)
at s (C:\Users\HP\n\express\app.js:1:316)
at C:\Users\HP\n\express\app.js:1:367
at Object.__dirname.153.express (C:\Users\HP\n\express\app.js:24010:15)
Browserify is designed specifically to package code for a browser.
Node.js supports a number of modules that a browser doesn't which have to be emulated by builtins. These modules will be replaced by a browser-specific shim. Some only supply a subset of the Node API that makes sense to have in a browser.
So you are running an app that has converted all the Node.js modules to support running what it can in a browser, back in Node where the modules are available but are no longer being used.
Try rollup or you could possibly configure babel to work like you need
I had this very same issue but like you said the compile code should work on server side. I solved it from this link:
https://www.linkedin.com/pulse/bundling-nodemodules-your-nodejs-app-one-single-file-xuan-son-nguyen/
Use browserify for bundling and terser for minifying. Starting by installing them globally:
npm install -g browserify
npm install -g terser
Next, we have to add a build script to package.json
...
"scripts": {
...
"build": "browserify --node --ignore-missing index.js | terser > bundle.js"
}
...
Each time you want to promote to production, you have to make a new bundle:
npm run build
A new file called "bundle.js" will be created.
Let there be peace, and there was peace. Happy coding.

Resources