Scripts in subfolder of Scripts directory / wrong script order

Topics: Core
Jul 1, 2013 at 1:50 PM
Edited Jul 1, 2013 at 2:00 PM
Hi,

I am trying to get some scripts inside subfolders of the Scripts directory to render correctly. This apparently doesn't work in Orchard?

I am experiencing some kind of bug with the following code:
public class ResourceManifest : IResourceManifestProvider
{
    public void BuildManifests(ResourceManifestBuilder builder)
    {
        global::Orchard.UI.Resources.ResourceManifest manifest = builder.Add();

        manifest.DefineScript("Common.namespace")
            .SetUrl("Common/namespace.js");

        manifest.DefineScript("FlightEngine.Models.FlightType")
            .SetUrl("FlightEngine/Models/FlightType.js")
            .SetDependencies("Common.namespace", "jQuery");

        manifest.DefineScript("FlightEngine.Search")
            .SetUrl("Search.js")
            .SetVersion("1.0.1")
            .SetDependencies("FlightEngine.Models.FlightType");
    }
}
output:
<script src="/Modules/FlightEngine/Scripts/Search.js" type="text/javascript"></script>
<script src="/Modules/FlightEngine/scripts/Common.namespace.js" type="text/javascript"></script>
<script src="/Modules/FlightEngine/scripts/FlightEngine.Models.FlightType.js" type="text/javascript"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.18/jquery.min.js" type="text/javascript"></script>
As you can see, the Search.js script is rendered FIRST even though it is dependent on the namespace.js and FlightType.js scripts (as declared in the ResourceManifest). It appears as if the only way it works is if I put the dependent scripts directly in the root of the 'Scripts' folder.
  • I tried looking at the code to see if there was something I could do; to no avail
  • I tried setting up IIS rewrite rules so I could register the scripts with underscores (to make Orchard believe the files are under the Scripts folder directly) instead of slashes and let IIS fixup the issue using a rewrite rule; --> didn't work because Orchard apparently checks the physical location of the file
  • I tried using absolute URLs -> this didn't work either (with SetUrl), in fact using SetCDN breaks the dependency chain completely as you can see from the jquery script that is rendered last in the example above (even though the code above it is dependent on it)
What could be the issue? is this a bug?

Thanks!

PS: I removed and manually adjusted some code to make the example more simple
PS2: Orchard v1.6.1
Coordinator
Jul 1, 2013 at 9:55 PM
Sounds like a bug, yes, but I'm wondering if you should maybe try ~/ rooted virtual paths instead of completely relative ones. All examples I see in the code are a single file name.
Jul 1, 2013 at 10:03 PM
I tried rooted virtual paths... it didn't work either :o(

And this also doesn't explain why CDNs don't work either...

Hopefully a fix will come with Orchard 1.7 as this is such an essential thing for modules with lots of script files!
Coordinator
Jul 2, 2013 at 12:57 AM
Only if you file a bug.
Developer
Jul 2, 2013 at 2:00 AM
Edited Jul 2, 2013 at 2:11 AM
It's a known issue. I swear I've opened it a while ago, but cannot find it now. Please file a new one.

The issue started happening when we started treating resources (Styles/Scripts) as shapes (ages ago) to allow easy overriding them by using alternates. And with that change came the necessity of discovering those resources when building a shape table, which is the source of the problem. Orchard scans only the root level of /Scripts and /Styles folders and does not recurse into subdirectories when discovering resource shapes. Because of this, all scripts residing in /Scripts will be treated as shapes and displayed accordingly, but those from subdirectories will be rendered directly to the response stream, ommitting the shape display pipeline (as those have no corresponding entry in Orchard shape table). So you'll end up with two separate groups being rendered instead of one (scripts from subdirs come first, then the rest) and possibly other weird behavior.

There is a simple solution to this which I've been using ever since. You need to tell Orchard to search subdirectories.
Add this class to your module and you're set:
    public class LibScriptsBindingStrategy : StaticFileBindingStrategy, IShapeTableProvider
    {
        public LibScriptsBindingStrategy(IExtensionManager extensionManager, ShellDescriptor shellDescriptor, IVirtualPathProvider virtualPathProvider)
            : base(extensionManager, shellDescriptor, virtualPathProvider) { }

        public override string GetFileExtension()
        {
            return ".js";
        }

        public override string GetFolder()
        {
            return "Scripts/libs";
        }

        public override string GetShapePrefix()
        {
            return "Script__";
        }
    }
Repeat this for each subdirectory containing script files. Same thing for stylesheets.
Oct 24, 2013 at 4:47 PM
Edited Oct 24, 2013 at 4:47 PM
Thank god I had seen this after spending several hours wondering the messed up order.
Oct 28, 2013 at 9:23 PM
Has this issue been fixed in the latest release of Orchard?