Specifying a specific module system when compiling Elm (vs. runtime checks) - elm

Is there an option to let Elm know which module system you're targeting during compile time? E.g. something like a --target flag. I must admit that I haven't dug into elm-make that much.
Currently it seems that it only occurs during runtime:
elm-make/issues/50
src/Pipeline/Generate.hs
For my situation I'm:
Using Electron which defines it's own module object and a global window.
Only using Elm for a portion of the project (See HTML interop).
By default, the compiled output defaults to exposing Elm on module.exports:
if (typeof define === "function" && define['amd'])
{
define([], function() { return Elm; });
return;
}
if (typeof module === "object")
{
module['exports'] = Elm;
return;
}
var globalElm = this['Elm'];
if (typeof globalElm === "undefined")
{
this['Elm'] = Elm;
return;
}
In debug tools:
Instead, I want it to expose it on this/window and not overwrite module.exports with the Elm object.
I was able to hack together a solution that abuses the AMD check:
<script>
window.define = (arr, fn) => {
const Elm = fn();
window.Elm = Elm;
};
window.define.amd = true;
</script>
<script src="build/tronwm.js"></script>
<script>
const node = document.getElementById('elm-render');
const app = window.Elm.TronWM.embed(node);
</script>
This works for now, but curious of alternate solutions if any.

As of 0.18, no there is not. The Elm compiler does not know about details of JS Loaders etc.

Related

How Vue knows which prefix should prepend when different browser?

Like
<template>
<h1 :style={ filter: 'blur(1px)' }>My Template!!</h1>
</template>
I used style and webkit to search source code from node_modules/Vue and node_modules/#Vue, but had no luck.
How Vue knows which prefix should prepend when different browser?? So magic it is!!
https://v2.vuejs.org/v2/guide/class-and-style.html#Auto-prefixing
I suppose I found the answer.
The code is under vue/src/platforms/web/runtime/modules/style.js line 32
const vendorNames = ['Webkit', 'Moz', 'ms']
let emptyStyle
const normalize = cached(function (prop) {
emptyStyle = emptyStyle || document.createElement('div').style
prop = camelize(prop)
if (prop !== 'filter' && (prop in emptyStyle)) {
return prop
}
const capName = prop.charAt(0).toUpperCase() + prop.slice(1)
for (let i = 0; i < vendorNames.length; i++) {
const name = vendorNames[i] + capName
if (name in emptyStyle) {
return name
}
}
})
The emptyStyle here is CSSStyleDeclaration from browser.
Vue will check every attribute with prefix in CSSStyleDeclaration or not.
If yes then will append it and cache it.
However, it looks like the filter attribute is an exception here.
Most of CSS we will write in CSS file then it will be compiled by PostCSS and Autoprefixer. Consider the runtime, the code above I guess is the easiest and smallest way to achieve, yet still have some surprises.

SailsJs Handlebar helper functions does not work

I am using Handlebars as templating engine for Sailsjs. Basic templating is working fine but I can't find out the way to use Handlebars helper function or even built in functions are not available.
I have managed to solve the issue with partials using following article.
https://github.com/balderdashy/sails/issues/2414
I have also registered the helpers.js in config folder but I can't call any custom, built in blocks or iteration helper function.
Any pointers to solve the issue of helpers will be helpful.
Sailsjs verion - 0.11.4
Handlebars version - 4.0.5
I have registered the helper function in above file like this:
Handlebars.registerHelper('help', function() {
return "help22";
});
And I am calling the same in my template:
{{{help}}}
Any idea why it is not rendering?
OK, after few hours trying, I come up with a solution:
You can add this line to the end of config/helpers.js
module.exports = Handlebars.helpers;
Inside view.js:
module.exports.views = {
engine: 'handlebars',
layout: 'layout',
partials: 'partials',
helpers: require('./helpers')
};
It will work.
Above solution didn't work for me - I got error "Handlebars is not defined" because I didn't check this link- https://github.com/balderdashy/sails/issues/2414
I have had to add Handlebars = require('handlebars'); in /config/helpers.js
Putting all together:
Edit file /config/views.js
module.exports.views = {
engine: 'handlebars',
extension: 'html', // optional
layout: 'layouts/main', // optional, will load /views/layouts/main.html
partials: 'partials', // optional, will load partials from /views/partials/
helpers: require('./helpers') // <-- this is it
};
Create file /config/helpers.js
Handlebars = require('handlebars');
module.exports = Handlebars.helpers;
Handlebars.registerHelper('stringify', function(obj) {
var json = {}, prop, tmp;
for (prop in obj) {
if (obj.hasOwnProperty(prop)) {
try {
tmp = JSON.stringify(obj[prop]);
json[prop] = obj[prop];
} catch (e) {
json[prop] = '[CAN NOT stringify]';
}
}
}
return JSON.stringify(json, null, 2);
});
In template I use {{stringify entry}}
Tested on Sails v0.12.13

