Sp-dev-docs: Extensions: Application Customizer - Loading JS Files in <HEAD> Tags

Created on 8 Jun 2017  ·  13Comments  ·  Source: SharePoint/sp-dev-docs

Category

  • [X] Question
  • [ ] Typo
  • [ ] Bug
  • [ ] Additional article idea

The current architecture of the SPFx Extensions allow for us to populate "Placeholders", such as PageHead and PageFooter with content.

If we need to load JS files though, be them stored within SP or externally, we would need to add external references into the "HEAD" tag of the page.

We can use the current placeholders to dynamically update the tag, but this seems less then optimal.

Classic UCA's allowed for multiple JS references, as well as the sequence in which they were loaded. (Ex: Load jQuery prior to loading a Utility JS file that is dependent on jQuery.)

Replicating this functionality for SPFx Extensions would allow better inclusion of JS functions needed site wide.

If you are planning to share a new feature request (enhancement / suggestion), please use SP Dev UserVoice at http://aka.ms/sp-dev-uservoice.
Created Here:
https://sharepoint.uservoice.com/forums/329220-sharepoint-dev-platform/suggestions/19536304-extensions-application-customizer-loading-js-fi

spfx-general uservoice-request

Most helpful comment

Application Customizers may or may not customize the rendering of the application. For example, if you want a timer job running in the background of your application w/o visual elements, you would not need to use placeholders.

We don't recommend creating an extension just for the sake of loading a library.

Right now, the best option is to make the external reference to your library (e.g. jQuery) in each extension separately (and the importing order would solve the problem). Unfortunately, this will result in bundling the library in each bundle file (for each extension/webpart) which is not optimal.

We are aware the issue and we're taking steps to make things simpler and more efficient for bundling third-party libraries and/or multiple SPFx component into one js file, and also particularly make it easier to use jQuery as a library in SPFx w/o having to bundle it for each component separately.

All 13 comments

Hi @PopWarner, thank you for your feedback. We greatly appreciate your feedback. We will add this to the list of requested enhancements for application customizers. @VesaJuvonen for visibility.

I'll just chime in here a bit. We don't really want to go down the path of injecting script tags into head elements. We would rather load scripts using the moduleloader, similar to how SPFX webparts work today.

Pat, thanks for your comment. As you could imagine, there are a variety of ways to accomplish any one thing.

If that is the recommendation from Microsoft for loading scripts that should be available and loaded globally, I would love to see example of how that can be done. I've used the modueloader inside of an SPFX webpart, but that is also done at the web part level, meaning that the JS is not loaded unless the webpart is used, correct?

Can you help me understand how one would properly do that using the Application Customizers extensions to sequentially load JS files and not just populate placeholders? (Example: Loading jquery and once it is loaded, load associated JS files that depend on it, say utility functions, etc.).

While the extensions dev preview is extremely brand new, it seems to be that you have to choose a placeholder upon which to execute and populate your content. But the inclusion of additional JS files is not exactly populating content as is performed in the examples.

Is using these placeholders to simply execute code, such as the moduleloader, to load additional JS files considered acceptable use?

Thanks so much for your input.

@patmill & @VesaJuvonen Thank you guys for listening...you rock.. :)

Hi @PopWarner,

Is using these placeholders to simply execute code, such as the moduleloader, to load additional JS files considered acceptable use?

No. As @patmill pointed out, placeholders should be used only for rendering purposes, not code loading and execution.

It seems you are already aware of how to refer external JavaScript in your web part (as explained here). You can use the same method in Extensions as well. This means that the moduleloader will take care of loading the external module for you upon loading your extension and you can use it in your extension code.

Note that not all ApplicationCustomizer extensions need to use placeholders. So, if you only want to execute code in your application customizer, you can put that code inside onRender() method, and you can obviously use the imported external module in there.

I hope this clarified things.

Hi @moyali

Thank you for following up. I do believe that helps quite a bit. I think the first glance belief for the extensions, at least for the AppCustomizer ext is that it must be used to populate a place holder.

But since you've cleared that up, I appreciate it. It does though I think create a few more questions? LOL

My initial thought is, if you can either execute JS or import 'external' JS, be it a library or any other JS file that may have been home grown, you could end up doing that all in a single AC Ext or you could do it in multiple AC Ext's, correct?

Let's say though you did it in multiple, is there a way to define the order in which your Multiple AC Ext's get executed?

Simple example would be, and not saying this is a preferred path, but it's a possible path one might take, let's say a developer uses two AC Ext's, one for loading jQuery and one for loading another JS file that does something specific and is dependent on jQuery.

Is it possible to define that the jQ Ext should load before the 2nd Ext, which is importing the JS file since it (2nd JS file) is dependent on the jQ Ext? Classic UCA's no doubt do this, allowing you to define the exact sequence JS is loaded, so looking for the equivalent here?

Perhaps the key is simply use one AC Ext for any and all importing and within such controlling the sequence of import, but I'm just thinking through all the scenario's that someone could do and any potential issues with each path, to help determine the best path that makes the most sense. :)

I believe it is also possible to have an AC Ext that executes JS and another that imports JS, if you for example, wanted to segregate execution from importation....so I suppose this too could benefit from a defined sequencing mechanism?

Thanks again so much. Very much appreciated!! :),

