How to fetch modules from npm as standalone AMD/CommonJS modules - node.js

So, I'm not using Node or WebPack serverside, but would still like to use modules from npm every now and then. My clientside uses requirejs, so I would need the modules in either AMD (preferred) or CommonJS.
What I want to archieve is a script that takes the module name + "external dependencies" as arguments and creates a module that contains all the other deps.
E.g.
sh npmtoamd.sh draft-js react react-dom
It creates an ES5 AMD module that contains draft-js and all of it's dependencies excluding react and react-dom. If it's not possible to eg. include css files and other non-js content in the module, providing them in eg. draft-js.css is tolerable.
While I don't use Node or Webpack serverside, we can use npm and webpack in the said script.
Fetching the module from npm is the trivial part, but I'm pretty lost in how to do the webpack parts. I know for a fact that it's possible though, as I managed to do it earlier with help, just don't have it down anywhere and no idea how it went.

I think as elmigranto commented, Browserify is what you're looking for. Unlike its name implies, it can be used in both the browser environment and the node environment. In a nutshell, it does this:
Browserify starts at the entry point files that you give it and searches for any require() calls it finds using static analysis of the source code's abstract syntax tree.
For every require() call with a string in it, browserify resolves those module strings to file paths and then searches those file paths for require() calls recursively until the entire dependency graph is visited.
Each file is concatenated into a single javascript file with a minimal require() definition that maps the statically-resolved names to internal IDs.
This means that the bundle you generate is completely self-contained and has everything your application needs to work with a pretty negligible overhead.
If you check out some of the demos you can see that all the dependencies (and their co-dependencies) are bundled into one file.
A simple example:
browserify main.js -o bundle.js
In regards to using AMD as well Browserify supports it by using deamdify.
Using AMD modules:
browserify -t deamdify main.js -o bundle.js

I ended up doing the npm fetch thingy in java instead of a batch script and finally got it working. Didn't get browserify to work however.
Heres what I do:
creating the following webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js',
library:"<modulename>",
libraryTarget:"amd"
},
externals: {
react: "React",
"react-dom": "ReactDOM",
immutable:"Immutable",
moment:"Moment"
}
};
npm install <modulename>
Creating the following main.js
define('FOOBAR', ['<modulename>'], function(Foo) {
return Foo;
});
Running webpack main.js

Related

Use an NPM module directly in the browser

This might be a stupid question, or the answer is so obvious that I just couldn't find it.
Basically I want to use Redux in my very simple web app. I wanna be able to include redux like this :
<script type="text/javascript" src="js/redux.js"></script>
And just use it directly in my code like this :
var store = redux.createStore(...);
I tried webpack and browserify but I couldn't make it work. Any ideas ?
To import Redux via a <script> tag you have to use the UMD builds.
According to the docs, they are present on the dist/ folder.
I got Redux working with their pre-built UMD files.
But to use other NPM modules directly in the browser here's what to to (I don't know if this is the correct method but it worked for me) :
1- Create a simple file main.js with :
window.Redux = require('redux');
2- Install browserify globally :
npm install -g browserify
3- Browserify the file from the command line (no config files) :
browserify main.js -o redux.js
Now just include redux.js as a <script> tag
If you want to include the package directly on the browser for a smaller use case you could use unpkg.com which is a fast prepackage list of everything available on NPM (per the claim on their website)

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.

node_modules packaging fail (Webpack or Browserify)

