Writing npm modules in TypeScript - javascript

I am working on my first npm module. I briefly worked with TypeScript before and a big problem was that for many modules there were no definition files available. So I thought it would be a good idea to write my module in TypeScript.
However, I can't find any information on the best way to do that. I found this related question "Can I write npm package in CoffeeScript?" where people suggest only publishing the JavaScript files. But in contrast to the CoffeeScript files, the TypeScript files might actually be useful if they are used within a TypeScript application.
Should I include TypeScript files when publishing an npm module, or should I only publish the JavaScript files and provide the generated .d.ts files to DefinitelyTyped?

Here is a sample Node module written in TypeScript : https://github.com/basarat/ts-npm-module
Here is a sample TypeScript project that uses this sample module https://github.com/basarat/ts-npm-module-consume
Basically you need to :
compile with commonjs and declaration:true
generate a .d.ts file
And then
Have your ide read the generated .d.ts.
Atom-TypeScript just provides a nice workflow around this : https://github.com/TypeStrong/atom-typescript#packagejson-support

With TypeScript 4.x, TypeScript 3.x or TypeScript 2.x, the following steps describe what you have to do to create a library (npm package) with TypeScript:
Create your project as you normally would (with tests and everything)
Add declaration: true to tsconfig.json to generate typings.
Export the API through an index.ts
In the package.json, point to your generated typings. For example if your outDir is dist, then add "types": "dist/index.d.ts" to your package json.
In the package.json, point to your main entry file. For example if your outDir is dist and the main entry file is index.js, then add "main": "dist/index.js" to your package.json.
In the package.json, whitelist the files you'd like to ship to npm: files: ["/dist"]. An alternative approach is blacklisting with .npmignore, but it's harder to keep up to date.
Publish to npm with npm publish. Use semver specifications for updates (patch / bug fix npm version patch, non-breaking additions npm version minor, breaking api changes npm version major)
Since it got me a while to sift through all the outdated resources on this topic on the internet (like the one on this page...) I decided to wrap it up in how-to-write-a-typescript-library with an up-to-date working minimal example.

This is a more recent answer using TypeScript 1.8.10:
My project structure is:
|
|--- src
|--- test
|--- dist <= My gulp file compiles and places the js, sourcemaps and .d.ts files here
| |--- src
| |--- test
|--- typings
.gitignore
.npmignore
gulpfile.js
package.json
README.md
tsconfig.json
tslint.json
typings.json
I added the following in .npmignore to avoid including extraneous files and keep the bare minimum to have the package imported and working:
node_modules/
*.log
*.tgz
src/
test/
gulpfile.js
tsconfig.json
tslint.json
typings.json
typings
dist/test
My .gitignore has:
typings
# ignore .js.map files
*.js.map
*.js
dist
My package.json has:
"main": "dist/src/index.js",
"typings": "dist/src/index.d.ts",
Now I run:
npm pack
The resultant file (when unzipped) has the following structure:
|
|--- dist
| |--- src
| |
| index.js
| index.js.map
| index.d.ts
|
package.json
README.md
Now I go to the project where I want to use this as a library and type:
npm install ./project-1.0.0.tgz
It successfully installs.
Now I create a file index.ts in my project where I just installed the npm
import Project = require("project");
Typing Project. gives me the Intellisense options which was the point of this whole exercise.
Hope this helps someone else in using their TypeScript npm projects as internal libraries in their bigger projects.
PS: I believe that this approach of compiling projects to npm modules which can be used in other projects is reminiscent of the .dll in the .NET world. I could well imagine projects being organised in a Solution in VS Code where each project produces a an npm package which can then be used in another project in the solution as a dependency.
Since it took a fair amount of time for me to figure this out, I have posted it in case someone is stuck here.
I also posted it for a closed bug at:
https://github.com/npm/npm/issues/11546
This example has been uploaded to Github: vchatterji/tsc-seed

You should publish the original typescript sources instead of the type definition. In package.json let the 'types' property point to the *.ts file.
*.d.ts are good to annotate existing JS libs, but as a consumer I'd rather read the typescript code than switching between type definitions and down-leveled, generated JS code.

I mainly follow the suggestion by Varun Chatterji
But, I would like to show a complete example with unit testing and code coverage and publishing it into npm and importing them using javascript or typescript
This module is written using typescript 2.2 and it is important to configure the prepublish hook to compile the code using tsc before publish it to npm
https://github.com/sweetim/haversine-position
https://www.npmjs.com/package/haversine-position

You can use autodts to handle distributing and using .d.ts files from npm also without support from the Atom IDE.
autodts generate will bundle all your own .d.ts files together for publishing on npm, and autodts link handles references to other installed packages, which may not always be directly under node_modules in a larger project split into several subpackages.
Both commands read their settings from package.json and tsconfig.json in "convention over configuration" style.
There's another answer on stackoverflow and a blog post with more details.

Related

Linking local library into Angular 5 Project

