module.exports "Module is not defined" - javascript

So, I am using RequireJS and React, trying to load a third-party component, which has been installed with:
npm install react-autocomplete
The structure is here: https://github.com/rackt/react-autocomplete/tree/master/lib
Now, I have a main.js file, initiated when requireJS is loaded, that looks like this:
require.config({
paths: {
"react" : "react/react",
"jsx-transformer" : "react/JSXTransformer",
"react-autocomplete" : "node_modules/react-autocomplete/lib/main"
}
});
require(["react"], function(react) {
console.log("React loaded OK.");
});
require(["jsx-transformer"], function(jsx) {
console.log("JSX transformer loaded OK.");
});
require(['react-autocomplete'], function (Autocomplete) {
console.log("React autocomplete component loaded OK.");
var Combobox = Autocomplete.Combobox;
var ComboboxOption = Autocomplete.Option;
console.log("Autocomplete initiated OK");
});
Now, it all loads OK, but the third require statement throws a "module is not defined", for the main.js file in the third-party component, which looks like this:
module.exports = {
Combobox: require('./combobox'),
Option: require('./option')
};
I've been reading about that this has to do with me trying to require a CommonJS-style module, but I can't figure out how to fix it on my own, as I'm new to this.
Does anyone have a clear example on how I could get around this?

RequireJS cannot load CommonJS modules as-is. However, there is a minimal modification you can make to them to load them. You have to wrap them in a define call like this:
define(function (require, exports, module) {
module.exports = {
Combobox: require('./combobox'),
Option: require('./option')
};
});
If you have a bunch of modules you need to convert, or if you are using a third-party library written in the CommonJS pattern and want to convert it as part of a build process, you can use r.js to perform the conversion for you.

The problem is that requireJS doesn't support CommonJS modules only AMD. So if the third party library doesn't support AMD then you'll have to jump through some hoops to get it to work.
If you have the option I would suggest using browserify or webpack for module loading since those are the tools that the majority of the react community have chosen and practically all third-party react components are published on npm as CommonJS modules.

Related

RequireJS: TypeError [ERR_INVALID_ARG_TYPE] when loading asynchronously

So I'm trying to use RequireJS in my project, but just putting require('fs') brings up an error about how it hasn't been loaded yet. On the RequireJS website, it says that the following code should be used instead:
require(['fs'], function (fs) {
//fs is now loaded.
});
However, when I use this code, I get the error TypeError [ERR_INVALID_ARG_TYPE] which says that I should be using a string as an argument to require, but RequireJS says that this does not work.
Would appreciate it if anybody could give me any tips on how to get this working, thanks.
According to docs, you need something like that.
const requirejs = require('requirejs');
requirejs.config({
//Pass the top-level main.js/index.js require
//function to requirejs so that node modules
//are loaded relative to the top-level JS file.
nodeRequire: require
});
requirejs(['fs'], function (fs) {
console.log('fs is now loaded.');
});
Of course, you need to install it first:
npm install requirejs

Making Webpack register modules in RequireJS cache

Currently I'm using RequireJS for all my modules.
I'm considering using Webpack for my main project but need to load modules not known during build time. Like plugins.
One approach would be to use Webpack at build time and then use RequireJS at runtime. The only problem is that files loaded from Webpack bundle won't be found in the RequireJS cache.
If I manually register them it works:
import jQuery from 'jquery';
define('jquery', [], function() { return jQuery; });
But is there some easier way? Like Webpack generating code that does this?
I ended up writing a custom loader that added the code at the end of each file. Using window.define instead of define makes Webpack leave it intact for RequireJS.

Require third party RequireJS modules with Webpack

