konsoletyper / teavm

Compiles Java bytecode to JavaScript, WebAssembly and C
https://teavm.org
Apache License 2.0
2.61k stars 263 forks source link

Support "reserved variables" when minifying for compatibility with other javascript libraries like Leaflet.js #305

Open jkoelewijn opened 6 years ago

jkoelewijn commented 6 years ago

Last period I've been experimenting with TeaVM combined with Leaflet.js.

I first include Leaflet.js, and then the TeaVM generated javascript files.

However, when using the minifying option of the maven plugin, a function L will be generated by TeaVM, which overrides the L object of Leaflet. My first solution was to copy the L object of Leaflet.js to a new Leaflet object before including the TeaVM generated javascript files. That works when using Leaflet.js stand-alone, but fails when using some Leaflet.js plugins, which assume the L object is present in the global scope.

Is there any option to specify "reserved variables" in the maven plugin of TeaVM? A list of variables that will not be used when minifying? Or is there any other solution for this problem? For now I've worked around it using a regex replace after TeaVM generates the javascript files, but that's not a robust solution.

konsoletyper commented 6 years ago

I think there should not be feature like "reserved variables". TeaVM should generate everything in a wrapper function and expose only main method (or other methods specified by user), just like modern module systems do.

jkoelewijn commented 6 years ago

Thanks for the suggestion. I changed my workaround to wrap the TeaVM generated javascript using the following Maven plugin:

<!-- TeaVM sometimes generates a function that conflicts with the L object of Leaflet.js, this regex 
        wraps all TeaVM generated code in a scoped object to fix that -->
<plugin>
    <groupId>com.google.code.maven-replacer-plugin</groupId>
    <artifactId>replacer</artifactId>
    <version>1.5.3</version>
    <executions>
        <execution>
            <id>web-client</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>replace</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <file>target/generated/js/teavm/classes.js</file>
        <replacements>
            <replacement>
                <token>(^)(.)</token>
                <value>$1var teaVm = (function(global) { $2</value>
            </replacement>
            <replacement>
                <token>(.)($)</token>
                <value>$1&#xA;&#xA;return {main: main}&#xA;&#xA;})(this)&#xA;$2</value>
            </replacement>
        </replacements>
    </configuration>
</plugin> 

This workaround requires <runtime>MERGED</runtime> in the configuration of the teavm-maven-plugin. Leaflet can then be called using a static method like:

@JSBody(params = {"element", "options"}, script = "return global.L.map(element, options);")
public static native LeafletMap map(HTMLElement element, LeafletMapOptions options);

The main method of the TeaVM generated javascript can be called using <script>teaVm.main();</script>.