I'm trying to bundle my node.js application with webpack or browserify, but I need some backend modules such as knex, bookshelf and others.
But webpack and browserify fail to package these modules since they do some strange stuff with require()...
I got these kind of errors :Cannot find module 'sqlite3' or Error: Cannot find module './dialects/postgres/index.js'
I can't ignore my node_modules directory since I need the modules in the package because I can't access the environment where my package will be used. (AWS Lambda)
I don't need webpack or browserify to optimize my node_modules but I need them, is there a way to tell webpack or browserify to just bundle the node_module folder and trust me if a require is missing ?
EDIT: I'm using serverless to test and deploy my lambdas and the only plugins allowing me to use ES2015 with babel force me to use webpack / browserify
Thank you :)
You can incorporate node_modules in the your Lambda package (the zip file containing your code that you upload in Amazon Lambda) and don't need to package it (I mean create a file with Webpack or Browserify).
Some node modules are not meant to be used in the browser and do not support packaging because they use dynamic requires. They can have good reasons to do that, specially ORMs like Bookshelf or Sequelize.
Webpack can manage simple dynamic requires, but it works only for rules easy to parse. If you really want to use webpack for whatever reason, you could have a look to the ContextReplacementPlugin but I don't think it worth the effort.
I had this exact problem and finally got it to work with webpack (don't know about browserify) by adding this to my webpack config:
{
plugins: [
new webpack.NormalModuleReplacementPlugin(/\.\.\/migrate/, '../util/noop.js'),
new webpack.NormalModuleReplacementPlugin(/\.\.\/seed/, '../util/noop.js'),
new webpack.IgnorePlugin(/mariasql/, /\/knex\//),
new webpack.IgnorePlugin(/mssql/, /\/knex\//),
new webpack.IgnorePlugin(/mysql/, /\/knex\//),
new webpack.IgnorePlugin(/mysql2/, /\/knex\//),
new webpack.IgnorePlugin(/oracle/, /\/knex\//),
new webpack.IgnorePlugin(/oracledb/, /\/knex\//),
new webpack.IgnorePlugin(/pg-query-stream/, /\/knex\//),
new webpack.IgnorePlugin(/sqlite3/, /\/knex\//),
new webpack.IgnorePlugin(/strong-oracle/, /\/knex\//),
new webpack.IgnorePlugin(/pg-native/, /\/pg\//)
]
}
If you're using serverless-webpack like me, you'll have to explicitly npm install the normal webpack module in your project and require it in your webpack config file.
This config is specifically for my setup where I use postgres without pg-native. Just ignore the modules you're not using.
The two top plugins aren't needed for webpack to build, but they get rid of a ton of annoying warnings. They're probably a little dangerous since they could match requires in other modules than knex. I couldn't find a better way without having to write my own plugin.
I was struggling to get webpack to bundle knex properly and want to share my configuration.
We could instead use ContextReplacementPlugin to avoid listing all drivers not needed for the project as when using webpack.IgnorePlugin. A side benefit is that it would avoid ignoring these packages in other modules (as mention by #Erik Frisk).
For example, I use a mysql database with mysql2 driver and my webpack config looks like this:
plugins: [
new webpack.ContextReplacementPlugin(/knex\/lib\/dialects/, /mysql2\/index.js/),
]
This will only bundle node_modules/knex/lig/dialects/mysql2/index.js excluding other dialects thus effectively ignoring the dependency in other packages like oracledb, mssql, etc.
To find more information about ContextReplacementPlugin have a look at Webpack’s ContextReplacementPlugin examples:

Do all npm packages need an export?

I am new to nodejs packages and what I understood was that to share code you had to do a module.export (in addition to adding a package.json)
For example bootstrap-select does not have an export function but is available on npm.
So my question is do all modules require an export and also can I do a require('bootstrap-select') in my code?
no, all npm modules do not require an export. npm is now being used more generally for not only javascript packages intended for use under node.js but front end code for browsers, CSS libraries, etc. At the very least, an npm package could just deliver a payload of files not even including any javascript, such as some images, some CSS, some HTML, etc.
So you can only do require('some-module') if that package has either an index.js file or has set the main property in it's package.json file properly.
However if you are authoring a javascript module for node.js, then yes you'll need to export something in order for your module to load properly.
No, npm modules do not require doing something with module.exports. If you do not touch that object, requireing your module will return an empty object (since that is the default for module.exports. However, this can be useful if your module is only intended to be required for side effects, rather than a return value.
For example, the module you linked to modifies global state by attaching a jQuery event handler.
As per i know ,
1.All npm modules are not required to build an app.
2.If we use var bootStrap = require('bootstrap-select'); using bootStrap variable you can access bootStrap module.
so we can pass that object in anywhere of your code
3.To install a dependency modules,
In package.json give dependency block as like this
"dependencies": {
"express": "2.3.12",
"jade": "latest",
"redis": "0.6.0"
}
you can change and edit your packages. then enter a command npm install in command prompt it will install only dependency modules.
If i made any mistakes please correct me Thanks.

webpack and amd modules integration

I have the following scenario in a web application:
I have some external js files containing multiple amd modules (they've been generated by typescript, but I don't want to use ts-loader, for now).
each one of these files contain more than one amd module, such as:
define("Namespace/Module1", ["require", "exports"], function (require, exports) {
....
}
define("Namespace/Module2", ["require", "exports"], function (require, exports) {
....
}
Inside my main application I request modules exported by these files using
var a = require("Namespace/Module1").
I used SystemJs until now, and using correct configuration, everything's working, but I would like to start using webpack for bundling and I don't know how to add these files as "require" dependencies.
I tried to add them as script tags after importing requireJS, but (of course), webpack loader uses its own "require" loader and it doesn't work.
Using externals in webpack configuration makes webpack consider that they are not modules, but globals, so it excludes require("aaa") from the generated bundle and expects a global aaa variable
function(module, exports) {
module.exports = aaa;
}
How can I tell webpack that when he's generating my bundle he should still use require("Namespace/Module") but before, calling all "define"s in my external files?
I hope my explanation is enough and If I am doing something wrong, if am following bad practices, or something, please explain.
Thanks in advance

Resources