How do I export a Kotlin JS project? - kotlin-js

Sorry, but the Kotlin documentation doesn't help me to export a Kotlin JS project to deploy it on my webserver.
I created a new Kotlin Browser Application with the new project wizard in IntelliJ.
build.gradle.kts:
plugins {
kotlin("js") version "1.4.21"
}
group = "com.foo"
version = "1.0-SNAPSHOT"
repositories {
jcenter()
mavenCentral()
}
kotlin {
js(LEGACY) {
browser {
binaries.executable()
}
}
}
simple.kt:
class APIModule {
fun greet() = "world"
}
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JS Client</title>
</head>
<body>
<script src="untitled.js"></script>
<script>
let module = new untitled.APIModule()
console.info(`greet: ${module.greet()}`)
</script>
<div id="root"></div>
hallo ralph
</body>
</html>
When I call ./gradlew clean browserRun, it opens a new browser window, and on the JavaScript console, I see the expected (index):11 greet: world.
The question now is: What is the right Gradle task to export it. I tried ./gradlew clean browserWebpack, but when I now open the generated HTML file, I get an index.html:10 Uncaught TypeError: untitled.APIModule is not a constructor at index.html:10 error.

When using IR compiler with #JsExport you can call Kotlin functions from JavaScript.
build.gradle.kts
kotlin {
js(IR) {
browser()
binaries.executable()
}
}
example.kt (in untitled project module)
#JsExport
fun hello() { console.info("hi") }
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JS Client</title>
</head>
<body>
<script src="untitled.js"></script>
<script>
untitled.hello(); // prints "hi" to console.
</script>
<div id="root"></div>
hallo ralph
</body>
</html>
Run ./gradlew browserDistribution then open build/distributions/index.html.
When using LEGACY compiler, I've only been able to invoke Kotlin from JavaScript (for static generated pages) when running the browserDevelopmentWebpack Gradle task. 😢

Related

jsPDF is not defined