What i want is to have a library locally that when i change it those changes are reflected in the project that is using the library.
i have check out this library here in my local machine: https://github.com/manfredsteyer/angular-oauth2-oidc
So what i'm doing right now, is that i go to the library directory and then
npm link
And then get in my project directory and do
npm link angular-oauth2-oidc
The library folder appears inside my node_modules folder but i can't manage to use it, since when i start the app ng serve it says:
Cannot find module 'angular-oauth2-oidc'
I'm importing like this:
import { OAuthModule } from 'angular-oauth2-oidc';
I've tried to add the the path under the compilerOptions of the tsconfig.json file but haven't been sucessful.
Any ideas on what i'm missing here? I've tried several suggestions i've found on angular github issues but none solved my problem.
Thanks in advance
npm link in a package folder will create a symlink in the global folder {prefix}/lib/node_modules/ that links to the package where the npm link command was executed
Dont use npm link to add a library to your project, use npm install :
npm install angular-oauth2-oidc --save
You have to install it not just link it, so use this line to with flag --save to ensure that it will be saved in your package.json
npm install [package_name] --save
You can get the package name from the source website or from
https://www.npmjs.com/package/angular2
When you say:
So what i'm doing right now, is that i go to the library directory and
then npm link
Do you mean you are executing npm link in the folder you cloned the repository in? Because if so, that's likely your issue as that's the source directory and not what's actually published as a package. You must build the library, change directory into the distribution folder for the package, and then run npm link. Then when you run builds of that library, any Angular applications with that linked will automatically have the last version of your build in their node_modules.
Also, in your Angular applications where you are using the linked library you'll want to make sure you are setting preserveSymlinks to true in your angular.json.
While you can create multiple projects (e.g. an Angular app and an Angular library) under one Angular project to make this process a bit easier, I prefer to separating these two since I like one git repository to present one module.
First, you need to link your modules to your project's package.json file. Here's how to link files locally in general:
Local dependency in package.json
Linking a plain Typescript library is pretty straight forward as you just create an entry point (usually index.ts) file and export everything you want from there. This file needs to be in the same folder as the package.json file in your project.
An Angular library is a bit different as angular modules needs to be compiled before it can be properly exported. If you just import the module to your project without compiling you will get an error stating this: cannot read property 'ɵmod'. This happens at least at the time of writing this.
So we need to compile the library and then link it:
open two terminal windows
in the first terminal, go to your Angular library's root folder and run ng build --watch
check the output folder of the compiled module, usually something like dist/[library name]
change your Angular project's package.json to point to the output folder e.g. "my-angular-library": "file:../my-angular-library/dist/my-angular-library"
run npm install in the same folder
Add path to your Angular project's tsconfig.json e.g:
compilerOptions: {
"paths": {
"my-angular-library": ["./node_modules/my-angular-library"]
}
}
Otherwise you'll get errors like Error: Symbol MyComponent declared in /path/to/library/my.component.d.ts is not exported from my-angular-library
in the second terminal, go to your Angular project's root folder and run ng serve. Make sure you serve the project only after you have installed the local dependency.
You should now be able to use components, services etc. exported via your library module.
TL;DR
for the library ng build --watch
make the library dependency to point to the output folder e.g. "my-angular-library": "file:../my-angular-library/dist/my-angular-library"
npm i
Add path to your Angular project's tsconfig.json e.g:
compilerOptions: {
"paths": {
"my-angular-library": ["./node_modules/my-angular-library"]
}
}
ng serve

Is the same a package.json and a composer.json?

Hello i would like to know if a package.json is the same as a composer.json.
I need to create one file with some content, i required to put it in a package.json file but in the project there is a composer.json already. So can i work in this file or they work diffent?
Thanks
They are not the same
package.json is a npm file to keep track of npm packages.
composer.json is a composer file to keep track of php packages.
Best difference between composer.json & package.json file.
composer.json
Composer is a package manger tool for php.
composer.json manages the PHP dependencies.
For Example composer require fzaninotto/faker. This command will open and write to the composer.json file and download all the dependencies
package.json
package.json manages the Node dependencies.
All npm packages contain a file, usually in the project root, called package.json - this file holds various metadata relevant to the project. This file is used to give information to npm that allows it to identify the project as well as handle the project's dependencies.
They are different files. composer.json is for Composer, a package manager for PHP, whereas package.json is for NPM or Yarn, primarily used together with Node.js.
In addition to the information you've already been given, about package.json being a file to manage Node dependencies, there is another possibility.
Composer also uses a packages.json file (note the plural) to define a composer repository. It consists of composer.json objects together with information about where to download the files from. https://getcomposer.org/doc/04-schema.md#repositories
Your question's unclear about what you're trying to do. Whilst you tagged javascript, you don't mention it anywhere in the question itself.

Role of the src and dist folders in NPM packages

