How to handle blocked scripts in requirejs - javascript

I am using require js to load google analytics.
In config I have
requirejs.config({
"paths": {
"ga": "//www.google-analytics.com/analytics",
...
And I have a module that depends on ga that initialises analytics.
Everything works fine until someone uses a browser plugin that blocks google analytics.
When that happens, the resulting javascript error breaks everything.
failed to load resource : blocked by clien
uncaught error: script error for: ga
How can I tell requirejs not to have a fit if a certain module fails to load?
How can you make a module optional?
Thanks.

require takes a 3rd argument which is an error callback, so you can assign window.ga to a function which always returns undefined. This avoids errors when calling google analytics functions elsewhere in your code.
require(['ga'], function(data) {
window.ga('create', 'UA-XXXXXXXX-X');
window.ga('send', 'pageview');
}, function() {
window.ga = function(){};
});

You could require the module within your own module code but outside of the module definiton requirements, but this does mean you can't quite as easily chain on dependencies you need. i.e.
define([ /* Normal dependencies here ... */], function() {
try {
require(['ga']);
} catch (error) {
// Handle lack of GA if needed
}
};
Alternatively you'd have to write your own module wrapper which synchronously blocks as it attempts the above, then returns GA if it was successful, or null otherwise.

I found the best way is to use the array notation for path definitions. This way you can define the external URL for the module, and a local fallback, in your requirejs path configuration. No need for additional try/catch blocks or module-specific error handling.
Documentation link:
http://requirejs.org/docs/api.html#pathsfallbacks
I defined a module named noop which defines an empty function, and then set up my paths like this:
requirejs.config({
"paths": {
"ga": [
"//www.google-analytics.com/analytics",
"util/noop"
],
...

The best solution, It works for me.
Open lib/mage/requirejs/resolver.js file.
/**
* Checks if provided module has unresolved dependencies.
*
* #param {Object} module - Module to be checked.
* #returns {Boolean}
*/
function isPending(module) {
return !!module.depCount;
}
Replace with this bellow code:
/**
* Checks if provided module is rejected during load.
*
* #param {Object} module - Module to be checked.
* #return {Boolean}
*/
function isRejected(module) {
return registry[module.id] && (registry[module.id].inited || registry[module.id].error);
}
/**
* Checks if provided module has unresolved dependencies.
*
* #param {Object} module - Module to be checked.
* #returns {Boolean}
*/
function isPending(module) {
if (!module.depCount) {
return false;
}
return module.depCount > _.filter(module.depMaps, isRejected).length;
}
Thanks

Related

How to exclude Express view engines from Webpack bundle

I'm bundling my CLI app using Webpack v4. One of the dependencies is Express, and this causes a warning:
WARNING in ./node_modules/express/lib/view.js 81:13-25
Critical dependency: the request of a dependency is an expression
# ./node_modules/express/lib/application.js
# ./node_modules/express/lib/express.js
# ./node_modules/express/index.js
That comes from this line within Express:
/**
* Initialize a new `View` with the given `name`.
*
* Options:
*
* - `defaultEngine` the default template engine name
* - `engines` template engine require() cache
* - `root` root path for view lookup
*
* #param {string} name
* #param {object} options
* #public
*/
function View(name, options) {
var opts = options || {};
this.defaultEngine = opts.defaultEngine;
this.ext = extname(name);
// ...
if (!opts.engines[this.ext]) {
// load engine
var mod = this.ext.substr(1)
debug('require "%s"', mod)
// default engine export
var fn = require(mod).__express // <-- this require is the problem
There's quite a few questions asking about how to fix this by not bundling express at all, or not bundling anything from node_modules.
For me that would defeat the point (I'm trying to shrink my deployed file footprint), so I want to fix this whilst keeping express inside my bundle. In my case I don't use view engines at all, and this require exists solely to load view engines on demand, so I really just want the warning to go away.
If I'm confident that this require will never be called, how can I tell webpack to ignore it completely?
What you could maybe try is alter you webpack config module rules so that
view unit uses the null-loader
This will of course make View return null but if you never touch views it might be ok.
example.
rules: [
{
test: require.resolve("express/view"),
use: 'null-loader',
},
],
Looking at application
this.set('view', View); hopefully View been null here doesn't cause issues.
The only other place View is then mentioned in application is then in render that you say your not using. So fingers crossed this won't cause any side effects.

Load ES6 module A if available, fall back to module B if not available

I'm currently working on a JavaScript library where we would like to migrate legacy AMD modules to ES6 modules.
The sample code for this library uses an AMD plugin that looks like this :
define([
"require",
"../../common/ModuleLoad"
], function(require,
ModuleLoad) {
/**
* Dynamically load the info panel.
* The actual implementation depends on whether the military symbology package is present.
*/
return {
load: function(name, parentRequire, onload, config) {
ModuleLoad.loadConditional(
"./SpotReportInfoPanelMilSym",
"./SpotReportInfoPanelFallback",
require,
onload,
config,
["MilSymMissing", "Military Symbology has not been installed.<br />This sample has additional features if Military Symbology is installed."]
);
}
};
});
This plugin has the following module as a dependency :
define([
"./toast",
"./request"
], function(toast,
request) {
return {
loadConditional: function(preferred, fallback, parentRequire, onload, config, message) {
if (config && config.isBuild) {
onload();
} else {
//do ajax call to check for presence of module.
return request(parentRequire.toUrl(preferred + ".js")).then(function() {
//the module exists -> load it using the AMD module loader
parentRequire([preferred], function(module) {
onload(module);
})
}).catch(function(err) {
//the module is not present -> return fallback
if(message) {
toast.error(message[0], message[1], err);
}
parentRequire([fallback], function(module) {
onload(module);
})
});
}
}
};
});
Basically, what this code does, is check for the existence of a file named SpotReportInfoPanelMilSym.js and return its content as an AMD module. If SpotReportInfoPanelMilSym.js is not found, it falls back to SpotReportInfoPanelFallback.js.
The reason for this, is that SpotReportInfoPanelMilSym.js is only shipped with an optional add-on for this library, whereas SpotReportInfoPanelFallback.js is always available. And the sample is supposed to automatically pick the right SpotReportInfoPanel implementation depending on the availability of this add-on.
Is there a way to achieve this same behavior with ES6 modules?
We're planning to ship our sample code with Webpack, so a Webpack based solution would be acceptable. However, I would prefer our sample code to work with any loader or bundler and thus would like to avoid and Webpack-specific stuff in our sample code if possible at all.

Call to undefined function asset() in Laravel project

I am trying to load my app.js file inside my welcome.blade.php but I get the following error:
Call to undefined function asset()
This is the instruction I used <script type="text/javascript" src="{{ asset('public/js/app.js') }}"></script>
What can be the problem? I also tried to run the same line without asset() and it does not work. My .js file is in the location I specified.
Thank you so much!
Process:
I am using Laravel 5.5 and had the same problem recently so I did a bit of debugging. Here are the steps:
Since the error was Call to undefined function asset() I checked the helpers.php in the Laravel repo to see if it existed. https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/helpers.php#L127 and it did.
if (! function_exists('asset')) {
/**
* Generate an asset path for the application.
*
* #param string $path
* #param bool $secure
* #return string
*/
function asset($path, $secure = null)
{
return app('url')->asset($path, $secure);
}
}
I looked on my local copy of Laravel and see if that same line existed, it did.
However my local copy was different than what was on the repo. This is how it looked:
if (! function_exists('asset')) {
/**
* Generate an asset path for the application.
*
* #param string $path
* #param bool $secure
* #return string
*/
function mixasset($path, $secure = null)
{
return app('url')->asset($path, $secure);
}
}
At some point, Laravel Mix seems to have changed asset() to mixasset().
Result:
Try using mixasset() as opposed to asset(). Otherwise delete your vendors folder and rebuild it by running composer install. This should get you the latest copy of your Laravel version with the correct asset() helper method.
The asset() is already point to your public folder so, don't specify the public in your asset()
Change your asset('public/js/app.js') to asset('js/app.js')
My Err: Call to undefined function set_active()...., when I move some functions in Laravel 5.2 to Laravel 6.x ...
My solution:
1. Added below in composer.json
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\": "app/"
},
"files": [
"app/helpers.php" . => New added
]
}
2.run composer install
it works for me.

Gulp Plugin Order

I'm concatenating my plugins using Gulp, but they seem to get minified in the wrong order, causing my application to break. I'm using the gulp-order plugin, which I believe I'm using correctly. For testing, I've disabled uglify(). However, the resulting file always starts with Angular, instead of jQuery. Any help would be greatly appreciated!
...
//Gulp-order to make sure we load things correctly
var order = require('gulp-order');
...
var pluginOrder = [
'src/bower_components/jquery/dist/jquery.js',
'src/bower_components/bootstrap/dist/js/bootstrap.js',
'src/bower_components/angular/angular.js',
'src/bower_components/angular-route/angular-route.js',
'src/bower_components/angular-animate/angular-animate.js',
'src/bower_components/angular-sanitize/angular-sanitize.js',
'src/bower_components/angular-bootstrap/ui-bootstrap.js',
'src/bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
'src/bower_components/**/*.js',
'!src/bower_components/**/*.min.js'
]; //make sure everything loads in the right order
gulp.task('squish-jquery', function() {
return gulp.src( 'src/bower_components/**/*.js' )
.pipe(ignore.exclude([ "**/*.map" ]))
.pipe(order( pluginOrder )).on('error', gutil.log)
//.pipe(plugins.uglify().on('error', gutil.log))
.pipe(plugins.concat('jquery.plugins.min.js'))
.pipe(gulp.dest('build')).on('error', gutil.log);
});
Beginning of the concatenated file, jquery.plugins.min.js:
/**
* #license AngularJS v1.3.15
* (c) 2010-2014 Google, Inc. http://angularjs.org
* License: MIT
*/
(function(window, angular, undefined) {'use strict';
/* jshint maxlen: false */
/**
* #ngdoc module
* #name ngAnimate
* #description
*
* The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives.
*
* <div doc-module-components="ngAnimate"></div>
*
* # Usage
*
* To see animations in action, all that is required is to define the appropriate CSS classes
* or to register a JavaScript animation via the `myModule.animation()` function. The directives that support animation automatically are:
* `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation
* by using the `$animate` service.
*
* Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives:
*
* |
I never used gulp-order, but I simply order it in the concatenation like this:
gulp.task('js', function(done) {
return gulp.src([
'./bower_components/angular/angular.js',
'./bower_components/angular-bootstrap/ui-bootstrap.js',
'./bower_components/angular-bootstrap/ui-bootstrap-tpls.js',
'./bower_components/angular-collection/angular-collection.js',
'./assets/js/shopApp.js',
'./assets/js/**/*.js'
])
.pipe(concat('all.js'))
//.pipe(uglify())
//.pipe(sourcemaps.write())
.pipe(gulp.dest('public/js/'))
.pipe(notify('js updated!!'));
});

Jenkins integration with Jest

Is there a way to have Jenkins integration in the Javascript Jest testing framework that is built on top of Jasmine?
I've tried to integrate Jest with jasmine-reporters, but didn't manage to get a JUnit XML output. I installed the reporters for Jasmine 1.3 with npm install jasmine-reporters#~1.0.0 and then in my setupTestFrameworkScriptFile:
require('jasmine-reporters');
jasmine.VERBOSE = true;
jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter({
savePath: "output/"
}));
When I run jest I get NodeJS attempt: Arguments to path.join must be strings or NodeJS attempt: Object [object Object] has no method 'join'.
I've managed to get a working version of it in this repo. The problem was I was not mocking path and fs in the test file.
You're using the syntax of jasmine-reporters 2.x with the 1.x branch. Specifically, you are passing an object of options but you need to send positional arguments.
Don't do this:
jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter({
savePath: "output/"
}));
Instead, you should do this:
jasmine.getEnv().addReporter(new jasmine.JUnitXmlReporter("output/"));
You can check out the source for the list of available options. Here are the current options:
/**
* Generates JUnit XML for the given spec run.
* Allows the test results to be used in java based CI
* systems like CruiseControl and Hudson.
*
* #param {string} [savePath] where to save the files
* #param {boolean} [consolidate] whether to save nested describes within the
* same file as their parent; default: true
* #param {boolean} [useDotNotation] whether to separate suite names with
* dots rather than spaces (ie "Class.init" not
* "Class init"); default: true
* #param {string} [filePrefix] is the string value that is prepended to the
* xml output file; default: 'TEST-'
* #param {boolean} [consolidateAll] whether to save test results from different
* specs all in a single file; filePrefix is then the whole file
* name without extension; default: false
*/
var JUnitXmlReporter = function(savePath, consolidate, useDotNotation, filePrefix, consolidateAll) {
/* ... */
}
Looks like jest-junit is also a option.

Categories