Load module with parameter after bundle - javascript

I've got the following codeblock in the layout.js
import $ from "jquery";
import LayoutModel from 'js/models/LayoutModel';
let elements = {
$window: $(window),
$html: $('html'),
$content: $('#content')
};
let viewmodel = null;
export function init(options) {
viewmodel = new LayoutModel(options, elements);
ko.applyBindings(viewmodel, elements.$content[0]);
}
and I load it in the view with system.js and call the init() with options. The options contains values and it has to be in the view because some of it comes from the back-end model.
System.import('resources/javascript/layout').then(function(controller) {
var options = {
something: 'value'
};
controller.init(options);
});
This solution works while it's not bundled with jspm:
jspm bundle resources\javascript\layout resources\javascript\dist\layout.min.js --minify
In production I have to do it, but in this case I'm not able to use the system.import() and the .then(), because I have to load the bundled script with a normal <script> tag:
<script src="resources\javascript\dist\layout.min.js"></script>
So the question: How can I bundle and minify it and call the init() method with the options?
Thank you!

Related

Creating a JS library with IIFE namespacing

If we don't want to use ES6 import nor any third party libraries (like require.js etc.) nor any package builder, what is the classical way to pack a library so that the user can use it with what seems to be a library-namespace?
index.html (from the perspective of the user of the library)
<canvas id="mycanvas"></canvas>
<script src="canvas.js"></script>
<script>
canvas.setup({"config1": true, "config2": false});
var mycanvas1 = canvas.get("#mycanvas");
</script>
I sometimes see code similar to
// canvas.js
(function (window, something, else) {
window.canvas.setup = function() { ... } // how to export functions setup and get?
})(window, ..., ...);
How to do this IIFE properly to create this canvas.js library example?
Note: with ES6 import, we can package this way a library called canvas.js:
const canvas = {
setup: config => { console.log("config"); },
get: id => { console.log("get"); }
};
export default canvas;
and use it a index.html this way:
<canvas id="mycanvas"></canvas>
<script type="module">
import canvas from "./canvas.js";
canvas.setup({"config1": true, "config2": false});
var mycanvas1 = canvas.get("#mycanvas");
</script>
but in this question here I am curious about the pre-ES6 solution.
A solution seems to be:
// canvas.js
canvas = (function(window) { // assign the result of the IIFE to a global var to make
// it available for the user of the lib
var internal_variable; // not accessible to the user of the lib
var state; // this variable will be available to the user of the lib
function setup(arg) {
console.log("setup");
}
function get(arg) {
console.log("get"); // + other lines using window object
}
return {setup: setup, get: get, state: state}; // important: here we choose what we
// export as an object
})(window);
Now the user can use the library this way:
<canvas id="mycanvas"></canvas>
<script src="canvas.js"></script> // object canvas is now available
<script>
canvas.setup({"config1": true, "config2": false});
var mycanvas1 = canvas.get("#mycanvas");
console.log(canvas.state);
</script>

Getting Monaco to work with Vuejs and electron

