You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@royale.apache.org by Kenny Lerma <ke...@kennylerma.com> on 2021/03/03 22:41:26 UTC

Re: Compiler options for reducing release build size of Royale projects

Josh, is there a compiler option to prevent the rename of generic object
keys?

var myvar:Object = {foo : 1, bar : 2}

Renamed by closure to...
  var myvar:Object = {ad: 1, hb: 2}

I'm using Tweener in SpriteFlexJS which receives a generic object of
properties for tweening, but I can't use ADVANCED_OPTIMIZATIONS because of
the re-name.

On Mon, Nov 9, 2020 at 4:16 PM Josh Tynjala <jo...@bowlerhat.dev>
wrote:

> Hi all,
>
> Some of you have probably been wondering about my changes to the compiler
> over the last year or more. I apologize again for occasionally breaking
> things for short periods. It's been quite a challenge getting this stuff
> working, but I'm excited to finally be able to report some real
> improvements that pretty much anyone should be able to take advantage of
> when building a Royale app.
>
> First some background. A while back, Harbs asked me to look into ways of
> reducing the file size of release builds. As you may know, we use Google's
> Closure compiler to optimize our generated JavaScript. Closure can be very
> aggressive in its optimizations, by renaming symbols (things like variable
> and function names) and removing "dead code" that is detected as never
> being called.
>
> Closure's optimizations are good, but they also require developers to be
> very careful about how they write their JavaScript code. When you enable
> Closure's full optimizations, you are not allowed to use certain JavaScript
> features because Closure cannot analyze them properly. For instance,
> consider the following code:
>
> var propName= "myProp";
> var value = obj[propName];
>
> When you dynamically access a property with a string, Closure cannot
> reliably know that the property exists and will be accessed at runtime. It
> may decide to rename or remove that property, which would break things at
> runtime.
>
> ActionScript supports many of the same restricted dynamic features too, so
> if you want to support the entire AS3 language, we can't let Closure do its
> full optimization. Luckily, Closure also provides a bit of a backdoor: it
> allows you to "export" symbols, which means that they won't be renamed and
> they won't be removed as dead code. Traditionally, we have made heavy use
> of this exporting feature in Royale.
>
> Harbs wanted to know if we absolutely needed to export everything that we
> currently export, and if we could potentially allow developers to turn off
> exporting entirely, as long as they follow the stricter rules required by
> Closure.
>
> I won't go into all of the details, but over the last several months, I've
> been changing the compiler to give developers more control over release
> builds. In particular, control over which symbols get exported, but also
> the ability to block Closure from renaming symbols that haven't been
> exported.
>
> Now, for some of the results. I'm going to share the output file size of
> the release build for several Royale projects with various different
> compiler options.
>
> For the example projects included with Royale, I built royale-asjs commit
> 94f12ed0e564b0b443834400dc2fc06d61b90a8a from October 26, 2020. If you want
> to try building these examples yourself, the file sizes of release builds
> may be slightly different, if you use a different commit.
>
> SpectrumBrowser is a project developed by Harbs and his team. I used commit
> d25a3def972b15ec029ae838f1a8a677d2d158bd from October 20 for the results
> below. Repo: https://github.com/unhurdle/spectrum-royale/
>
> To establish a baseline, I built all of these projects with the older
> Royale 0.9.7 compiler first.
>
> ==========
> Baseline: royale-compiler 0.9.7
> ==========
>
> HelloWorld: 68 KB
> ASDoc: 231 KB
> TourDeJewel: 1074 KB
> SpectrumBrowser: 900 KB
>
> Again, I am building the same AS3/MXML code every time, but these first
> numbers are from building with the older compiler. All apps build and run
> successfully.
>
> -----
>
> The rest of the results are built with royale-compiler commit
> df8bd9f686f1bbf89539e545377b2797c646172c from November 3.
>
> All results below include the difference in KB and %. These values are
> always in comparison to the baseline numbers above.
>
> ==========
> Result 1: 0.9.8 default options
> ==========
>
> HelloWorld: 84 KB (+10 KB / +24%)
> ASDoc: 254 KB (+23 KB / +10%)
> TourDeJewel: 1105 KB (+31 KB / +3%)
> SpectrumBrowser: 936 KB (+36 KB / +4%)
>
> These examples are slightly larger when built with the newer compiler.
> That's expected. It's not ideal, but in the process of testing a multitude
> of things to be sure that nothing had broken after my compiler changes, I
> discovered some cases where exporting a symbol didn't actually work
> correctly in 0.9.7! To properly fix the bug and export these symbols, there
> was no choice but to make the file size a bit larger.
>
> ==========
> Result 2: Disable export
> ==========
>
> HelloWorld: 74 KB (+6 KB / +9%)
> ASDoc: 227 KB (-4 KB / -2%)
> TourDeJewel: 942 KB (-132 KB / -12%)
> SpectrumBrowser: 882 KB (-18 KB / -2%)
>
> In this round, I added the *-export-public-symbols=false* compiler option.
> You may recall that I said earlier that I also modified the compiler to
> allow a symbol not to be exported, but still prevent it from being renamed.
> With that in mind, -export-public-symbols=false basically tells the
> compiler that it still can't rename things, but it is allowed to remove
> what it perceives as dead code.
>
> HelloWorld is still slightly larger than 0.9.7, but the three other
> examples are now slightly smaller than 0.9.7.
>
> Most developers should be able to safely add -export-public-symbols=false
> to their compiler options when building a Royale app. The only time that
> you might still want this exporting is if you have external JavaScript in
> your page that isn't part of your Royale app, but it needs to call
> functions/classes in your Royale app.
>
> ==========
> Result 3: Allow non-public things to be renamed
> ==========
>
> HelloWorld: 72 KB (+4 KB / +6%)
> ASDoc: 221 KB (-10 KB / -4%)
> TourDeJewel: 918 KB (-156 KB / -15%)
> SpectrumBrowser: 861 KB (-39 KB / -4%)
>
> In this round, I used the following compiler options:
>
> -export-public-symbols=false
>
>
> *-prevent-rename-protected-symbols=false-prevent-rename-internal-symbols=false*
>
> The two new options allow Closure compiler to rename protected and internal
> symbols. Once again, HelloWorld is still slightly larger than 0.9.7, but
> the other three examples have gotten smaller again.
>
> While -prevent-rename-public-symbols=false exists too, we cannot use it.
> The examples would not work correctly at runtime. This option would
> probably work in a pure AS3 app, but our implementation of MXML in Royale
> uses dynamic language features that Closure restricts. Unless that is
> fixed, we need to avoid renaming certain public symbols.
>
> Again, most developers should be able to add
> -prevent-rename-protected-symbols=false
> and -prevent-rename-internal-symbols=false to their Royale app's compiler
> options. You might need to prevent renaming of protected/internal symbols
> if you access them dynamically. However, in my experience, people are much
> more likely to access public symbols dynamically.
>
> -----
>
> ==========
> Result 4: Allow public methods to be renamed
> ==========
>
> HelloWorld: 64 KB (-4 KB / -6%)
> ASDoc: 206 KB (-25 KB / -11%)
> TourDeJewel: 881 KB (-193 KB / -18%)
> SpectrumBrowser: 828 KB (-72 KB / -8%)
>
> In this round, I used the following compiler options:
>
> -export-public-symbols=false
> -prevent-rename-protected-symbols=false
> -prevent-rename-internal-symbols=false
>
>
> *-prevent-rename-public-static-methods=false-prevent-rename-public-instance-methods=false
> *
>
> The two new options allow Closure to rename methods that are public. Now,
> all four examples are smaller than 0.9.7, and the file size difference is
> getting even more dramatic.
>
> Once again, -prevent-rename-public-static-methods=false and
> -prevent-rename-public-instance-methods=false should be safe for most
> developers to enable when compiling their Royale app. In my experience,
> calling methods dynamically is rare.
>
> ==========
> More new compiler options
> ==========
>
> There are some additional new compiler options available, but using them is
> likely to break most Royale apps.
>
> -prevent-rename-public-static-variables=false
> -prevent-rename-public-instance-variables=false
> -prevent-rename-public-static-accessors=false
> -prevent-rename-public-instance-accessors=false
>
> These options control whether Closure allows variables or accessors
> (getters and setters) to be renamed. There are also similarly-named options
> for protected and internal symbols, if you want more control over those
> too, instead of using -prevent-rename-protected-symbols=false and
> -prevent-rename-internal-symbols=false.
>
> Unfortunately, renaming public variables/accessors is usually not possible
> without breaking the app at runtime. In some apps, you might be able to
> allow public static members to be renamed. However, in my experience,
> binding to static constants is pretty common, and renaming breaks those
> bindings.
>
> ==========
> Next Steps
> ==========
>
> Ideally, I'd like to make it possible for developers to be able to tell
> Closure that it's allowed to rename all symbols, including public ones. I
> believe that we could see even more file size savings in release builds if
> Closure works with full optimizations for all symbols. Obviously,
> ActionScript developers would be required to strictly follow Closure's
> rules, if they opt into renaming of public symbols, but that's a choice
> that they should be allowed to make.
>
> As I mentioned above, our implementation of MXML and binding uses dynamic
> access, which is not compatible with Closure's full optimizations. To
> support those optimizations, I will need to explore changes to how we
> generate JS for MXML, and how it gets parsed at runtime.
>
> We previously discussed this subject a bit in this older thread from
> January 2020:
>
>
> https://lists.apache.org/thread.html/r843e55252e37967b71b1430a2a904719791d698f3e5e2a79de74e493%40%3Cdev.royale.apache.org%3E
>
> At the time, I tried out some ideas that we came up with while
> brainstorming, but all had various downsides that didn't make for an
> obvious winner. In the end, I decided to set further investigation aside
> and first focus on exporting/renaming stuff. Now, I'm ready to take a
> second look with a fresh perspective, and maybe we'll have some new ideas
> to try.
>
> -----
>
> That was really long, so thank you for reading, if you made it to the end!
>
> TL;DR: By enabling certain, new compiler options, most Royale developers
> can make their app release builds smaller. Additionally, I plan to keep
> investigating, and I expect to find more ways to reduce file size in the
> future.
>
> --
> Josh Tynjala
> Bowler Hat LLC <https://bowlerhat.dev>
>

