browserify 'require' placement - javascript

Usually all dependencies are required in the head of the file.
var Backbone = require('backbone');
var $ = require('jquery');
I wonder if it is correct to require in code body. Example:
template: require('./home.tpl.hbs'),
module.exports = Backbone.View.extend({
template: require('./home.tpl.hbs'),
render: function () {
...
return this;
}
});

It's going to work, but require function is taken from nodejs world (CommonJS modules) and you can read about best practices in its usage here. So my point is that you need to add local variable at the beggining of the file and then use it wherever you want.

Related

How to import a Backbone/RequireJS module into a React/Webpack app

We have a legacy Backbone application that we are moving over to React. An interim step we are attempting is loading a bundled Backbone module into a React page, until we have time to fully rewrite it. I am halfway there, I can bundle up the app and all its dependencies with r.js using a config like this:
({
...
baseUrl: './',
name: 'myapp',
paths: {
'myapp': './legacy/app'
},
out: 'src/appbuilt.js'
...
})
The module is set up like this:
define(function(require) {
var $ = require('jquery'),
_ = require('underscore'),
...
templates = $(require('text!templates/app.html')),
app = {};
app.View = .....
app.Model = .....
return app;
});
That bundle works on the Backbone side. Next I need to turn that into something I can import into React and render. I am trying things like this:
npx babel src/appbuilt.js --out-file src/appbuilt.es6.js --plugins=#babel/transform-modules-umd
Which works to give me a UMD module, but importing it like this:
import * as legacyapp from '../../appbuilt.es6';
Gives me warnings on the build like:
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
And errors on page load that are probably symptoms of something:
Uncaught TypeError: name.split is not a function
What is the secret sauce to get my module converted into something I can use? I am open to modifying how the Backbone app does its imports, or making a wrapper of some kind that is more easily translatable.
I am not sure but I can guess that the format of your AMD modules is the problem here. Try converting them to regular AMD modules:
define(
['jquery', 'underscore', 'text!templates/app.html' /* add rest of dependencies here */],
function ($, underscore, templates /** add parameters for rest of dependencies here */)
{
var app = {};
// app.View = ...
// app.Model = ...
return app;
}
);

Inject angularjs directive

I have this structure in my script A:
module.exports = angular.module('myApp').controller(..).directive(..)
I want to inject additional directive so that I have something like this:
module.exports = angular.module('myApp').controller(..).directive(..).directive(..)
I want to do this from the outside of the script A.
Any ideas how this can be achieved? I am still catching up with the angular, and any help is really appreciated! Thanks a lot!
If I understand correctly, you want to create your directive dynamically. (within different angular module) You can code in the way blow,
//dynamic directive dyDir.js
module.exports = function (app) {
app.directive(...)
};
your script
var dyDir = require('./dyDir.js');
var yourApp = angular.module('appName',[]);
yourApp.controller('testCtrl', ...)
dyDir(yourApp); //parse angular module instance as parameter
Although this would work, but I really don't think use angular.module and the commonjs module at the same time is a good practice, coz this would make the other developer so confused.
Hope this would solve your problem. : )
I got this solved in a following way - if it can be of any help to anyone:
Assume you have an existing module myModule, and two controllers myController1 and myController2 (code for the two controllers is in files controller1.js and controller2.js). This is your code in a file myapp.js:
module.exports = angular.module("myModule", [])
.controller('myController1', require('./controller1.js'))
.controller('myController2', require('./controller2.js'))
Assume you would like to inject additional directive into your module myModule. You would reuse that module.
You would create a new file with the following content:
require('./myapp.js');
require('./mydirective.js'); //this is your new directive
var app = angular.module("myModule"); //get an existing module
app.directive('directiveName', function() {
return {
...
}
})

Javascript, multi file modules and Require.Js

I am designing a not-trivial application in Javascript.
From what i read so far a common practice is to avoid cluttering the global namespace by defining everything into modules.
And for convenience and code clarity a module can be divided into separate files using the module Augmentation pattern
var MODULE = (function (my) {
// functions, objects, etc ...
return my;
}(MODULE || {}));
Now when having many modules and module dependencies, require.Js seems like a promising tool to add order, decoupling and cleaner namespace. having all modules loaded asynchronously and make sure they run only after their dependencies are ready.
define(["depenencyModule1", "depenencyModule2"],
function(depenencyModule1, depenencyModule2) {
// define MyModule
return MyModule;
}
);
This usage however interferes with the module augmentation pattern from before, at first it seems like i am using it wrong but then i went through require.js documentation and found this:
"Only one module should be defined per JavaScript file, given the nature of the module name-to-file-path lookup algorithm."
So now i am confused, If i write my module to a single file it will be huge and maintainable, doesn't that make require.js useless?
Or perhaps Javascript concept of a module is a tiny bit of code compare to modules in other languages ?
RequireJS allows you to have a facade module which is implemented as a group of RequireJS modules. For instance, you could have:
define(function (require, exports, module) {
'use strict';
var foo = require("./foo");
var bar = require("./bar");
for(var prop in foo) {
exports[prop] = foo[prop];
}
for(var prop in bar) {
exports[prop] = bar[prop];
}
});
This module exports everything from foo and bar. From the point of view of someone importing it, it looks like a single module, even though three RequireJS modules are involved (the facade, and the two modules it imports).
Another thing I've done is declare a single class across multiple modules. I might have a foo module that exports the class Foo:
define(function (require, exports, module) {
'use strict';
var core = require("./foo_core");
require("./foo_init");
require("./foo_gui");
...
exports.Foo = core.Foo;
});
The foo_core module actually defines the class:
define(function (require, exports, module) {
'use strict';
function Foo () {
// ...
}
Foo.prototype.bar = function () { ... };
exports.Foo = Foo
});
Other modules add to it. foo_init:
define(function (require, exports, module) {
'use strict';
var Foo = require("./foo_core").Foo;
Foo.prototype.init = function () { ... };
});
foo_gui:
define(function (require, exports, module) {
'use strict';
var Foo = require("./foo_core").Foo;
Foo.prototype.render = function () { ... };
Foo.prototype.erase = function () { ... };
});
I've used both methods above to split code which from the standpoint of the API should appear as a single module but is implemented across multiple files.

