RequireJS plugin, load files on demand - requirejs

I have RequireJS implemented fine, and a Grunt based build process which is optimizing the all the JS files app into one file via r.js which is also working fine. All my app files are concatenated into one big JS file for efficient production deployment.
Now I'm having the following requirements:
I need to write a plugin for requirejs, that will not load(not include the file) into the optimized file in the build process, but will required on demand:
Meaning in my code I'll have:
var myObj = require("myplugIn!jsFile");
So in the end when this line runs, it will runs in 2 options:
on build process, the file is not included in the optimized file
The application is running, it will be request the file on demand.
I wrote the following plugin, but is not working:
define(function () {
"use strict";
return {
load : function (name, req, onload, config) {
// we go inside here we are running the application not in build process
if (!config.isBuild) {
req([name], function () {
onload(arguments[0]);
});
}
}
};
});
What I'm missing here.

In your build configuration you can exclude files that you don't want to bundle. They will still be loaded on demand when needed. You may also do something like this:
define(function (){
// module code...
if (condition){
require(['mymodule'], function () {
// execute when mymodule has loaded.
});
}
}):
This way mymodule will be loaded only if condition is met. And only once, if you use same module dependency elsewhere it will return loaded module.

It was more simpler that I though, if helps someone, I'm posting the solution, I create a plugin , that in build process return nothing and in run time, returns the required file, hope helps someone.
define(function () {
"use strict";
return {
load : function (name, req, onload, config) {
if (config.isBuild) {
onload(null);
} else {
req([name], function () {
onload(arguments[0]);
});
}
}
};
});

Related

Mock file in Jest and prevent getting loaded

I have a file that uses a webworker that I want to unit test. But because Jest is flaky on ESModules, it doesn't like import.meta.url.
I don't want to test this part, I need to test the functionality around it. But because it's still included in the build, js-test keeps tripping over having this included in the build.
I abstracted it into a separate JS file worker-loader.js:
const spawnWorker = () => {
return new Worker(new URL('./worker.ts', import.meta.url));
};
module.exports = { spawnSqlJsWorker};
Which is use with a require in the main source code.
I tried adding a mocks directory with an empty mock:
const spawnWorker = () => {
return null;
};
module.exports = { spawnSqlJsWorker};
And ignore this file from jest in jest.config.js:
transformIgnorePatterns: ['worker-loader.js'],
But the loader keeps wanting to include this file. Is there a way in jest to completely ignore a file and mock the complete contents of it?

change requireJS from adding the .js file extension automatically on intern.js

Currently I am working in custom html reporter for intern.js. The Templating engine that i am using is marko.js.
marko.js have extension file with ".marko" for me to input my html syntax
The file is generated correctly in normal node.js (common.js)
The issue occurred when i integrate the same code to intern.js. The requirejs(AMD) that use by internjs is adding the .js file extension automatically to my marko extension when i do
var template = require('./hello-world.marko');
which make the file become hello-world.marko.js and this caused the code broke in markojs
the custom html reporter code is below
define(function (require) {
// require('intern/dojo/node!marko/node-require').install();
var fs = require('intern/dojo/node!fs');
var template = require('./hello-world.marko');
console.log(template);
function JsonReporter(config) {
config = config || {};
this.output = config.output;
}
JsonReporter.prototype = {
runEnd(executor) {
// console.log("toJson: " + JSON.stringify(executor.suites))
data = JSON.stringify(executor.suites);
template.renderToString(data,
function (err, output) {
console.log(output);
fs.writeFile('result.html', output, function (err) {
if (err) return console.log(err);
console.log('Save done');
});
});
},
}
return JsonReporter;
})
The require function isn't really meant for loading arbitrary text resources in either Node's loader or an AMD loader. In Node, whether you're running Intern or not, you can use fs.readFile or fs.readFileSync. In Intern's Dojo-based AMD environment you can also use the dojo/text loader plugin, like this:
var template = require('dojo/text!./hello-world.marko');

Understanding ExpressJS application start-up

I am struggling with how application start-up works in Express. I am going to explain my use-case:
I have a configuration-Manager module which is used by all other application modules to load required configuration. I am setting configuration in app.listen:
app.listen(9000, function () {
try
{
config_manager.setSiteConfig();
console.log('settings..!!!')
}
catch(err)
{
console.log(err.stack);
}
});
In another module of the same application I call the Configuration-Manager function to load config, but it returns empty. Code is something like this:
var config_manager = require('configuration-manager');
console.log(config_manager.loadConfig()); // returns empty object {}
I am running the application using node app.js. The empty object gets printed first then ('settings..!!!'). Does Express compile the script before calling app.listen()? How do I make sure that my configuration is set before compilation/loading other files?
Express indeed first processes all statements in a file, basically anything that isn't in a function on startup.
In your case var config_manager = require('configuration-manager');
console.log(config_manager.loadConfig()); // returns empty object {} is executed before your app.listen because you are requering the config before the app.listen.
You're best off processing your configuration right after the first time it is required (if app.js is your main file, this means the first time it comes across a require statement pointing to configuration-manager in any file).
This should make your code work:
var config_manager = require('configuration-manager');
try {
config_manager.setSiteConfig();
} catch(err) {
console.log(err.stack);
}
console.log(config_manager.loadConfig()); // returns empty object {}
and then
app.listen(9000, function () {
console.log('settings..!!!', config_manager.loadConfig()) // Should correctly print your config
});
If this doesn't work the problem does not lay in the order of execution.

Can't figure out where to put require.config when using TypeScript, RequireJs, and Jasmine

