adams85 / bundling

A library for optimizing and bundling web assets of ASP.NET Core applications.
MIT License
44 stars 7 forks source link

Issue when script file has been modified outside of Visual studio #14

Closed josefinscreentek closed 2 years ago

josefinscreentek commented 3 years ago

Hi, I'm not sure if this has been mentioned before. But I have a problem with Karambolo.AspNetCore.Bundling.BundlingOptions and javascript files being modified outside of Visual Studio. If a file is modified when the solution isn't opened in Visual studio, no new version number is generated and you get an old version of the bundle when running localhost with no other way of getting a new version without adding yet another change (e.g. a space).

If it's not possible to fix within the package by you, is there a way to force it to update the version number in any way manually from Visual studio for all bundles? We have a lot of bundles in our solution, so it's not possible to manually make a change inside of each time e.g. after a merge from another branch where several files might have been changed outside of VS.

Thx

adams85 commented 3 years ago

Without details like library version, bundling mode used (run-time or design-time) and configuration it's hard to make an exact diagnosis. So it's just a wild guess but I suspect that "when the solution isn't opened in Visual studio", your application is running in Production mode, while in the other case (when it's open in VS) you run it in Development mode. (If you're not familiar with the concept of runtime environments, see the official docs on the topic.)

When using run-time bundling with default settings, the runtime environment makes a big difference, as it's also pointed out in the docs:

When hosting environment is set to Development, UseDefaults

  • enables change detection (cache invalidation on change of source files) and
  • enables including of source files instead of the actual bundled output (of course, this will apply only to bundles which allow this),

otherwise

  • enables minification.

As you can see, this implies that change detection is only enabled for Development environments by default. In Production mode source files are not watched. Bundles get built, versioned and cached on the first request and stay the same throughout the run of the application.

If you want change detection to happen in any circumstances, you need to force it like this:

services.AddBundling()
    .UseDefaults(Environment)
    .EnableChangeDetection()
    // ...

(Please note that the order of calls matter: EnableChangeDetection must come after UseDefaults.)

josefinscreentek commented 3 years ago

Thx for the quick answer. It might be that .EnableChangeDetection() is the solution. I will try that out. Otherwise, I'm using Microsoft Visual Studio Community 2019, Version 16.9.2 with the extension Karambolo.AspNetCore.Bundling, Version=3.4.0.0 (asfak)

What I meant with "when the solution isn't opened in Visual Studio", I mean that if I have the files locally on my PC without any environment opened. I then use e.g. TortoiseGit and do a merge between two branches and the js file is being changed and I save the change from TortoiseGit (I suppose the same thing would happen if I'd changed it in Notepad++ or similar editor as well).

When I then open the solution file in VS and run the project localhost as usual, then it doesn't detect that the file has been changed "outside of the system" and keeps the same version number.

It doesn't seem to be any problem in production environments. The problem occurs if you change a js file in a default editor when VS isn't opened, then it seems to not trigger a new version when building and running the project localhost.

josefinscreentek commented 3 years ago

EnableChangeDetection() seems to have done the trick. What is the reason that this setting is set to false by default?

Have I understood this correctly, that if it's a development environment (like localhost), then you want to use the combination of UseDefault() + EnableChangeDetection(), but on a production server, you don't want to use either of them (use min files)?

So you would actually want something like this in Startup.cs to achieve what I was asking about? Thx for helping out

          if (Environment.IsDevelopment())
            {
                services.AddBundling()
                    .UseDefaults(Environment)
                    .EnableChangeDetection()
                    .UseNUglify()
                    .AddLess()
                    .EnableCacheHeader(TimeSpan.FromDays(1));
            }
            else
            {
                services.AddBundling()
                    .UseNUglify()
                    .AddLess()
                    .EnableCacheHeader(TimeSpan.FromDays(1));
            }
adams85 commented 3 years ago

What I meant with "when the solution isn't opened in Visual Studio", I mean that if I have the files locally on my PC without any environment opened. I then use e.g. TortoiseGit and do a merge between two branches and the js file is being changed and I save the change from TortoiseGit (I suppose the same thing would happen if I'd changed it in Notepad++ or similar editor as well).

When I then open the solution file in VS and run the project localhost as usual, then it doesn't detect that the file has been changed "outside of the system" and keeps the same version number.

If you're using run-time bundling (and based on the config posted you are), this simply can't happen:

In the case of run-time mode, bundles get always completely rebuilt during each run of the project (at the first time when the bundle URL is encountered). When building a bundle, the library always reads the then current content of the source files from the file system. So it doesn't matter what application (git client, text editor or VS) modifies the files as long as the changes are made before running the project.

Even change detection has nothing to do with this as that only applies to changes which are made during (not before) execution.

When I then open the solution file in VS and run the project localhost as usual, then it doesn't detect that the file has been changed "outside of the system" and keeps the same version number.

I'm quite puzzled by this behavior but I'm pretty sure that it isn't caused by the library but something else. E.g. when I was doing tests, I noticed that the browser (Firefox) heavily caches the page sources (right click + View Page Sources). You need to hit F5 to view the actual content returned by the application. Without doing that it may seem that the bundle versions are not updated but the Network tab of Dev Tools clearly shows that they are. Can't this be the explanation for your observations, by any chance?

EnableChangeDetection() seems to have done the trick.

Now it gets even weirder. According to the above, having change detection on or off should be irrelevant to the issue.

What is the reason that this setting is set to false by default?

It's not. UseDefaults sets it to true for Development environments.

Have I understood this correctly, that if it's a development environment (like localhost), then you want to use the combination of UseDefault() + EnableChangeDetection(), but on a production server, you don't want to use either of them (use min files)?

Nope. Just take a look at the definition of UseDefaults and it'll be clear.

As you can see, the extra EnableChangeDetection call makes no difference in your setup. Having just

services.AddBundling()
    .UseDefaults(Environment)
    .UseNUglify()
    .AddLess()
    .EnableCacheHeader(TimeSpan.FromDays(1));

would achieve exactly the same.

You would add EnableChangeDetection if you wanted change detection in Production. This is what I talked about in my first comment. But this seems irrelevant in your case anyway.

So it's still inexplicable to me how EnableChangeDetection could solved the issue... I hope you can shed some light on this.

BTW, I suggest updating to v3.5.0. It comes with a bunch of improvements including support for this feature, which makes development more convenient. However, if you go for the upgrade, please note that the defaults for Development env changed slightly:

josefinscreentek commented 3 years ago

Sorry that I can't be more specific than that. What I did was like I said, I merged from one branch to another without having VS opened. When I then a couple of days later ran the project localhost, I noticed that some functionality was missing, that worked on the server and that I knew were part of the merge. I then checked the source file from Chrome developer tools and my "new" code was missing from the source file, hence things didn't work properly on localhost. I tried to restart VS, clean bin/obj, clean project etc, without any luck. I then posted the issue here and you advised me to try EnableChangeDetection(). When I added that to Startup.cs and ran the project localhost, the version number was updated and the "missing" code was visible from source tab in Chrome. The code was never missing from the physical file in VS, only runtime from localhost.

I will try and upgrade to v3.5.0 and if I experience this error again, I can write a new thread. The problem is that I don't know if this has happened to any file on the server (though I doubt it). This feels like a weird issue when running localhost.