NPM Modules + TypeScript Best Practices - javascript

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.

Related

Workflow to use a sub-module typescript written module into a non-typescript module?

I'm having a private typescript module that is a dependency of another major project. This dependency is achieved by having the typescript repository as sub-module and installed using npm to the local sub-folder. The typescript module can compile into JavaScript on its dist folder and by doing so the major module that consumes it can make use of it without issues. But here is my problem, the dist folder isn't committed to the typescript repository.
What should be the workflow to follow in order to consume this typescript module from a JavaScript-only major project? The best I can think at this moment is to instruct someone, or something, to run the $ tsc command before using the major project but it's "annoying" since it isn't a transparent step. If this is a weird approach, what would be a more ideal approach? Thanks everyone.
You have a couple of options.
Assuming you're not planning to have a private npm registry using e.g. Verdaccio you can simply commit the dist folder. This is definitely the simplest option and it's not completely unheard of, I'd probably go with that option.
This solution is actually quite unusual, but it's pretty clever and it works. You could add a postinstall script in package.json of your TypeScript package that would run tsc after installing the package. The downside is that you'd have to add typescript as your dependency, which is not ideal (it should generally be a dev dependency, in which case it wouldn't be installed in the project using the package), but for some it might not be a big deal at all.
Instead of installing the package, you could use npm link and then have a script in your main project that would compile it. You'd have to run it every time something changes in that package, though. You could also append it to your npm start script, so it runs before it, e.g. "start": "npm compile-package && webpack" (assuming your current start script is "start": "webpack"). It doesn't scale very well though.
If your Javascript project uses Babel (and I'd assume so considering you said it's a "major" project) you could change its config so it transpiles Typescript for you using #babel/plugin-transform-typescript, however it can be a bit complicated, IIRC e.g. projects created with create-react-app by default don't recompile the code from node_modules.
There are probably more solutions, but I'd probably go with 1 or 2.

Publish NPM package with only non-bundled dependencies

Lets say we're developing a small javascript library L.
The code is in ES6. To use some utility function, like debounce, we install lodash as a dependency.
At build the webpack transpiles the code, bundling the tree shaked lodash code, and we end up with a nice little javascript file we want to publish and share as a npm package.
Now, the package.json file lists lodash as a dependency. But that is only true at build time, it is not really needed in production.
What's the proper way to handle this kind of situation?
Does it make sense to consider lodash a devDependency? As such, only webpack's externals would be "real" dependencies?
Or should we somehow tamper the package.json file before publishing it?
Do you know any real examples of projects handling this question?
Webpack "merges" the code of the project with that of the used code of the non-external dependencies into some bundle.js file. This file is then published to NPM, along with a package.json file, which lists all of the dependencies, independently of these being external or embedded.
All of the code of packages referenced in dependencies (or optionalDependencies, or peerDependencies) is expected to be "production" code.
While code in devDependencies is expected to be used only at "development" time, and is thus "development" code. Under this principle, I believe that it would be incorrect to declare non-external dependencies as development dependencies.
However, if all dependencies, embedded or external, are declared equally in the published package.json file, there is no way for a runtime environment to know which are the real dependencies that need to be made available to the package — the ones that the package will import at runtime and which better be available.
For the Node.js environment, bundles and Webpack are not normally used, so this never came to be an issue — all dependencies are always installed (never merged/bundled).
However, if you use the package.json file to drive some web-packages runtime environment, the way that dependencies are currently included in published package.json is not suitable.
You might want to take a look at Pika Web's devDependencies package.json property, which aims to solve a comparable problem (even though their mojo is "a future without Webpack"). They also introduce the concept of publishing a different package.json file than that which is checked-in (tampering the package.json before publishing, as you say).
Interestingly, it looks like a related tool, Pika Pack, caught the attention of NPM folks and is being considered to become part of NPM. So, maybe, NPM has become aware of the specific package format needs of web projects' workflows.

Should you commit the typings folder for es6 projects when using vscode?

So I have been using Visual Studio Code (vscode) when playing with some sample es6 projects.
My understanding is that in order to get intellisense to work properly with node modules, you need to include the typings of the projects that you're working on (Link here).
What I also understand is that you can have a typings.json file that stores all the "type definitions" and you run a typings install to retrieve all the typings.
This is all to get the intellisense working in vscode. What I am not sure is whether you should exclude this (typings folder and typings.json) from version control altogether?
At the moment I think that the editor should not influence the source code structure. I'm pretty sure that you should exclude the typings folder. I am not sure about typings.json. It could be useful for vscode users, but will most likely be pointless for WebStorm/Atom/Sublime/Vim users?
The content of the typings folder can easily be recreated by running typings install. If you have any kind of build process like webpack, browserify, gulp or similar, then you also need to have these definitions to be able to run the typescript compiler in your continuous integration system for example.
So you should commit the typings.json and add some npm postinstall scripts to automatically download the typings when you run npm install to be able to build your code in an automated way.

VS2015 Convert javascript to typescript and node modules

I developed a javascript web app with npm and webpack. Now I converted all those .js files to .ts by using the powershell command stated here. The succeeding actions in the link is using grunt; I want to directly use VS2015 Typescript project but I cannot find any reference on the net about what to do with the node_modules and how I can fully convert all my package.json and webpack into Typescript project. The Task Runner Explorer in VS2015 only supports Grunt and Gulp tasks.
I recommend going with the "bare-foot" solution first. I'd rely much less on VS2015. It's maybe the best IDE available, but JS and TS projects can be handled from command line without relying on the magic of the IDE. This way you can gain a deeper understanding of these technologies and I think now it would be easier too.
I recommend the following steps:
create a tsconfig.json in the root folder. Read around, there's plenty of info available. Just one hint: use 'filesGlob' to specify the files to compile.
use TSD to get the .d.ts files of the libs you use from DefinitelyTyped. You might create, or at least just declare, the missing packages.
run 'tsc --project .' from command line to compile everything. You'll see the errors that are to be solved.
I'm typing from mobile, I can edit the codes tomorrow. Have any comments?

When it comes to using react with yeoman

There are a ton of packages out there that have this all bundled up but I dont like the way they set up the projects and such so I was reading the Reactjs docs on installing with npm and my confusion is:
After installing it using npm install react or adding react to
package.json
Do I add this to the "devDependencies": {} or ...
for the require statement to work, do I need to include requirejs?
Can I just do grunt serv to start everything and auto compile the jsx or do I need to do this? (it seems like that might be answered for me ..... but how can I get it to auto compile the jsx when I run grunt serv)
I ask these questions and state I don't like the existing yo ... commands for this because they don't play nicely with bacbone.js So I was going to set this up my self. if there are any repos out there for yeoman that do this for me please point me to them.
dependencies vs devDependencies: for npm package.json, devDependencies are mainly used for the tooling around working on the project itself: testing tool chain and project building modules, for example. Things you'd often see in there: Mocha, Grunt, etc. So mostly for repo contributors and alike. As a consumer of React, you'd put it in dependencies, which are for modules that your code actually needs in order to work.
require isn't for requirejs. The naming clash is unfortunate. require() is part of CommonJS. Node uses CommonJS. Browserify too. Here, it's assuming that you're using Browserify, or maybe doing server-side React with Node.
I'm not sure what you've set up to use with grunt serve. There's nothing magical that makes it work by default. You do need to do what the link said. The --watch option will look for changes to your files and auto compile the jsx to js.
Hope that helps!

Categories