Re: Compiler options for reducing release build size of Royale projects

Posted by Kenny Lerma <ke...@kennylerma.com>.
Perfect!  I forgot about that option since I last attempted using
AVANCED_OPTIMIZATIONS.

That fix it.

Thanks,
Kenny

On Wed, Mar 3, 2021 at 4:50 PM Josh Tynjala <jo...@bowlerhat.dev>
wrote:

> Does -js-dynamic-access-unknown-members=true help? I think that also
> applies to the keys of anonymous objects.
>
> --
> Josh Tynjala
> Bowler Hat LLC <https://bowlerhat.dev>
>
>
> On Wed, Mar 3, 2021 at 2:41 PM Kenny Lerma <ke...@kennylerma.com> wrote:
>
> > Josh, is there a compiler option to prevent the rename of generic object
> > keys?
> >
> > var myvar:Object = {foo : 1, bar : 2}
> >
> > Renamed by closure to...
> >   var myvar:Object = {ad: 1, hb: 2}
> >
> > I'm using Tweener in SpriteFlexJS which receives a generic object of
> > properties for tweening, but I can't use ADVANCED_OPTIMIZATIONS because
> of
> > the re-name.
> >
> > On Mon, Nov 9, 2020 at 4:16 PM Josh Tynjala <jo...@bowlerhat.dev>
> > wrote:
> >
> > > Hi all,
> > >
> > > Some of you have probably been wondering about my changes to the
> compiler
> > > over the last year or more. I apologize again for occasionally breaking
> > > things for short periods. It's been quite a challenge getting this
> stuff
> > > working, but I'm excited to finally be able to report some real
> > > improvements that pretty much anyone should be able to take advantage
> of
> > > when building a Royale app.
> > >
> > > First some background. A while back, Harbs asked me to look into ways
> of
> > > reducing the file size of release builds. As you may know, we use
> > Google's
> > > Closure compiler to optimize our generated JavaScript. Closure can be
> > very
> > > aggressive in its optimizations, by renaming symbols (things like
> > variable
> > > and function names) and removing "dead code" that is detected as never
> > > being called.
> > >
> > > Closure's optimizations are good, but they also require developers to
> be
> > > very careful about how they write their JavaScript code. When you
> enable
> > > Closure's full optimizations, you are not allowed to use certain
> > JavaScript
> > > features because Closure cannot analyze them properly. For instance,
> > > consider the following code:
> > >
> > > var propName= "myProp";
> > > var value = obj[propName];
> > >
> > > When you dynamically access a property with a string, Closure cannot
> > > reliably know that the property exists and will be accessed at runtime.
> > It
> > > may decide to rename or remove that property, which would break things
> at
> > > runtime.
> > >
> > > ActionScript supports many of the same restricted dynamic features too,
> > so
> > > if you want to support the entire AS3 language, we can't let Closure do
> > its
> > > full optimization. Luckily, Closure also provides a bit of a backdoor:
> it
> > > allows you to "export" symbols, which means that they won't be renamed
> > and
> > > they won't be removed as dead code. Traditionally, we have made heavy
> use
> > > of this exporting feature in Royale.
> > >
> > > Harbs wanted to know if we absolutely needed to export everything that
> we
> > > currently export, and if we could potentially allow developers to turn
> > off
> > > exporting entirely, as long as they follow the stricter rules required
> by
> > > Closure.
> > >
> > > I won't go into all of the details, but over the last several months,
> > I've
> > > been changing the compiler to give developers more control over release
> > > builds. In particular, control over which symbols get exported, but
> also
> > > the ability to block Closure from renaming symbols that haven't been
> > > exported.
> > >
> > > Now, for some of the results. I'm going to share the output file size
> of
> > > the release build for several Royale projects with various different
> > > compiler options.
> > >
> > > For the example projects included with Royale, I built royale-asjs
> commit
> > > 94f12ed0e564b0b443834400dc2fc06d61b90a8a from October 26, 2020. If you
> > want
> > > to try building these examples yourself, the file sizes of release
> builds
> > > may be slightly different, if you use a different commit.
> > >
> > > SpectrumBrowser is a project developed by Harbs and his team. I used
> > commit
> > > d25a3def972b15ec029ae838f1a8a677d2d158bd from October 20 for the
> results
> > > below. Repo: https://github.com/unhurdle/spectrum-royale/
> > >
> > > To establish a baseline, I built all of these projects with the older
> > > Royale 0.9.7 compiler first.
> > >
> > > ==========
> > > Baseline: royale-compiler 0.9.7
> > > ==========
> > >
> > > HelloWorld: 68 KB
> > > ASDoc: 231 KB
> > > TourDeJewel: 1074 KB
> > > SpectrumBrowser: 900 KB
> > >
> > > Again, I am building the same AS3/MXML code every time, but these first
> > > numbers are from building with the older compiler. All apps build and
> run
> > > successfully.
> > >
> > > -----
> > >
> > > The rest of the results are built with royale-compiler commit
> > > df8bd9f686f1bbf89539e545377b2797c646172c from November 3.
> > >
> > > All results below include the difference in KB and %. These values are
> > > always in comparison to the baseline numbers above.
> > >
> > > ==========
> > > Result 1: 0.9.8 default options
> > > ==========
> > >
> > > HelloWorld: 84 KB (+10 KB / +24%)
> > > ASDoc: 254 KB (+23 KB / +10%)
> > > TourDeJewel: 1105 KB (+31 KB / +3%)
> > > SpectrumBrowser: 936 KB (+36 KB / +4%)
> > >
> > > These examples are slightly larger when built with the newer compiler.
> > > That's expected. It's not ideal, but in the process of testing a
> > multitude
> > > of things to be sure that nothing had broken after my compiler
> changes, I
> > > discovered some cases where exporting a symbol didn't actually work
> > > correctly in 0.9.7! To properly fix the bug and export these symbols,
> > there
> > > was no choice but to make the file size a bit larger.
> > >
> > > ==========
> > > Result 2: Disable export
> > > ==========
> > >
> > > HelloWorld: 74 KB (+6 KB / +9%)
> > > ASDoc: 227 KB (-4 KB / -2%)
> > > TourDeJewel: 942 KB (-132 KB / -12%)
> > > SpectrumBrowser: 882 KB (-18 KB / -2%)
> > >
> > > In this round, I added the *-export-public-symbols=false* compiler
> > option.
> > > You may recall that I said earlier that I also modified the compiler to
> > > allow a symbol not to be exported, but still prevent it from being
> > renamed.
> > > With that in mind, -export-public-symbols=false basically tells the
> > > compiler that it still can't rename things, but it is allowed to remove
> > > what it perceives as dead code.
> > >
> > > HelloWorld is still slightly larger than 0.9.7, but the three other
> > > examples are now slightly smaller than 0.9.7.
> > >
> > > Most developers should be able to safely add
> -export-public-symbols=false
> > > to their compiler options when building a Royale app. The only time
> that
> > > you might still want this exporting is if you have external JavaScript
> in
> > > your page that isn't part of your Royale app, but it needs to call
> > > functions/classes in your Royale app.
> > >
> > > ==========
> > > Result 3: Allow non-public things to be renamed
> > > ==========
> > >
> > > HelloWorld: 72 KB (+4 KB / +6%)
> > > ASDoc: 221 KB (-10 KB / -4%)
> > > TourDeJewel: 918 KB (-156 KB / -15%)
> > > SpectrumBrowser: 861 KB (-39 KB / -4%)
> > >
> > > In this round, I used the following compiler options:
> > >
> > > -export-public-symbols=false
> > >
> > >
> > >
> >
> *-prevent-rename-protected-symbols=false-prevent-rename-internal-symbols=false*
> > >
> > > The two new options allow Closure compiler to rename protected and
> > internal
> > > symbols. Once again, HelloWorld is still slightly larger than 0.9.7,
> but
> > > the other three examples have gotten smaller again.
> > >
> > > While -prevent-rename-public-symbols=false exists too, we cannot use
> it.
> > > The examples would not work correctly at runtime. This option would
> > > probably work in a pure AS3 app, but our implementation of MXML in
> Royale
> > > uses dynamic language features that Closure restricts. Unless that is
> > > fixed, we need to avoid renaming certain public symbols.
> > >
> > > Again, most developers should be able to add
> > > -prevent-rename-protected-symbols=false
> > > and -prevent-rename-internal-symbols=false to their Royale app's
> compiler
> > > options. You might need to prevent renaming of protected/internal
> symbols
> > > if you access them dynamically. However, in my experience, people are
> > much
> > > more likely to access public symbols dynamically.
> > >
> > > -----
> > >
> > > ==========
> > > Result 4: Allow public methods to be renamed
> > > ==========
> > >
> > > HelloWorld: 64 KB (-4 KB / -6%)
> > > ASDoc: 206 KB (-25 KB / -11%)
> > > TourDeJewel: 881 KB (-193 KB / -18%)
> > > SpectrumBrowser: 828 KB (-72 KB / -8%)
> > >
> > > In this round, I used the following compiler options:
> > >
> > > -export-public-symbols=false
> > > -prevent-rename-protected-symbols=false
> > > -prevent-rename-internal-symbols=false
> > >
> > >
> > >
> >
> *-prevent-rename-public-static-methods=false-prevent-rename-public-instance-methods=false
> > > *
> > >
> > > The two new options allow Closure to rename methods that are public.
> Now,
> > > all four examples are smaller than 0.9.7, and the file size difference
> is
> > > getting even more dramatic.
> > >
> > > Once again, -prevent-rename-public-static-methods=false and
> > > -prevent-rename-public-instance-methods=false should be safe for most
> > > developers to enable when compiling their Royale app. In my experience,
> > > calling methods dynamically is rare.
> > >
> > > ==========
> > > More new compiler options
> > > ==========
> > >
> > > There are some additional new compiler options available, but using
> them
> > is
> > > likely to break most Royale apps.
> > >
> > > -prevent-rename-public-static-variables=false
> > > -prevent-rename-public-instance-variables=false
> > > -prevent-rename-public-static-accessors=false
> > > -prevent-rename-public-instance-accessors=false
> > >
> > > These options control whether Closure allows variables or accessors
> > > (getters and setters) to be renamed. There are also similarly-named
> > options
> > > for protected and internal symbols, if you want more control over those
> > > too, instead of using -prevent-rename-protected-symbols=false and
> > > -prevent-rename-internal-symbols=false.
> > >
> > > Unfortunately, renaming public variables/accessors is usually not
> > possible
> > > without breaking the app at runtime. In some apps, you might be able to
> > > allow public static members to be renamed. However, in my experience,
> > > binding to static constants is pretty common, and renaming breaks those
> > > bindings.
> > >
> > > ==========
> > > Next Steps
> > > ==========
> > >
> > > Ideally, I'd like to make it possible for developers to be able to tell
> > > Closure that it's allowed to rename all symbols, including public
> ones. I
> > > believe that we could see even more file size savings in release builds
> > if
> > > Closure works with full optimizations for all symbols. Obviously,
> > > ActionScript developers would be required to strictly follow Closure's
> > > rules, if they opt into renaming of public symbols, but that's a choice
> > > that they should be allowed to make.
> > >
> > > As I mentioned above, our implementation of MXML and binding uses
> dynamic
> > > access, which is not compatible with Closure's full optimizations. To
> > > support those optimizations, I will need to explore changes to how we
> > > generate JS for MXML, and how it gets parsed at runtime.
> > >
> > > We previously discussed this subject a bit in this older thread from
> > > January 2020:
> > >
> > >
> > >
> >
> https://lists.apache.org/thread.html/r843e55252e37967b71b1430a2a904719791d698f3e5e2a79de74e493%40%3Cdev.royale.apache.org%3E
> > >
> > > At the time, I tried out some ideas that we came up with while
> > > brainstorming, but all had various downsides that didn't make for an
> > > obvious winner. In the end, I decided to set further investigation
> aside
> > > and first focus on exporting/renaming stuff. Now, I'm ready to take a
> > > second look with a fresh perspective, and maybe we'll have some new
> ideas
> > > to try.
> > >
> > > -----
> > >
> > > That was really long, so thank you for reading, if you made it to the
> > end!
> > >
> > > TL;DR: By enabling certain, new compiler options, most Royale
> developers
> > > can make their app release builds smaller. Additionally, I plan to keep
> > > investigating, and I expect to find more ways to reduce file size in
> the
> > > future.
> > >
> > > --
> > > Josh Tynjala
> > > Bowler Hat LLC <https://bowlerhat.dev>
> > >
> >
>