Browserify and Vue: uncaught reference error: Vue is not defined

This is my first foray into any front-end development beyond basic jQuery stuff, and I'm using Vue.js along with some other packages with Browserify. My main 'app.js' looks like this:
window.$ = window.jQuery = require('jquery');
require('bootstrap');
var moment = require('moment');
var fullCalendar = require('./vendor/fullcalendar.min.js');
var datetimepicker = require('./vendor/bootstrap-datetimepicker.min.js');
var select2 = require('./vendor/select2.min.js');
var VueResource = require('vue-resource');
var Vue = require('vue');
require('./videos/show.js');
require('./home.js');
require('./search.js');
Vue.use(VueResource);
new Vue({
el: '#search',
data: {
message: 'Hello World!'
},
});
...
It works as expected this way, but when I try to create a new Vue instance in another file (in search.js, for instance) I can't do it. I get the 'Uncaught reference error: Vue is not defined' in my console. No problem with using the other required packages elsewhere - although I don't understand why I need to import jQuery the way I'm doing it... it won't work if I do:
var $, jQuery = require('jquery');
I'm sure this is something very basic and fundamental that I am not understanding yet but any help would be greatly appreciated!
The problem you are having is the basics of using modules. In general, a module should always export some behavior or property and then you require that module and use it. For example, say I wanted to add a hidden into to a form on some pages. I would do this:
AddSecretToken.js
module.exports = function(form) {
// code here to add the hidden input to the passed in form
}
Then somewhere else where I had a form that needed the secret input, I would require it:
MyForm.js
var addSecretToken = require('./AddSecretToken');
...
// some code that makes a form
addSecretToken(myForm);
...
Obviously, at some point you need some code that actually runs something but that would be your root module or the page where you require the root module. So maybe you have an app.js at the top and it requires what it needs and then runs app() without exporting anything. That makes sense. But the majority of modules shouldn't be doing that.
Any time you need some behavior, you should make a module and then anywhere you need the behavior, you require the module. Each module should require what it depends on -- it shouldn't depend on any global (sometimes jQuery is an exception).

Declare all dependencies in a Marionette+RequireJS application before Application is created

I'm building a new application using Marionette and RequireJS, and I've got the following structure:
/main.js -- Main require() call that includes app.js and calls Application.start()
/app.js -- Application definition
/modules
/sub
/controller.js -- Defines a sub-application, requires app.js
...
I'm trying to keep dependencies at the top level of each file, as opposed to using require() inline, so that the r.js compiler can find them. The problem is, in my controller.js file, I am requiring app.js (in order to add initializers) and so I cannot require controller.js in app.js until after the Application has initialized, which means I can't put controller in the top-level define() array.
A simplified example of the currently working code:
// app.js
define(['marionette'], function(Marionette) {
var Application = new Marionette.Application();
Application.on("initialize:after", function() {
require(['modules/sub/controller'], function() {
Backbone.history.start();
});
});
});
// controller.js
define(['app'], function(Application) {
Application.module('SubApplication', function(SubApplication, Application, Backbone, Marionette, $, _) {
var router = Marionette.AppRouter.extend({
appRoutes: { "foo": "bar" }
});
var controller = { foo: function() {} };
Application.addInitializer(function() {
new router({ controller: controller });
});
});
});
I'm still fairly new to both Require and Marionette, so any suggestions would be welcome! I do know that I can include the files I want via the include option to r.js, but I thought this question was worth asking nonetheless.
The way I've chosen to do it in my book on Marionette and RequireJS is to require inline the modules that are only necessary for a subset of functionality. This simplifies development, and also means that modules won't be loaded unless that code path is triggered.
R.js will find inline dependencies just fine (provided they're defined as strings, i.e. not computed dynamically). In addition, they will also work with Almond.js (but don't forget to use the findNestedDependencies option in your build file).
Hope this helps!

Categories

Resources