Application Customizers may or may not customize the rendering of the application. For example, if you want a timer job running in the background of your application w/o visual elements, you would not need to use placeholders.

We don't recommend creating an extension just for the sake of loading a library.

Right now, the best option is to make the external reference to your library (e.g. jQuery) in each extension separately (and the importing order would solve the problem). Unfortunately, this will result in bundling the library in each bundle file (for each extension/webpart) which is not optimal.

We are aware the issue and we're taking steps to make things simpler and more efficient for bundling third-party libraries and/or multiple SPFx component into one js file, and also particularly make it easier to use jQuery as a library in SPFx w/o having to bundle it for each component separately.

@moyali Thanks!! :)

Makes sense on the fact that an ACExt could simply execute logic, with no effect on the presentation layer of the application.

You said that currently, the best option would be to make an external reference to your libraries (e.g. jQuery) in each ACExt separately. This makes sense..sort of like a classic UCA that is using a ScriptLink property. You said 'the importing order would solve the problem' and I think this might be where I'm a little confused.

What do you mean by this? The reason I'm confused is I've not seen any specific properties around the order in which SP will parse or process the ACExt's. So if you have multiple ACExt's, each one loading a different JS file or JS library, how does SP choose the order in which each is loaded? Will it load it based on the order in which their created? The Order in which their added to the app catalog? Or perhaps some other property? Sorry for the confusion and I appreciate your patience. :)

Regarding the redundant loading of an external library or file that is being loaded by way of an Ext AND an SPFx web part, that makes total sense and I look forward to seeing what you guys cook up. :)

Thanks again!!!

The ordering of loading modules is taken care of by module loader by looking at package dependencies.
Also, inside each module, the bundler e.g. webpack can figure out the order of execution inside your bundle by looking at your 'import' (or 'require' statements depending on your js flavor) at bundle time. So, in a very summarized way, in the world of modular JavaScript the order of things are figured out by bundlers and loaders, as opposed to classic JS where you had to carefully craft the order of your script tags (e.g. jquery-ui after jquery).

I suggest looking into modular JS and how it works in general (out of SPFx context) to get a better picture.

Thanks for your interest. Build cool things with SPFx :)

@moyali thank you so much, that helps tremendously and will do much more research on the different bundlers!!

Correct me if I'm wrong, but the bundling, importing and modularizing is all done outside of the context of SPFx? While it may be done in VS using webpack, by the time it's ready for SP, it's been bundled?

If that's correct, I have just one more question (for now at least, lol), and really appreciate your help thus-far.

What happens if you have an organization that has built their own JS application architecture of functions, methods, etc and simply has no interest in using a separate bundler/loader.

I talk to alot of clients who are concerned with the rapid rise and fall of JS libraries and frameworks and the cost to maintain such libraries/frameworks when it comes to version updates and staff training and they prefer to manage their own classic JS proprietary architecture. (An entirely different conversation though..no doubt!) ;)

Their question is then simply, we need to be able to reference our own internally managed and 'bundled' JS files for use within SP in the Modern experience and we need to be able to define the exact sequential order of their loading, how can we do so?

I'm guessing, as it stands today, if one needs to accomplish the exact order of JS being loaded, then managing the loading of the JS within a single ACExt is the only way to ensure exact sequential loading of the individual JS files? They could simply use the TS SPFx moduleloader to sequentially load them I suppose?

Additionally, I'm afraid I did not see this the first time, but you had mentioned previously, "We don't recommend creating an extension just for the sake of loading a library." What is the alternative to load a JS file that is needed for every page in the application? Not necessarily a third party library or framework, such as jQuery or BS, but even a collection of proprietary functions, methods, etc...built using namespaacing best practices, etc by the organization.

So I guess that's a bit more then 'one' more question. But I do appreciate your help. Thanks... :)

We closed this issue as it had not activity within last 180 days. This is a generic process we have decided to perform for issues, which have not been explicitly marked still to be "work in progress" based on tags. We are performing this cleaning to make sure that old issues that have already been solved (but not closed) or are no longer relevant are cleaned out and make the issues more manageable. If this issue still valid, we would ask you to open a new issue and follow the guidance in the issue template related on the recommended location. We do apologize any inconveniences this might cause. Please do remember that issues in the issue lists are also messages for others in the community, so you can also check if you can assist on any of them. “Sharing is caring!”

This is the exact scenario we are in. @PopWarner have asked right questions but no acceptable responses :(
Any update on this?

We want to load our JS before the tag renders. Any solution on that? Tried ApplicationCustomizer but it is not we want because it is just inserting the reference on head tag after body tag renders.

Do you have any other solution on new SPFx v1.6?

@dmahendranme just curious, what is the functionality that your js is performing? Are you populating the SPFx Placeholders? Or something else altogether?

Thanks in advance! :)

Issues that have been closed & had no follow-up activity for at least 7 days are automatically locked. Please refer to our wiki for more details, including how to remediate this action if you feel this was done prematurely or in error: Issue List: Our approach to locked issues

Was this page helpful?
0 / 5 - 0 ratings

Related issues

waldekmastykarz picture waldekmastykarz  ·  3Comments

mikeparkie picture mikeparkie  ·  3Comments

SteIvanov picture SteIvanov  ·  3Comments

bengtmoss picture bengtmoss  ·  3Comments

StfBauer picture StfBauer  ·  3Comments