I'm interested in using the Monaco editor in a Vue.js backed Electron project.
Thus far:
Microsoft provides an Electron Sample (which I've run and works correctly)
There are a variety of vue.js npm repos for monaco - yet none of them seem to fully support Electron right out of the box.
The one that looks most promising is vue-monaco but I've run into issues correctly integrating it.
AMD Require?
This is the code from the Microsoft sample for using with Electron
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Monaco Editor!</title>
</head>
<body>
<h1>Monaco Editor in Electron!</h1>
<div id="container" style="width:500px;height:300px;border:1px solid #ccc"></div>
</body>
<script>
// Monaco uses a custom amd loader that overrides node's require.
// Keep a reference to node's require so we can restore it after executing the amd loader file.
var nodeRequire = global.require;
</script>
<script src="../node_modules/monaco-editor/min/vs/loader.js"></script>
<script>
// Save Monaco's amd require and restore Node's require
var amdRequire = global.require;
global.require = nodeRequire;
</script>
<script>
// require node modules before loader.js comes in
var path = require('path');
function uriFromPath(_path) {
var pathName = path.resolve(_path).replace(/\\/g, '/');
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
pathName = '/' + pathName;
}
return encodeURI('file://' + pathName);
}
amdRequire.config({
baseUrl: uriFromPath(path.join(__dirname, '../node_modules/monaco-editor/min'))
});
// workaround monaco-css not understanding the environment
self.module = undefined;
// workaround monaco-typescript not understanding the environment
self.process.browser = true;
amdRequire(['vs/editor/editor.main'], function() {
var editor = monaco.editor.create(document.getElementById('container'), {
value: [
'function x() {',
'\tconsole.log("Hello world!");',
'}'
].join('\n'),
language: 'javascript'
});
});
</script>
</html>
The module I'm using allows for something like this:
<template>
<monaco-editor :require="amdRequire" />
</template>
<script>
export default {
methods: {
amdRequire: window.amdRequire
// Or put this in `data`, doesn't really matter I guess
}
}
</script>
I can't seem to figure out how to get the correct amdRequire variable defined in Electon + vue. I believe if i can conquer this everything else becomes simple.
The Electron FAQ mentions something about this (i think): I can not sue jQuery/RequireJS/Meteor/AngularJS in Electron
Sample Code
I put a sample project up on GitHub https://github.com/jeeftor/Vue-Monaco-Electron with the "offending" component being in ./src/renderer/components/Monaco.vue
Summary
How can I get this Monaco Editor to load correctly inside of a Vue.js component that will be run inside electron?
Thanks for any help you can offer.
I'm doing nearly the same, just without the extra vue-monaco component. After struggling quite a bit, I could solve the problem:
function loadMonacoEditor () {
const nodeRequire = global.require
const loaderScript = document.createElement('script')
loaderScript.onload = () => {
const amdRequire = global.require
global.require = nodeRequire
var path = require('path')
function uriFromPath (_path) {
var pathName = path.resolve(_path).replace(/\\/g, '/')
if (pathName.length > 0 && pathName.charAt(0) !== '/') {
pathName = '/' + pathName
}
return encodeURI('file://' + pathName)
}
amdRequire.config({
baseUrl: uriFromPath(path.join(__dirname, '../../../node_modules/monaco-editor/min'))
})
// workaround monaco-css not understanding the environment
self.module = undefined
// workaround monaco-typescript not understanding the environment
self.process.browser = true
amdRequire(['vs/editor/editor.main'], function () {
this.monaco.editor.create(document.getElementById('container'), {
value: [
'function x() {',
'\tconsole.log("Hello world!");',
'}'
].join('\n'),
language: 'javascript'
})
})
}
loaderScript.setAttribute('src', '../node_modules/monaco-editor/min/vs/loader.js')
document.body.appendChild(loaderScript)
}
I've just taken the electron-amd sample and adjusted it a bit. I call the loadMonacoEditor function in the components' created function.
In order to not get the Not allowed to load local resource: file:///C:/.../node_modules/monaco-editor/min/vs/editor/editor.main.css problem, you also have to set
webPreferences: {
webSecurity: false
}
in your instance of the BrowserWindow.

Vue custom directive with function in js file

