I have a nestJS application and added a CLI command using nest-commander according to their official docs:
https://docs.nestjs.com/recipes/nest-commander
My directory looks like this:
+ src
+ command
+ test.command.js
- app.controller.spec.ts
- app.controller.ts
- app.module.ts
- app.service.ts
- main.ts
+ test
To launch the web-application, I usually execute
yarn start:dev
But how can I start the command provided by nest-commander? It seems that official docs and even those of the github repository don't tell anything about it.
I need something like
yarn run test-command
or something like that. How to make it?
As is written in the docs generally you should build the application (yarn build should call nest build which should output the dist) and then you should be able to call node dist/path/to/main-cli where main-cli is the file in which you use the CommandFactory.run() method.
You could set up a package.json script like "test-command": "nest build && node dist/path/to/main-cli" so you can run yarn test-command and it'll run all the steps for you.
The above all also assumes you do not have ts files outside of the src that get compiled as well. If so, then your dist path would be dist/src/path/to/main-cli, so keep that in mind.
The last option would be to use ts-node and call ts-node src/path/to/main-cli, compiling the TS at runtime in memory.
I have a Nest project with TypeORM. Few months ago, I setup my database, but I didn't test the database anymore (run migrations, seeding, drop schema, etc.).
Now, I'm trying to run any TypeORM command and nothing happens.
I tried to run TypeORM with this two:
ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js
node --require ts-node/register ./node_modules/typeorm/cli.js
Nest: v7.4
Nest TypeORM: v7.1.5
TypeORM: v0.2.24 (but CLI returns v6.14.11)
Oh, almost forgot, I realized that my Node was outdated, in v13, then I updated to the v14, so maybe it brokes some package or build, I don't know.
Some points that might help:
TypeORM operates on the generated JS code. Build the project first before running a migration or schema log command.
There must be a ormconfig.js file being generated into the build output directory. Make sure the file is there.
Check the glob patterns in the ormconfig file. I first made the mistake and defined the wildcards for Typescript files. But again, TypeORM CLI is working on the build output, so the glob patterns must target JS files. If I remember right, TypeORM schema:log command was telling me that there are no changes in my schema, but I knewthere were. And the problem was my faulty ormconfig file.
I have these scripts defined in my package.json and noticed that I explicitly provide the path to the ormconfig file compared to your command. Maybe you can try this:
"typeorm:cli": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli -f dist/src/database/config/ormconfig.js"
"migration:show": "npm run typeorm:cli -- migration:show",
"schema:log": "npm run build && npm run typeorm:cli -- schema:log",
Your problem is probably caused by this bug.
Solution is to downgrade Node or upgrade pg package.
I imagine people commonly use Flow and Jest (and React) together, but Flow doesn't seem to know about Jest (or Jasmine) globals. When I add // #flow to my tests, I get Flow errors like this:
src/__tests__/Thing-test.js:3
3: jest.unmock('../Thing')
^^^^ identifier `jest`. Could not resolve name
src/__tests__/Thing-test.js:7
7: describe('Thing', () => {
^^^^^^^^ identifier `describe`. Could not resolve name
src/__tests__/Thing-test.js:8
8: it('does stuff', () => {
^^ identifier `it`. Could not resolve name
I could write a Flow interface for Jest/Jasmine, but that seems lengthy and like I must be missing something. Letting Flow process node_modules/jest-cli doesn't seem to help.
Although Jest is written with flow annotations they strip types for the npm version so we don't need babel to run it. Fortunately the types are already in flow-type so the solution is quite easy (just as mentioned in the comment):
npm install -g flow-typed
flow-typed install jest#22.x.x # <-- replace the version with the latest
Although I had to add this line as well to my .eslintrc.json:
{
"env": {
"jest": true
}
}
The accepted answer does not work if you use Create-React-App. Here is how you would set up jest with CRA:
1.Install flow to your project
If you use create-reat-app, here is a guide for this step.
yarn add -D flow-bin
yarn run flow init
2. Install jest flow types
npx flow-typed install jest#22 // maybe you need a different version
(You can use npx jest -v to check your jest version if you use create-react-app.)
3. Register flow-typed in config
(Update: as #Black points out in the comments, this step may not even be neccessary)
In your .flowconfig, add flow-typed to libs section.
...
[libs]
flow-typed
...
I use yarn, npm should work just the same.
If you created your project with create-react-app you have to manually add jest to your packages.json. Otherwise flow-typed won't install the needed type definitions because create-react-app doesn't add this dependency to packages.json.
yarn add --dev jest
flow-typed install
You can also run it as a one liner.
Here you go:
npm i -D flow-typed && npx flow-typed install jest#"$(npx jest -v)"
I think declare var jest: any; should do the trick (put it either on top of each test file, or somewhere in your flow lib directory).
I'm having a surprisingly hard time finding an answer to this. With plain Node.JS, you can run any js file with node path/to/file.js, with CoffeeScript it's coffee hello.coffee and ES6 has babel-node hello.js. How do I do the same with Typescript?
My project has a tsconfig.json which is used by Webpack/ts-loader to build a nice little bundle for the browser. I have a need for a build step run from the console before that, though, that would use some of the .ts files used in the project to generate a schema, but I can't seem to be able to run a single Typescript file without compiling the whole project.
How do I do the same with Typescript
You can leave tsc running in watch mode using tsc -w -p . and it will generate .js files for you in a live fashion, so you can run node foo.js like normal
TS Node
There is ts-node : https://github.com/TypeStrong/ts-node that will compile the code on the fly and run it through node 🌹
npx ts-node src/foo.ts
Run the below commands and install the required packages globally:
npm install -g ts-node typescript '#types/node'
Now run the following command to execute a typescript file:
ts-node typescript-file.ts
We have following steps:
First you need to install typescript
npm install -g typescript
Create one file helloworld.ts
function hello(person){
return "Hello, " + person;
}
let user = "Aamod Tiwari";
const result = hello(user);
console.log("Result", result)
Open command prompt and type the following command
tsc helloworld.ts
Again run the command
node helloworld.js
Result will display on console
To add to #Aamod answer above, If you want to use one command line to compile and run your code, you can use the following:
Windows:
tsc main.ts | node main.js
Linux / macOS:
tsc main.ts && node main.js
Edit: May 2022
ts-node now has an --esm flag use it.
Old Answer:
None of the other answers discuss how to run a TypeScript script that uses modules, and especially modern ES Modules.
First off, ts-node doesn't work in that scenario, as of March 2020. So we'll settle for tsc followed by node.
Second, TypeScript still can't output .mjs files. So we'll settle for .js files and "type": "module" in package.json.
Third, you want clean import lines, without specifying the .js extension (which would be confusing in .ts files):
import { Lib } from './Lib';
Well, that's non-trivial. Node requires specifying extensions on imports, unless you use the experimental-specifier-resolution=node flag. In this case, it would enable Node to look for Lib.js or Lib/index.js when you only specify ./Lib on the import line.
Fourth, there's still a snag: if you have a different main filename than index.js in your package, Node won't find it.
Transpiling makes things a lot messier than running vanilla Node.
Here's a sample repo with a modern TypeScript project structure, generating ES Module code.
I created #digitak/esrun, a thin wrapper around esbuild and that executes a TypeScript file almost instantly. esrun was made because I was disappointed with ts-node: too slow, and just didn't work most of the time.
Advantages of esrun over ts-node include:
very fast (uses esbuild),
can import ESM as well as CJS (just use the libraries of your choice and esrun will work out of the box),
there is an included watch mode, run your script with the --watch option and any change to your entry file or any of its dependencies will re-trigger the result
you can use esrun in inspect mode to use the DevTools console instead of your terminal console.
After installing, just run:
npx #digitak/esrun file.ts
Just helpful information - here is newest TypeScript / JavaScript runtime Deno.
It was created by the creator of node Ryan Dahl, based on what he would do differently if he could start fresh.
You can also try tsx.
tsx is a CLI command (alternative to node) for seamlessly running TypeScript, its build upon esbuild so its very fast.
https://github.com/esbuild-kit/tsx
Example:
npx tsx ./script.ts
As of May 2022 ts-node does support es modules
npx ts-node --esm file.ts
you will likely need to add "type": "module", to your package.json. And some of the imports might be wonky unless you turn on experimental-specifier-resolution=node
npmjs.com/package/ts-node#commonjs-vs-native-ecmascript-modules
For linux / mac you can add the ts-node-script shebang.
Install typescript / ts-node globally (see 1 below for non global install):
npm install ts-node typescript --save-dev --global
Add this as the first line in your .ts file:
#!/usr/bin/env ts-node-script
Then make the file executable:
$ chmod +x ./your-file.ts
You can then run the file directly from the command line:
$ ./your-file.ts
Notes:
1 For non global install you can install local to your project
npm install ts-node typescript --save-dev
and add the relative path to the shebang script eg:
#!/usr/bin/env ./node_modules/.bin/ts-node-script
2 Support for shebangs was officially added in ts-node v8.9.0.
Like Zeeshan Ahmad's answer, I also think ts-node is the way to go. I would also add a shebang and make it executable, so you can just run it directly.
Install typescript and ts-node globally:
npm install -g ts-node typescript
or
yarn global add ts-node typescript
Create a file hello with this content:
#!/usr/bin/env ts-node-script
import * as os from 'os'
function hello(name: string) {
return 'Hello, ' + name
}
const user = os.userInfo().username
console.log(`Result: ${hello(user)}`)
As you can see, line one has the shebang for ts-node
Run directly by just executing the file
$ ./hello
Result: Hello, root
Some notes:
This does not seem to work with ES modules, as Dan Dascalescu has pointed out.
See this issue discussing the best way to make a command line script with package linking, provided by Kaspar Etter. I have improved the shebang accordingly
Update 2020-04-06: Some changes after great input in the comments: Update shebang to use ts-node-script instead of ts-node, link to issues in ts-node.
Write yourself a simple bash wrapper may helps.
#!/bin/bash
npx tsc $1 && node ${1%%.ts}
For environments such as Webstorm where the node command cannot be changed to ts-node or npx:
npm install ts-node typescript (Install dependencies)
node --require ts-node/register src/foo.ts (Add --require ts-node/register to "Node parameters")
This answer may be premature, but deno supports running both TS and JS out of the box.
Based on your development environment, moving to Deno (and learning about it) might be too much, but hopefully this answer helps someone in the future.
Just in case anyone is insane like me and wants to just run typescript script as though it was a .js script, you can try this. I've written a hacky script that appears to execute the .ts script using node.
#!/usr/bin/env bash
NODEPATH="$HOME/.nvm/versions/node/v8.11.3/bin" # set path to your node/tsc
export TSC="$NODEPATH/tsc"
export NODE="$NODEPATH/node"
TSCFILE=$1 # only parameter is the name of the ts file you created.
function show_usage() {
echo "ts2node [ts file]"
exit 0
}
if [ "$TSCFILE" == "" ]
then
show_usage;
fi
JSFILE="$(echo $TSCFILE|cut -d"." -f 1).js"
$TSC $TSCFILE && $NODE $JSFILE
You can do this or write your own but essentially, it creates the .js file and then uses node to run it like so:
# tsrun myscript.ts
Simple. Just make sure your script only has one "." else you'll need to change your JSFILE in a different way than what I've shown.
Install ts-node node module globally.
Create node runtime configuration (for IDE) or use node in command line to run below file js file (The path is for windows, but you can do it for linux as well)
~\AppData\Roaming\npm\node_modules\ts-node\dist\bin.js
Give your ts file path as a command line argument.
Run Or Debug as you like.
Create your TypeScript file (ex. app.ts)
npm i -D typescript ts-node -> to install the dev dependencies local
npx nodemon app.ts
Using nodemon, automatically recompile app.ts every time you change the file
Here is the command
tsc index.ts --outDir .temp && node .temp/index.js && rm -rf .temp
<<<<<<<<< Compile >>>>>>>>> <<<<<<< Run >>>>>>> << Clean >>
There is also an option to run code directly from the CLI, not the *.ts file itself.
It's perfectly described in the ts-node manual.
As a first step, install ts-node globally via npm, yarn, or whatever you like.
...and now just use ts-node -e 'console.log("Hello, world!")' (you may also add the -p flag for printing code)
This little command is perfect for checking, does everything installed fine. And for finding some other error, relevant with tsconfig.json options.
We can run it using nodemon as well
nodemon ./filepath/filename.ts
This question was posted in 2015. In 2018, node recognizes both .js and .ts. So, running node file.ts will also run.
I'm attempting to build a package.json so that when running a NodeJS app on Heroku it will run the scripts.postinstall step using an environment variable. For example:
...
"scripts": {
"postinstall": "command $ENV_VAR"}
},
...
I've looked at the docs and wasn't able to find something saying I can.
Is this even possible? Is this even desirable and "I'm Doing It Wrong"â„¢?
Ignore the nay-sayers. You can do this in a cross-platform manner using cross-var:
"scripts": {
"postinstall": "cross-var command $ENV_VAR"
}
Updated answer due to new packages having been written
You can use the cross-var package to do this in a clean way:
...
"scripts": {
...
"postinstall": "cross-var command $ENV_VAR",
...
},
"dependencies": {
...
"cross-var": "^1.1.0",
...
}
...
Original answer
To answer the last questions, because they're the most important one: yes, no, and absolutely, because you've just broken cross-platform compatibility. There is no guarantee your environment syntax works for all shells on all operating systems, so don't do this.
We have a guaranteed cross-platform technology available to us already: Node. So, create a file called something like bootstrap.js, and then make npm run node bootstrap as your postinstall script. Since the code inside bootstrap.js will run like any other node script, it'll have access to process.env in a fully cross-platform compatible way, and everyone will be happy.
And many, many, many things that use common utils have node equivalents, so you can npm install them, locally rather than globally, and then call them in an npm script. For instance mkdir -p is not cross-platform, but installing the mkdirp module is, and then an npm script like "ensuredirs": "mkdirp dist/assets" works fine everywhere when run as npm run ensuredirs
And for convenience, the most common unix utilities have their own runner package, shx, which is fully cross-platform and makes the lives of devs even easier, with the "if you're writing code" equivalent being fs-extra.