Browserify External Requires with Grunt-Browserify - javascript

The Browserify docs section on external requires shows how to make a module within a bundle available to the global environment:
browserify -r through -r duplexer -r ./my-file.js:my-module > bundle.js
But I'm having trouble configuring this to work with Grunt-Browserify.
The -r flag seems to correspond to the require option in Grunt-Browserify, but the docs description for this option doesn't make any mention of external requires or exporting a require() function.
In my Gruntfile, I've tried setting the require option to the module I need to expose (which is already in the bundle, by the way):
options: {
require: ['./dev/js/foomod.js'],
}
And then in my page script, I try to require() the module as shown in the docs:
<script>
var Foomod = require('./foomod.js');
Foomod.init({foo: 'bar'});
</script>
But that logs the error require is not defined.
My goal is to call the module's init() method as shown so that I can pass in runtime data without putting it in a window global.

Using browserify version 5.11.1 and grunt-browserify version 3.0.1, I have managed to get similar setup to work:
options:{
preBundleCB: function (b) {
b.require("./dev/js/foomod.js",{expose: 'foomod'});
}
}

Related

How VSCode injects "vscode" engine into the extensions?

When developing extensions for VSCode. We see this import:
import * as vscode from 'vscode';
and in package.json, we have
"engines": {
"vscode": "*"
}
Nowhere in the dependencies we have 'vscode'. But, looks like it is available for extension. Any explanation would be appreciated.
Imports are resolved by the host environment, in this case VSCode's possibly-modified version of Electron. So when it sees a request for the vscode module, it provides it (internally) rather than looking for an external dependency.
FWIW, a defacto standard is emerging that "raw" module names, like 'vscode', tend to be provided directly by the host environment whereas ones with paths ('./foo') are external. (That's why the src on script type="module" tags is required to have a path, at least for now.)
The "engines" section in package.json is not related with module import system.
It's for some native module to know howto compile when npm install.
And can check engine version. eg: you can set engines: {node: >=8}, then node v7 will deny to run your code, but that's not enforce.
VS Code is using vscode-loader as module loader, it's very like require.js, but has many other function for vscode.
The "global" function "require" you called, is override by vscode-loader, not node's native "require".
Same with any other module loader system, vscode-loader allows you to modify the "require" function.
vscode is changing so fast, you can do a simple search with nodeRequire('module').
Currentlly, related code is in src/vs/workbench/api/node/extHost.api.impl.ts file:
const node_module = <any>require.__$__nodeRequire('module');
const original = node_module._load;
node_module._load = function load(request: string, parent: any, isMain: any) {
if (request !== 'vscode') {
return original.apply(this, arguments);
}
.....
.....
// and finally, return apiImpl, the "vscode" object
}
require() will call module._load(), but this module._load is already overrided by vscode-loader.
You can also override it again like this.
That is called "Monkey Patch".

Can I use unpkg or browserify to include single NPM packages in a frontend project?

So I'm working with JS on the frontend, building something for a client. Details aren't super important except that I do not have access to node.
I'm using unpkg to include various NPM packages in the browser (like React/ReactDOM/Babel for instance). These packages have a UMD build so they work out of the box.
However, there are a few packages I'd like to use that do not have a UMD build (namely react-dates or react-datepicker). I've tried serving different files via unpkg and referencing the exported modules. Since they don't have UMD builds, I'll either get an error module is not defined which makes sense, or that the module I'm referencing DatePicker is not defined.
So I thought maybe I could build a single file with browserify but I've never used it before and any docs I could find are lacking. Heres what I did
var DatePicker = require("react-dates");
In a file called test.js and then:
browserify test.js -o bundle.js
Output that, upload it to the client assets, reference it like:
<script src="/js/bundle.js"></script>
But var DatePicker = require("DatePicker") throws error require is not defined (I thought that was the point of browserify?) and console.log(DatePicker) throws is not defined as well.
At this point I'm at a loss. I'm being stubborn but I really really just want to use a react datepicker and avoid adding jQuery to this project for the sole purpose of a datepicker. As far as I can tell unpkg is not an option but I feel like browserify could work and I'm just doing something wrong.
Any help is greatly appreciated!
You don't have to do this, you can find the needed files in the dist folder (New folder\node_modules\react-datepicker) after you "npm install react-datepicker" within a folder, but be sure you have a package file into that, otherwise the install won't work.
The files should look like this
EDIT:
The requirejs code that you need is
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.2/require.min.js"></script>
<script>
requirejs.config({
paths: {
'react': 'https://unpkg.com/react#15.3.2/dist/react',
'react-dom': 'https://unpkg.com/react-dom#15.3.2/dist/react-dom',
'prop-types': 'https://unpkg.com/prop-types#15.6.0/prop-types',
'react-onclickoutside': 'https://unpkg.com/react-onclickoutside#6.7.0/dist/react-onclickoutside',
'react-popper': 'https://unpkg.com/react-popper#0.7.4/dist/react-popper',
'moment': 'https://unpkg.com/moment#2.19.3/moment',
'datepicker': 'https://unpkg.com/react-datepicker#0.61.0/dist/react-datepicker'
}
});
requirejs(['react', 'react-dom', 'prop-types', 'react-onclickoutside', 'react-popper', 'moment', 'datepicker'], function(React, ReactDOM, PropTypes, onClickOutside, Popper, moment, DatePicker) {
ReactDOM.render(
React.createElement('p', {}, 'Hello, World!'),
document.getElementById('root')
)
});
but as far as I got, datepicker requested for "module" which is not defined, this can be the same problem as here. I will investigate more about this issue.

import requirejs amd module with webpack

I'm using Converse.js and it's prebuilt into the RequireJS/AMD syntax. Including the file from a CDN you could use it like require(['converse'], function (converse) { /* .. */ }). How is it possible to use this with webpack? I would like to bundle converse.js with my webpack output.
I have the file on disk, and want to import it like
import converse from './converse.js';
converse.initialize({ .. });
Webpack picks up the file and bundles it correctly, although it's not useable yet as it throws 'initialize is not a function'. What am I missing?
I suspect the way their bundle is built will not work correctly with how Webpack evaluates modules in a limited context.
From their builds, taking the built AMD module via NPM without dependencies should be parsable by Webpack and it will enable you to provide the dependencies to avoid dupes in the final output.
If all else fails, using the script-loader will evaluate the script in the global context and you'd get the same experience as if you'd have followed their usage guidelines to reference it from a CDN, just don't forget to configure the globals for your linter.

Use Browserify with JavaScript libraries such as Backbone or Underscore?

I know I can install underscore using npm but that's not what I can do in my work environment. I need to be able to download the Underscore.js library and then make it "browserify-compatible".
So let's assume Underscore.js looks something like this:
(function() {
var root = this;
// Rest of the code
}.call(this));
I downloaded that file on my hard drive and saved it as under.js.
My file that requires underscore looks like this:
var underscore = require("./under");
console.log(underscore);
And then I run browserify from the cli.
I have an HTML page called test.html and basically all it does is load the generated bundle.js.
However, the console.log(underscore) line fails - says that underscore is undefined.
What have I tried?
Obviously I added module.exports to the first line - right before the function definition in under.js, and that's how I got the error mentioned above. I also tried the method from this answer , still got the same error.
So, how would I use Browserify to load libraries such as Underscore.js or Backbone without using npm-installed modules?
That's because browserify does not add variables to the global scope. The version you download is identical to the version that you install via NPM.
You need to explicitly attach it to the window to export it to the top level scope.
If you create a file called "expose_underscore.js" and put this in it:
var _ = require('./under');
window._ = _;
Will do it, followed by: browserify expose_underscore.js > bundle.js and then add bundle.js as a <script> tag you will be able to do the following in your console:
HOWEVER, you shouldn't do this if you're using browserify. The point behind it (and Node's version of commonJS) is that you explicitly require it everywhere you need it. So every file you have that needs underscore should import it to a local variable.
Don't worry -- you will still only have one copy loaded.
I typically add my vendor libs like Underscore as script tags. Underscore will attach itself to the global scope, so then you don't need to require it anywhere to use it.
If you do want to use it in a Browserified fashion, verify that you have the correct path in your require statement (browserify requires are relative paths) and move the module.exports statement to the end of the file.

browserify detect custom require()

I want to use a custom require() function in my application.
Namely I have node's standard require() and a custom one I wrote to require files starting from the root called rootRequire() which internally all it does is:
// rootRequire.js
var path = require('path');
var rootPath = __dirname;
global.rootRequire = function (modulePath) {
var filepath = path.join(rootPath, modulePath);
return require(filepath);
};
module.exports = rootRequire;
But even though rootRequire() internally uses node's require(), it does not pick up any files required through that method
Example:
require('rootRequire.js');
rootRequire('/A.js'); // server side it works, in the browser I get an error saying can't find module A.js
Perhaps, this will answer your question on why it is not working on browser.
Quoting the owner's comment: "Browserify can only analyze static requires. It is not in the scope of browserify to handle dynamic requires".
Technically, you are trying to load files dynamically from a variable with your custom require. Obviously, node.js can handle that.
In case of browserify, all requires are statically loaded and packaged when you run the CLI to build the bundle.
HTH.
What i recommend doing here is this:
First create a bundle to be required of anything you might use in rootRequire().
Something like browserify -r CURRENT_PATH/A.js -r CURRENT_PATH/B.js > rootRequirePackages.js
Then, in your webpage, you can include both rootRequirePackages.js and your regular browserified file.
Perhaps just use RequireJS ? It's simple to set up and relatively easy to use.

Categories

Resources