requirejs unable to find module returning undefined - requirejs

i've been working with require before, but never ran into this issue,
maybe i got a path wrong somewhere but this is my filestructure:
js
├───main.js
│
├───app
│ ├───app.js
│ ├───hello.js
│ ├───world.js
│ │
│ └───models
│ └───game.js
│
└───vendor
├───jquery.js
└───require.js
main.js
require.config({
paths: {
'jquery': '../js/vendor/jquery'
},
shim: {
'jquery': {
exports: '$'
}
}
});
require(['app/app', 'jquery', 'app/models/game'], function (App, $, Game) {
console.log(arguments);
$(function () {
console.log('why is my App undefined?', App);
App.init();
});
});
app/app.js
define('App', ['hello', 'world'], function (hello, world) {
var App = {};
App.init = function () {
alert(hello + ' ' + world);
};
return App;
});
the code fires alright, however my dependencies seem to fail on app or hello or world module, App logs as undefined, so does my game module.
app/app should be the right path to my App module or am I thinking that wrong?
Update
I thought the capital A for App fixed the issue (but at the same time I took a swing at Jlange's comment, so I fired up the app/App module from the index.html. Which seemed ok, but after continuing the development it came up again.
I can load every module in the same directory just fine, but I cannot modules from subdirectories.
like the initial example couldn't load app/App from within the Main module, so can the app/App module not import the models/Game module.
I literally have no clue what this can be, as I said before, I have worked with requirejs and have not run into this issue.
Update 2
I can make it work if I drop all the named modules,
define([dependencies], function (dependencies) {});
that works fine
but as soon as I change it into a named module I cannot find it
define("moduleA", ['subdir/moduleB'], function (moduleB) {
console.log(moduleB); // >> undefined
});
define("subdir/moduleB", [dependencies], function (dependencies) { return 'B'; });

edited
after many tries, to fix the above code, and reading up in the requirejs help pages, I found a small passage, saying it is best not to use named modules and let the optimizer name them for you.
So I decided to remove all module names
moduleA.js
define(['subdir/moduleB'], function (moduleB) {
console.log(moduleB); // >> 'B'
});
subdir/moduleB.js
define([dependencies], function (dependencies) { return 'B'; });
this works just fine...
don't know how I got fixed on using those moduleNames, Thought it would be better to name your modules.

Related

node + requirejs: module is not defined

Getting a module is not defined error attempting to import a module from the local project. Using node and requirejs -
Error: Evaluating /Users/Projects/stash/NODE/project_js/src/foo.js as module "foo" failed with error: ReferenceError: module is not defined
Code looks like -
(function() {
const requirejs = require('requirejs')
requirejs.config({
baseUrl: __dirname,
nodeRequire:require
});
//var foo = requirejs('foo.js');
requirejs(['foo'], function() {
foo().then(data => {
data.foreach(function(item, index, data) {
console.log(JSON.stringify(item))
})
});
})
})();
The module has the following export -
module.exports = function foo() {
.
.
.
return results
}
I've tried loading the module synchronously as well.
Check this part of their doc: if the module to be loaded (foo here) is found by RequireJS (i.e. its configuration allows it to find the module), then this module has to be declared using define instead of Node's exports.
I just tried this, which works:
directory structure
test/
index.js
foo.js
index.js
(function() {
const requirejs = require('requirejs');
requirejs.config({
baseUrl: __dirname,
nodeRequire:require
});
requirejs(['foo'], (foo) => {
console.log('loaded!', foo, foo());
});
})();
foo.js (that's the interesting part)
define(function() {
return function foo() {
return 'fooResult';
}
});
Using module.exports = ... gave me the error you have.
However this RequireJS API is not "loadable" by Node's built-in require, hence the need for a precise configuration that reflects a clear separation between Node-required modules (CommonJS API) and RequireJS-defined modules (AMD API). (Actually you can check the whole "Why AMD?" page, that should help a lot for your work with RequireJS.)

Gulp + Browserify + TypeScript To Browser

My problem is the following:
I use gulp+browserify to compile my TypeScript to JavaScript that you can use on normal HTML pages, the problem is that my class is never available on the browser:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
This is my TypeScript File:
class Test {
public test(): void {
console.log("aa");
}
}
This is my gulpfile
var gulp = require("gulp");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");
gulp.task("default", function () {
return browserify({
//basedir: '.',
debug: true,
entries: ['app/Resources/typescript/Test.ts'],
cache: {},
packageCache: {}
})
.plugin(tsify)
.bundle()
.pipe(source('bundle.js'))
.pipe(gulp.dest("web/bundles/framework/js"));
});
The file compiles without problem, and is included in my index.html (the compiled js file).
But when i try:
var t = new Test();
I get the following error:
VM633:1 Uncaught ReferenceError: Test is not defined
at <anonymous>:1:13
I can't resolve it, I have read a lot and I haven't found anything clear, I tried all and nothing worked.
There are a few things missing here:
If you want your class to be accessible outside of your module, you have to export it:
export class Test {
// ...
}
Browserify creates functions on top of the classes you define. So it won't be accessible globally (which is a good thing). Normally you would import it in another file and use it:
// in any TS file that wants to use `Test` class. Make sure this is included in the gulp entries as well
import {Test} from "test";
var t = new Test();
console.log(t);
Or if really want it to be accessible globally, you can attach it to window object:
// In Test.ts file:
(window as any).Test = Test; // This can be useful when debuging. But don't do this in production code.

Durandal optimization with Gulp and Gulp-Durandal not working

We are building an application with Durandal which is quite big at the moment and we currently looking into bundling all JS files located in the App folder into a main-built.js file. Pretty basic and usual stuff I guess.
I'm using Gulp with the Gulp-Durandal extension. Here our gulpfile :
var gulp = require('gulp');
var durandal = require('gulp-durandal');
gulp.task('build-portal', function () {
durandal({
baseDir: 'app',
main: 'main.js',
output: 'main-built.js',
almond: false,
minify: false
}).pipe(gulp.dest('app'));
});
And here's a snippet of our main.js file
require.config({
paths: {
'text': '../Scripts/text',
'durandal': '../Scripts/durandal',
'plugins': '../Scripts/durandal/plugins',
'transitions': '../Scripts/durandal/transitions'
},
shim: {
},
waitSeconds: 0
});
define('jquery', [], function () { return jQuery; });
define('knockout', [], function () { return ko; });
define('ga', function () { return ga; });
define(
["require", "exports", "durandal/app", "durandal/viewLocator", "durandal/system", "plugins/router", "services/logger", "modules/knockout.extensions", "modules/knockout.validation.custom"],
function (require, exports, __app__, __viewLocator__, __system__, __router__, __logger__, __koExtensions__, __koValidationCustom__) {
var app = __app__;
var viewLocator = __viewLocator__;
var system = __system__;
var router = __router__;
As you can see in the gulpfile, we do not want to use Almond but RequireJs instead, for some reasons almond isn't workin with our project and anyhow, we prefer RequireJs whether its bigger than almond at the end. That's where it look to brake. Running the command to build the main-built.js file took sometime but at the end I get the file built with everything in it.
The problem is that when I try to load the application, it is stuck to the loading screen. It doesn't go any further and there's no errors at all in the browser console.
I created a new project on the side to test if our code was somewhat faulty and found that it might not. You can found that project here :
https://github.com/maroy1986/DurandalGulpBundling
If I build that project with almond option to true, everything works fine but if I switch almound off to tell gulp to use RequireJs, I got the same behavior as our app. You got stuck at the loading screen, without any errors.
So here I am, I do read a lot on the subject but didn't found anything to solve this. Hope someone here already encounter these behavior and have a solution to share.
Thanks!
I had the same requirement and issue. It seems require.js wasn't calling the main module which will startup the Durandal app, that's why it's stuck in the loading screen. I was able to resolve it by implicitly calling the main module:
gulp.task("durandal", function() {
return durandal({
baseDir: "app",
main: "main.js",
output: "main-built.js",
almond: false,
minify: true,
rjsConfigAdapter: function(config) {
//Tell requirejs to load the "main" module
config.insertRequire = ["main"];
return config;
}
})
.pipe(gulp.dest("dist"));
});
I downloaded your project and tried building it with the latest versions of gulp and durandal. Initially it didn't build and gave me the following error:
TypeError: Cannot read property 'normalize' of undefined
This is a problem with the text-plugin of rjs and you can solve this by adding the following to your gulp-file (next to the almond, minify, output... properties):
rjsConfigAdapter : function(rjsConfig){
rjsConfig.deps = ['text'];
return rjsConfig;
}
Once I did that, the build finished and I could build with or without minify, almond and require and the application works fine.

requirejs callback undefined

Project Structure
root
wwwroot <-- files under this location are static files public to the site
css
lib
bootstrap/js/bootstrap.js
jquery/js/jquery.js
knockout/knockout.js
requires/require.js
scripts
modules ┌───────────────┐
global.js <--│ Built modules │
dropdown.js └───────────────┘
modules
global.js ┌────────────────┐
dropdown <--│ Source modules │
dropdown.js └────────────────┘
gruntfile.js
global.cs Contents (pre-built version at ~/modules/global.js)
require.config({
baseUrl: "scripts/modules",
paths: {
jquery: "../../lib/jquery/js/jquery",
bootstrap: "../../lib/bootstrap/js/bootstrap",
knockout: "../../lib/knockout/knockout"
},
shims: {
bootstrap: {
deps: ['jquery']
}
},
});
define(function (require) {
var $ = require('jquery');
var ko = require('knockout');
var bootstrap = require('bootstrap');
});
dropdown.js Contents (pre-built version at ~/modules/dropdown.js)
define(function () {
console.log('dropdown initialized');
return 'foo';
});
HTML Page
Contains this script tag in the <head> of the page for loading requires config:
<script src="~/lib/requirejs/require.js" data-main="scripts/modules/global"></script>
In the body of the HTML page, I have the following:
<script>
require(['global'], function () {
require(['dropdown'], function (dropdown) {
console.log(dropdown);
});
});
</script>
Issue
The dropdown callback is undefined instead of the expected "foo" string that I'm returning from the defined module.
In fact, the console does not contain a log item for "dropdown initialized" either. This makes me believe the module is not being invoked somehow? However, it's strange the dropdown.js is present in F12 debugger as a script loaded into the page. Therefore, requires did make a call to load it, but did not run the contents of the define?
Noteworthy mentions
I'm using r.js to optimize and build. Both global.js and dropdown.js are processed over.
The name assigned to the dropdown module by r.js processing is "modules/dropdown/dropdown.js". I'm unsure if I should be using this somehow, or if I'm referring to the module correctly as just dropdown and relying on my baseUrl config having the correct path.
Edit #1
I have added the r.js build configuration used with grunt per commenter request. In conjunction, I updated the file structure to include the overall project structure, instead of just the runtime public wwwroot structure.
The r.js process will compile built forms of global.js + other modules in ~/wwwroot/scripts/modules from the source location ~/modules in summary.
function getRequireJsConfiguration() {
var baseUrl = './';
var paths = {
jquery: "wwwroot/lib/jquery/js/jquery",
bootstrap: "wwwroot/lib/bootstrap/js/bootstrap",
knockout: "wwwroot/lib/knockout/knockout"
};
var shims = {
bootstrap: {
deps: ['jquery']
}
};
var optimize = 'none';
var configuration = {};
var jsFilePaths = grunt.file.expand('modules/**/*.js');
jsFilePaths.forEach(function (jsFilePath) {
var fileName = jsFilePath.split('/').pop();
if (configuration[fileName]) {
throw 'Duplicate module name conflict: ' + fileName;
}
configuration[fileName] = {
options: {
baseUrl: './',
name: jsFilePath,
out: 'wwwroot/scripts/modules/' + fileName,
paths: paths,
shims: shims,
optimize: optimize,
exclude: ['jquery', 'knockout', 'bootstrap']
}
};
});
configuration['global'] = {
options: {
baseUrl: './',
name: 'modules/global.js',
out: 'wwwroot/scripts/modules/global.js',
paths: paths,
shims: shims,
optimize: optimize,
}
};
return configuration;
}
Edit #2
Thought it'd be a good idea to include the versions of requirejs packages I'm using:
requirejs: 2.1.15
grunt-contrib-requirejs: 0.4.4
Thanks.
The name assigned to the dropdown module by r.js processing is "modules/dropdown/dropdown.js". I'm unsure if I should be using this somehow, or if I'm referring to the module correctly as just dropdown and relying on my baseUrl config having the correct path.
In a sense, yes, you should be using that full path. That's what Require refers to as the module id - "modules/dropdown/dropdown" (if the .js in the above output was real, I suggest stripping that extension in the "name" config. .js is assumed by RequireJS, you don't want that string in your module ids). The basePath is used, when given IDs, to transform some unknown ID to a file path (e.g. 'bootstrap' id -> (applying path config) -> '../../lib/bootstrap/js/bootstrap' -> (applying base URL) -> 'scripts/modules/../../lib/bootstrap/js/bootstrap').
Really, though, just allowing r.js to concatenate everything into one file
is the preferred way to go. You could use the include option to include modules un-referenced by global.js in with the optimized bundle, too ( https://github.com/jrburke/r.js/blob/master/build/example.build.js#L438 )
As to your specific problem: your lazy require(['dropdown']) call is misleading you. By combining the requested module id with the basePath, RequireJS comes up with the URL you want - scripts/modules/dropdown - which defines a module with the module id scripts/module/dropdown - but since you requested the module id dropdown, you get nothing. (I would've guessed you'd get a RuntimeError instead of undefined, but I suppose that's how things go). One way or another you need to address the id/path mismatches.
Although I have resolved my issue with the hints wyantb's answer provided, I've since changed my approach to a single file concat due to the simplicity it brings. I still wanted to post the specifics of how I solved this question's issue for anyone else to happens along it.
In the grunt build configuration options, I added the onBuildWrite field to transform the content, so my assigned module IDs lined up with how I was lazily loading them.
onBuildWrite: function (moduleName, path, contents) {
return contents.replace(/modules\/global.js/, 'global');
}
This code is specifically for the global.js file. I implemented a similar onBuildWrite for the other module files (in the foreach loop). The transformation will essentially strip the path and extension from the module name that r.js assigns.
Here are some examples of before and after:
Before After
/modules/global.js global
/modules/dropdown/dropdown.js dropdown
/modules/loginButton/loginButton.js loginButton
Therefore, when I load the modules using the HTML script from my original question, requirejs resolves and finds a match.
Either require by path or define global and dropdown in global.cs
require(['./global'], function () {
require(['./dropdown'], function (dropdown) {
console.log(dropdown);
});
});

RequireJS issues accessing app object across app

I have an application which has an app object which does the start routine and stores useful things like app.state and app.user. However I am trying to access this app instance without passing this from the app instance all the way around my large codebase.
Strangely I work on other projects which include app in the same way as in something.js and it works but I can't see why.
index.html
<!DOCTYPE html>
<html>
<head>
<title>Cannot require app in another file</title>
</head>
<body>
<script data-main="config" src="require.js"></script>
</body>
</html>
config.js
requirejs.config({
deps: ['app']
});
app.js
define([
'something'
], function(Something) {
'use strict';
var App = function() {
this.name = 'My app';
};
return new App();
});
something.js
define([
'require',
'app'
], function (require, app) {
'use strict';
var SomeModule = function() {
app = require('app'); // EXCEPTION
console.log('App:', app);
};
return new SomeModule();
});
When loading this requirejs exception is throw because of the require in SomeModule:
Uncaught Error: Module name "app" has not been loaded yet for context: _
Demo of above (see console for error): http://dominictobias.com/circulardep/
It's not clear to me why you need to have a circular dependency. As stated in the documentation for RequireJS:
Circular dependencies are rare, and usually a sign that you might want to rethink the design.
This being said, if you do need the circular dependency, the issue with your code is that require('app') is called too early. It cannot be called until after the module something has returned its value. Right now, it is called before the value is returned. If you look at the code given as example in the documentation:
define(["require", "a"],
function(require, a) {
//"a" in this case will be null if a also asked for b,
//a circular dependency.
return function(title) {
return require("a").doSomething();
}
}
);
you see that the module returns a function which then would be called by the code that required the module, which happens after this module has returned its value.
So how do you fix this? What you could do is have the class you return call a function that fetches module app whenever needed. So:
define([
'require',
'app'
], function (require) {
'use strict';
var app_;
function fetch_app() {
if (app_ === undefined)
app_ = require("app");
return app_;
}
var SomeModule = function() {
// ...
};
SomeModule.prototype.doSomethingWithApp = function () {
var app = get_app();
app.whatever();
};
return new SomeModule();
});
I've removed app from the list of arguments and store the value of the app module in app_ because doing it this way provides for early detection of a missing call to get_app() in any method of SomeModule. If app is made a parameter of the module's factory function then using app inside a method without calling get_app() first would be detected only if it so happened that no other method that calls get_app() was called first. (Of course, I could type app_ and face the same problem as the one I aim to prevent. It's a matter of respective likelihoods: I'd be very likely to forget to call get_app() everywhere it is needed because I don't usually write code with circular dependencies. However, I'd be unlikely to type app_ for app because I don't usually put _ at the end of my variable names.)

Resources