I'm trying to make a custom directive in Vue to be able to use these simple tooltips. I have the tooltip javascript in a js file in the static folder which is required into the main.js file. I've turned it into a function that will run for each tooltip. The problem is that the function is undefined even though I have required the the file above. How do I use the 'makeTooltip' function in the custom directive?
MAIN.JS
import Vue from 'vue'
require('../static/js/scripts.js')
Vue.directive('tooltip', function(el, binding){
makeTooltip($(el), binding.value);
$('.tooltip').click(function(){
$('.tooltip').hide();
})
})
SCRIPTS.JS
function makeTooltip(el, title){
var target = false,
tooltip = false,
title = false;
el.bind( 'mouseenter', function()
{
target = $( this );
tip = title;
tooltip = $( '<div id="tooltip"></div>' );
...
};
For each tooltip that is trying to render I get ReferenceError: makeTooltip is not defined

angular TinyMCE integration

I follow official doc for integrating TinyMCE with Angular: https://www.tinymce.com/docs/integrations/angular2/.
Now everything works fine, but TinyMCEs plugins loaded in application start, but I want it load asynchronously from /src/assets/tinymce. Question is,
How can I load TinyMCE asynchronously when I need it?
~ apologies for grammatical mistakes
In .angular-cli.json I have scripts array:
"scripts": [
"../node_modules/tinymce/tinymce.js",
"../node_modules/tinymce/themes/modern/theme.js",
"../node_modules/tinymce/plugins/link/plugin.js",
"../node_modules/tinymce/plugins/paste/plugin.js",
"../node_modules/tinymce/plugins/table/plugin.js",
"../node_modules/tinymce/plugins/image/plugin.js",
"../node_modules/tinymce/plugins/imagepicker/plugin.js",
"../node_modules/tinymce/plugins/imagetools/plugin.js",
"../node_modules/tinymce/plugins/advlist/plugin.js",
"../node_modules/tinymce/plugins/autolink/plugin.js",
"../node_modules/tinymce/plugins/lists/plugin.js",
"../node_modules/tinymce/plugins/charmap/plugin.js",
"../node_modules/tinymce/plugins/print/plugin.js",
"../node_modules/tinymce/plugins/preview/plugin.js",
"../node_modules/tinymce/plugins/hr/plugin.js",
"../node_modules/tinymce/plugins/anchor/plugin.js",
"../node_modules/tinymce/plugins/pagebreak/plugin.js",
"../node_modules/tinymce/plugins/searchreplace/plugin.js",
"../node_modules/tinymce/plugins/wordcount/plugin.js",
"../node_modules/tinymce/plugins/visualblocks/plugin.js",
"../node_modules/tinymce/plugins/visualchars/plugin.js",
"../node_modules/tinymce/plugins/fullscreen/plugin.js",
"../node_modules/tinymce/plugins/insertdatetime/plugin.js",
"../node_modules/tinymce/plugins/media/plugin.js",
"../node_modules/tinymce/plugins/nonbreaking/plugin.js",
"../node_modules/tinymce/plugins/save/plugin.js",
"../node_modules/tinymce/plugins/contextmenu/plugin.js",
"../node_modules/tinymce/plugins/directionality/plugin.js",
"../node_modules/tinymce/plugins/template/plugin.js",
"../node_modules/tinymce/plugins/textcolor/plugin.js",
"../node_modules/tinymce/plugins/colorpicker/plugin.js",
"../node_modules/tinymce/plugins/textpattern/plugin.js",
"../node_modules/tinymce/plugins/toc/plugin.js",
"../node_modules/tinymce/plugins/code/plugin.js",
"../node_modules/tinymce/plugins/autoresize/plugin.js",
"../node_modules/tinymce/plugins/help/plugin.js"
],
these scripts are plugins of TinyMCE
Declare these 2 on top in your component:
declare var tinymce: any;
const url = '//cdn.tinymce.com/4/tinymce.min.js';
Use this function to load the script in your component's onInit function:
loadScript() {
let scriptTag = document.querySelector('script[src="//cdn.tinymce.com/4/tinymce.min.js"]');
let node;
if (!scriptTag) {
node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
node.async = true;
node.charset = 'utf-8';
document.getElementsByTagName('head')[0].appendChild(node);
}
}
and then use the following function to load the tinymce:
loadTinyMCE() {
if (tinymce)
tinymce.init({
selector: '#tinymce',
skin_url: 'assets/skins/lightgray',
plugins: ['paste', 'link', 'autoresize','image'],
setup: editor => {
this.editor = editor;
}
})
}
and finally destroy the tinymce object on ngdestroy:
ngOnDestroy() {
tinymce.remove();
}
It might be the bad approach but it saves me from loading the script on application load and gives me the ability to load it only when it is needed.

How do I include a JavaScript script file in Angular and call a function from that script?

I have a JavaScript file called abc.js that has a 'public' function called xyz(). I want to call that function in my Angular project. How do I do that?
Refer the scripts inside the angular-cli.json (angular.json when using angular 6+) file.
"scripts": [
"../path"
];
then add in typings.d.ts (create this file in src if it does not already exist)
declare var variableName:any;
Import it in your file as
import * as variable from 'variableName';
In order to include a global library, eg jquery.js file in the scripts array from angular-cli.json (angular.json when using angular 6+):
"scripts": [
"../node_modules/jquery/dist/jquery.js"
]
After this, restart ng serve if it is already started.
Add external js file in index.html.
<script src="./assets/vendors/myjs.js"></script>
Here's myjs.js file :
var myExtObject = (function() {
return {
func1: function() {
alert('function 1 called');
},
func2: function() {
alert('function 2 called');
}
}
})(myExtObject||{})
var webGlObject = (function() {
return {
init: function() {
alert('webGlObject initialized');
}
}
})(webGlObject||{})
Then declare it is in component like below
demo.component.ts
declare var myExtObject: any;
declare var webGlObject: any;
constructor(){
webGlObject.init();
}
callFunction1() {
myExtObject.func1();
}
callFunction2() {
myExtObject.func2();
}
demo.component.html
<div>
<p>click below buttons for function call</p>
<button (click)="callFunction1()">Call Function 1</button>
<button (click)="callFunction2()">Call Function 2</button>
</div>
It's working for me...
You can either
import * as abc from './abc';
abc.xyz();
or
import { xyz } from './abc';
xyz()
I resolved this issue by adding "allowJs": true within "compilerOptions" in tsconfig.json file!
- Let us assume our script file custom.js looks like this: -
var utilObj = {
dummyFunc: () => {
console.log('Calling dummy function!');
}
}
- Add your javascript/script file in scripts array in angular.json file.
"scripts": [
"src/custom.js"
],
Should look like this: -
- Add below code snippet in typings.d.ts. If this file doesn't exist, create one in src folder.
declare var utilObj:any;
Keep your variable name similar to property of script file. Here utilObj is the property name.
- Now, You can consume this script/js file directly in your component or .ts file.
You need not import the file in component file or .ts file now as we have given the typing defination for the script file already in typings.d.ts file.
Example: -
ngOnInit() {
console.log('Starting Application!');
utilObj.dummyFunc();
}
- Output: -
This might sound silly, but if you feel that you are properly exporting your JavaScript helper function utils/javaScriptHelperFunction.js
export function javaScriptFunction() {
// DO HELPER FUNCTION STUFF
}
If you have done your checks as mentioned in the above answers, just close and open your code editor...start with the quick basic troubleshooting before going down the rabbit hole.

Categories

Resources