I'm working on an application that needs to pull in the ReadiumJS library, which uses AMD modules. The app itself is written in es6 w/ webpack and babel. I've gotten the vendor bundle working correctly, and it's pulling in the built Readium file, but when I try to require any of the modules Webpack says it can't resolve them. Anyone ever do this before with Webpack and RequireJS? Here's some info that may help - not sure what else to include as this is my first time really using Webpack..
Folder Structure
/readium-src
/readium-js
/ *** all readium-specific files and build output (have to pull down repo and build locally)
/node_modules
/src
/app.js -> main entry for my app
/webpack.config.babel.js
webpack.config.js entries
entry: {
vendorJs: [
'jquery',
'angular',
'../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js',
'bootstrap/js/alert.js' //bootstrap js example
],
appJs: './app.js'
}
Trying to require it in app.js
var readiumSharedGlobals = require('readium_shared_js/globals');
I never really got into using RequireJS, so really struggling to understand how to consume that type of module along side other types of modules with webpack. Any help greatly appreciated :)
Update
If I change my app.js to use this instead:
window.rqReadium = require('../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js');
Then it appears to try to load all the modules, but I get a strange error:
Uncaught Error: No IPv6
At this point, I'm unsure of
Should I have to require the entire path like that?
Is this error something from webpack, requirejs, or Readium? Tried debugging, but couldn't find anything useful...
UPDATE 8/12/2016
I think this is related to an issue with a library that Readium is depending on: https://github.com/medialize/URI.js/issues/118
However, I'm still not clear on how to correctly import AMD modules with webpack. Here's what I mean:
Let's say I have an amd module defined in moneyService.amd.js like this:
define('myMoneyService', ['jquery'], function($) {
//contrived simple example...
return function getDollaz() { console.log('$$$'); }
});
Then, in a sibling file, app.js, I want to pull in that file.
//this works
var getDollaz = require('./moneyService.amd.js');
//this works
require(['./moneyService.amd.js'], function(getDollaz) { getDollaz(); }
//this does not
require(['myMoneyService' /*require by its ID vs file name*/], function(getDollaz) {
getDollaz();
}
So, if we cannot require named modules, how would we work with a third party lib's dist file that has all the modules bundled into a single file?
Ok, so there's a repo out there for an Electron ePub reader using Readium, and it's using webpack: https://github.com/clebeaupin/readium-electron This shows a great way to handle pulling in RequireJS modules with webpack.
One super awesome thing I found is that you can specify output.library and output.libraryTarget and webpack will transpose from one module format to another... freaking awesome! So, I can import the requirejs module, set output library and libraryTarget to 'readium-js' and 'commonjs2' respectively, then inside my application code I can do import Readium from 'readium-js';

Node JS fs module inside browser

I have a scenario where I want to export data to CSV from the client-side. I will have a textbox/area or whatever where the user can input data and then ideally with one click, a local CSV file will be updated with that data.
This is easily achievable with NodeJS with server interaction, and its core modules (specifically fs module), but apparently not so much from a browser.
I found out that certain node modules (for example underscore), support RequireJS's method of making a particular module work in the browser. So for underscore I did this:
methods.js
define(['underscore'],function(_) {
var Methods = {
doSomething: function() {
var x = _.size({one: 1, two: 2, three: 3, xuz: 3});
alert(x);
}
};
return Methods;
});
common.js
requirejs.config({
baseURL: 'node_modules',
paths: {
underscore: 'underscore/underscore',
}
});
require(['methods'], function(y){
y.doSomething();
});
index.html
<script data-main="common" src="require.js"></script>
<script>
require(['common'], function() {
require(['methods.js']);
});
</script>
The above works fine and will show an alert: 4.
But when I try the same with the fs module it won't work. It will show this error:
Module name "util" has not been loaded yet for context: _. Use require([])
As far as I can understand, this is because fs requires several other modules, one of them being util.
So I proceeded to add all these modules to the RequireJS config. But still no luck, so I specifically tested util module by itself as this doesn't seem to require other modules to work.
And now I am stuck on this error: Uncaught ReferenceError: exports is not defined
I tried modularizing this util module by encapsulating the whole module source code in this:
define([], function() {})
But it didn't work either... I've also tried copying underscore's model but still no luck.
So I was wondering if anyone managed to use util & fs modules (or any other core NodeJS modules) within the browser with libraries such as RequireJS or Browserify.
That's right, exports is node-specific JS (used to make part of your module available outside the module) and isn't supported by web-browsers. Even though NodeJS is technically JS, there are client specific properties (like the window property for browsers, and exports for NodeJS apps) that can't be interchanged.
That said, here's a client side JS answer to the CSV problem.
Your best bet (and probably only one) is to use HTML5 FileSystem API. I am not aware of any other browser feature that would allow to work with files on client computer except maybe Flash and similar solution.
I am bit confused by your browserify tag since you are not obviously using Browserify. That would fix your issue with "exports is not defined".

Load scripts with requireJs, issue with absolute path

I'm trying to load scripts using requireJs() function, based on requirejs.
Here my app.js:
// Other stuff...
__config.path.base = __dirname + '/../';
requireJs = require('requirejs'),// To use to require AMD typescript files.
requireJs.config({
baseUrl: __config.path.base,
nodeRequire: require
});
But I got an issue... This script isn't app.js actually, it's /config/boostrap.js, now, if I want to import a file in the file /api/db/models/UserModel.ts, the path is actually '/$APPPATH/' instead of '/$APPPATH/api/db/models/'
So, when I try to import, from /api/db/models/UserModel.ts:
import model = require('./Model');
It fails, because it tries to load the file '/$APPPATH/Model.js' instead of '/$APPPATH/api/db/models/Model.ts'.
If I try to import differently like that:
import model = require('./../api/db/models/Model');
Typescript display an error and doesn't compile anymore, because it cannot find the file.
So, how can I fix this? My solution here was to change the compilation mode and don't use requireJs to load file into /api (CommonJs), but I'm not sure I won't have other problem later, I would prefer use the same compilation mode everywhere if it's possible!
Typescript's import statement (using requireJS) will always use your application root path for the start point, as will the compiler.
From /api/db/models/UserModel.ts:
import model = require('api/db/models/Model');
Make sure Model.ts is structured like...
class Model {
...
}
export = Model;

Categories

Resources