Using knockout-jqueryui with bundling - jquery-ui

According to "Reference bundles on requirejs" the solution to the problem of getting requirejs to reference modules delivered in a bundle is to name them with a name exactly matching the filename so that with optimisations turned off they resolve from the filesystem and with optimisations turned on they resolve from the bundle.
This is the start of knockout-jqueryui
/*! knockout-jqueryui - v1.0.0 - 3/21/2014
* https://github.com/gvas/knockout-jqueryui
* Copyright (c) 2014 Vas Gabor <gvas.munka#gmail.com>; Licensed MIT */
/*global require, define, exports*/
/*jslint browser:true, maxlen:256*/
(function (root, factory) {
'use strict';
if (typeof exports === 'object') {
// CommonJS
factory(exports, require('jquery'), require('knockout'), require('jquery-ui'));
} else if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['exports', 'jquery', 'knockout', 'jquery-ui'], factory);
} else {
// Browser globals
factory((root.kojqui = {}), root.jQuery, root.ko);
}
} (this, function (exports, $, ko) {
'use strict';
As you can see it's anonymous. I have two conspicuous options:
Edit the file and give it a name matching the file.
Somehow wrap it so as to name it.
Option one is straightforward:
if (typeof exports === 'object') {
// CommonJS
factory(exports, require('jquery'), require('knockout'), require('jquery-ui'));
} else if (typeof define === 'function' && define.amd) {
// AMD. Register as a module named 'knockout-jqueryui'.
define('knockout-jqueryui',
['exports', 'jquery', 'knockout', 'jquery-ui'], factory);
} else {
// Browser globals
factory((root.kojqui = {}), root.jQuery, root.ko);
}
But it doesn't seem like a great idea. I'm pretty new to AMD so if anyone can advise me on a good way to implement an option two wrapper, that would be excellent.

I am pleased to report that I have found a nice clean solution.
Bundling causes knockout-jqueryui.js to be loaded directly by a script tag. As a result it uses the third factory option in the code extract shown in the question, producing a global kojqui.
This global is in scope for main.js and can be captured:
requirejs.config({
paths: {
'text': '../Scripts/text',
'durandal': '../Scripts/durandal',
'plugins': '../Scripts/durandal/plugins',
'transitions': '../Scripts/durandal/transitions'
}
});
define('jquery', function () { return jQuery; });
define('knockout', ko);
define('moment', function () { return moment; });
define('knockout-jqueryui', kojqui);
No change is required in knockout-jqueryui.js and I have verified that this works both with optimisations enabled and with optimisations off for debugging.

Related

webpacker and injectStylesIntoStyleTag.js breaks CSP

My ruby on rails app's CSP was working perfectly until I added webpacker. Now I get this:
Content Security Policy: The page’s settings observed the loading of a resource at inline (“style-src”). A CSP report is being sent. injectStylesIntoStyleTag.js:117
Content Security Policy: The page’s settings observed the loading of a resource at inline (“style-src”). A CSP report is being sent. injectStylesIntoStyleTag.js:190
The code in question looks like this:
function insertStyleElement(options) {
var style = document.createElement('style');
...
if (typeof options.insert === 'function') {
options.insert(style);
} else {
var target = getTarget(options.insert || 'head');
if (!target) {
throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
}
target.appendChild(style); //LINE 117//
}
return style;
}
And:
function applyToTag(style, options, obj) {
var css = obj.css;
...
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
while (style.firstChild) {
style.removeChild(style.firstChild);
}
style.appendChild(document.createTextNode(css)); //LINE 190//
}
}
How do I add a nonce? This says to add __webpack_nonce__ = 'random'; to my entry file ( in this case app/javascript/packs/application.js), yet adding that nonce to my csp file has no effect on the style-src violation. Which in this case, looks like this: config.style_src :self, 'https://fonts.googleapis.com', 'nonce-random'
I somehow wasn't able to find the injected styles in source, but the answer was to open the page in Chrome (I was using Firefox) and copy the sha-256 hash from the console log into the app's CSP.

Electron ES6 module import

Electron 3.0.0-beta.1
Node 10.2.0
Chromium 66.0.3359.181
The problem I'm having is importing a module. I created the following protocol:
protocol.registerFileProtocol('client', (request, callback) => {
var url = request.url.substr(8);
callback({path: path.join(__dirname, url)});
});
The output of the protocol is the correct path
"/Users/adviner/Projects/Client/src/ClientsApp/app.js"
I have the following module app.js with the following code:
export function square() {
return 'hello';
}
in my index.html I import the module like so:
<script type="module" >
import square from 'client://app.js';
console.log(square());
</script>
But I keep getting the error:
app.js/:1 Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.
I'm done searches but can't seem to find a solution. Can anyone suggest a way I can make this work?
Thanks
This is a tricky question and i will refer to Electron#12011 and this GitHub Gist for a deeper explaination but the core learning is that the corresponding HTML spec, disallows import via file:// (For XSS reasons) and a protocol must have the mime types defined.
The file protocol you use client:// has to set the correct mime-types when serving the files. Currently i would guess they are not set when you define the protocol via protocol.registerBufferProtocol thus you recive a The server responded with a non-JavaScript MIME type of "", the gist above has a code sample on how to do it.
Edit: I just want to emphasize the other answers here do only cover the absolute minimum basics implementation with no consideration of exceptions, security, or future changes. I highly recommend taking the time and read trough the gist I linked.
To confirm: this is there for security reasons.
However, in the event that you just need to get it deployed:
Change "target": "es2015" to "target": "es5" in your tsconfig.json file
Quick Solution:
const { protocol } = require( 'electron' )
const nfs = require( 'fs' )
const npjoin = require( 'path' ).join
const es6Path = npjoin( __dirname, 'www' )
// <= v4.x
// protocol.registerStandardSchemes( [ 'es6' ] )
// >= v5.x
protocol.registerSchemesAsPrivileged([
{ scheme: 'es6', privileges: { standard: true } }
])
app.on( 'ready', () => {
protocol.registerBufferProtocol( 'es6', ( req, cb ) => {
nfs.readFile(
npjoin( es6Path, req.url.replace( 'es6://', '' ) ),
(e, b) => { cb( { mimeType: 'text/javascript', data: b } ) }
)
})
})
<script type="module" src="es6://main.js"></script>
Based on flcoder solution for older Electron version.
Electron 5.0
const { protocol } = require('electron')
const nfs = require('fs')
const npjoin = require('path').join
const es6Path = npjoin(__dirname, 'www')
protocol.registerSchemesAsPrivileged([{ scheme: 'es6', privileges: { standard: true, secure: true } }])
app.on('ready', async () => {
protocol.registerBufferProtocol('es6', (req, cb) => {
nfs.readFile(
npjoin(es6Path, req.url.replace('es6://', '')),
(e, b) => { cb({ mimeType: 'text/javascript', data: b }) }
)
})
await createWindow()
})
Attention! The path always seems to be transformed to lowercase
<script type="module" src="es6://path/main.js"></script>
Sorry Viziionary, not enough reputation to answer the comment.
I've now done it like this:
https://gist.github.com/jogibear9988/3349784b875c7d487bf4f43e3e071612
my problem was, I also wanted to support modules which are imported via none relative path's, so I don't need to transpile my code.

How to ignore lines for code coverage in Jest

In Jest, is there any way to ignore code for test coverage?
I tried using
/* istanbul ignore next */
But it doesn't seem to work.
It works.
(function(global) {
var defineAsGlobal = true;
/* istanbul ignore next */
if(typeof exports === 'object') {
module.exports = lib;
defineAsGlobal = false;
}
/* istanbul ignore next */
if(typeof modules === 'object' && typeof modules.define === 'function') {
modules.define('lib', function(provide) {
provide(lib);
});
defineAsGlobal = false;
}
/* istanbul ignore next */
if(typeof define === 'function') {
define(function(require, exports, module) {
module.exports = lib;
});
defineAsGlobal = false;
}
/* istanbul ignore next */
defineAsGlobal && (global.lib = lib);
})(this);
Sample project https://github.com/ilyar/sandbox/tree/master/jest
Update for anyone that finds this at a later date.
/* istanbul ignore next */
Will work but as read from The Jest Official Documentation:
coveragePathIgnorePatterns seems to not have any effect.
Make sure you are not using the babel-plugin-istanbul plugin. Jest
wraps Istanbul, and therefore also tells Istanbul what files to
instrument with coverage collection. When using babel-plugin-istanbul,
every file that is processed by Babel will have coverage collection
code, hence it is not being ignored by coveragePathIgnorePatterns.
The documentation can be found here: Documentation
So in order to fix this issue uninstall babel-plugin-istanbul:
If it is a library based only on javascript, than you can just run npm uninstall --save babel-plugin-istanbul or npm uninstall --save-dev babel-plugin-istanbul
If you've installed a library with native content that requires linking, and you've linked it with rnpm then you can do: rnpm unlink package_name then follow step 1 - Aakash Sigdel
This quote was from Aakash Sigdel found here: quote
Found a workaround (spaces before and after the comment seem to be necessary):
class Foo {
bar /* istanbul ignore next */ () {
return 'biu~';
}
}
Just for anyone finding this who uses the v8 provider:
the docs now state how to ignore lines with different providers, and link to more details. But basically either /* c8 ignore next */ or /* c8 ignore start */ + /*c8 ignore end */ should work well with the v8 provider.
Example:
/* c8 ignore next */
if (process.env.DEBUG) console.log('debug');
/* c8 ignore start */
switch (process.env.DEBUG) {
case '1':
console.log('some verbosity');
break;
case '2':
console.log('a lot of verbosity');
break;
}
/* c8 ignore end */
In my case, I had coverageProvider: 'v8', and it was causing this to break. doing: coverageProvider: 'babel', fixed it and the pragma works great.
According to a babel issue thread Istambul appears to have a bug where it assumes the preceding line of code is terminated with a semi-colon...
constructor(message: string) {
// TODO: how do I get Jest code coverage for "super(message)?
// /* istanbul ignore next */ assumes the preceding line of code is terminated with a ;
DEBUG: console.log();
/* istanbul ignore next */
super(message);
}

Yeoman-angular grunt generates faulty vendor.js with animation

I've got an app that uses a javascript animation.
When I run the build, grunt minifies and uglifies the code and creates a file 'vendor.js' containing all the library js code including angular. However the code that is generated is broken when I use my animate method shown below.
The error I see in the browser console is caused by the minified and uglified vendor.js
Error: [$injector:unpr] Unknown provider: aProvider <- a
I may need to find a different approach to what I am doing, but I'd still like to address this problem specifically if possible.
In the following code I'm using angular to get access to the global rootscope as I want to trigger an action higher in the scope hierarchy than the element where the animation is registered.
Without this added behaviour, the animations are all working correctly, so there is no problem with the actual libraries that are ending up in vendor.js The answer may be to turn off uglification, or find a way to copy this specific script directly to the target instead of passing it through magnification and uglification.
angular.module('myApp').animation('.theme-content', function() {
return {
enter: function(element, done) {
var rootScope = angular.element(document).injector().invoke(function($rootScope){return $rootScope;});
rootScope.$broadcast('page-start-animation', null );
return function(cancelled) {
};
},
leave: function(element, done) { },
move: function(element, done) { },
beforeAddClass: function(element, className, done) { },
addClass: function(element, className, done) { },
beforeRemoveClass: function(element, className, done) { },
removeClass: function(element, className, done) { }
};
});

Error: Unknown provider: aProvider <- a

I'm using AngularJS in a Ruby on Rails 3.2.8 project with assets.
When I load up my form which is using AngularJS on my development machine I don't have a problem. However when I load the same form up on my production server I get this error in the Javascript console:
Error: Unknown provider: aProvider <- a
I've tracked it back to my coffeescript file where I setup AngularJS for use within a form:
$ (event) ->
$("#timesheet_description").autocomplete({source: '/autocomplete/work_descs'})
# Create AngularJS module
app = angular.module 'timesheetApp', []
# Create a AngularJS controller
app.controller "TimesheetCtrl", ($scope) ->
$scope.costed_amount = 0
# Bind my module to the global variables so I can use it.
angular.bootstrap document, ["timesheetApp"]
If I comment all this out the page will load without errors and without AngularJS abilities.
Is the problem due to Rails assets compiling and minify?
Is there a way to fix this and still use coffeescript and Rails assets?
AngularJS, when using the style you're using right now (called pretotyping), uses the function argument names to do dependency injection. So yes, minification does break this completely.
The fix is simple, though. In every case where you need injection (are using '$xxx') variables, do this:
app.controller "TimesheetCtrl", ['$scope', ($scope) ->
$scope.costed_amount = 0
]
Basically, replace all function definitions with an array. The last element should be the function definition itself, and the first ones are the $names of the objects you want injected.
There's some more (albeit not clear enough) info on the docs.
If you miss the array notation somewhere , to locate this we need to modify the angular code little bit, but its very quick solution.
change is console.log("Array Notation is Missing",fn); ( line no 11 from function start)
Find out annotate function in angular.js (non-minified)
function annotate(fn) {
var $inject,
fnText,
argDecl,
last;
if (typeof fn == 'function') {
if (!($inject = fn.$inject)) {
$inject = [];
if (fn.length) {
console.log("Array Notation is Missing",fn);
fnText = fn.toString().replace(STRIP_COMMENTS, '');
argDecl = fnText.match(FN_ARGS);
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
arg.replace(FN_ARG, function(all, underscore, name){
$inject.push(name);
});
});
}
fn.$inject = $inject;
}
} else if (isArray(fn)) {
last = fn.length - 1;
assertArgFn(fn[last], 'fn');
$inject = fn.slice(0, last);
} else {
assertArgFn(fn, 'fn', true);
}
return $inject;
}
To minify angular all you need is to do is to change your declaration to the "array" declaration "mode" for example:
From:
var demoApp= angular.module('demoApp', []);
demoApp.controller(function demoCtrl($scope) {
} );
To
var demoApp= angular.module('demoApp', []);
demoApp.controller(["$scope",function demoCtrl($scope) {
}]);
How to declare factory services?
demoApp.factory('demoFactory', ['$q', '$http', function ($q, $http) {
return {
//some object
};
}]);

Resources