bower init - difference between amd, es6, globals and node - node.js

I am creating my first Bower component. After running bower init the script asks me 'what types of modules does this package expose?' with these options:
amd
es6
globals
node
what is the difference between these options?

If you don't know, it's quite likely globals is the right answer for you.
Either way, you need to understand:
what is and why AMD
what is a nodejs module
what is ecmascript 6 and especially es6 modules
[UPDATE]
This feature was introduced very recently in bower and is not documented at all yet (AFAIK). It essentially describes the moduleType, which states for what module technology the package is meant to be consumed (see above).
Right now, It doesn't have any effect apart from setting the moduleType property in the bower.json file of the package.
See https://github.com/bower/bower/pull/934 for the original pull-request.
[UPDATE #2]
A few additional points, to answer comments:
right now AFAIK there is no validation done on the moduleType property - which means that people are technically allowed to use whatever value they want for it, including angularjs if they feel inclined to do so
the bower committee seems to not be keen toward the inclusion of additional non-interoperable/proprietary moduleTypes (think composer, angular, etc) - which is easily understandable, but yet again, nothing really prevents people from using the moduleType value they want
an exception to the previous is the (somewhat) recent inclusion of the yui moduleType, so, there are "exceptions" to be made, assuming they are part of a concerted plan
What I would do if I were to author a package for a not-listed package manager and publish it on bower?
I would author an es6 module, and use / patch es6-transpiler to output the package format I need. Then I would either/and:
petition the bower guys to include my package technology as a choice (based on the fact it's supported by es6-transpiler as a target)
publish my package including both the es6 module version of it and the transpiled XXX version of it, and use es6 as a moduleType
Disclaimer: I don't have real-life experience authoring angularjs modules.

Initial
I'm using bower init for first time too.
The options should refer to the different ways to modularize some JavaScript code:
amd: using AMD define, like requirejs.
node: using Node.js require.
globals: using JavaScript module pattern to expose a global variable (like window.JQuery).
es6: using upcoming EcmaScript6 module feature.
In my case I wrote a Node.js module dflow but I'm using browserify to create a dist/dflow.js file that exports a global dflow var: so I selected globals.
Other Updates
The command I used to browserify dflow as a window global object was
browserify -s dflow -e index.js -o dist/dflow.js
I changed it cause I prefer to use require also inside the browser, so now I am using
browserify -r ./index.js:dflow -o dist/dflow.js
and so I changed the bower.moduleType to node in my bower.json file.
The main motivation was that if my module name has a dash, for example my project flow-view, I need to camelize the global name in flowView.
This new approach has two other benefits:
Node and browser interface are the same. Using require on both client side and server side, let me write only once the code examples, and reuse them easily on both contexts.
I use npm scripts and so, I can take advantage of ${npm_package_name} variable and write once the script I use to browserify.
This is another topic, but, it is really worth that you consider how it is useful the latter benefit: let me share the npm.scripts.browserify attribute I use in my package.json
"browserify": "browserify -r ./index.js:${npm_package_name} -o dist/${npm_package_name}.js"

Just for reference, this is precisely what bower specifies regarding the module types:
The type of module defined in the main JavaScript file. Can be one or an array of the following strings:
globals: JavaScript module that adds to global namespace, using window.namespace or this.namespace syntax
amd: JavaScript module compatible with AMD, like RequireJS, using define() syntax
node: JavaScript module compatible with node and CommonJS using module.exports syntax
es6: JavaScript module compatible with ECMAScript 6 modules, using export and import syntax
yui: JavaScript module compatible with YUI Modules, using YUI.add() syntax
Relevant link: https://github.com/bower/spec/blob/master/json.md#moduletype

Related

What Modern Ways (If Any) Does Node Have to "Override" It's Import System?

In Node you can make an importText function fairly easily, and then use it in another file like so:
import importText from 'importText'
const css = await importText('./someFile.css')
// (This isn't technically possible yet, but top-level await is coming someday)
By using Webpack or a similar tool, you can also do the same thing, only with a more convenient syntax:
import css from './someFile.css';
Node used to have a way to do the same thing without Webpack, but the API for it, "require extensions", was deprecated (emphasis added):
Deprecated. In the past, this list has been used to load non-JavaScript modules into Node.js by compiling them on-demand. However, in practice, there are much better ways to do this, such as loading modules via some other Node.js program, or compiling them to JavaScript ahead of time.
https://nodejs.org/api/modules.html#modules_require_extensions
My question is: what are the "much better ways"?
They mention "compiling them to JavaScript ahead of time", which I would assume is the Webpack approach. But how would one "load a module via some other Node.js program" ... or solve the problem any other way (the text I quoted implied those two weren't the only options)?

Make Typescript node modules work together

Has anybody got a setup working in which module 1 using typescript is referencing another module 2 also with typescript and both use tsd types such as node.d.ts ?
I have no problem compiling both and using them, as long as i simply require module 2. But as soon as i use import instead, i get into duplicate identifier hell, due to the fact that source files in both modules import e.g. node.d.ts typings from obviously different paths. Classes in both projects use e.g 'streams' or 'lodash' thus both use them in typings and thus use the /// reference syntax. The tsconfig in both projects excludes typings.
Typescript has come a long way since this was asked, and it's now much easier. You can link the proper files in package.json:
{
"main": "library-commonjs.js",
"module": "library-es6-module.js",
"typings": "library-commonjs.d.ts"
}
main is used by packages using CommonJS and Node.js module resolution. module is used by packages supporting ES6 imports. And typings is followed by Typescript (currently Typescript 2.2) to resolve type definitions for the package.
After struggling with this, I spent some time creating a typescript boilerplate/starter project that demonstrates how to do it properly:
https://github.com/bitjson/typescript-starter
That project includes a lot more documentation, and several examples of how to import code from typescript projects.
EDIT: With TS 2.2 this has gotten quite a lot better. See the accepted answer.
It seems this is not really possible yet in typescript 1.8.x. But they seem to work on it via https://github.com/Microsoft/TypeScript/issues/7156.
Also the problem is supposedly mitigated by using a jsconfig.json which should be used by VScode (see https://blogs.msdn.microsoft.com/vscode/2015/07/06/visual-studio-code-es6/). Sadly i didnt get it working yet.

TypeScript Import Confusion - It Can't Be This Hard

I have been working with TypeScript off and on for two years now. I am not an expert by any means, but I've spent some time in the eco-system: with VS2015 and node tools, with VSCode, and at the command line with tsc and typings (also used by VSCode).
And I have struggled with the correct way to get static typing and auto-complete etc in the code I've been writing.
I have a repo I maintain (EasyNodeQ) which was the start of my TypeScript experience and I sort of got that to a manageable place with ///reference and DefinitelyTyped. But any time I tried to use that within another project I had issues.
Things got a little better when I started using typings (rather than downloading the *.d.ts files myself) and especially with the ambient flag.
But I still have lots of issues trying to use that package within other projects. Depending on the approach I take, I get lots of Duplicate Identifier's, or module not found's or...
And this can range from Node definitions, to packages I use in both places (like node-uuid).
All I want to understand is this: how to I structure EasyNodeQ so that as I'm working on it, I get the static typings benefits of TypeScript but also have it be seamlessly included in other projects which can then also get these benefits?
Does that make sense?
The basic use cases are: npm install a package and get its typings, use my EasyNodeQ package and get its typings, work in a new project that uses EasyNodeQ and other packages and easily manage those typings.
Preferably in a VSCode or command line way...
This is with ES6 and the latest version of TypeScript (though an answer that works with ES5 would be nice - just not required).
I hope this makes sense. I've looked all over and I can't cobble together an answer that works.
UPDATE
I'm not convinced I've done this the "right" way, but it's working now so I thought I'd post the various things I've done (generally in the order I think they mattered and not inclusive because I may have forgotten some).
I hadn't npm'd the dependency package (easynodeq) and was just using a git url in the package.json - so I created a proper npm package and now install that package from npm
Instead of trying to use Bus.ts as both code and definition, I made Bus.js the "meat" of the npm, and built a Bus.d.ts file (also in the npm)
Embraced typings, using non-ambient definitions where possible and a mix of ambient definitions downloaded (via git) from DefinitelyTyped and "--ambient" definitions for the rest (because I'm still confused about the difference). The ambient definitions ended-up being the majority: node, express, serve-static, express-serve-static-core, mime, amqplib, when vs just bluebird and node-uuid, even though most of them were found by "typings search ..." Am I doing something wrong?
Modified package.json to also do "typings install"
Cleaned-up the git repo
There are several ways to make this work today. As you mentioned, using Typings works for definitions that aren't natively included in their NPM packages. For ones that do, you can using the typings field in package.json and it'll work with node module resolution. When you combine this together, you can publish packages that use both typings.json and relies on packaged typings - though this now forces your consumers to be using Typings to install the definitions. None of this, however, works with "ambient" definitions as they can not be namespaced properly.
This may be useful: https://github.com/typings/typings/blob/master/docs/faq.md#should-i-use-the-typings-field-in-packagejson. There's also dozens of examples I have using both workflows: https://github.com/blakeembrey/change-case/blob/master/package.json#L6 which uses node module resolution all the way down and https://github.com/blakeembrey/popsicle/blob/master/typings.json which uses Typings instead. Using Typings is only possible because it works to create namespaced ambient modules for you, but they won't conflict.

How can I include additional modules in a NodeJS custom binary?

I am building a custom binary of NodeJS from the latest code base for an embedded system. I have a couple modules that I would like to ship as standard with the binary - or even run a custom script the is compiled into the binary and can be invoked through a command line option.
So two questions:
1) I vaguely remember that node allowed to include custom modules during build time but I went through the latest 5.9.0 configure script and I can't see anything related - or maybe I am missing it.
2) Did someone already do something similar? If yes, what were the best practices you came up with?
I am not looking for something like Electron or other binary bundlers but actually building into the node binary.
Thanks,
Andy
So I guess I figure it out much faster that I thought.
For anyone else, you can add any NPM module to it and just add the actual source files to the node.gyp configuration file.
Compile it and run the custom binary. It's all in there now.
> var cmu = require("cmu");
undefined
> cmu
{ version: [Function] }
> cmu.version()
'It worked!'
> `
After studying this for quite a while, I have to say that the flyandi's answer is not quite true. You cannot add any NPM module just by adding it to the node.gyp.
You can only add pure JavaScript modules this way. To be able to embed a C++ module (I deliberately don't use the word "native", because that one is quite ambiguous in nodeJS terminology - just look at the sources).
To summarize this:
To embed a JS module to your custom nodejs, just add it in the library_files section of the node.gyp file. Also note that it should be placed within the lib folder, otherwise you'll have troubles requiring the module. That's because the name/path listed in node.gyp / library_files is used to encode the id of the module in the node_javascript.cc intermediate file which is then used when searching for the built-in modules.
To embed a native module is much more difficult. The best way I have found so far is to build the module as a static library instead of dynamic, which for cmake(-js) based module you can achieve by changing the SHARED parameter to STATIC like this:
add_library(${PROJECT_NAME} STATIC ${SRC})
instead of:
add_library(${PROJECT_NAME} SHARED ${SRC})
And also changing the suffix:
set_target_properties(
${PROJECT_NAME}
PROPERTIES
PREFIX ""
SUFFIX ".lib") /* instead of .node */
Then you can link it from node.gyp by adding this section:
'link_settings': {
'libraries' : [
"path/to/my/library.lib",
#...add other static dependencies
],
},
(how to do this with node-gyp based project should be quite ease to google)
This allows you to build the module, but you won't be able to require it, because require() function in node can only be used to load built-in JS modules, external JS modules or external dynamic node modules. But now we have a built-in C++ module. Well, lot of node integrated modules are C++, but they always have a JS wrapper in /lib, and those wrappers they use process.binding() to load the C++ module. That is, process.binding() is sort of a require() function for integrated C++ modules.
That said, we also need to call require.binding() instead of require to load our integrated module. To be able to do that, we have to make our module "built-in" first.
We can do that by replacing
NODE_MODULE(mymodule, InitAll)
int the module definition with
NODE_BUILTIN_MODULE_CONTEXT_AWARE(mymodule, InitAll)
which will register it as internal module and from now on we can process.binding() it.
Note that NODE_BUILTIN_MODULE_CONTEXT_AWARE is not defined in node.h as NODE_MODULE but in node_internals.h so you either have to include that one, or copy the macro definition over to your cpp file (the first one is of course better because the nodejs API tends to change quite often...).
The last thing we need to do is to list our newly integrated module among the others so that the node knows to initialize them (that is include them within the list of modules used when searching for the modules loaded with process.binding()). In node_internals.h there is this macro:
#define NODE_BUILTIN_STANDARD_MODULES(V) \
V(async_wrap) \
V(buffer) \
V(cares_wrap) \
...
So just add the your module to the list the same way as the others V(mymodule).
I might have forgotten some step, so ask in the comments if you think I have missed something.
If you wonder why would anyone even want to do this... You can come up with several reasons, but here's one most important to me: Those package managers used to pack your project within one executable (like pkg or nexe) work only with node-gyp based modules. If you, like me, need to use cmake based module, the final executable won't work...

Importing Node.js npm modules (node_modules) & declarations in TypeScript

I think it would be great to directly import modules from node_modules directory without need to manually provide a declaration file for it (let us assume that declaration is provided with module itself). I guess that problem are dependencies that come with declarations (file paths could be resolved relative to the module, but that would cause duplicates and compiler can't handle that).
Currently working with node modules is very inconvenient because simple install from npm repository just isn't enough and we have to manually search for declarations and provide them in our project. Let's say that our project is dependent on 10 node modules (all of them have declarations) and after a year we would like to update them. We would have to manually search for new declarations and let's say that we have around 20 projects like this (it would become a nightmare). Maybe there should be an option to directly import .ts file from node module?
Do you have any suggestions?
This is a re-post from CodePlex to hear your opinions ...
If you use grunt-typescript then I've got a pull request which solves this at least for me. See https://github.com/k-maru/grunt-typescript/pull/36
From the pull request README
Working with modules in node_modules (i.e. npm)
The standard way to use npm packages is to provide a definition file
that specifies the package to the typescript and import the module from there.
///<reference path="path/to/mod.d.ts" />
import mod = module('mod')
The typescript compiler will convert the import to a nodejs require.
var mod = require('mod')
This is pretty unwieldy as you need to know the precise path to the
npm installed package and npm can put the package at pretty much any
level when you are working with multiple levels of dependencies.
With the node_modules option in the grunt config you can just
import a npm package without need to know the exact level where the
package has been installed by npm as long as it is installed locally
and not globally.
To import an npm module in your typescript source do
import npmModule = module('node_modules/npmModule/foo')
Mostly due to a lucky chance this works. Typescript compiler will read
the typescript definition file node_modules/npmModule/foo.d.ts if it
is present at some point on the way towards the root and the resulting
javascript file will contain a require for npmModule/foo if needed.
I don't think that node modules will ever contain built-in typescript support. The language still is a 0.x release and officially described as an alpha version.
Nevertheless there are means to ease the configuration process for typescript. Github already contains huge collections of .d.ts files such as:
https://github.com/borisyankov/DefinitelyTyped
or
https://github.com/soywiz/typescript-node-definitions
You might want to take a look at this tool: https://github.com/Diullei/tsd .
I've never used it but it seems like it's almost what you're looking for.
Moreover I've heard that an official database of .d.ts files is planned. Unfortunately I couldn't find the link but it will probably be some time before this is implemented anyways.

Resources