I have a project that has old-school, pre-module style JS for use in a browser. The JS consists of hundreds of components built like this:
Root:
(function() {
"use strict"
window.App = {};
App.SomeNameSpace = {};
App.SomeOtherNameSpace = {};
})();
ExampleComponent:
(function() {
"use strict";
App.SomeNameSpace.ExampleComponent = function () { };
App.SomeNameSpace.ExampleComponent.prototype.func = function () {
// Do some random things here
};
})();
ExampleComponent2:
(function() {
"use strict";
App.SomeNameSpace.ExampleComponent2 = function () { };
App.SomeNameSpace.ExampleComponent2.prototype.func = function () {
// Do some other random things here
};
})();
And the file layout would be something like this:
some-namespace/component.0.js
some-namespace/component.1.js
some-other-namespace/other-component.0.js
root-component.js
And the bundling process would be to concatinate all scripts in a single folder (namespace), minify the result and output it as a single bundle (some-namespace.js, for example). And then the website would output the scripts in the correct order so root.js would be run first (so that all namespaces are defined), and then the bundles with actual "classes" would follow.
There are no imports, there's no ES5/ES6 functionality in there, except for some APIs that are polyfilled, it relies on jQuery and some other external libs.
Also it's important to note that each namespace has its own bundle and not all of them get used in each page. Each app page picks and chooses the components it needs, only the root script is loaded in all pages.
How can I "webpack-ify" this in the least painful way possible? Since there are no imports, there are no real entrypoints and everything is is defined globally using namespaces.
You change only the root, to expose App variable to the window.
(function() {
"use strict"
App = App || {};
App.SomeNameSpace = {};
App.SomeOtherNameSpace = {};
window.App = App;
// ----^ exposing App variable to window
})();
Then create additional file, let's call it loader.js, that will require all the files by the correct order.
Related
I have 2 model files containing a constructor in each, and an index.js file, that I wish to use to insert elements into a HTML file, using innerHTML. I want to use one of the variables from the js model file, however when I try to require the files in the index.js file, the innerHTML file suddenly stops working. Please note, the code in the current `window.onload' function is inserting h1 elements as a test, I will be replacing this with a return value from the constructor, but at the moment, when I require the files, even the h1 insert stops working. Code snippets that I think are relevant can be seen below:
index.js file:
var ToDo = require('../src/toDo.js');
var ToDoList = require('../src/toDoList.js');
window.onload = function() {
// create a couple of elements in an otherwise empty HTML page
var heading = document.createElement("h1");
var heading_text = document.createTextNode("Big Head!");
heading.appendChild(heading_text);
document.body.appendChild(heading);
}
Model file 1:
function ToDo(task) {
this.task = task;
this.complete = false;
}
module.exports = ToDo;
function ToDoList() {
this.array = [];
}
ToDoList.prototype.add = function(task) {
this.array.push(task);
};
ToDoList.prototype.popTask = function() {
var poppedTask = this.array.pop();
var concat = "<ul><li>";
var concat2 = "</li></ul>";
return (concat + poppedTask.task + concat2);
};
module.exports = ToDoList;
require is CommonJs feature, and it's not supported by browsers without this library. So you would need to use it in your project if you want modules with require syntax.
Update
To use require feature, you would need some module loader. There are two very popular that you could check out - Webpack or Browserify. They both support CommonJS require that you are looking for. As for me, I like webpack most, cause it is very powerful out of the box.
To read about their comparison :
https://medium.com/#housecor/browserify-vs-webpack-b3d7ca08a0a9#.lb3sscovr
RequireJS is another module loader, but he works not with CommonJs-style modules (require). He implements AMD-style modules.
You can check this article to understand how AMD is different from CommonJS:
https://auth0.com/blog/2016/03/15/javascript-module-systems-showdown/
I am working on converting part of a large Backbone application to use Typescript. Some of the core js files have been converted to Typescript and are referenced by other non-TS js files.
Before we converted our requirejs modules would be of the form:
View.js
define([backbone, deps...], function (backbone, deps...) {
return backbone.View.extend({
render: function () {...}
});
});
Which in the consuming code we could do:
define([View, ...], function (View,....) {
var view = new View({...});
view.render();
});
Using Typescript external modules and exports I can compile a file containing a Typescript class to AMD but the code generated sets a property on an exports object as the results which means consuming code looks like this now, given the file name is View.js:
var view = new View.View();
This is annoying and also means we can't maintain backward compatibility with the legacy non-TS code without changes (though minor). Is there anyway to get around this?
EDIT:
Relevant generated code (the define callback)
function (require, exports) {
var Backbone = require('backbone');
var View = (function (_super) {
__extends(View, _super);
function View(options) {
_super.call(this, options);
}
})(Backbone.View);
exports.View = View;
}
The aim is to have some core components in typescript so that we can use TS going forward, and have other older libraries require the completed js components.
I've recently started writing CommonJS modules but facing issues in requiring modules. Why is storage.js unable to reach the example module which I have required? What is the proper way to require a dependent module in this case?
EDIT: Included more information because the previous question omitted hello.js, which I thought wasn't the cause of the problem. Seems like including it causes a uncaught type error. Also, this is part of the code for a chrome extension, and main.js is the content script.
// main.js
var hello = require('./hello');
var storage = require('./storage');
var example = require('./example');
storage.store();
// storage.js
var example = require('./example');
module.exports = (function() {
function store() {example.ex();}
return {store: store};
})();
// example.js
var storage = require('./storage');
module.exports = (function() {
function ex() {
console.log('example');
}
return {ex: ex};
})();
// hello.js
var example = require('./example'); // <<<< Including this gives Uncaught TypeError: example.ex is not a function
module.exports = (function() {
function hello() {
console.log('hello');
}
return {hello:hello};
})();
Not a direct answer to your question, but Browserify will wrap in a self-invoking function for you. You can simplify your lib files:
// main.js
var storage = require('./storage');
storage.store();
Because you don't use hello or example, don't require them.
// storage.js
var example = require('./example');
function store() {example.ex();}
module.exports.store = store;
No need to go through the self-invoking function here.
// example.js
module.exports.ex = ex;
function ex() {
console.log('Example');
}
This doesn't use storage, so don't include it.
hello.js does nothing but trigger the circular dependency, remove it.
In your updated code, you have a circular dependency between storage.js and example.js. Because you don't use anything from storage in example, you can just remove that require. I still think you should remove the self-invoking functions, as that's already part of commonjs.
When loading a module, Commonjs will only execute the file a single time. Everything on module.exports is then cached for future calls. When you include the circular dependency for the first time, the module loader sees that its currently being loaded, and you don't get any results back. Subsequent calls will complete as normal.
I'd like require a module and somehow pass in the current module, or something like that, such that the module being required has the properties of the module requiring it.
For example if I have a file I'm requiring:
(function(global) {
console.log(this.exists);
}(this));
And am requiring it like so:
this.exists = "I exist.";
var myFile = require("my-file"); // Somehow make require pass in 'this'.
The file being required should be able to see this.exists since I've passed this into the require function somehow. I'm not sure if this is possible. I would think you would need to fiddle with the different module objects.
The one constraint of this is that the module being required can't have any nodejs specific things, like code to export it on the module. It has to stay the same as the way I've written it.
Edit:
Turns out there is no way to do this exactly the way I want to. There have been some awesome suggestions on how to do this in other ways, though.
I had to do something similar to this once... best way I figured out was through a level of indirection.
Part1:
define(function() {
"use strict";
function init() {
console.log("this = " + this);
}
return init;
});
Part2:
var myFileInit = require("my-file");
var myFile = myFileInit.init.call(this);
Edit: Another possibility
Create a wrapper for the original module:
// my-file-wrapper
define(["my-file"], function(myFunc) {
"use strict";
function init() {
myFunc.call(this);
}
return init;
});
// Elsewhere
var myFileWrapper = require("my-file-wrapper");
var myFile = myFileInit.init.call(this);
I am trying to create javascript extendable library with submodules in different files. I am using Module Pattern based on Ben Cherry article
module.js
var SERVICES = (function (service) {
var service = {},
privateVariable = 1;
function privateMethod() {
//
}
service.moduleMethod = function () {
//
};
return service;
}());
submodule.js
SERVICES.submodule = (function (service) {
var submodule = {},
privateVariable = 1;
submodule.moduleMethod = function () {
//
};
return submodule;
}(SERVICES));
What I want to achieve is the following. The module.js is a module which I want to act as a library. Submodules are separated in the different files, thus I am using Module Pattern. Clients will be able to write new submodules for the mentioned library (module.js). I want to create a script which will call library SERVICES with all submodules available. This script will be included in one front-end file just once, and there will be no need to change anything when someone writes new submodule. Library should load it.