Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minimization #116

Closed
yaras6 opened this issue Feb 17, 2017 · 7 comments
Closed

Minimization #116

yaras6 opened this issue Feb 17, 2017 · 7 comments
Assignees
Labels
platform-javascript Related to the JavaScript version of alphaTab state-accepted This is a valid topic to work on. state-needs-discussion 💬

Comments

@yaras6
Copy link

yaras6 commented Feb 17, 2017

Hi,

Code works fine, until I have in C# MVC BundleTable.Optimization = false. When optimization is enabled I have following error:

Error: Uncaught ReferenceError: jQuery is not defined
at self.onmessage (blob:http://localhost/24ae1dc7-2b46-488f-b546-5c2366a47256:3)

Problematic function is importScripts(e.data.alphaSynthScript);

My bundle is
bundles.Add(new ScriptBundle("/Scripts/alphaTab/bundle").Include(
"
/Scripts/alphaTab/AlphaTab.js",
"/Scripts/alphaTab/jquery.alphaTab.js",
"
/Scripts/alphaTab/lib/swfobject/swfobject.js",
"/Scripts/alphaTab/lib/alphaSynth/AlphaSynth.js",
"
/Scripts/alphaTab/jquery.alphaTab.alphaSynth.js"));

I saw that the problematic function 'importScripts' is defined in string. Could you change this code or it is not possible to do that in easy way? Or may be am I doing something wrong? Thanks in advance for your support

@Danielku15
Copy link
Member

Danielku15 commented Feb 17, 2017

Hi.
For now there are 2 solutions on this problem.

  1. Create 2 bundles, one for the jQuery part, one for the rest.
bundles.Add(new ScriptBundle("~/Scripts/alphaTab/bundle").Include(
    "~/Scripts/alphaTab/AlphaTab.js",
    "~/Scripts/alphaTab/lib/alphaSynth/alphaSynth.js"
);
bundles.Add(new ScriptBundle("~/Scripts/alphaTabJQuery/bundle").Include(
    "~/Scripts/alphaTab/lib/swfobject.js"
    "~/Scripts/alphaTab/jquery.alphaTab.js",
    "~/Scripts/alphaTab/jquery.alphaTab.alphaSynth.js",
);
  1. Explicitely tell alphaTab where the "raw" alphaTab script file is.
$('.alphaTab').alphaTab({
    scriptFile: '@Url.Content("~/Scripts/alphaTab/AlphaTab.js")'
});

The reason is quite simple: for convenience alphaTab tries to find the path to the alphaTab.js automatically and uses it when rendering in a WebWorker. If you bundle the jQuery plugin with the main script, it will load the bundle in the worker where jQuery is missing.

I will try to add some checks to the jQuery files whether jQuery is even available and skip any initialization in this case. This way you should be able to bundle everything together without errors.

Danielku15 added a commit that referenced this issue Feb 17, 2017
…and font variables for better minification support (#106, #116)
@Danielku15
Copy link
Member

I did a small test on minification and was able to setup a project where minification works. Sadly one (newly introduced) global variable or initialization value needs to be set. AlphaTab itself was working nice, but the Web-Font also needs to be properly located. I had this setup:

// BundleConfig.cs
bundles.Add(new ScriptBundle("~/bundles/alphaTab").Include(
    "~/Scripts/alphaTab/AlphaTab.js",
    "~/Scripts/alphaSynth/AlphaSynth.js",
    "~/Scripts/swfobject/swfobject.js",
    "~/Scripts/alphaTab/jquery.alphaTab.js",
    "~/Scripts/alphaTab/jquery.alphaTab.alphaSynth.js"
));

And the initialization via:

<script type="text/javascript">
    // this global variable tells alphaTab where to find the WebFonts
    var ALPHATAB_FONT = '@Url.Content("~/Scripts/alphaTab/Font")';
    var at = $('#alphaTab');
    at.alphaTab({
        width: -1,
        useWorker: true
    });
</script>
or 
<script type="text/javascript">  
    var at = $('#alphaTab');
    at.alphaTab({
        width: -1,
        useWorker: true,
        fontDirectory: '@Url.Content("~/Scripts/alphaTab/Font")'
    });
</script>

I introduced the global variable because it suits the bundeling better. If you want to put also your initialization code into the bundle or a separate JS file, you only need to define the global variable somewhere in your Razor templates. If you use other mechanisms to build application relative URLs you would also not need the global variable. It just gives the biggest amount of flexibility.

@Danielku15 Danielku15 self-assigned this Feb 17, 2017
@Danielku15 Danielku15 added state-accepted This is a valid topic to work on. Improvement platform-javascript Related to the JavaScript version of alphaTab state-needs-discussion 💬 labels Feb 17, 2017
@yaras6
Copy link
Author

yaras6 commented Feb 18, 2017

Hey,

Looks better, but now I have error like this

Uncaught ReferenceError: window is not defined (anonymous) @ alphaTab?v=8irVtNu4ypmERibLkWH-KF0PbpgboKFucMK25s_9N-w1:1 (anonymous) @ alphaTab?v=8irVtNu4ypmERibLkWH-KF0PbpgboKFucMK25s_9N-w1:1 alphaTab?v=8irVtNu4ypmERibLkWH-KF0PbpgboKFucMK25s_9N-w1:1 Uncaught TypeError: Cannot read property 'GetMasterBarStart' of undefined at HTMLDivElement.<anonymous> (alphaTab?v=8irVtNu4ypmERibLkWH-KF0PbpgboKFucMK25s_9N-w1:1) at HTMLDivElement.dispatch (jquery?v=DilzeZuJxdbQsfc_JOwsWB4VFDhTPM73urYeggaKdL81:1) at HTMLDivElement.a.handle (jquery?v=DilzeZuJxdbQsfc_JOwsWB4VFDhTPM73urYeggaKdL81:1)

In this code:

       var tickCache = at.alphaTab('getTickCache');

        var scope = angular.element($("#player-footer")).scope();
        var mb = scope.Score.MasterBars[index];
        var realStart = tickCache.GetMasterBarStart(mb);

        as.SetPositionTick(realStart);

But getTickCache it is new api function, so may by you forgotten something? Problem occures only when I have
BundleTable.EnableOptimizations = true;

Thanks,
Jarek

@Danielku15
Copy link
Member

The code you posted is not from alphaTab. Just from what I see is: you are using angularjs. I told you: alphaTab is launching itself in a worker. Angular cannot run in WebWorkers. You can't access any DOM elements within the WebWorkers. So basically: the error you posted is not alphaTab's fault. Even the code you pasted is not from alphaTab. It's your own code that is not working. I am happy to assisst you with alphaTab specific scenarios, but this is definitly something specific to your bundeling and your project.

@yaras6
Copy link
Author

yaras6 commented Feb 19, 2017

Ok, may be you are right, it is not good example. I made second test based on this example:
https://jsfiddle.net/danielku15/zvq0mm14/

To HTML I added bundles to alphaTab and js from your example (I added only fontDirectory to js eample)
@section scripts {
@Scripts.Render("/bundles/alphaTab")
@Scripts.Render("
/bundles/test")
}

In this case again it do not work when in BundleConfig I defined BundleTable.EnableOptimizations = true; Without optimization this example works fine. If it is possible please test it on your example. I can prepare a test project and share it with you if you prefer. This issue it is not very urgent, but I love Bundle concept, because I don't need to care about cached scripts after library changes.

To be honest, in my case angular works because I update my scope only on loaded event. Angular only renders tracks and bars. Is it bad solution in your opinion?

@Danielku15
Copy link
Member

In my opinion it would be better to bundle all alphaTab and alphaSynth libs but keep your page/UI specific code separately. This way you do not need to worry about the issues of anybody accessing the DOM from the WebWorker that alphaTab launches.

Both alphaTab and alphaSynth launch workers in the background that will be based on the bundle. There is a solution where you tell alphaTab to only load a specific JS file for the worker, but this way clients would need to load the alphaTab/alphaSynth bundle + alphaTab.js + alphaSynth.js (bad for bundeling/latency). If you bundle alphaTab and alphaSynth together, the browser will load the bundle only once and can spawn all Workers from it (yeay, no DOM access in workers). The init code would need to be separately loaded.

If you really also want to bundle your custom script together with alphaTab you would need to add a dedicated check whether you are running in a WebWorker and skip all your code:

// alphaTabInit.js
(function() {
  // skip UI specific code in case document is not available (like in workers)
  if(!self.document) { return; }

  // your UI specific code.   
})();

@Danielku15
Copy link
Member

I will close this issue. I've added to alphaTab what's possible to support various mechanisms of minifications. If you have some more alphaTab dedicated questions, feel free to reopen this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
platform-javascript Related to the JavaScript version of alphaTab state-accepted This is a valid topic to work on. state-needs-discussion 💬
Projects
None yet
Development

No branches or pull requests

2 participants