diff --git a/examples.md b/examples.md
index bc1abf4..16beaf2 100644
--- a/examples.md
+++ b/examples.md
@@ -144,45 +144,48 @@ You can use Compose Wasm.
```kotlin
-import androidx.compose.ui.ExperimentalComposeUiApi
-import androidx.compose.ui.window.CanvasBasedWindow
import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
+import androidx.compose.ui.window.ComposeViewport
+import kotlinx.browser.document
//sampleStart
@OptIn(ExperimentalComposeUiApi::class)
fun main() {
- CanvasBasedWindow { App() }
+ ComposeViewport(viewportContainer = document.body!!, content = {
+ App()
+ })
}
@Composable
fun App() {
MaterialTheme {
- var greetingText by remember { mutableStateOf("Hello World!") }
- var showImage by remember { mutableStateOf(false) }
- var counter by remember { mutableStateOf(0) }
- Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
- Button(onClick = {
- counter++
- greetingText = "Compose: ${Greeting().greet()}"
- showImage = !showImage
- }) {
- Text(greetingText)
+ var showContent by remember { mutableStateOf(false) }
+ Column(
+ modifier = Modifier
+ .fillMaxSize(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Button(onClick = { showContent = !showContent }) {
+ Text("Click me!")
}
- AnimatedVisibility(showImage) {
- Text(counter.toString())
+ AnimatedVisibility(showContent) {
+ val greeting = remember { Greeting().greet() }
+ Column(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ ) {
+ Text("Compose: $greeting")
+ }
}
}
}
diff --git a/package.json b/package.json
index 1d9a8a7..efbb76e 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,7 @@
"copy-examples": "node utils/copy-examples",
"release:ci": "rm -rf dist && npm run build:all && $NPM_TOKEN=%env.NPM_TOKEN% npm publish",
"start": "webpack-dev-server --port 9002",
- "start-with-local-compiler": "webpack-dev-server --port 9002 --env webDemoUrl='//localhost:8080' webDemoResourcesUrl='//localhost:8081'",
+ "start-with-local-compiler": "webpack-dev-server --port 9002 --env webDemoUrl='http://localhost:8080' webDemoResourcesUrl='http://localhost:8081'",
"lint": "eslint . --ext .ts",
"fix": "eslint --fix --ext .ts .",
"test": "npm run build:all && npm run test:run",
diff --git a/src/config.js b/src/config.js
index 6faf923..4487369 100644
--- a/src/config.js
+++ b/src/config.js
@@ -11,11 +11,14 @@ export const RUNTIME_CONFIG = { ...getConfigFromElement(currentScript) };
* @type {{COMPILE: string, COMPLETE: string, VERSIONS: string, JQUERY: string, KOTLIN_JS: string}}
*/
export const API_URLS = {
- server: (RUNTIME_CONFIG.server || __WEBDEMO_URL__).replace(/\/$/, ''),
- composeServer: 'https://compose-stage.sandbox.intellij.net'.replace(
+ server: (__WEBDEMO_URL__ || RUNTIME_CONFIG.server).replace(/\/$/, ''),
+ composeServer: (__WEBDEMO_URL__ || 'https://compose-stage.sandbox.intellij.net').replace(
/\/$/,
'',
),
+ composeResources: (__WEBDEMO_RESOURCES_URL__ || 'https://compose-stage.sandbox.intellij.net').replace(
+ /\/$/, ''
+ ),
COMPILE(platform, version) {
let url;
@@ -60,21 +63,6 @@ export const API_URLS = {
get VERSIONS() {
return `${this.server}/versions`;
},
- RESOURCE_VERSIONS() {
- return `${this.composeServer}/api/resource/compose-wasm-versions`;
- },
- SKIKO_MJS(version) {
- return `${this.composeServer}/api/resource/skiko-${version}.mjs`;
- },
- SKIKO_WASM(version) {
- return `${this.composeServer}/api/resource/skiko-${version}.wasm`;
- },
- STDLIB_MJS(hash) {
- return `${this.composeServer}/api/resource/stdlib-${hash}.mjs`;
- },
- STDLIB_WASM(hash) {
- return `${this.composeServer}/api/resource/stdlib-${hash}.wasm`;
- },
get JQUERY() {
return `https://cdn.jsdelivr.net/npm/jquery@1/dist/jquery.min.js`;
},
diff --git a/src/executable-code/executable-fragment.js b/src/executable-code/executable-fragment.js
index c1cd477..5ae3c8e 100644
--- a/src/executable-code/executable-fragment.js
+++ b/src/executable-code/executable-fragment.js
@@ -412,24 +412,15 @@ export default class ExecutableFragment extends ExecutableCodeTemplate {
targetPlatform,
compilerVersion,
);
- const additionalRequests = [];
- if (targetPlatform === TargetPlatforms.COMPOSE_WASM) {
- if (this.jsExecutor.stdlibExports) {
- additionalRequests.push(this.jsExecutor.stdlibExports);
- }
- }
- Promise.all([
- WebDemoApi.translateKotlinToJs(
+ WebDemoApi.translateKotlinToJs(
this.getCode(),
compilerVersion,
targetPlatform,
args,
hiddenDependencies,
- ),
- ...additionalRequests,
- ]).then(
- ([state, ...additionalRequestsResults]) => {
+ ).then(
+ (state) => {
state.waitingForOutput = false;
const jsCode = state.jsCode;
const wasm = state.wasm;
@@ -454,7 +445,6 @@ export default class ExecutableFragment extends ExecutableCodeTemplate {
outputHeight,
theme,
onError,
- additionalRequestsResults,
compilerVersion,
)
.then((output) => {
diff --git a/src/js-executor/execute-es-module.js b/src/js-executor/execute-es-module.js
index 3a49daf..14d13b9 100644
--- a/src/js-executor/execute-es-module.js
+++ b/src/js-executor/execute-es-module.js
@@ -1,26 +1,22 @@
+import {API_URLS} from "../config";
+
export async function executeWasmCode(container, jsCode, wasmCode) {
const newCode = prepareJsCode(jsCode);
return execute(container, newCode, wasmCode);
}
-export async function executeWasmCodeWithSkiko(container, jsCode) {
- return executeJs(container, prepareJsCode(jsCode));
-}
-
-export async function executeWasmCodeWithStdlib(container, jsCode, wasmCode) {
- return execute(container, prepareJsCode(jsCode), wasmCode);
-}
-
function execute(container, jsCode, wasmCode) {
container.wasmCode = Uint8Array.from(atob(wasmCode), c => c.charCodeAt(0));
return executeJs(container, jsCode);
}
-export function executeJs(container, jsCode) {
+function executeJs(container, jsCode) {
return container.eval(`import(/* webpackIgnore: true */ '${'data:text/javascript;base64,' + btoa(jsCode)}');`)
}
function prepareJsCode(jsCode) {
+ const re = /instantiateStreaming\(fetch\(new URL\('([^']*)',\s*import\.meta\.url\)\.href\),\s*importObject\s*,\s*\{\s*builtins\s*:\s*\[''\]\s*\}\s*\)\)\.instance;/g;
+
return `
class BufferedOutput {
constructor() {
@@ -30,12 +26,20 @@ function prepareJsCode(jsCode) {
export const bufferedOutput = new BufferedOutput()
` +
jsCode
+ .replaceAll(
+ "await import('./",
+ "await import('" + API_URLS.composeResources + "/"
+ )
+ .replaceAll(
+ "%3",
+ "%253"
+ )
.replace(
"instantiateStreaming(fetch(wasmFilePath), importObject)).instance;",
"instantiate(window.wasmCode, importObject)).instance;\nwindow.wasmCode = undefined;"
)
.replace(
- "instantiateStreaming(fetch(new URL('./playground.wasm',import.meta.url).href), importObject)).instance;",
+ re,
"instantiate(window.wasmCode, importObject)).instance;\nwindow.wasmCode = undefined;"
)
.replace(
diff --git a/src/js-executor/index.js b/src/js-executor/index.js
index a080a48..dd7eec3 100644
--- a/src/js-executor/index.js
+++ b/src/js-executor/index.js
@@ -3,13 +3,7 @@ import { API_URLS } from '../config';
import { showJsException } from '../view/output-view';
import { processingHtmlBrackets } from '../utils';
import { isJsLegacy, isWasmRelated, TargetPlatforms } from '../utils/platforms';
-import {
- executeJs,
- executeWasmCode,
- executeWasmCodeWithSkiko,
- executeWasmCodeWithStdlib,
-} from './execute-es-module';
-import { fetch } from 'whatwg-fetch';
+import { executeWasmCode } from './execute-es-module';
const INIT_SCRIPT =
'if(kotlin.BufferedOutput!==undefined){kotlin.out = new kotlin.BufferedOutput()}' +
@@ -31,7 +25,6 @@ const normalizeJsVersion = (version) => {
export default class JsExecutor {
constructor(kotlinVersion) {
this.kotlinVersion = kotlinVersion;
- this.stdlibExports = undefined;
}
async executeJsCode(
@@ -42,7 +35,6 @@ export default class JsExecutor {
outputHeight,
theme,
onError,
- additionalRequestsResults,
compilerVersion,
) {
if (platform === TargetPlatforms.SWIFT_EXPORT) {
@@ -75,15 +67,12 @@ export default class JsExecutor {
// for some reason resize function in Compose does not work in Firefox in invisible block
this.iframe.style.display = 'block';
- const additionalRequestsResult = additionalRequestsResults[0];
const result = await this.executeWasm(
jsCode,
wasm,
- executeWasmCodeWithStdlib,
+ executeWasmCode,
theme,
- processError,
- additionalRequestsResult.stdlib,
- additionalRequestsResult.output,
+ processError
);
if (exception) {
@@ -146,8 +135,6 @@ export default class JsExecutor {
executor,
theme,
onError,
- imports,
- output,
) {
try {
const exports = await executor(
@@ -155,8 +142,8 @@ export default class JsExecutor {
jsCode,
wasmCode,
);
- await exports.instantiate({ 'playground.master': imports });
- const bufferedOutput = output ?? exports.bufferedOutput;
+ await exports.instantiate();
+ const bufferedOutput = this.iframe.contentWindow.bufferedOutput ?? exports.bufferedOutput;
const outputString = bufferedOutput.buffer;
bufferedOutput.buffer = '';
return outputString
@@ -202,124 +189,10 @@ export default class JsExecutor {
);
}
if (targetPlatform === TargetPlatforms.COMPOSE_WASM) {
- const skikoStdlib = fetch(API_URLS.RESOURCE_VERSIONS(), {
- method: 'GET',
- })
- .then((response) => response.json())
- .then((versions) => {
- const skikoVersion = versions['skiko'];
-
- const skikoExports = fetch(API_URLS.SKIKO_MJS(skikoVersion), {
- method: 'GET',
- headers: {
- 'Content-Type': 'text/javascript',
- },
- })
- .then((script) => script.text())
- .then((script) =>
- script.replace(
- 'new URL("skiko.wasm",import.meta.url).href',
- `'${API_URLS.SKIKO_WASM(skikoVersion)}'`,
- ),
- )
- .then((skikoCode) =>
- executeJs(this.iframe.contentWindow, skikoCode),
- )
- .then((skikoExports) => fixedSkikoExports(skikoExports));
-
- const stdlibVersion = versions['stdlib'];
-
- const stdlibExports = fetch(API_URLS.STDLIB_MJS(stdlibVersion), {
- method: 'GET',
- headers: {
- 'Content-Type': 'text/javascript',
- },
- })
- .then((script) => script.text())
- .then((script) =>
- // necessary to load stdlib.wasm before its initialization to parallelize
- // language=JavaScript
- (
- `const stdlibWasm = fetch('${API_URLS.STDLIB_WASM(stdlibVersion)}'); ` +
- script
- )
- .replace(
- "fetch(new URL('./stdlib_master.wasm',import.meta.url).href)",
- 'stdlibWasm',
- )
- .replace(
- '(extends) => { return { extends }; }',
- '(extends_) => { return { extends_ }; }',
- ),
- )
- .then((stdlibCode) =>
- executeWasmCodeWithSkiko(this.iframe.contentWindow, stdlibCode),
- );
-
- return Promise.all([skikoExports, stdlibExports]);
- });
-
- this.stdlibExports = skikoStdlib
- .then(async ([skikoExportsResult, stdlibExportsResult]) => {
- return [
- await stdlibExportsResult.instantiate({
- './skiko.mjs': skikoExportsResult,
- }),
- stdlibExportsResult,
- ];
- })
- .then(([stdlibResult, outputResult]) => {
- return {
- stdlib: stdlibResult.exports,
- output: outputResult.bufferedOutput,
- };
- });
-
- this.iframe.height = '1000';
- iframeDoc.write(``);
+ this.iframe.height = "1000"
+ iframeDoc.write(``);
}
iframeDoc.write('');
iframeDoc.close();
}
}
-
-function fixedSkikoExports(skikoExports) {
- return {
- ...skikoExports,
- org_jetbrains_skia_Bitmap__1nGetPixmap: function () {
- console.log(
- 'org_jetbrains_skia_TextBlobBuilderRunHandler__1nGetFinalizer',
- );
- },
- org_jetbrains_skia_Bitmap__1nIsVolatile: function () {
- console.log(
- 'org_jetbrains_skia_TextBlobBuilderRunHandler__1nGetFinalizer',
- );
- },
- org_jetbrains_skia_Bitmap__1nSetVolatile: function () {
- console.log(
- 'org_jetbrains_skia_TextBlobBuilderRunHandler__1nGetFinalizer',
- );
- },
- org_jetbrains_skia_TextBlobBuilderRunHandler__1nGetFinalizer: function () {
- console.log(
- 'org_jetbrains_skia_TextBlobBuilderRunHandler__1nGetFinalizer',
- );
- },
- org_jetbrains_skia_TextBlobBuilderRunHandler__1nMake: function () {
- console.log(
- 'org_jetbrains_skia_TextBlobBuilderRunHandler__1nGetFinalizer',
- );
- },
- org_jetbrains_skia_TextBlobBuilderRunHandler__1nMakeBlob: function () {
- console.log(
- 'org_jetbrains_skia_TextBlobBuilderRunHandler__1nGetFinalizer',
- );
- },
- org_jetbrains_skia_svg_SVGCanvasKt__1nMake: function () {
- console.log(
- 'org_jetbrains_skia_TextBlobBuilderRunHandler__1nGetFinalizer',
- );
- },
- };
-}