I'm trying to use jsPDF with Vue but I get a ReferenceError: jsPDF is not defined. See the snippet :
let jsPrint = () => {
const doc = new jsPDF()
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
<button onclick="jsPrint()">
print
</button>
The script is linked in the head tag :
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= $site->title() ?> - <?= $page->title() ?></title>
<link rel="stylesheet" href="<?= url('assets') ?>/css/style.css">
<!--========== JSPDF ==========-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.4.0/jspdf.umd.min.js"></script>
<!--========== VUE ==========-->
<!-- development version, includes helpful console warnings -->
<script src="<?= url('assets') ?>/js/libs/vue.js"></script>
<script src="<?= url('assets') ?>/js/app.js" type="module" defer></script>
</head>
Then in a component, I have a method that should be triggered on click on a button :
exportSimple: function() {
const doc = new jsPDF()
// const target = document.querySelector('#dialog-export-content')
// doc.html(target, {
// callback: function(doc) {
// doc.save()
// },
// x: 10,
// y: 10
// })
}
But i throws an error.
I tried alternative methods to link the library : local, npm, other sources like jspdf.es.min.js. Nothing works.
Any idea ?
Using CDN the jsPDF object is available as property of jspdf which is available globally :
const { jsPDF } = jspdf
let print = () => {
const doc = new jsPDF()
}

Make callback in Vue

My vue widget works like this.
I use https://github.com/karol-f/vue-custom-element to make embed widget to any webpage.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Foo Page</title>
</head>
<body>
<vue-widget>...</vue-widget>
<script type="text/javascript" src="/js/app.js"></script>
</body>
</html>
My task is to make callback function in my app which can be triggered OUTSIDE <vue-widget>...</vue-widget>.
I tried this bit it don't work and I don't know why
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>Foo Page</title>
</head>
<body>
<vue-widget>...</vue-widget>
<script type="text/javascript" src="/js/app.js"></script>
<script>
vueWidget_onInitCallback = function() {
console.log('foo')
}
</script>
</body>
</html>
App.vue:
methods: {
someFunction() {
if (typeof vueWidget_onInitCallback == 'function') {
vueWidget_onInitCallback();
}
},
},
mounted() {
this.someFunction()
}
Okay I figured it out.
index.html
<script>
function vueWidget_onInitCallback () {
console.log('plugin initiated');
}
</script>
App.vue
methods: {
someFunction() {
function onInit(callback) {
if (callback && typeof(callback) == "function") callback();
}
onInit(vueWidget_onInitCallback);
},
},
mounted() {
this.someFunction()
}
Everything works just fine.

How to fix "Multiple instances of Vue detected!" with parcel.js and bootstrap-vue

How do I solve the warning multiple instances of vue detected! please?
My index.html file
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="style/cssreset.css">
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap-reboot.css">
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="../node_modules/bootstrap-vue/dist/bootstrap-vue.css">
<link rel="stylesheet" href="style/main.css">
</head>
<body>
<div class='app' id='app'>
</div>
<script src="code/app.js"></script>
</body>
</html>
My app.js file:
import Vue from '../../node_modules/vue/dist/vue.common'
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
Vue.use(BootstrapVue)
Vue.use(IconsPlugin)
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
const app = new Vue
({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
and my package.json file has this (which doesn't seem to make a difference):
"alias": {
"vue" : "./node_modules/vue/dist/vue.common.js"
},
The alias field in the package.json needs to change to "vue": "/../node_modules/vue/dist/vue.common.js". Parcel will not complain if your alias field is wrong when compiling so you have to be very careful about specifying the correct path yourself, depending on your build command's root folder.
I found two solutions ( maybe this will save time for someone).
1: add this line in the webpack config file :
let whiteListedModules = ['vue', 'bootstrap-vue']
2: Change the import line to :
Vue.use(require('bootstrap-vue/dist/bootstrap-vue.common.min'));
source

Problem with Cesium integration in OpenLayers 5 - Cesium is not defined

One quick question regarding ol-Cesium. I'm trying to integrate ol-Cesium into my Vue - Openlayers app. But I'm getting this type of error:
"ReferenceError: Cesium is not defined"
Basically what I'm trying is to activate 3d functionality on click but I'm stuck with error above.
I literally used code provided in examples
import OLCesium from 'olcs/OLCesium.js';
const ol3d = new OLCesium({map: this.$store.getters.olMap});
ol3d.setEnabled(true);
I'm using OpenLayers v 5.3.0
Ok, I've figured it out. I only needed to add script tag inside an index.html file that points to Cesium build
Example below:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta name="Vue-OpenLayers" content="Author: Agrivi d.o.o.; Wraping OpenLayers inside Vue.js">
<link rel="icon" href="<%= BASE_URL %>agrivi.ico">
<title>Agrivi Maps</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons">
<script src="https://cesiumjs.org/releases/1.53/Build/Cesium/Cesium.js" charset="UTF-8"></script>
</head>
<body>
<noscript>
<strong>We're sorry but web-app doesn't work properly without JavaScript enabled. Please enable it to
continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
Hope it will help someone :)
The error is indicating it's a webpack error.
I'm referencing documentation found here: https://github.com/gberaudo/ol-cesium-webpack-example/blob/master/webpack.config.js
Make sure you've installed Cesium through NPM:
npm i --save-dev cesium olcs copy-webpack-plugin
Then, in your webpack.config.js file, add these lines:
const cesiumSource = 'node_modules/cesium/Source';
const cesiumWorkers = '../Build/Cesium/Workers';
const CopywebpackPlugin = require('copy-webpack-plugin');
And in the configuration object of this file, add these lines:
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
// Needed to compile multiline strings in Cesium
sourcePrefix: ''
},
amd: {
// Enable webpack-friendly use of require in Cesium
toUrlUndefined: true
},
node: {
// Resolve node module use of fs
fs: 'empty'
},
Then, add Cesium alias to this file:
resolve: {
alias: {
// CesiumJS module name
cesium: path.resolve(__dirname, cesiumSource)
}
},
Then, add this to plugins in this file:
plugins: [
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
// Copy Cesium Assets, Widgets, and Workers to a static directory
new CopywebpackPlugin([ { from: path.join(cesiumSource, cesiumWorkers), to: 'Workers' } ]),
new CopywebpackPlugin([ { from: path.join(cesiumSource, 'Assets'), to: 'Assets' } ]),
new CopywebpackPlugin([ { from: path.join(cesiumSource, 'Widgets'), to: 'Widgets' } ]),
new webpack.DefinePlugin({
// Define relative base path in cesium for loading assets
CESIUM_BASE_URL: JSON.stringify('')
})
],

"React is undefined" error in CycleJs app

I am experimenting with cycle.js and webpack. I have got the following index.js file which almost a copy of what I found on cycle.js documentation.
import Cycle from '#cycle/core';
import {makeDOMDriver, hJSX} from '#cycle/dom';
function main(drivers) {
return {
DOM: drivers.DOM.select('input').events('click')
.map(ev => ev.target.checked)
.startWith(false)
.map(toggled =>
<div>
<input type="checkbox" /> Toggle me
<p>{toggled ? 'ON' : 'off'}</p>
</div>
)
};
}
const drivers = {
DOM: makeDOMDriver('#app')
};
Cycle.run(main, drivers);
And here is my index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Cycle.js checkbox</title>
</head>
<body>
<div id="app"></div> <!-- Our container -->
<script src="./dist/bundle.js"></script>
</body>
</html>
I am using webpack to generate bundle.js inside dist folder. When I run the app by opening index.html in chrome, I get following error in chrome console
cycle.js:51ReferenceError: React is not defined
at index.js:10
at tryCatcher (rx.all.js:63)
at InnerObserver.next (rx.all.js:5598)
at InnerObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (rx.all.js:1762)
at InnerObserver.tryCatcher (rx.all.js:63)
at AutoDetachObserverPrototype.next (rx.all.js:11810)
at AutoDetachObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (rx.all.js:1762)
at ConcatObserver.next (rx.all.js:3466)
at ConcatObserver.Rx.internals.AbstractObserver.AbstractObserver.onNext (rx.all.js:1762)
at ConcatObserver.tryCatcher (rx.all.js:63)
Not sure what I am doing wrong in this seemingly simple first step in a cycle.js app.
You need to set the correct pragma for JSX, or the JSX will be transformed incorrectly.
You can add the correct pragma to the top of your .js file:
/** #jsx hJSX */
Or put this in your babel configuration:
[ "transform-react-jsx", { "pragma": "hJSX" } ]
Relevant GitHub thread.