Re: Compiler options for reducing release build size of Royale projects

Posted by Josh Tynjala <jo...@bowlerhat.dev>.
Does -js-dynamic-access-unknown-members=true help? I think that also
applies to the keys of anonymous objects.

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


On Wed, Mar 3, 2021 at 2:41 PM Kenny Lerma <ke...@kennylerma.com> wrote:

> Josh, is there a compiler option to prevent the rename of generic object
> keys?
>
> var myvar:Object = {foo : 1, bar : 2}
>
> Renamed by closure to...
>   var myvar:Object = {ad: 1, hb: 2}
>
> I'm using Tweener in SpriteFlexJS which receives a generic object of
> properties for tweening, but I can't use ADVANCED_OPTIMIZATIONS because of
> the re-name.
>
> On Mon, Nov 9, 2020 at 4:16 PM Josh Tynjala <jo...@bowlerhat.dev>
> wrote:
>
> > Hi all,
> >
> > Some of you have probably been wondering about my changes to the compiler
> > over the last year or more. I apologize again for occasionally breaking
> > things for short periods. It's been quite a challenge getting this stuff
> > working, but I'm excited to finally be able to report some real
> > improvements that pretty much anyone should be able to take advantage of
> > when building a Royale app.
> >
> > First some background. A while back, Harbs asked me to look into ways of
> > reducing the file size of release builds. As you may know, we use
> Google's
> > Closure compiler to optimize our generated JavaScript. Closure can be
> very
> > aggressive in its optimizations, by renaming symbols (things like
> variable
> > and function names) and removing "dead code" that is detected as never
> > being called.
> >
> > Closure's optimizations are good, but they also require developers to be
> > very careful about how they write their JavaScript code. When you enable
> > Closure's full optimizations, you are not allowed to use certain
> JavaScript
> > features because Closure cannot analyze them properly. For instance,
> > consider the following code:
> >
> > var propName= "myProp";
> > var value = obj[propName];
> >
> > When you dynamically access a property with a string, Closure cannot
> > reliably know that the property exists and will be accessed at runtime.
> It
> > may decide to rename or remove that property, which would break things at
> > runtime.
> >
> > ActionScript supports many of the same restricted dynamic features too,
> so
> > if you want to support the entire AS3 language, we can't let Closure do
> its
> > full optimization. Luckily, Closure also provides a bit of a backdoor: it
> > allows you to "export" symbols, which means that they won't be renamed
> and
> > they won't be removed as dead code. Traditionally, we have made heavy use
> > of this exporting feature in Royale.
> >
> > Harbs wanted to know if we absolutely needed to export everything that we
> > currently export, and if we could potentially allow developers to turn
> off
> > exporting entirely, as long as they follow the stricter rules required by
> > Closure.
> >
> > I won't go into all of the details, but over the last several months,
> I've
> > been changing the compiler to give developers more control over release
> > builds. In particular, control over which symbols get exported, but also
> > the ability to block Closure from renaming symbols that haven't been
> > exported.
> >
> > Now, for some of the results. I'm going to share the output file size of
> > the release build for several Royale projects with various different
> > compiler options.
> >
> > For the example projects included with Royale, I built royale-asjs commit
> > 94f12ed0e564b0b443834400dc2fc06d61b90a8a from October 26, 2020. If you
> want
> > to try building these examples yourself, the file sizes of release builds
> > may be slightly different, if you use a different commit.
> >
> > SpectrumBrowser is a project developed by Harbs and his team. I used
> commit
> > d25a3def972b15ec029ae838f1a8a677d2d158bd from October 20 for the results
> > below. Repo: https://github.com/unhurdle/spectrum-royale/
> >
> > To establish a baseline, I built all of these projects with the older
> > Royale 0.9.7 compiler first.
> >
> > ==========
> > Baseline: royale-compiler 0.9.7
> > ==========
> >
> > HelloWorld: 68 KB
> > ASDoc: 231 KB
> > TourDeJewel: 1074 KB
> > SpectrumBrowser: 900 KB
> >
> > Again, I am building the same AS3/MXML code every time, but these first
> > numbers are from building with the older compiler. All apps build and run
> > successfully.
> >
> > -----
> >
> > The rest of the results are built with royale-compiler commit
> > df8bd9f686f1bbf89539e545377b2797c646172c from November 3.
> >
> > All results below include the difference in KB and %. These values are
> > always in comparison to the baseline numbers above.
> >
> > ==========
> > Result 1: 0.9.8 default options
> > ==========
> >
> > HelloWorld: 84 KB (+10 KB / +24%)
> > ASDoc: 254 KB (+23 KB / +10%)
> > TourDeJewel: 1105 KB (+31 KB / +3%)
> > SpectrumBrowser: 936 KB (+36 KB / +4%)
> >
> > These examples are slightly larger when built with the newer compiler.
> > That's expected. It's not ideal, but in the process of testing a
> multitude
> > of things to be sure that nothing had broken after my compiler changes, I
> > discovered some cases where exporting a symbol didn't actually work
> > correctly in 0.9.7! To properly fix the bug and export these symbols,
> there
> > was no choice but to make the file size a bit larger.
> >
> > ==========
> > Result 2: Disable export
> > ==========
> >
> > HelloWorld: 74 KB (+6 KB / +9%)
> > ASDoc: 227 KB (-4 KB / -2%)
> > TourDeJewel: 942 KB (-132 KB / -12%)
> > SpectrumBrowser: 882 KB (-18 KB / -2%)
> >
> > In this round, I added the *-export-public-symbols=false* compiler
> option.
> > You may recall that I said earlier that I also modified the compiler to
> > allow a symbol not to be exported, but still prevent it from being
> renamed.
> > With that in mind, -export-public-symbols=false basically tells the
> > compiler that it still can't rename things, but it is allowed to remove
> > what it perceives as dead code.
> >
> > HelloWorld is still slightly larger than 0.9.7, but the three other
> > examples are now slightly smaller than 0.9.7.
> >
> > Most developers should be able to safely add -export-public-symbols=false
> > to their compiler options when building a Royale app. The only time that
> > you might still want this exporting is if you have external JavaScript in
> > your page that isn't part of your Royale app, but it needs to call
> > functions/classes in your Royale app.
> >
> > ==========
> > Result 3: Allow non-public things to be renamed
> > ==========
> >
> > HelloWorld: 72 KB (+4 KB / +6%)
> > ASDoc: 221 KB (-10 KB / -4%)
> > TourDeJewel: 918 KB (-156 KB / -15%)
> > SpectrumBrowser: 861 KB (-39 KB / -4%)
> >
> > In this round, I used the following compiler options:
> >
> > -export-public-symbols=false
> >
> >
> >
> *-prevent-rename-protected-symbols=false-prevent-rename-internal-symbols=false*
> >
> > The two new options allow Closure compiler to rename protected and
> internal
> > symbols. Once again, HelloWorld is still slightly larger than 0.9.7, but
> > the other three examples have gotten smaller again.
> >
> > While -prevent-rename-public-symbols=false exists too, we cannot use it.
> > The examples would not work correctly at runtime. This option would
> > probably work in a pure AS3 app, but our implementation of MXML in Royale
> > uses dynamic language features that Closure restricts. Unless that is
> > fixed, we need to avoid renaming certain public symbols.
> >
> > Again, most developers should be able to add
> > -prevent-rename-protected-symbols=false
> > and -prevent-rename-internal-symbols=false to their Royale app's compiler
> > options. You might need to prevent renaming of protected/internal symbols
> > if you access them dynamically. However, in my experience, people are
> much
> > more likely to access public symbols dynamically.
> >
> > -----
> >
> > ==========
> > Result 4: Allow public methods to be renamed
> > ==========
> >
> > HelloWorld: 64 KB (-4 KB / -6%)
> > ASDoc: 206 KB (-25 KB / -11%)
> > TourDeJewel: 881 KB (-193 KB / -18%)
> > SpectrumBrowser: 828 KB (-72 KB / -8%)
> >
> > In this round, I used the following compiler options:
> >
> > -export-public-symbols=false
> > -prevent-rename-protected-symbols=false
> > -prevent-rename-internal-symbols=false
> >
> >
> >
> *-prevent-rename-public-static-methods=false-prevent-rename-public-instance-methods=false
> > *
> >
> > The two new options allow Closure to rename methods that are public. Now,
> > all four examples are smaller than 0.9.7, and the file size difference is
> > getting even more dramatic.
> >
> > Once again, -prevent-rename-public-static-methods=false and
> > -prevent-rename-public-instance-methods=false should be safe for most
> > developers to enable when compiling their Royale app. In my experience,
> > calling methods dynamically is rare.
> >
> > ==========
> > More new compiler options
> > ==========
> >
> > There are some additional new compiler options available, but using them
> is
> > likely to break most Royale apps.
> >
> > -prevent-rename-public-static-variables=false
> > -prevent-rename-public-instance-variables=false
> > -prevent-rename-public-static-accessors=false
> > -prevent-rename-public-instance-accessors=false
> >
> > These options control whether Closure allows variables or accessors
> > (getters and setters) to be renamed. There are also similarly-named
> options
> > for protected and internal symbols, if you want more control over those
> > too, instead of using -prevent-rename-protected-symbols=false and
> > -prevent-rename-internal-symbols=false.
> >
> > Unfortunately, renaming public variables/accessors is usually not
> possible
> > without breaking the app at runtime. In some apps, you might be able to
> > allow public static members to be renamed. However, in my experience,
> > binding to static constants is pretty common, and renaming breaks those
> > bindings.
> >
> > ==========
> > Next Steps
> > ==========
> >
> > Ideally, I'd like to make it possible for developers to be able to tell
> > Closure that it's allowed to rename all symbols, including public ones. I
> > believe that we could see even more file size savings in release builds
> if
> > Closure works with full optimizations for all symbols. Obviously,
> > ActionScript developers would be required to strictly follow Closure's
> > rules, if they opt into renaming of public symbols, but that's a choice
> > that they should be allowed to make.
> >
> > As I mentioned above, our implementation of MXML and binding uses dynamic
> > access, which is not compatible with Closure's full optimizations. To
> > support those optimizations, I will need to explore changes to how we
> > generate JS for MXML, and how it gets parsed at runtime.
> >
> > We previously discussed this subject a bit in this older thread from
> > January 2020:
> >
> >
> >
> https://lists.apache.org/thread.html/r843e55252e37967b71b1430a2a904719791d698f3e5e2a79de74e493%40%3Cdev.royale.apache.org%3E
> >
> > At the time, I tried out some ideas that we came up with while
> > brainstorming, but all had various downsides that didn't make for an
> > obvious winner. In the end, I decided to set further investigation aside
> > and first focus on exporting/renaming stuff. Now, I'm ready to take a
> > second look with a fresh perspective, and maybe we'll have some new ideas
> > to try.
> >
> > -----
> >
> > That was really long, so thank you for reading, if you made it to the
> end!
> >
> > TL;DR: By enabling certain, new compiler options, most Royale developers
> > can make their app release builds smaller. Additionally, I plan to keep
> > investigating, and I expect to find more ways to reduce file size in the
> > future.
> >
> > --
> > Josh Tynjala
> > Bowler Hat LLC <https://bowlerhat.dev>
> >
>