Im using Restangular for HTTP requests. I want to use the method customPATCH. I can see it in the Restangular src/ directory here.
However when I ran 'npm install restangular' and pointed to the dist/ folder, I was getting the error "customPATCH is not a function". I noticed the source code in the dist/ folder isnt the same as what's in the src/ folder (it doesnt define the customPATCH method).
Why would there be a difference between what's in src/ and what's in dist/ for an NPM package? Are these normally kept in sync? In this case, the dist/ directory hasn't been updated in 8 months. Should I just use the source in the src/ folder? Maybe I'm misunderstanding how to use NPM packages (I always use the source in the dist/ folder)...
src/ and dist/ is a common naming convention for most packages. In most instances a developer has the code that they are working on src/ and the distribution version of the code they want others to use dist/. Most developers, my self included will either compile, minify or concatenate their code in to production facing version of the code. They usually include the src/ file in their public repositories so that people can see the source code and modify it as they see fit.
tdlr;
src/is the code the developer is working in.
dist/ is the distribution version that has been modified to perform better for users not looking to modify how the code works.
Typically src contains source code and dist code after minification and other changes (anyway, derived code - what would be target in Java world).
Sometimes when main repo is written in EcmaScript6 or newer, then dist folder contains code transpiled down to EcmaScript5 to support older versions of nodejs / older browsers.
You can use code from src if it works for you - however typically code in dist is minified and hence faster.
But sometimes authors forget to update dist folder and then you might have discrepancies. You might ping the author to rebuild the dist folder.

NPM Modules + TypeScript Best Practices

i want to write a npm module in TypeScript.
Can someone recommend me a best practice guide how to get started?
My Questions are:
Node.js don't support TypeScript out of the box, right? So how is the recommended way to publish a npm module? Make 2 Folders /ts /js and reference in the package.json to js/index.js as entry point. Or use some kind of a runtime transpiler and run the TypeScript file directly? Or is it not recommended anyway to publish any TypeScript Code in a npm module and just compile it down to normal Javascript and provide the TypeScript source in a Git repository?
What is the recommended way for Typing Support? I saw i can reference in my package.json to the Typing Files. Can they be online, should i provide them with the npm module or should ts and dtd files not be published at all? Install them with typings and provide the typings.json as well?
If i want to provide typing support for my code how is the recommended way to do this? even my modules are very small and simple (do one thing and do it right) it could be useful to provide some information and autocompletion support. I'm still new to TypeScript so not sure whats the best way to do this. I would guess writing a Interface and provide it with my npm module. Should these files later be uploaded to the DefinitelyTyped directory or does this only for larger libraries sense?
I would love to here how to do it correctly with the current TypeScript and Node Version since lot of the informations i found are outdated referring to stuff like autodts, tsd and so on.
Im very glad if someone can help me. As soon i know how this is done the right way i will make a documentation and provide these information for others on Github.
Cheers
To your first question: Yes, you have to transpile the typescript code before you can publish you npm package but you can do this very easily by making sure you have this in your package.json:
"scripts": {
"prepublish": "tsc",
}
Best practice for structering the files is to use e.g. a src directory for your ts files and then the root level or another directory (e.g. dist) for the js files. You can set this up by defining the "outDir" in your tsconfig.json:
"compilerOptions": {
[...]
"outDir": "dist"
}
Also the links in the accepted answer here helped me with similar questions: Writing NPM modules in Typescript
As for your question about the typing in the npm package: For providing the typing in the current typescript version you don't need to change anything in your package.json. You can just add a file called index.d.ts to the root level of your package. If somebody uses your module typescript will automatically find the typing there.

How to link tsd definitions automatically with bower and npm?

I'm in the process of converting an existing project to TypeScript with many bower and npm dependencies (bower.json and package.json). According to the tsd github page,
TSD supports discovery and linking of definitions from packages
installed with node or bower. Use the link command and your tsd.d.ts will be updated with paths to the files in the node_modules or bower_modules folders.
However when I run the command tsd link after tsd init it just says no (new)packages to link even though my package.json is chalk full of modules. This led me to discover, maybe it does not do what I think it does.
This feature will scan package.json and bower.json files for a
typescript element. This element then contains definition or
definitions sub-element that contain relative path(s) to .d.ts files:
What? What is the purpose of this link feature if it doesn't just get type definitions from my package.json? Is this command merely to pull tsd configurations from my package.json instead of in my tsd.json file? What then, is the point, other than eliminating the tsd.json file?
So if it's not tsd link, I'm asking if there is any better way to automatically include tsd definitions for all my dependencies. It seems kind of crazy to me that these would all be managed by hand.
tsd link is not a magical command. I assume just like you when I see this command first time.
If you install new packages via bower or NPM, and the package bundled with .d.ts and also have a "typescript": { "definition": "..." } in the config file, that .d.ts will include into your tsd.d.ts file like below:
/// <reference path="jquery/jquery.d.ts" />
/// <reference path="../bower_components/angular/angular.d.ts" />
If the package doesn't serve a d.ts file and definition configuration, this command can do nothing.

Categories