Using Babel with PhantomJS, evaluate function being executed in browser context doesn't have access to helper functions

I'm trying to use PhantomJS with a script that's compiled by Babel from ES6 to ES5.
For some of the features, Babel puts in some helper functions at the end of the file (like _asyncToGenerator and _typeof) to evaluate the code.
But in Phantom, there's a function evaluate(function(){…}) which is executed in the browser context, so it doesn't have access to those helper functions babel puts in.
Ex, if I have a code:
var page = require('webpage').create();
page.open(url, function(status) {
var title = page.evaluate(function() {
typeof(document.title);
});
});
It compiles to
var page = require('webpage').create();
page.open(url, function(status) {
var title = page.evaluate(function Executed_in_Browser_Context() {
_typeof(document.title);
});
});
function _typeof(obj) { return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj; }
Notice the typeof has been changed to _typeof (for some feature involving ES6 Symbols)
Here, the function Executed_in_Browser_Context is executed in browser context, and so it doesn't have access to the function _typeof defined in the file at the bottom. And so it results in error
Can't find variable: _typeof
How to solve this?
I tried copying the _typeof inside Executed_in_Browser_Context (pre-compilation) but then upon compiling, Babel sees that and thinks that it may be some other function that I have in my code, and just renames its own to _typeof2 resulting in same error.

How to implement bootstrap-datepicker as Aurelia custom element

