Hey folks,

I just pushed some commits to royale-compiler and royale-asjs, and I wanted
to add a little explanation, and some possible troubleshooting advice if
anything seems to have broken in your apps.

My work over the last week has been to fix an issue related to specifying
dependencies when compiling libraries for JS. As you probably know, the
compiler supports two options for adding libraries as dependencies,
library-path and external-library-path. The library-path compiler option
basically says "include all classes that I use from this SWC in the final
output". It's typically what you use when compiling an app that uses a
library. The external-library-path compiler option basically says "if I use
anything from this SWC, check that I'm using the types correctly, but don't
include any of classes from this SWC in the final output".

If you're compiling an app, you typically use library-path for everything.
You use external-library-path only for dependencies like
playerglobal.swc/airglobal.swc in Flash or typedef SWCs in JS. Basically,
for an app project, external-library-path is for classes that are provided
natively by the Flash runtime or a web browser, like Chrome or Firefox.

When compiling libraries, external-library-path is also used to prevent the
compiler from creating a "fat" library that stuffs in all of the
dependencies. Let's say that you have a library, A.swc. It provides some
core functionality that is needed by both B.swc and C.swc. When we compile
B.swc and C.swc, we don't want the classes from A.swc duplicated in both of
them. So we add A.swc to the external-library-path when compiling B.swc or
C.swc. Then, if you use those SWCs when compiling an app, you need to add
A.swc, B.swc, and C.swc to the library-path.

To put that in Royale terms, A.swc is something like LanguageJS.swc or
CoreJS.swc. They're some of our lowest-level SWCs in the framework. B.swc
and C.swc are more like BasicJS.swc or JewelJS.swc, and they tend to share
multiple classes from the lower-level stuff.

Up until now, library-path and external-library-path were a little quirky
when compiling to JS. It was related to the goog.provide() and
goog.require() calls that you might have seen in the generated JS. These
are from the module system that we use in Royale. The compiler didn't know
how to differentiate between classes that had goog.provide() and classes
that were typedefs for JS libraries. It treated everything on the
external-library-path as a typedef, and this led to missing goog.require()
calls in the generated JS. To work around this, when we specified
dependencies in our framework SWCs, we used library-path to ensure that
goog.require() would be used.

This workaround of using library-path led to "fat" SWCs that contained all
of their dependencies. Low-level classes in SWCs like CoreJS were
duplicated in higher-level SWCs. This led to the compiler getting confused
about exactly where a class was defined.

This has resulted in some minor issues here and there, but nothing too
major until recently. However, Harbs noticed the other day that it caused
the compiler to copy extra default CSS into apps from SWCs that you may not
have been using. So, you might build an app with the Basic components, but
you'd get extra CSS from Jewel or MaterialDesignLite. This could mess up
your app's styling pretty dramatically.

I updated the compiler to better detect when a class needs goog.require()
and when it's a typedef. If that class comes from a SWC, the compiler knows
to check for an included file like, js/out/com/example/MyClass.js. If the
generated JS is there, goog.require() is necessary. If it's missing, it's
treated as a typedef class instead. If the class is an .as source file
instead, the compiler looks for the @externs asdoc tag to determine if it's
a typedef class (and everything else needs goog.require() instead).

By the way, if we ever support other module systems, it shouldn't be too
difficult to extend this code to detect different SWC layouts for each
module system.

If your project is an app, this change should not cause any problems.
You're probably using library-path and external-library-path correctly.

If you have a project that is a library, you should check your compiler
options to see if you are using library-path and external-library-path
correctly. If your library depends on another library, you probably should
be using external-library-path because you don't want a "fat" SWC. In other
words, if you're using library-path in a library project, you probably need
to change that to external-library-path.

If you have any custom typedef SWCs, you may want to recompile them. At one
point, the compiler had a bug where classes in typedef SWCs were being
incorrectly added to the "js/out" folder in the SWC, but that was
incorrect. They should have been placed in an "externs" folder instead. The
compiler handles this correctly now, but old typedef SWCs may look like
goog.require() SWCs instead. To be sure, you can open a SWC file in any
program that can read ZIP files, and you'll see the internal folder
structure. If a typedef SWC has a "js/out" folder, it's not going to work
properly.

If you're working directly out of the royale-compiler and royale-asjs Git
repos, be sure to update and rebuild them both. The nightly builds should
be updated shortly.

When you build any apps, be sure to clean first, just to be sure that you
have the latest JS files from the SWCs.

If you run into any other problems with these changes, please let me know.
I'll get them fixed right away!

--
Josh Tynjala
Bowler Hat LLC <https://bowlerhat.dev>

Reply via email to