I've been following the pattern for setting up TypeScript, RequireJS, and Jasmine that Steve Fenton describes here:
https://www.stevefenton.co.uk/Content/Blog/Date/201407/Blog/Combining-TypeScript-Jasmine-And-AMD-With-RequireJS/
That pattern as really worked well and truly unblocked me (yay!), but I'm now at the point where I need to customize some settings for RequireJS but I can't seem to figure out where to put my require.config call. Everywhere I've tried has caused breaks and regressions. Here are the two approaches that seem most logical/promising
In SpecRunner.cshtml
<script data-main="/Scripts/TypeScript/RequireJsConfig" src="/Scripts/require.js"></script>
In RequireJsConfig.ts
require.config({
baseUrl: "../Scripts",
paths: {
jquery: "../jquery-2.1.3"
}
});
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Attempt 1: When I try it this way I immediately get this error
//
// JavaScript runtime error: Object doesn't support property or method 'config'
//
import TestLoader = require("Tests/TestLoader");
TestLoader.Run();
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Attempt 2: When I try it this way, everything builds and runs without errors, but
// Jasmine doesn't find any of the tests. All I get is "No specs found" even
// though I see the breakpoints on my "it" statements getting hit.
//
require(["Tests/TestLoader"], (testLoader) => {
testLoader.Run();
});
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
jasmine.getEnv().execute();
In TestLoader.ts
import GuidHelperTests = require("Tests/T3/Helpers/GuidHelperTests");
import ObjectHelperTests = require("Tests/T3/Helpers/ObjectHelperTests");
class TestLoader {
public static Run: () => void = () => {
GuidHelperTests.Run();
ObjectHelperTests.Run();
}
}
export var Run = () => TestLoader.Run();
In GuidHelperTests.ts
import T3 = require("T3/T3Lib");
export var Run = () => {
describe("GuidHelper tests", () => {
it("GUID validator validates good GUID", () => {
// etc. ...
My guess is that Attempt 2 doesn't work because of some kind of sequencing issue where the test discovery process is happening before modules are loaded, or something like that. I'm just not versed enough in RequireJS to know what my options are here.
I prefer to keep my configuration away from my application - you can pre-register the configuration like this, and it will be picked up by RequireJS when it loads. No need to add it to your first file.
<script>
var require = {
baseUrl: "../Scripts",
paths: {
jquery: "../jquery-2.1.3"
}
};
</script>
<script data-main="/Scripts/TypeScript/RequireJsConfig" src="/Scripts/require.js"></script>

Can Blanket.js work with Jasmine tests if the tests themselves are loaded with RequireJS?

We've been using Jasmine and RequireJS successfully together for unit testing, and are now looking to add code coverage, and I've been investigating Blanket.js for that purpose. I know that it nominally supports Jasmine and RequireJS, and I'm able to successfully use the "jasmine-requirejs" runner on GitHub, but this runner is using a slightly different approach than our model -- namely, it loads the test specs using a script tag in runner.html, whereas our approach has been to load the specs through RequireJS, like the following (which is the callback for a requirejs call in our runner):
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.TrivialReporter();
var jUnitReporter = new jasmine.JUnitXmlReporter('../JasmineTests/');
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.addReporter(jUnitReporter);
jasmineEnv.specFilter = function (spec) {
return htmlReporter.specFilter(spec);
};
var specs = [];
specs.push('spec/models/MyModel');
specs.push('spec/views/MyModelView');
$(function () {
require(specs, function () {
jasmineEnv.execute();
});
});
This approach works fine for simply doing unit testing, if I don't have blanket or jasmine-blanket as dependencies for the function above. If I add them (with require.config paths and shim), I can verify that they're successfully fetched, but all that appears to happen is that I get jasmine-blanket's overload of jasmine.getEnv().execute, which simply prints "waiting for blanket..." to the console. Nothing is triggering the tests themselves to be run anymore.
I do know that in our approach there's no way to provide the usual data-cover attributes, since RequireJS is doing the script loading rather than script tags, but I would have expected in this case that Blanket would at least calculate coverage for everything, not nothing. Is there a non-attribute-based way to specify the coverage pattern, and is there something else I need to do to trigger the actual test execution once jasmine-blanket is in the mix? Can Blanket be made to work with RequireJS loading the test specs?
I have gotten this working by requiring blanket-jasmine then setting the options
require.config({
paths: {
'jasmine': '...',
'jasmine-html': '...',
'blanket-jasmine': '...',
},
shim: {
'jasmine': {
exports: 'jasmine'
},
'jasmine-html': {
exports: 'jasmine',
deps: ['jasmine']
},
'blanket-jasmine': {
exports: 'blanket',
deps: ['jasmine']
}
}
});
require([
'blanket-jasmine',
'jasmine-html',
], function (blanket, jasmine) {
blanket.options('filter', '...'); // data-cover-only
blanket.options('branchTracking', true); // one of the data-cover-flags
require(['myspec'], function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 250;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function (spec) {
return htmlReporter.specFilter(spec);
};
jasmineEnv.addReporter(new jasmine.BlanketReporter());
jasmineEnv.currentRunner().execute();
});
});
The key lines are the addition of the BlanketReporter and the currentRunner execute. Blanket jasmine adapter overrides jasmine.execute with a no-op that just logs a line, because it needs to halt the execution until it is ready to begin after it has instrumented the code.
Typically the BlanketReport and currentRunner execute would be done by the blanket jasmine adapter but if you load blanket-jasmine itself in require, the event for starting blanket test runner will not get fired as subscribes to the window.load event (which by the point blanket-jasmine is loaded has already fired) therefore we need to add the report and execute the "currentRunner" as it would usually execute itself.
This should probably be raised as a bug, but for now this workaround works well.

Resources