Having first read this http://www.danyow.net/jquery-ui-datepicker-with-aurelia/ and with inspiration from https://gist.github.com/charlespockert/6a1fef3f546f6d37d1dc here follows my attempt to implement the https://github.com/eternicode/bootstrap-datepicker version of bootstrap datepicker:
http://plnkr.co/edit/TkbT6E?p=preview
I'm getting self.datePicker.datepicker is not a function(…) although I've checked that bootstrap-datepicker is correctly installed with jspm and that the .js is loaded. The datepicker does show up (which confirms that the js is loaded correctly), and I can select a date, but the value is not set.
What am I doing wrong here?
Update:
A friendly soul ,#SamDeBlock, in gitter.im/Aurelia put together this http://plnkr.co/edit/hKit8pigwL1ijr2DmbGP?p=preview with the dependencies so it'll run. I keep getting the above error however, when running this in my own application. I'm gonna investigate it problem further and update here, if I get to the bottom of this.
Update 2:
I've now located the problem down to being an issue with system.js/jspm. That's also why the above plunkr works, since it just reference the files directly instead of defining them in config.js.
If I add the file manually like proposed in the above plunkr - AND if I change the following in moment.js file from:
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
global.moment = factory()
}(this, function () { 'use strict';
...
to:
(function (global = typeof window !== "undefined" ? window : this, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
global.moment = factory()
}(this, function () { 'use strict';
...
the global = typeof window !== "undefined" ? window : this part..
THEN it seems to work, with the Aurelia navigation skeleton as well.
But why is this necessary? And how can I get this to work, without all the hacks? I've built my application on the Aurelia Navigation Starter project
https://github.com/aurelia/skeleton-navigation
Chances are that jspm caused this when doing jspm install -y npm:bootstrap-datepickerso check in config.js
Look for this:
"npm:bootstrap-datepicker#1.5.0": {
"fs": "github:jspm/nodelibs-fs#0.1.2",
"jquery": "npm:jquery#2.1.4"
},
And change it to this:
"npm:bootstrap-datepicker#1.5.0": {
"fs": "github:jspm/nodelibs-fs#0.1.2",
"jquery": "github:components/jquery#2.1.4"
},
The important part being: "jquery": "github:components/jquery#2.1.4"
Then everything should work through System.config without the need for the moment.js workaround or anything else.
http://plnkr.co/edit/OeVeiLXwfpTlorDZjBQe?p=preview

fairytale about mvc, require.js and angular. is there happily ever after?

So. Once upon a time there were four magical creatures: asp.net mvc, require.js and angular. And one wise wizard decided to put them in the same house, and let for every single view of asp.net to have its own "code-behind" javascript file;
first he added to the _Layout.cshtml
<script data-main="/main" src="~/Scripts/require.js"></script>
and then he created main.js in the root:
require.config({
baseUrl: "/Scripts/",
paths: {
'jquery': 'jquery-1.9.1.min',
'jquery-ui': 'jquery-ui-1.10.2.custom.min',
'angular': 'angular.min',
'ng-grid': 'ng-grid-2.0.2.debug'
},
shim: {
'jquery': { exports: "$" },
'underscore': { exports: "_" },
'jquery-ui': ['jquery'],
},
});
// Standard Libs
require(['jquery','jquery-ui','underscore','angular']);
nothing fancy and magical yet. But then he created an html helper as such:
public static MvcHtmlString RequireJs(this HtmlHelper helper)
{
var controllerName = helper.ViewContext.RouteData.Values["Controller"].ToString(); // get the controllername
var viewName = Regex.Match((helper.ViewContext.View as RazorView).ViewPath, #"(?<=" + controllerName + #"\/)(.*)(?=\.cshtml)").Value; //get the ViewName - extract it from ViewPath by running regex - everything between controllerName +slash+.cshtml should be it;
// chek if file exists
var filename = helper.ViewContext.RequestContext.HttpContext.Request.MapPath("/Scripts/views/" + controllerName.ToLower() + "-" +
viewName.ToLower()+".js");
if (File.Exists(filename))
{
return helper.RequireJs(#"views/" + controllerName.ToLower() + "-" + viewName.ToLower());
}
return new MvcHtmlString("");
}
public static MvcHtmlString RequireJs(this HtmlHelper helper, string module)
{
var require = new StringBuilder();
require.AppendLine(" <script type=\"text/javascript\">");
require.AppendLine(" require(['Scripts/ngcommon'], function() {");
require.AppendLine(" require( [ \"" + module + "\"] );");
require.AppendLine(" });");
require.AppendLine(" </script>");
return new MvcHtmlString(require.ToString());
}
and then he could use it in _Layout.cshtml just like that:
#Html.RequireJs()
and if you were listening carefully to the story, you probably noticed that there was also Scripts/ngcommon.js file to manually bootstrap angular.js and have commonly used angular directives and services
require(['angular', 'jquery'], function() {
angular.module("common",[]).directive('blabla', function() {
return {
restrict: 'A',
scope: { value: "#blabla" },
link: function(scope, element, attrs) { }
}
});
//manually bootstrap it to html body
$(function(){
angular.bootstrap(document.getElementsByTagName('body'), ["common"]);
});
});
And here comes the magic: from now on if it was a javascript file in \Scripts\views named as controllerName-viewName.js as home-index.js for Home\Index.cshtml it would be automagically picked up by require.js and loaded. Beautiful isn't it?
But then the magician thought: What If I need to load something else (like ng-grid) and that something should not be injected into common angular module because not all the pages will be using it. Of course he could always manually bootstrap another module into a page element in each code-behind javascript where he needed, but he's not wise enough to find answer to the question:
Is it possible to inject some angular.js component (like ng-grid) directly into a controller, without having it as a part of the app module?
If I understand magician's idea right, then it is possible to go on by splitting your application into sub-modules being defined as a collection of components.
It will work if he sets up dependencies for main myApp module like:
var myApp = angular.module('myApp', ['Constants', 'Filters', 'Services', 'Directives', 'Controllers']);
myApp.Constants = angular.module('Constants', []);
myApp.Controllers = angular.module('Controllers', []);
myApp.Filters = angular.module('Filters', []);
myApp.Services = angular.module('Services', []);
myApp.Directives = angular.module('Directives', []);
Then each of sub-modules: Services etc. - can be extended with single component, like:
myApp.Controllers.controller('MyController', function () {});
myApp.Services.factory('myService', function () {});
myApp.Directives.directive('myDirective', function () {});
myApp.Filters.filter('myFilter', []);
myApp.Constants.constant('myConstant', []);
That way main application module is loaded with several sub-modules, but each structure is not important. It makes possible to include individual controllers, services, directives and filters on each page served from back-end - magician just needs to be sure that all needed dependencies are loaded.
DI is the magic key for having separate angular codebehind in MVC views.
You don't even need the requirejs at all, because angular is a dependency injector and module loader by nature, angular.bootstrap is the magic place to start.
So let wizard became more powerfull with the spell - $inject.
var TmplController = function($scope, $compile, $http... // any module itself
{
this.parts = ['legs','arms','head'];
$scope.dynamicPageTemplate = function($compile)
{
$compile('<div><p ng-repeat="each in parts">{{each}}</p></div>' )( $scope );
}
}
TmplController.$inject = ['$scope','$comple', '$http']; //try legs or head
refer complete annotated source of angular-scenario.js from https://github.com/angular/bower-angular-scenario, and you will find how to inject code with define manner helpers.